2008-01-24 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
10 //
11 #define USE_OLD
12
13 namespace Mono.CSharp {
14         using System;
15         using System.Collections;
16         using System.Reflection;
17         using System.Reflection.Emit;
18         using System.Text;
19
20         //
21         // This is an user operator expression, automatically created during
22         // resolve phase
23         //
24         public class UserOperatorCall : Expression {
25                 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
26
27                 readonly ArrayList arguments;
28                 readonly MethodGroupExpr mg;
29                 readonly ExpressionTreeExpression expr_tree;
30
31                 public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
32                 {
33                         this.mg = mg;
34                         this.arguments = args;
35                         this.expr_tree = expr_tree;
36
37                         type = ((MethodInfo)mg).ReturnType;
38                         eclass = ExprClass.Value;
39                         this.loc = loc;
40                 }
41
42                 public override Expression CreateExpressionTree (EmitContext ec)
43                 {
44                         if (expr_tree != null)
45                                 return expr_tree (ec, mg);
46
47                         ArrayList args = new ArrayList (arguments.Count + 1);
48                         args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
49                         args.Add (new Argument (mg.CreateExpressionTree (ec)));
50                         foreach (Argument a in arguments) {
51                                 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
52                         }
53
54                         return CreateExpressionFactoryCall ("Call", args);
55                 }
56
57                 public override Expression DoResolve (EmitContext ec)
58                 {
59                         //
60                         // We are born fully resolved
61                         //
62                         return this;
63                 }
64
65                 public override void Emit (EmitContext ec)
66                 {
67                         mg.EmitCall (ec, arguments);
68                 }
69
70                 [Obsolete ("It may not be compatible with expression trees")]
71                 static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
72                                                          Expression e, Location loc)
73                 {
74                         ArrayList args;
75                         
76                         args = new ArrayList (1);
77                         Argument a = new Argument (e, Argument.AType.Expression);
78
79                         // We need to resolve the arguments before sending them in !
80                         if (!a.Resolve (ec, loc))
81                                 return null;
82
83                         args.Add (a);
84                         mg = mg.OverloadResolve (ec, ref args, false, loc);
85
86                         if (mg == null)
87                                 return null;
88
89                         return new UserOperatorCall (mg, args, null, loc);
90                 }
91
92                 [Obsolete ("It may not be compatible with expression trees")]
93                 public MethodInfo Method {
94                         get { return (MethodInfo)mg; }
95                 }
96         }
97
98         public class ParenthesizedExpression : Expression
99         {
100                 public Expression Expr;
101
102                 public ParenthesizedExpression (Expression expr)
103                 {
104                         this.Expr = expr;
105                 }
106
107                 public override Expression DoResolve (EmitContext ec)
108                 {
109                         Expr = Expr.Resolve (ec);
110                         return Expr;
111                 }
112
113                 public override void Emit (EmitContext ec)
114                 {
115                         throw new Exception ("Should not happen");
116                 }
117
118                 public override Location Location
119                 {
120                         get {
121                                 return Expr.Location;
122                         }
123                 }
124
125                 protected override void CloneTo (CloneContext clonectx, Expression t)
126                 {
127                         ParenthesizedExpression target = (ParenthesizedExpression) t;
128
129                         target.Expr = Expr.Clone (clonectx);
130                 }
131         }
132         
133         //
134         //   Unary implements unary expressions.
135         //
136         public class Unary : Expression {
137                 public enum Operator : byte {
138                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
139                         Indirection, AddressOf,  TOP
140                 }
141
142                 public readonly Operator Oper;
143                 public Expression Expr;
144
145                 public Unary (Operator op, Expression expr, Location loc)
146                 {
147                         this.Oper = op;
148                         this.Expr = expr;
149                         this.loc = loc;
150                 }
151
152                 /// <summary>
153                 ///   Returns a stringified representation of the Operator
154                 /// </summary>
155                 static public string OperName (Operator oper)
156                 {
157                         switch (oper){
158                         case Operator.UnaryPlus:
159                                 return "+";
160                         case Operator.UnaryNegation:
161                                 return "-";
162                         case Operator.LogicalNot:
163                                 return "!";
164                         case Operator.OnesComplement:
165                                 return "~";
166                         case Operator.AddressOf:
167                                 return "&";
168                         case Operator.Indirection:
169                                 return "*";
170                         }
171
172                         return oper.ToString ();
173                 }
174
175                 public static readonly string [] oper_names;
176
177                 static Unary ()
178                 {
179                         oper_names = new string [(int)Operator.TOP];
180
181                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
182                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
183                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
184                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
185                         oper_names [(int) Operator.Indirection] = "op_Indirection";
186                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
187                 }
188
189                 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
190                 {
191                         Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
192                 }
193
194                 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
195                 {
196                         Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
197                                 oper, type);
198                 }
199
200                 void Error23 (Type t)
201                 {
202                         Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
203                 }
204
205                 // <summary>
206                 //   This routine will attempt to simplify the unary expression when the
207                 //   argument is a constant.
208                 // </summary>
209                 Constant TryReduceConstant (EmitContext ec, Constant e)
210                 {
211                         Type expr_type = e.Type;
212                         
213                         switch (Oper){
214                                 case Operator.UnaryPlus:
215                                         // Unary numeric promotions
216                                         if (expr_type == TypeManager.byte_type)
217                                                 return new IntConstant (((ByteConstant)e).Value, e.Location);
218                                         if (expr_type == TypeManager.sbyte_type)
219                                                 return new IntConstant (((SByteConstant)e).Value, e.Location);
220                                         if (expr_type == TypeManager.short_type)
221                                                 return new IntConstant (((ShortConstant)e).Value, e.Location);
222                                         if (expr_type == TypeManager.ushort_type)
223                                                 return new IntConstant (((UShortConstant)e).Value, e.Location);
224                                         if (expr_type == TypeManager.char_type)
225                                                 return new IntConstant (((CharConstant)e).Value, e.Location);
226
227                                         // Predefined operators
228                                         if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
229                                                 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
230                                                 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
231                                                 expr_type == TypeManager.decimal_type)
232                                         {
233                                                 return e;
234                                         }
235
236                                         return null;
237                                 
238                                 case Operator.UnaryNegation:
239                                         // Unary numeric promotions
240                                         if (expr_type == TypeManager.byte_type)
241                                                 return new IntConstant (-((ByteConstant)e).Value, e.Location);
242                                         if (expr_type == TypeManager.sbyte_type)
243                                                 return new IntConstant (-((SByteConstant)e).Value, e.Location);
244                                         if (expr_type == TypeManager.short_type)
245                                                 return new IntConstant (-((ShortConstant)e).Value, e.Location);
246                                         if (expr_type == TypeManager.ushort_type)
247                                                 return new IntConstant (-((UShortConstant)e).Value, e.Location);
248                                         if (expr_type == TypeManager.char_type)
249                                                 return new IntConstant (-((CharConstant)e).Value, e.Location);
250
251                                         // Predefined operators
252                                         if (expr_type == TypeManager.int32_type) {
253                                                 int value = ((IntConstant)e).Value;
254                                                 if (value == int.MinValue) {
255                                                         if (ec.ConstantCheckState) {
256                                                                 ConstantFold.Error_CompileTimeOverflow (loc);
257                                                                 return null;
258                                                         }
259                                                         return e;
260                                                 }
261                                                 return new IntConstant (-value, e.Location);
262                                         }
263                                         if (expr_type == TypeManager.int64_type) {
264                                                 long value = ((LongConstant)e).Value;
265                                                 if (value == long.MinValue) {
266                                                         if (ec.ConstantCheckState) {
267                                                                 ConstantFold.Error_CompileTimeOverflow (loc);
268                                                                 return null;
269                                                         }
270                                                         return e;
271                                                 }
272                                                 return new LongConstant (-value, e.Location);
273                                         }
274
275                                         if (expr_type == TypeManager.uint32_type) {
276                                                 UIntLiteral uil = e as UIntLiteral;
277                                                 if (uil != null) {
278                                                         if (uil.Value == 2147483648)
279                                                                 return new IntLiteral (int.MinValue, e.Location);
280                                                         return new LongLiteral (-uil.Value, e.Location);
281                                                 }
282                                                 return new LongConstant (-((UIntConstant)e).Value, e.Location);
283                                         }
284
285                                         if (expr_type == TypeManager.uint64_type) {
286                                                 ULongLiteral ull = e as ULongLiteral;
287                                                 if (ull != null && ull.Value == 9223372036854775808)
288                                                         return new LongLiteral (long.MinValue, e.Location);
289                                                 return null;
290                                         }
291
292                                         if (expr_type == TypeManager.float_type) {
293                                                 FloatLiteral fl = e as FloatLiteral;
294                                                 // For better error reporting
295                                                 if (fl != null) {
296                                                         fl.Value = -fl.Value;
297                                                         return fl;
298                                                 }
299                                                 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
300                                         }
301                                         if (expr_type == TypeManager.double_type) {
302                                                 DoubleLiteral dl = e as DoubleLiteral;
303                                                 // For better error reporting
304                                                 if (dl != null) {
305                                                         dl.Value = -dl.Value;
306                                                         return dl;
307                                                 }
308
309                                                 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
310                                         }
311                                         if (expr_type == TypeManager.decimal_type)
312                                                 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
313
314                                         return null;
315                                 
316                                 case Operator.LogicalNot:
317                                         if (expr_type != TypeManager.bool_type)
318                                                 return null;
319                                         
320                                         BoolConstant b = (BoolConstant) e;
321                                         return new BoolConstant (!(b.Value), b.Location);
322                                 
323                                 case Operator.OnesComplement:
324                                         // Unary numeric promotions
325                                         if (expr_type == TypeManager.byte_type)
326                                                 return new IntConstant (~((ByteConstant)e).Value, e.Location);
327                                         if (expr_type == TypeManager.sbyte_type)
328                                                 return new IntConstant (~((SByteConstant)e).Value, e.Location);
329                                         if (expr_type == TypeManager.short_type)
330                                                 return new IntConstant (~((ShortConstant)e).Value, e.Location);
331                                         if (expr_type == TypeManager.ushort_type)
332                                                 return new IntConstant (~((UShortConstant)e).Value, e.Location);
333                                         if (expr_type == TypeManager.char_type)
334                                                 return new IntConstant (~((CharConstant)e).Value, e.Location);
335
336                                         // Predefined operators
337                                         if (expr_type == TypeManager.int32_type)
338                                                 return new IntConstant (~((IntConstant)e).Value, e.Location);
339                                         if (expr_type == TypeManager.uint32_type)
340                                                 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
341                                         if (expr_type == TypeManager.int64_type)
342                                                 return new LongConstant (~((LongConstant)e).Value, e.Location);
343                                         if (expr_type == TypeManager.uint64_type){
344                                                 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
345                                         }
346                                         if (e is EnumConstant) {
347                                                 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
348                                                 if (e != null)
349                                                         e = new EnumConstant (e, expr_type);
350                                                 return e;
351                                         }
352                                         return null;
353
354                                 case Operator.AddressOf:
355                                         return e;
356
357                                 case Operator.Indirection:
358                                         return e;
359                         }
360                         throw new Exception ("Can not constant fold: " + Oper.ToString());
361                 }
362
363                 Expression ResolveOperator (EmitContext ec)
364                 {
365                         //
366                         // Step 1: Default operations on CLI native types.
367                         //
368
369                         // Attempt to use a constant folding operation.
370                         Constant cexpr = Expr as Constant;
371                         if (cexpr != null) {
372                                 cexpr = TryReduceConstant (ec, cexpr);
373                                 if (cexpr != null) {
374                                         return cexpr;
375                                 }
376                         }
377
378                         //
379                         // Step 2: Perform Operator Overload location
380                         //
381                         Type expr_type = Expr.Type;
382                         string op_name = oper_names [(int) Oper];
383
384                         MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
385                         if (user_op != null) {
386                                 ArrayList args = new ArrayList (1);
387                                 args.Add (new Argument (Expr));
388                                 user_op = user_op.OverloadResolve (ec, ref args, false, loc);
389
390                                 if (user_op == null) {
391                                         Error23 (expr_type);
392                                         return null;
393                                 }
394
395                                 return new UserOperatorCall (user_op, args, CreateExpressionTree, loc);
396                         }
397
398                         switch (Oper){
399                         case Operator.LogicalNot:
400                                 if (expr_type != TypeManager.bool_type) {
401                                         Expr = ResolveBoolean (ec, Expr, loc);
402                                         if (Expr == null){
403                                                 Error23 (expr_type);
404                                                 return null;
405                                         }
406                                 }
407                                 
408                                 type = TypeManager.bool_type;
409                                 return this;
410
411                         case Operator.OnesComplement:
412                                 // Unary numeric promotions
413                                 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
414                                         expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
415                                         expr_type == TypeManager.char_type) 
416                                 {
417                                         type = TypeManager.int32_type;
418                                         return EmptyCast.Create (this, type);
419                                 }
420
421                                 // Predefined operators
422                                 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
423                                         expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
424                                         TypeManager.IsEnumType (expr_type))
425                                 {
426                                         type = expr_type;
427                                         return this;
428                                 }
429
430                                 type = TypeManager.int32_type;
431                                 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
432                                 if (Expr != null)
433                                         return this;
434
435                                 Error23 (expr_type);
436                                 return null;
437
438                         case Operator.AddressOf:
439                                 if (!ec.InUnsafe) {
440                                         UnsafeError (loc); 
441                                         return null;
442                                 }
443                                 
444                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
445                                         return null;
446                                 }
447
448                                 IVariable variable = Expr as IVariable;
449                                 bool is_fixed = variable != null && variable.VerifyFixed ();
450
451                                 if (!ec.InFixedInitializer && !is_fixed) {
452                                         Error (212, "You can only take the address of unfixed expression inside " +
453                                                "of a fixed statement initializer");
454                                         return null;
455                                 }
456
457                                 if (ec.InFixedInitializer && is_fixed) {
458                                         Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
459                                         return null;
460                                 }
461
462                                 LocalVariableReference lr = Expr as LocalVariableReference;
463                                 if (lr != null){
464                                         if (lr.local_info.IsCaptured){
465                                                 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
466                                                 return null;
467                                         }
468                                         lr.local_info.AddressTaken = true;
469                                         lr.local_info.Used = true;
470                                 }
471
472                                 ParameterReference pr = Expr as ParameterReference;
473                                 if ((pr != null) && pr.Parameter.IsCaptured) {
474                                         AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
475                                         return null;
476                                 }
477
478                                 // According to the specs, a variable is considered definitely assigned if you take
479                                 // its address.
480                                 if ((variable != null) && (variable.VariableInfo != null)){
481                                         variable.VariableInfo.SetAssigned (ec);
482                                 }
483
484                                 type = TypeManager.GetPointerType (Expr.Type);
485                                 return this;
486
487                         case Operator.Indirection:
488                                 if (!ec.InUnsafe){
489                                         UnsafeError (loc);
490                                         return null;
491                                 }
492                                 
493                                 if (!expr_type.IsPointer){
494                                         Error (193, "The * or -> operator must be applied to a pointer");
495                                         return null;
496                                 }
497                                 
498                                 //
499                                 // We create an Indirection expression, because
500                                 // it can implement the IMemoryLocation.
501                                 // 
502                                 return new Indirection (Expr, loc);
503                         
504                         case Operator.UnaryPlus:
505                                 // Unary numeric promotions
506                                 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
507                                         expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
508                                         expr_type == TypeManager.char_type) 
509                                 {
510                                         return EmptyCast.Create (Expr, TypeManager.int32_type);
511                                 }
512
513                                 // Predefined operators
514                                 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
515                                         expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
516                                         expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
517                                         expr_type == TypeManager.decimal_type)
518                                 {
519                                         return Expr;
520                                 }
521
522                                 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
523                                 if (Expr != null) {
524                                          // Because we can completely ignore unary +
525                                         return Expr;
526                                 }
527
528                                 Error23 (expr_type);
529                                 return null;
530
531                         case Operator.UnaryNegation:
532                                 //
533                                 // transform - - expr into expr
534                                 //
535                                 Unary u = Expr as Unary;
536                                 if (u != null && u.Oper == Operator.UnaryNegation) {
537                                         return u.Expr;
538                                 }
539
540                                 // Unary numeric promotions
541                                 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
542                                         expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
543                                         expr_type == TypeManager.char_type) 
544                                 {
545                                         type = TypeManager.int32_type;
546                                         return EmptyCast.Create (this, type);
547                                 }
548
549                                 //
550                                 // Predefined operators
551                                 //
552                                 if (expr_type == TypeManager.uint32_type) {
553                                         type = TypeManager.int64_type;
554                                         Expr = Convert.ImplicitNumericConversion (Expr, type);
555                                         return this;
556                                 }
557
558                                 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type || 
559                                         expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
560                                         expr_type == TypeManager.decimal_type)
561                                 {
562                                         type = expr_type;
563                                         return this;
564                                 }
565
566                                 //
567                                 // User conversion
568
569                                 type = TypeManager.int32_type;
570                                 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
571                                 if (Expr != null)
572                                         return this;
573
574                                 Error23 (expr_type);
575                                 return null;
576                         }
577
578                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
579                                TypeManager.CSharpName (expr_type) + "'");
580                         return null;
581                 }
582
583                 public override Expression CreateExpressionTree (EmitContext ec)
584                 {
585                         return CreateExpressionTree (ec, null);
586                 }
587
588                 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
589                 {
590                         string method_name; 
591                         switch (Oper) {
592                                 case Operator.UnaryNegation:
593                                         method_name = "Negate";
594                                         break;
595
596                                 default:
597                                         throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
598                         }
599
600                         ArrayList args = new ArrayList (2);
601                         args.Add (new Argument (Expr.CreateExpressionTree (ec)));
602                         if (user_op != null)
603                                 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
604                         return CreateExpressionFactoryCall (method_name, args);
605                 }
606
607                 public override Expression DoResolve (EmitContext ec)
608                 {
609                         if (Oper == Operator.AddressOf) {
610                                 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
611
612                                 if (Expr == null || Expr.eclass != ExprClass.Variable){
613                                         Error (211, "Cannot take the address of the given expression");
614                                         return null;
615                                 }
616                         }
617                         else
618                                 Expr = Expr.Resolve (ec);
619
620                         if (Expr == null)
621                                 return null;
622
623 #if GMCS_SOURCE
624                         if (TypeManager.IsNullableValueType (Expr.Type))
625                                 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
626 #endif
627
628                         eclass = ExprClass.Value;
629                         return ResolveOperator (ec);
630                 }
631
632                 public override Expression DoResolveLValue (EmitContext ec, Expression right)
633                 {
634                         if (Oper == Operator.Indirection)
635                                 return DoResolve (ec);
636
637                         return null;
638                 }
639
640                 public override void Emit (EmitContext ec)
641                 {
642                         ILGenerator ig = ec.ig;
643
644                         switch (Oper) {
645                         case Operator.UnaryPlus:
646                                 throw new Exception ("This should be caught by Resolve");
647                                 
648                         case Operator.UnaryNegation:
649                                 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
650                                         ig.Emit (OpCodes.Ldc_I4_0);
651                                         if (type == TypeManager.int64_type)
652                                                 ig.Emit (OpCodes.Conv_U8);
653                                         Expr.Emit (ec);
654                                         ig.Emit (OpCodes.Sub_Ovf);
655                                 } else {
656                                         Expr.Emit (ec);
657                                         ig.Emit (OpCodes.Neg);
658                                 }
659                                 
660                                 break;
661                                 
662                         case Operator.LogicalNot:
663                                 Expr.Emit (ec);
664                                 ig.Emit (OpCodes.Ldc_I4_0);
665                                 ig.Emit (OpCodes.Ceq);
666                                 break;
667                                 
668                         case Operator.OnesComplement:
669                                 Expr.Emit (ec);
670                                 ig.Emit (OpCodes.Not);
671                                 break;
672                                 
673                         case Operator.AddressOf:
674                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
675                                 break;
676                                 
677                         default:
678                                 throw new Exception ("This should not happen: Operator = "
679                                                      + Oper.ToString ());
680                         }
681                 }
682
683                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
684                 {
685                         if (Oper == Operator.LogicalNot)
686                                 Expr.EmitBranchable (ec, target, !on_true);
687                         else
688                                 base.EmitBranchable (ec, target, on_true);
689                 }
690
691                 public override string ToString ()
692                 {
693                         return "Unary (" + Oper + ", " + Expr + ")";
694                 }
695
696                 protected override void CloneTo (CloneContext clonectx, Expression t)
697                 {
698                         Unary target = (Unary) t;
699
700                         target.Expr = Expr.Clone (clonectx);
701                 }
702         }
703
704         //
705         // Unary operators are turned into Indirection expressions
706         // after semantic analysis (this is so we can take the address
707         // of an indirection).
708         //
709         public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
710                 Expression expr;
711                 LocalTemporary temporary;
712                 bool prepared;
713                 
714                 public Indirection (Expression expr, Location l)
715                 {
716                         this.expr = expr;
717                         type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
718                         eclass = ExprClass.Variable;
719                         loc = l;
720                 }
721                 
722                 public override void Emit (EmitContext ec)
723                 {
724                         if (!prepared)
725                                 expr.Emit (ec);
726                         
727                         LoadFromPtr (ec.ig, Type);
728                 }
729
730                 public void Emit (EmitContext ec, bool leave_copy)
731                 {
732                         Emit (ec);
733                         if (leave_copy) {
734                                 ec.ig.Emit (OpCodes.Dup);
735                                 temporary = new LocalTemporary (expr.Type);
736                                 temporary.Store (ec);
737                         }
738                 }
739                 
740                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
741                 {
742                         prepared = prepare_for_load;
743                         
744                         expr.Emit (ec);
745
746                         if (prepare_for_load)
747                                 ec.ig.Emit (OpCodes.Dup);
748                         
749                         source.Emit (ec);
750                         if (leave_copy) {
751                                 ec.ig.Emit (OpCodes.Dup);
752                                 temporary = new LocalTemporary (expr.Type);
753                                 temporary.Store (ec);
754                         }
755                         
756                         StoreFromPtr (ec.ig, type);
757                         
758                         if (temporary != null) {
759                                 temporary.Emit (ec);
760                                 temporary.Release (ec);
761                         }
762                 }
763                 
764                 public void AddressOf (EmitContext ec, AddressOp Mode)
765                 {
766                         expr.Emit (ec);
767                 }
768
769                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
770                 {
771                         return DoResolve (ec);
772                 }
773
774                 public override Expression DoResolve (EmitContext ec)
775                 {
776                         //
777                         // Born fully resolved
778                         //
779                         return this;
780                 }
781                 
782                 public override string ToString ()
783                 {
784                         return "*(" + expr + ")";
785                 }
786
787                 #region IVariable Members
788
789                 public VariableInfo VariableInfo {
790                         get { return null; }
791                 }
792
793                 public bool VerifyFixed ()
794                 {
795                         // A pointer-indirection is always fixed.
796                         return true;
797                 }
798
799                 #endregion
800         }
801         
802         /// <summary>
803         ///   Unary Mutator expressions (pre and post ++ and --)
804         /// </summary>
805         ///
806         /// <remarks>
807         ///   UnaryMutator implements ++ and -- expressions.   It derives from
808         ///   ExpressionStatement becuase the pre/post increment/decrement
809         ///   operators can be used in a statement context.
810         ///
811         /// FIXME: Idea, we could split this up in two classes, one simpler
812         /// for the common case, and one with the extra fields for more complex
813         /// classes (indexers require temporary access;  overloaded require method)
814         ///
815         /// </remarks>
816         public class UnaryMutator : ExpressionStatement {
817                 [Flags]
818                 public enum Mode : byte {
819                         IsIncrement    = 0,
820                         IsDecrement    = 1,
821                         IsPre          = 0,
822                         IsPost         = 2,
823                         
824                         PreIncrement   = 0,
825                         PreDecrement   = IsDecrement,
826                         PostIncrement  = IsPost,
827                         PostDecrement  = IsPost | IsDecrement
828                 }
829
830                 Mode mode;
831                 bool is_expr = false;
832                 bool recurse = false;
833
834                 Expression expr;
835
836                 //
837                 // This is expensive for the simplest case.
838                 //
839                 UserOperatorCall method;
840
841                 public UnaryMutator (Mode m, Expression e, Location l)
842                 {
843                         mode = m;
844                         loc = l;
845                         expr = e;
846                 }
847
848                 static string OperName (Mode mode)
849                 {
850                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
851                                 "++" : "--";
852                 }
853
854                 /// <summary>
855                 ///   Returns whether an object of type `t' can be incremented
856                 ///   or decremented with add/sub (ie, basically whether we can
857                 ///   use pre-post incr-decr operations on it, but it is not a
858                 ///   System.Decimal, which we require operator overloading to catch)
859                 /// </summary>
860                 static bool IsIncrementableNumber (Type t)
861                 {
862                         return (t == TypeManager.sbyte_type) ||
863                                 (t == TypeManager.byte_type) ||
864                                 (t == TypeManager.short_type) ||
865                                 (t == TypeManager.ushort_type) ||
866                                 (t == TypeManager.int32_type) ||
867                                 (t == TypeManager.uint32_type) ||
868                                 (t == TypeManager.int64_type) ||
869                                 (t == TypeManager.uint64_type) ||
870                                 (t == TypeManager.char_type) ||
871                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
872                                 (t == TypeManager.float_type) ||
873                                 (t == TypeManager.double_type) ||
874                                 (t.IsPointer && t != TypeManager.void_ptr_type);
875                 }
876
877                 Expression ResolveOperator (EmitContext ec)
878                 {
879                         Type expr_type = expr.Type;
880
881                         //
882                         // Step 1: Perform Operator Overload location
883                         //
884                         Expression mg;
885                         string op_name;
886                         
887                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
888                                 op_name = "op_Increment";
889                         else 
890                                 op_name = "op_Decrement";
891
892                         mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
893
894                         if (mg != null) {
895                                 method = UserOperatorCall.MakeSimpleCall (
896                                         ec, (MethodGroupExpr) mg, expr, loc);
897
898                                 type = method.Type;
899                         } else if (!IsIncrementableNumber (expr_type)) {
900                                 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
901                                        TypeManager.CSharpName (expr_type) + "'");
902                                    return null;
903                         }
904
905                         //
906                         // The operand of the prefix/postfix increment decrement operators
907                         // should be an expression that is classified as a variable,
908                         // a property access or an indexer access
909                         //
910                         type = expr_type;
911                         if (expr.eclass == ExprClass.Variable){
912                                 LocalVariableReference var = expr as LocalVariableReference;
913                                 if ((var != null) && var.IsReadOnly) {
914                                         Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
915                                         return null;
916                                 }
917                         } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
918                                 expr = expr.ResolveLValue (ec, this, Location);
919                                 if (expr == null)
920                                         return null;
921                         } else {
922                                 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
923                                 return null;
924                         }
925
926                         return this;
927                 }
928
929                 public override Expression DoResolve (EmitContext ec)
930                 {
931                         expr = expr.Resolve (ec);
932                         
933                         if (expr == null)
934                                 return null;
935
936                         eclass = ExprClass.Value;
937
938 #if GMCS_SOURCE
939                         if (TypeManager.IsNullableValueType (expr.Type))
940                                 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
941 #endif
942
943                         return ResolveOperator (ec);
944                 }
945
946                 //
947                 // Loads the proper "1" into the stack based on the type, then it emits the
948                 // opcode for the operation requested
949                 //
950                 void LoadOneAndEmitOp (EmitContext ec, Type t)
951                 {
952                         //
953                         // Measure if getting the typecode and using that is more/less efficient
954                         // that comparing types.  t.GetTypeCode() is an internal call.
955                         //
956                         ILGenerator ig = ec.ig;
957                                                      
958                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
959                                 LongConstant.EmitLong (ig, 1);
960                         else if (t == TypeManager.double_type)
961                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
962                         else if (t == TypeManager.float_type)
963                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
964                         else if (t.IsPointer){
965                                 Type et = TypeManager.GetElementType (t);
966                                 int n = GetTypeSize (et);
967                                 
968                                 if (n == 0)
969                                         ig.Emit (OpCodes.Sizeof, et);
970                                 else
971                                         IntConstant.EmitInt (ig, n);
972                         } else 
973                                 ig.Emit (OpCodes.Ldc_I4_1);
974
975                         //
976                         // Now emit the operation
977                         //
978                         if (ec.CheckState){
979                                 if (t == TypeManager.int32_type ||
980                                     t == TypeManager.int64_type){
981                                         if ((mode & Mode.IsDecrement) != 0)
982                                                 ig.Emit (OpCodes.Sub_Ovf);
983                                         else
984                                                 ig.Emit (OpCodes.Add_Ovf);
985                                 } else if (t == TypeManager.uint32_type ||
986                                            t == TypeManager.uint64_type){
987                                         if ((mode & Mode.IsDecrement) != 0)
988                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
989                                         else
990                                                 ig.Emit (OpCodes.Add_Ovf_Un);
991                                 } else {
992                                         if ((mode & Mode.IsDecrement) != 0)
993                                                 ig.Emit (OpCodes.Sub_Ovf);
994                                         else
995                                                 ig.Emit (OpCodes.Add_Ovf);
996                                 }
997                         } else {
998                                 if ((mode & Mode.IsDecrement) != 0)
999                                         ig.Emit (OpCodes.Sub);
1000                                 else
1001                                         ig.Emit (OpCodes.Add);
1002                         }
1003
1004                         if (t == TypeManager.sbyte_type){
1005                                 if (ec.CheckState)
1006                                         ig.Emit (OpCodes.Conv_Ovf_I1);
1007                                 else
1008                                         ig.Emit (OpCodes.Conv_I1);
1009                         } else if (t == TypeManager.byte_type){
1010                                 if (ec.CheckState)
1011                                         ig.Emit (OpCodes.Conv_Ovf_U1);
1012                                 else
1013                                         ig.Emit (OpCodes.Conv_U1);
1014                         } else if (t == TypeManager.short_type){
1015                                 if (ec.CheckState)
1016                                         ig.Emit (OpCodes.Conv_Ovf_I2);
1017                                 else
1018                                         ig.Emit (OpCodes.Conv_I2);
1019                         } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1020                                 if (ec.CheckState)
1021                                         ig.Emit (OpCodes.Conv_Ovf_U2);
1022                                 else
1023                                         ig.Emit (OpCodes.Conv_U2);
1024                         }
1025                         
1026                 }
1027
1028                 void EmitCode (EmitContext ec, bool is_expr)
1029                 {
1030                         recurse = true;
1031                         this.is_expr = is_expr;
1032                         ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1033                 }
1034
1035                 public override void Emit (EmitContext ec)
1036                 {
1037                         //
1038                         // We use recurse to allow ourselfs to be the source
1039                         // of an assignment. This little hack prevents us from
1040                         // having to allocate another expression
1041                         //
1042                         if (recurse) {
1043                                 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1044                                 if (method == null)
1045                                         LoadOneAndEmitOp (ec, expr.Type);
1046                                 else
1047                                         ec.ig.Emit (OpCodes.Call, method.Method);
1048                                 recurse = false;
1049                                 return;
1050                         }
1051
1052                         EmitCode (ec, true);
1053                 }
1054
1055                 public override void EmitStatement (EmitContext ec)
1056                 {
1057                         EmitCode (ec, false);
1058                 }
1059
1060                 protected override void CloneTo (CloneContext clonectx, Expression t)
1061                 {
1062                         UnaryMutator target = (UnaryMutator) t;
1063
1064                         target.expr = expr.Clone (clonectx);
1065                 }
1066         }
1067
1068         /// <summary>
1069         ///   Base class for the `Is' and `As' classes. 
1070         /// </summary>
1071         ///
1072         /// <remarks>
1073         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
1074         ///   size. 
1075         /// </remarks>
1076         public abstract class Probe : Expression {
1077                 public Expression ProbeType;
1078                 protected Expression expr;
1079                 protected TypeExpr probe_type_expr;
1080                 
1081                 public Probe (Expression expr, Expression probe_type, Location l)
1082                 {
1083                         ProbeType = probe_type;
1084                         loc = l;
1085                         this.expr = expr;
1086                 }
1087
1088                 public Expression Expr {
1089                         get {
1090                                 return expr;
1091                         }
1092                 }
1093
1094                 public override Expression DoResolve (EmitContext ec)
1095                 {
1096                         probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1097                         if (probe_type_expr == null)
1098                                 return null;
1099
1100                         expr = expr.Resolve (ec);
1101                         if (expr == null)
1102                                 return null;
1103                         
1104                         if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1105                                 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1106                                         OperatorName);
1107                                 return null;
1108                         }
1109
1110                         if (expr.Type == TypeManager.anonymous_method_type) {
1111                                 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1112                                         OperatorName);
1113                                 return null;
1114                         }
1115
1116                         return this;
1117                 }
1118
1119                 protected abstract string OperatorName { get; }
1120
1121                 protected override void CloneTo (CloneContext clonectx, Expression t)
1122                 {
1123                         Probe target = (Probe) t;
1124
1125                         target.expr = expr.Clone (clonectx);
1126                         target.ProbeType = ProbeType.Clone (clonectx);
1127                 }
1128
1129         }
1130
1131         /// <summary>
1132         ///   Implementation of the `is' operator.
1133         /// </summary>
1134         public class Is : Probe {
1135                 public Is (Expression expr, Expression probe_type, Location l)
1136                         : base (expr, probe_type, l)
1137                 {
1138                 }
1139                 
1140                 public override void Emit (EmitContext ec)
1141                 {
1142                         ILGenerator ig = ec.ig;
1143
1144                         expr.Emit (ec);
1145                         ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1146                         ig.Emit (OpCodes.Ldnull);
1147                         ig.Emit (OpCodes.Cgt_Un);
1148                 }
1149
1150                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1151                 {
1152                         ILGenerator ig = ec.ig;
1153
1154                         expr.Emit (ec);
1155                         ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1156                         ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1157                 }
1158
1159                 Expression CreateConstantResult (bool result)
1160                 {
1161                         if (result)
1162                                 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1163                                         TypeManager.CSharpName (probe_type_expr.Type));
1164                         else
1165                                 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1166                                         TypeManager.CSharpName (probe_type_expr.Type));
1167
1168                         return new BoolConstant (result, loc);
1169                 }
1170
1171                 public override Expression DoResolve (EmitContext ec)
1172                 {
1173                         if (base.DoResolve (ec) == null)
1174                                 return null;
1175
1176                         Type d = expr.Type;
1177                         bool d_is_nullable = false;
1178
1179                         if (expr is Constant) {
1180                                 //
1181                                 // If E is a method group or the null literal, of if the type of E is a reference
1182                                 // type or a nullable type and the value of E is null, the result is false
1183                                 //
1184                                 if (expr.IsNull)
1185                                         return CreateConstantResult (false);
1186                         } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1187                                 d = TypeManager.GetTypeArguments (d) [0];
1188                                 d_is_nullable = true;
1189                         }
1190
1191                         type = TypeManager.bool_type;
1192                         eclass = ExprClass.Value;
1193                         Type t = probe_type_expr.Type;
1194                         bool t_is_nullable = false;
1195                         if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1196                                 t = TypeManager.GetTypeArguments (t) [0];
1197                                 t_is_nullable = true;
1198                         }
1199
1200                         if (t.IsValueType) {
1201                                 if (d == t) {
1202                                         //
1203                                         // D and T are the same value types but D can be null
1204                                         //
1205                                         if (d_is_nullable && !t_is_nullable)
1206                                                 return Nullable.HasValue.Create (expr, ec);
1207                                         
1208                                         //
1209                                         // The result is true if D and T are the same value types
1210                                         //
1211                                         return CreateConstantResult (true);
1212                                 }
1213
1214                                 if (TypeManager.IsGenericParameter (d))
1215                                         return ResolveGenericParameter (t, d);
1216
1217                                 //
1218                                 // An unboxing conversion exists
1219                                 //
1220                                 if (Convert.ExplicitReferenceConversionExists (d, t))
1221                                         return this;
1222                         } else {
1223                                 if (TypeManager.IsGenericParameter (t))
1224                                         return ResolveGenericParameter (d, t);
1225
1226                                 if (d.IsValueType) {
1227                                         bool temp;
1228                                         if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1229                                                 return CreateConstantResult (true);
1230                                 } else {
1231                                         if (TypeManager.IsGenericParameter (d))
1232                                                 return ResolveGenericParameter (t, d);
1233
1234                                         if (TypeManager.ContainsGenericParameters (d))
1235                                                 return this;
1236
1237                                         if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1238                                                 Convert.ExplicitReferenceConversionExists (d, t)) {
1239                                                 return this;
1240                                         }
1241                                 }
1242                         }
1243
1244                         return CreateConstantResult (false);
1245                 }
1246
1247                 Expression ResolveGenericParameter (Type d, Type t)
1248                 {
1249 #if GMCS_SOURCE
1250                         GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1251                         if (constraints != null) {
1252                                 if (constraints.IsReferenceType && d.IsValueType)
1253                                         return CreateConstantResult (false);
1254
1255                                 if (constraints.IsValueType && !d.IsValueType)
1256                                         return CreateConstantResult (false);
1257                         }
1258
1259                         expr = new BoxedCast (expr, d);
1260                         return this;
1261 #else
1262                         return null;
1263 #endif
1264                 }
1265                 
1266                 protected override string OperatorName {
1267                         get { return "is"; }
1268                 }
1269         }
1270
1271         /// <summary>
1272         ///   Implementation of the `as' operator.
1273         /// </summary>
1274         public class As : Probe {
1275                 public As (Expression expr, Expression probe_type, Location l)
1276                         : base (expr, probe_type, l)
1277                 {
1278                 }
1279
1280                 bool do_isinst = false;
1281                 Expression resolved_type;
1282                 
1283                 public override void Emit (EmitContext ec)
1284                 {
1285                         ILGenerator ig = ec.ig;
1286
1287                         expr.Emit (ec);
1288
1289                         if (do_isinst)
1290                                 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1291
1292 #if GMCS_SOURCE
1293                         if (TypeManager.IsNullableType (type))
1294                                 ig.Emit (OpCodes.Unbox_Any, type);
1295 #endif
1296                 }
1297
1298                 static void Error_CannotConvertType (Type source, Type target, Location loc)
1299                 {
1300                         Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1301                                 TypeManager.CSharpName (source),
1302                                 TypeManager.CSharpName (target));
1303                 }
1304                 
1305                 public override Expression DoResolve (EmitContext ec)
1306                 {
1307                         if (resolved_type == null) {
1308                                 resolved_type = base.DoResolve (ec);
1309
1310                                 if (resolved_type == null)
1311                                         return null;
1312                         }
1313
1314                         type = probe_type_expr.Type;
1315                         eclass = ExprClass.Value;
1316                         Type etype = expr.Type;
1317
1318                         if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1319                                 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1320                                               TypeManager.CSharpName (type));
1321                                 return null;
1322                         
1323                         }
1324
1325 #if GMCS_SOURCE
1326                         //
1327                         // If the type is a type parameter, ensure
1328                         // that it is constrained by a class
1329                         //
1330                         TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1331                         if (tpe != null){
1332                                 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1333                                 bool error = false;
1334                                 
1335                                 if (constraints == null)
1336                                         error = true;
1337                                 else {
1338                                         if (!constraints.HasClassConstraint)
1339                                                 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1340                                                         error = true;
1341                                 }
1342                                 if (error){
1343                                         Report.Error (413, loc,
1344                                                       "The as operator requires that the `{0}' type parameter be constrained by a class",
1345                                                       probe_type_expr.GetSignatureForError ());
1346                                         return null;
1347                                 }
1348                         }
1349 #endif
1350                         if (expr.IsNull && TypeManager.IsNullableType (type)) {
1351                                 Report.Warning (458, 2, loc, "The result of the expression is always `null' of type `{0}'",
1352                                         TypeManager.CSharpName (type));
1353                         }
1354                         
1355                         Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1356                         if (e != null){
1357                                 expr = e;
1358                                 do_isinst = false;
1359                                 return this;
1360                         }
1361
1362                         if (Convert.ExplicitReferenceConversionExists (etype, type)){
1363                                 if (TypeManager.IsGenericParameter (etype))
1364                                         expr = new BoxedCast (expr, etype);
1365
1366                                 do_isinst = true;
1367                                 return this;
1368                         }
1369
1370                         if (TypeManager.ContainsGenericParameters (etype) ||
1371                             TypeManager.ContainsGenericParameters (type)) {
1372                                 expr = new BoxedCast (expr, etype);
1373                                 do_isinst = true;
1374                                 return this;
1375                         }
1376
1377                         Error_CannotConvertType (etype, type, loc);
1378                         return null;
1379                 }
1380
1381                 protected override string OperatorName {
1382                         get { return "as"; }
1383                 }
1384         
1385                 public override bool GetAttributableValue (Type value_type, out object value)
1386                 {
1387                         return expr.GetAttributableValue (value_type, out value);
1388                 }
1389         }
1390         
1391         /// <summary>
1392         ///   This represents a typecast in the source language.
1393         ///
1394         ///   FIXME: Cast expressions have an unusual set of parsing
1395         ///   rules, we need to figure those out.
1396         /// </summary>
1397         public class Cast : Expression {
1398                 Expression target_type;
1399                 Expression expr;
1400                         
1401                 public Cast (Expression cast_type, Expression expr)
1402                         : this (cast_type, expr, cast_type.Location)
1403                 {
1404                 }
1405
1406                 public Cast (Expression cast_type, Expression expr, Location loc)
1407                 {
1408                         this.target_type = cast_type;
1409                         this.expr = expr;
1410                         this.loc = loc;
1411
1412                         if (target_type == TypeManager.system_void_expr)
1413                                 Error_VoidInvalidInTheContext (loc);
1414                 }
1415
1416                 public Expression TargetType {
1417                         get { return target_type; }
1418                 }
1419
1420                 public Expression Expr {
1421                         get { return expr; }
1422                 }
1423
1424                 public override Expression DoResolve (EmitContext ec)
1425                 {
1426                         expr = expr.Resolve (ec);
1427                         if (expr == null)
1428                                 return null;
1429
1430                         TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1431                         if (target == null)
1432                                 return null;
1433
1434                         type = target.Type;
1435
1436                         if (type.IsAbstract && type.IsSealed) {
1437                                 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1438                                 return null;
1439                         }
1440
1441                         eclass = ExprClass.Value;
1442
1443                         Constant c = expr as Constant;
1444                         if (c != null) {
1445                                 c = c.TryReduce (ec, type, loc);
1446                                 if (c != null)
1447                                         return c;
1448                         }
1449
1450                         if (type.IsPointer && !ec.InUnsafe) {
1451                                 UnsafeError (loc);
1452                                 return null;
1453                         }
1454                         expr = Convert.ExplicitConversion (ec, expr, type, loc);
1455                         return expr;
1456                 }
1457                 
1458                 public override void Emit (EmitContext ec)
1459                 {
1460                         throw new Exception ("Should not happen");
1461                 }
1462
1463                 protected override void CloneTo (CloneContext clonectx, Expression t)
1464                 {
1465                         Cast target = (Cast) t;
1466
1467                         target.target_type = target_type.Clone (clonectx);
1468                         target.expr = expr.Clone (clonectx);
1469                 }
1470         }
1471         
1472         //
1473         // C# 2.0 Default value expression
1474         //
1475         public class DefaultValueExpression : Expression
1476         {
1477                 Expression expr;
1478
1479                 public DefaultValueExpression (Expression expr, Location loc)
1480                 {
1481                         this.expr = expr;
1482                         this.loc = loc;
1483                 }
1484
1485                 public override Expression DoResolve (EmitContext ec)
1486                 {
1487                         TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1488                         if (texpr == null)
1489                                 return null;
1490
1491                         type = texpr.Type;
1492
1493                         if (type == TypeManager.void_type) {
1494                                 Error_VoidInvalidInTheContext (loc);
1495                                 return null;
1496                         }
1497
1498                         if (TypeManager.IsGenericParameter (type))
1499                         {
1500                                 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1501                                 if (constraints != null && constraints.IsReferenceType)
1502                                         return new NullDefault (new NullLiteral (Location), type);
1503                         }
1504                         else
1505                         {
1506                                 Constant c = New.Constantify(type);
1507                                 if (c != null)
1508                                         return new NullDefault (c, type);
1509
1510                                 if (!TypeManager.IsValueType (type))
1511                                         return new NullDefault (new NullLiteral (Location), type);
1512                         }
1513                         eclass = ExprClass.Variable;
1514                         return this;
1515                 }
1516
1517                 public override void Emit (EmitContext ec)
1518                 {
1519                         LocalTemporary temp_storage = new LocalTemporary(type);
1520
1521                         temp_storage.AddressOf(ec, AddressOp.LoadStore);
1522                         ec.ig.Emit(OpCodes.Initobj, type);
1523                         temp_storage.Emit(ec);
1524                 }
1525                 
1526                 protected override void CloneTo (CloneContext clonectx, Expression t)
1527                 {
1528                         DefaultValueExpression target = (DefaultValueExpression) t;
1529                         
1530                         target.expr = expr.Clone (clonectx);
1531                 }
1532         }
1533
1534         /// <summary>
1535         ///   Binary operators
1536         /// </summary>
1537         public class Binary : Expression {
1538                 public enum Operator : byte {
1539                         Multiply, Division, Modulus,
1540                         Addition, Subtraction,
1541                         LeftShift, RightShift,
1542                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1543                         Equality, Inequality,
1544                         BitwiseAnd,
1545                         ExclusiveOr,
1546                         BitwiseOr,
1547                         LogicalAnd,
1548                         LogicalOr,
1549                         TOP
1550                 }
1551
1552                 readonly Operator oper;
1553                 protected Expression left, right;
1554                 readonly bool is_compound;
1555
1556                 // This must be kept in sync with Operator!!!
1557                 public static readonly string [] oper_names;
1558                 
1559                 static Binary ()
1560                 {
1561                         oper_names = new string [(int) Operator.TOP];
1562
1563                         oper_names [(int) Operator.Multiply] = "op_Multiply";
1564                         oper_names [(int) Operator.Division] = "op_Division";
1565                         oper_names [(int) Operator.Modulus] = "op_Modulus";
1566                         oper_names [(int) Operator.Addition] = "op_Addition";
1567                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1568                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1569                         oper_names [(int) Operator.RightShift] = "op_RightShift";
1570                         oper_names [(int) Operator.LessThan] = "op_LessThan";
1571                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1572                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1573                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1574                         oper_names [(int) Operator.Equality] = "op_Equality";
1575                         oper_names [(int) Operator.Inequality] = "op_Inequality";
1576                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1577                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1578                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1579                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1580                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1581                 }
1582
1583                 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1584                         : this (oper, left, right)
1585                 {
1586                         this.is_compound = isCompound;
1587                 }
1588
1589                 public Binary (Operator oper, Expression left, Expression right)
1590                 {
1591                         this.oper = oper;
1592                         this.left = left;
1593                         this.right = right;
1594                         this.loc = left.Location;
1595                 }
1596
1597                 public Operator Oper {
1598                         get {
1599                                 return oper;
1600                         }
1601                 }
1602                 
1603                 /// <summary>
1604                 ///   Returns a stringified representation of the Operator
1605                 /// </summary>
1606                 string OperName (Operator oper)
1607                 {
1608                         string s;
1609                         switch (oper){
1610                         case Operator.Multiply:
1611                                 s = "*";
1612                                 break;
1613                         case Operator.Division:
1614                                 s = "/";
1615                                 break;
1616                         case Operator.Modulus:
1617                                 s = "%";
1618                                 break;
1619                         case Operator.Addition:
1620                                 s = "+";
1621                                 break;
1622                         case Operator.Subtraction:
1623                                 s = "-";
1624                                 break;
1625                         case Operator.LeftShift:
1626                                 s = "<<";
1627                                 break;
1628                         case Operator.RightShift:
1629                                 s = ">>";
1630                                 break;
1631                         case Operator.LessThan:
1632                                 s = "<";
1633                                 break;
1634                         case Operator.GreaterThan:
1635                                 s = ">";
1636                                 break;
1637                         case Operator.LessThanOrEqual:
1638                                 s = "<=";
1639                                 break;
1640                         case Operator.GreaterThanOrEqual:
1641                                 s = ">=";
1642                                 break;
1643                         case Operator.Equality:
1644                                 s = "==";
1645                                 break;
1646                         case Operator.Inequality:
1647                                 s = "!=";
1648                                 break;
1649                         case Operator.BitwiseAnd:
1650                                 s = "&";
1651                                 break;
1652                         case Operator.BitwiseOr:
1653                                 s = "|";
1654                                 break;
1655                         case Operator.ExclusiveOr:
1656                                 s = "^";
1657                                 break;
1658                         case Operator.LogicalOr:
1659                                 s = "||";
1660                                 break;
1661                         case Operator.LogicalAnd:
1662                                 s = "&&";
1663                                 break;
1664                         default:
1665                                 s = oper.ToString ();
1666                                 break;
1667                         }
1668
1669                         if (is_compound)
1670                                 return s + "=";
1671
1672                         return s;
1673                 }
1674
1675                 public override string ToString ()
1676                 {
1677                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1678                                 right.ToString () + ")";
1679                 }
1680                 
1681                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1682                 {
1683                         if (expr.Type == target_type)
1684                                 return expr;
1685
1686                         return Convert.ImplicitConversion (ec, expr, target_type, loc);
1687                 }
1688
1689                 void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1690                 {
1691                         Report.Error (
1692                                 34, loc, "Operator `" + OperName (oper) 
1693                                 + "' is ambiguous on operands of type `"
1694                                 + TypeManager.CSharpName (l) + "' "
1695                                 + "and `" + TypeManager.CSharpName (r)
1696                                 + "'");
1697                 }
1698
1699                 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1700                 {
1701                         return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1702                 }
1703
1704                 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1705                 {
1706                         if (!IsConvertible (ec, left, right, t))
1707                                 return false;
1708                         left = ForceConversion (ec, left, t);
1709                         right = ForceConversion (ec, right, t);
1710                         type = t;
1711                         return true;
1712                 }
1713
1714                 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1715                 {
1716                         bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1717                         bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1718
1719                         if (oper == Operator.Equality || oper == Operator.Inequality)
1720                                 return l && r;
1721                         if (oper == Operator.Addition)
1722                                 return l || r;
1723                         return false;
1724                 }
1725
1726                 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1727                 {
1728                         if (!IsApplicable_String (ec, left, right, oper))
1729                                 return false;
1730                         
1731                         Type l = left.Type;
1732                         Type r = right.Type;
1733                         if (OverloadResolve_PredefinedIntegral (ec) ||
1734                                 OverloadResolve_PredefinedFloating (ec)) {
1735                                 Error_OperatorAmbiguous (loc, oper, l, r);
1736                         }
1737                         
1738                         Type t = TypeManager.string_type;
1739                         if (Convert.ImplicitConversionExists (ec, left, t))
1740                                 left = ForceConversion (ec, left, t);
1741                         if (Convert.ImplicitConversionExists (ec, right, t))
1742                                 right = ForceConversion (ec, right, t);
1743                         type = t;
1744                         return true;
1745                 }
1746
1747                 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1748                 {
1749                         return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1750                                 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1751                                 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1752                                 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1753                                 false;
1754                 }
1755
1756                 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1757                 {
1758                         return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1759                                 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1760                                 false;
1761                 }
1762
1763                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1764                 {
1765                         Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1766                 }
1767
1768                 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1769                 {
1770                         Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1771                                 name, left, right);
1772                 }
1773                 
1774                 protected void Error_OperatorCannotBeApplied ()
1775                 {
1776                         Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1777                                 TypeManager.CSharpName(right.Type));
1778                 }
1779
1780                 static bool IsUnsigned (Type t)
1781                 {
1782                         while (t.IsPointer)
1783                                 t = t.GetElementType ();
1784
1785                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1786                                 t == TypeManager.ushort_type || t == TypeManager.byte_type);
1787                 }
1788
1789                 Expression Make32or64 (EmitContext ec, Expression e)
1790                 {
1791                         Type t= e.Type;
1792                         
1793                         if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1794                             t == TypeManager.int64_type || t == TypeManager.uint64_type)
1795                                 return e;
1796                         Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1797                         if (ee != null)
1798                                 return ee;
1799                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1800                         if (ee != null)
1801                                 return ee;
1802                         ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1803                         if (ee != null)
1804                                 return ee;
1805                         ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1806                         if (ee != null)
1807                                 return ee;
1808                         return null;
1809                 }
1810                                         
1811                 Expression CheckShiftArguments (EmitContext ec)
1812                 {
1813                         Expression new_left = Make32or64 (ec, left);
1814                         Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1815                         if (new_left == null || new_right == null) {
1816                                 Error_OperatorCannotBeApplied ();
1817                                 return null;
1818                         }
1819                         type = new_left.Type;
1820                         int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1821                         left = new_left;
1822                         right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1823                         return this;
1824                 }
1825
1826                 //
1827                 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1828                 // i.e., not invoke op_Equality.
1829                 //
1830                 static bool EqualsNullIsReferenceEquals (Type t)
1831                 {
1832                         return t == TypeManager.object_type || t == TypeManager.string_type ||
1833                                 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1834                 }
1835
1836                 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1837                 {
1838                         Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1839                                 "Possible unintended reference comparison; to get a value comparison, " +
1840                                 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1841                 }
1842
1843                 static void Warning_Constant_Result (Location loc, bool result, Type type)
1844                 {
1845                         Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1846                                         "This operation is undocumented and it is temporary supported for compatibility reasons only",
1847                                         TypeManager.CSharpName (type), result ? "true" : "false"); 
1848                 }
1849                         
1850                 Expression ResolveOperator (EmitContext ec)
1851                 {
1852                         Type l = left.Type;
1853                         Type r = right.Type;
1854
1855                         if (oper == Operator.Equality || oper == Operator.Inequality){
1856                                 if (right.Type == TypeManager.null_type){
1857                                         if (TypeManager.IsGenericParameter (l)){
1858                                                 if (l.BaseType == TypeManager.value_type) {
1859                                                         Error_OperatorCannotBeApplied ();
1860                                                         return null;
1861                                                 }
1862                                                 
1863                                                 left = new BoxedCast (left, TypeManager.object_type);
1864                                                 Type = TypeManager.bool_type;
1865                                                 return this;
1866                                         } 
1867
1868                                         //
1869                                         // 7.9.9 Equality operators and null
1870                                         //
1871                                         // CSC 2 has this behavior, it allows structs to be compared
1872                                         // with the null literal *outside* of a generics context and
1873                                         // inlines that as true or false.
1874                                         //
1875                                         // This is, in my opinion, completely wrong.
1876                                         //
1877                                         if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType) {
1878                                                 if (!TypeManager.IsPrimitiveType (l) && !TypeManager.IsEnumType (l)) {
1879                                                         if (MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
1880                                                                 MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
1881                                                                 Error_OperatorCannotBeApplied ();
1882                                                                 return null;
1883                                                         }
1884                                                 }
1885
1886                                                 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1887                                                 return new BoolConstant (oper == Operator.Inequality, loc);
1888                                         }
1889                                 }
1890
1891                                 if (left is NullLiteral){
1892                                         if (TypeManager.IsGenericParameter (r)){
1893                                                 if (r.BaseType == TypeManager.value_type) {
1894                                                         Error_OperatorCannotBeApplied ();
1895                                                         return null;
1896                                                 }
1897                                                 
1898                                                 right = new BoxedCast (right, TypeManager.object_type);
1899                                                 Type = TypeManager.bool_type;
1900                                                 return this;
1901                                         }
1902
1903                                         //
1904                                         // 7.9.9 Equality operators and null
1905                                         //
1906                                         // CSC 2 has this behavior, it allows structs to be compared
1907                                         // with the null literal *outside* of a generics context and
1908                                         // inlines that as true or false.
1909                                         //
1910                                         // This is, in my opinion, completely wrong.
1911                                         //
1912                                         if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1913                                                 if (!TypeManager.IsPrimitiveType (r) && !TypeManager.IsEnumType (r)) {
1914                                                         if (MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
1915                                                                 MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
1916                                                                 Error_OperatorCannotBeApplied ();
1917                                                                 return null;
1918                                                         }
1919                                                 }
1920
1921                                                 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1922                                                 return new BoolConstant (oper == Operator.Inequality, loc);
1923                                         }
1924                                 }
1925
1926                                 //
1927                                 // Optimize out call to op_Equality in a few cases.
1928                                 //
1929                                 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1930                                     (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1931                                         Type = TypeManager.bool_type;
1932                                         return this;
1933                                 }
1934
1935                                 // IntPtr equality
1936                                 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1937                                         Type = TypeManager.bool_type;
1938                                         return this;
1939                                 }
1940
1941 #if GMCS_SOURCE                                                                                         
1942                                 //
1943                                 // Delegate equality
1944                                 //
1945                                 MethodGroupExpr mg = null;
1946                                 Type delegate_type = null;
1947                                 if (left.eclass == ExprClass.MethodGroup) {
1948                                         if (!TypeManager.IsDelegateType(r)) {
1949                                                 Error_OperatorCannotBeApplied(Location, OperName(oper),
1950                                                         left.ExprClassName, right.ExprClassName);
1951                                                 return null;
1952                                         }
1953                                         mg = (MethodGroupExpr)left;
1954                                         delegate_type = r;
1955                                 } else if (right.eclass == ExprClass.MethodGroup) {
1956                                         if (!TypeManager.IsDelegateType(l)) {
1957                                                 Error_OperatorCannotBeApplied(Location, OperName(oper),
1958                                                         left.ExprClassName, right.ExprClassName);
1959                                                 return null;
1960                                         }
1961                                         mg = (MethodGroupExpr)right;
1962                                         delegate_type = l;
1963                                 }
1964
1965                                 if (mg != null) {
1966                                         Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1967                                         if (e == null)
1968                                                 return null;
1969
1970                                         // Find operator method
1971                                         string op = oper_names[(int)oper];
1972                                         MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1973                                                 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1974
1975                                         ArrayList args = new ArrayList(2);
1976                                         args.Add(new Argument(e, Argument.AType.Expression));
1977                                         if (delegate_type == l)
1978                                                 args.Insert(0, new Argument(left, Argument.AType.Expression));
1979                                         else
1980                                                 args.Add(new Argument(right, Argument.AType.Expression));
1981
1982                                         return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1983                                 }
1984 #endif                          
1985                                 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1986                                         Error_OperatorCannotBeApplied(Location, OperName(oper),
1987                                                 left.ExprClassName, right.ExprClassName);
1988                                         return null;
1989                                 }                               
1990                         }
1991
1992
1993                         //
1994                         // Do not perform operator overload resolution when both sides are
1995                         // built-in types
1996                         //
1997                         MethodGroupExpr left_operators = null, right_operators = null;
1998                         if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1999                                 //
2000                                 // Step 1: Perform Operator Overload location
2001                                 //
2002                                 string op = oper_names [(int) oper];
2003
2004                                 MethodGroupExpr union;
2005                                 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2006                                 if (r != l){
2007                                         right_operators = MemberLookup (
2008                                                 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2009                                         union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2010                                 } else
2011                                         union = left_operators;
2012
2013                                 if (union != null) {
2014                                         ArrayList args = new ArrayList (2);
2015                                         args.Add (new Argument (left, Argument.AType.Expression));
2016                                         args.Add (new Argument (right, Argument.AType.Expression));
2017
2018                                         union = union.OverloadResolve (ec, ref args, true, Location.Null);
2019
2020                                         if (union != null) {
2021                                                 MethodInfo mi = (MethodInfo) union;
2022                                                 return new BinaryMethod (mi.ReturnType, mi, args);
2023                                         }
2024                                 }
2025                         }
2026
2027                         //
2028                         // String concatenation
2029                         // 
2030                         // string operator + (string x, string y);
2031                         // string operator + (string x, object y);
2032                         // string operator + (object x, string y);
2033                         //
2034                         if (oper == Operator.Addition && !TypeManager.IsDelegateType (l)) {
2035                                 // 
2036                                 // Either left or right expression is implicitly convertible to string
2037                                 //
2038                                 if (OverloadResolve_PredefinedString (ec, oper)) {
2039                                         if (r == TypeManager.void_type || l == TypeManager.void_type) {
2040                                                 Error_OperatorCannotBeApplied ();
2041                                                 return null;
2042                                         }
2043
2044                                         //
2045                                         // Constants folding for strings and nulls
2046                                         //
2047                                         if (left.Type == TypeManager.string_type && right.Type == TypeManager.string_type &&
2048                                                 left is Constant && right is Constant) {
2049                                                 string lvalue = (string)((Constant) left).GetValue ();
2050                                                 string rvalue = (string)((Constant) right).GetValue ();
2051                                                 return new StringConstant (lvalue + rvalue, left.Location);
2052                                         }
2053
2054                                         // 
2055                                         // Append to existing string concatenation
2056                                         //
2057                                         if (left is StringConcat) {
2058                                                 ((StringConcat) left).Append (ec, right);
2059                                                 return left;
2060                                         }
2061
2062                                         //
2063                                         // Otherwise, start a new concat expression using converted expression
2064                                         //
2065                                         return new StringConcat (ec, loc, left, right).Resolve (ec);
2066                                 }
2067
2068                                 //
2069                                 // Transform a + ( - b) into a - b
2070                                 //
2071                                 if (right is Unary){
2072                                         Unary right_unary = (Unary) right;
2073
2074                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
2075                                                 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
2076                                         }
2077                                 }
2078                         }
2079
2080                         if (oper == Operator.Equality || oper == Operator.Inequality){
2081                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2082                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2083                                                 Error_OperatorCannotBeApplied ();
2084                                                 return null;
2085                                         }
2086
2087                                         type = TypeManager.bool_type;
2088                                         return this;
2089                                 }
2090
2091                                 if (l.IsPointer || r.IsPointer) {
2092                                         if (l.IsPointer && r.IsPointer) {
2093                                                 type = TypeManager.bool_type;
2094                                                 return this;
2095                                         }
2096
2097                                         if (l.IsPointer && r == TypeManager.null_type) {
2098                                                 right = new EmptyConstantCast (NullPointer.Null, l);
2099                                                 type = TypeManager.bool_type;
2100                                                 return this;
2101                                         }
2102
2103                                         if (r.IsPointer && l == TypeManager.null_type) {
2104                                                 left = new EmptyConstantCast (NullPointer.Null, r);
2105                                                 type = TypeManager.bool_type;
2106                                                 return this;
2107                                         }
2108                                 }
2109
2110 #if GMCS_SOURCE
2111                                 if (l.IsGenericParameter && r.IsGenericParameter) {
2112                                         GenericConstraints l_gc, r_gc;
2113
2114                                         l_gc = TypeManager.GetTypeParameterConstraints (l);
2115                                         r_gc = TypeManager.GetTypeParameterConstraints (r);
2116
2117                                         if ((l_gc == null) || (r_gc == null) ||
2118                                             !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
2119                                             !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
2120                                                 Error_OperatorCannotBeApplied ();
2121                                                 return null;
2122                                         }
2123
2124                                 }
2125 #endif
2126
2127                                 //
2128                                 // operator != (object a, object b)
2129                                 // operator == (object a, object b)
2130                                 //
2131                                 // For this to be used, both arguments have to be reference-types.
2132                                 // Read the rationale on the spec (14.9.6)
2133                                 //
2134                                 if (!(l.IsValueType || r.IsValueType)){
2135                                         type = TypeManager.bool_type;
2136
2137                                         if (l == r)
2138                                                 return this;
2139                                         
2140                                         //
2141                                         // Also, a standard conversion must exist from either one
2142                                         //
2143                                         // NOTE: An interface is converted to the object before the
2144                                         // standard conversion is applied. It's not clear from the
2145                                         // standard but it looks like it works like that.
2146                                         //
2147                                         if (l.IsInterface)
2148                                                 l = TypeManager.object_type;
2149                                         if (r.IsInterface)
2150                                                 r = TypeManager.object_type;                                    
2151                                         
2152                                         bool left_to_right =
2153                                                 Convert.ImplicitStandardConversionExists (left, r);
2154                                         bool right_to_left = !left_to_right &&
2155                                                 Convert.ImplicitStandardConversionExists (right, l);
2156
2157                                         if (!left_to_right && !right_to_left) {
2158                                                 Error_OperatorCannotBeApplied ();
2159                                                 return null;
2160                                         }
2161
2162                                         if (left_to_right && left_operators != null &&
2163                                             Report.WarningLevel >= 2) {
2164                                                 ArrayList args = new ArrayList (2);
2165                                                 args.Add (new Argument (left, Argument.AType.Expression));
2166                                                 args.Add (new Argument (left, Argument.AType.Expression));
2167                                                 if (left_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
2168                                                         Warning_UnintendedReferenceComparison (loc, "right", l);
2169                                         }
2170
2171                                         if (right_to_left && right_operators != null &&
2172                                             Report.WarningLevel >= 2) {
2173                                                 ArrayList args = new ArrayList (2);
2174                                                 args.Add (new Argument (right, Argument.AType.Expression));
2175                                                 args.Add (new Argument (right, Argument.AType.Expression));
2176                                                 if (right_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
2177                                                         Warning_UnintendedReferenceComparison (loc, "left", r);
2178                                         }
2179
2180                                         //
2181                                         // We are going to have to convert to an object to compare
2182                                         //
2183                                         if (l != TypeManager.object_type)
2184                                                 left = EmptyCast.Create (left, TypeManager.object_type);
2185                                         if (r != TypeManager.object_type)
2186                                                 right = EmptyCast.Create (right, TypeManager.object_type);
2187
2188                                         return this;
2189                                 }
2190                         }
2191
2192                         // Only perform numeric promotions on:
2193                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2194                         //
2195                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2196                                 if (TypeManager.IsDelegateType (l)){
2197                                         if (((right.eclass == ExprClass.MethodGroup) ||
2198                                              (r == TypeManager.anonymous_method_type))){
2199                                                 if ((RootContext.Version != LanguageVersion.ISO_1)){
2200                                                         Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2201                                                         if (tmp == null)
2202                                                                 return null;
2203                                                         right = tmp;
2204                                                         r = right.Type;
2205                                                 }
2206                                         }
2207
2208                                         if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2209                                                 MethodInfo method;
2210                                                 ArrayList args = new ArrayList (2);
2211                                         
2212                                                 args = new ArrayList (2);
2213                                                 args.Add (new Argument (left, Argument.AType.Expression));
2214                                                 args.Add (new Argument (right, Argument.AType.Expression));
2215                                         
2216                                                 if (oper == Operator.Addition)
2217                                                         method = TypeManager.delegate_combine_delegate_delegate;
2218                                                 else
2219                                                         method = TypeManager.delegate_remove_delegate_delegate;
2220
2221                                                 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2222                                                         Error_OperatorCannotBeApplied ();
2223                                                         return null;
2224                                                 }
2225
2226                                                 return new BinaryDelegate (l, method, args);
2227                                         }
2228                                 }
2229
2230                                 //
2231                                 // Pointer arithmetic:
2232                                 //
2233                                 // T* operator + (T* x, int y);
2234                                 // T* operator + (T* x, uint y);
2235                                 // T* operator + (T* x, long y);
2236                                 // T* operator + (T* x, ulong y);
2237                                 //
2238                                 // T* operator + (int y,   T* x);
2239                                 // T* operator + (uint y,  T *x);
2240                                 // T* operator + (long y,  T *x);
2241                                 // T* operator + (ulong y, T *x);
2242                                 //
2243                                 // T* operator - (T* x, int y);
2244                                 // T* operator - (T* x, uint y);
2245                                 // T* operator - (T* x, long y);
2246                                 // T* operator - (T* x, ulong y);
2247                                 //
2248                                 // long operator - (T* x, T *y)
2249                                 //
2250                                 if (l.IsPointer){
2251                                         if (r.IsPointer && oper == Operator.Subtraction){
2252                                                 if (r == l)
2253                                                         return new PointerArithmetic (
2254                                                                 false, left, right, TypeManager.int64_type,
2255                                                                 loc).Resolve (ec);
2256                                         } else {
2257                                                 Expression t = Make32or64 (ec, right);
2258                                                 if (t != null)
2259                                                         return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2260                                         }
2261                                 } else if (r.IsPointer && oper == Operator.Addition){
2262                                         Expression t = Make32or64 (ec, left);
2263                                         if (t != null)
2264                                                 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2265                                 }
2266                         }
2267                         
2268                         //
2269                         // Enumeration operators
2270                         //
2271                         bool lie = TypeManager.IsEnumType (l);
2272                         bool rie = TypeManager.IsEnumType (r);
2273                         if (lie || rie){
2274                                 Expression temp;
2275
2276                                 // U operator - (E e, E f)
2277                                 if (lie && rie){
2278                                         if (oper == Operator.Subtraction){
2279                                                 if (l == r){
2280                                                         type = TypeManager.EnumToUnderlying (l);
2281                                                         return this;
2282                                                 }
2283                                                 Error_OperatorCannotBeApplied ();
2284                                                 return null;
2285                                         }
2286                                 }
2287                                         
2288                                 //
2289                                 // operator + (E e, U x)
2290                                 // operator - (E e, U x)
2291                                 //
2292                                 if (oper == Operator.Addition || oper == Operator.Subtraction){
2293                                         Type enum_type = lie ? l : r;
2294                                         Type other_type = lie ? r : l;
2295                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2296                                         
2297                                         if (underlying_type != other_type){
2298                                                 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2299                                                 if (temp != null){
2300                                                         if (lie)
2301                                                                 right = temp;
2302                                                         else
2303                                                                 left = temp;
2304                                                         type = enum_type;
2305                                                         return this;
2306                                                 }
2307                                                         
2308                                                 Error_OperatorCannotBeApplied ();
2309                                                 return null;
2310                                         }
2311
2312                                         type = enum_type;
2313                                         return this;
2314                                 }
2315                                 
2316                                 if (!rie){
2317                                         temp = Convert.ImplicitConversion (ec, right, l, loc);
2318                                         if (temp != null)
2319                                                 right = temp;
2320                                         else {
2321                                                 Error_OperatorCannotBeApplied ();
2322                                                 return null;
2323                                         }
2324                                 } if (!lie){
2325                                         temp = Convert.ImplicitConversion (ec, left, r, loc);
2326                                         if (temp != null){
2327                                                 left = temp;
2328                                                 l = r;
2329                                         } else {
2330                                                 Error_OperatorCannotBeApplied ();
2331                                                 return null;
2332                                         }
2333                                 }
2334
2335                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2336                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2337                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2338                                         if (left.Type != right.Type){
2339                                                 Error_OperatorCannotBeApplied ();
2340                                                 return null;
2341                                         }
2342                                         type = TypeManager.bool_type;
2343                                         return this;
2344                                 }
2345
2346                                 if (oper == Operator.BitwiseAnd ||
2347                                     oper == Operator.BitwiseOr ||
2348                                     oper == Operator.ExclusiveOr){
2349                                         if (left.Type != right.Type){
2350                                                 Error_OperatorCannotBeApplied ();
2351                                                 return null;
2352                                         }
2353                                         type = l;
2354                                         return this;
2355                                 }
2356                                 Error_OperatorCannotBeApplied ();
2357                                 return null;
2358                         }
2359                         
2360                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2361                                 return CheckShiftArguments (ec);
2362
2363                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2364                                 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2365                                         type = TypeManager.bool_type;
2366                                         return this;
2367                                 }
2368
2369                                 Expression left_operators_e = l == TypeManager.bool_type ?
2370                                         left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2371                                 Expression right_operators_e = r == TypeManager.bool_type ?
2372                                         right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2373
2374                                 if (left_operators_e != null && right_operators_e != null) {
2375                                         left = left_operators_e;
2376                                         right = right_operators_e;
2377                                         type = TypeManager.bool_type;
2378                                         return this;
2379                                 }
2380
2381                                 Expression e = new ConditionalLogicalOperator (
2382                                         oper == Operator.LogicalAnd, left, right, l, loc);
2383                                 return e.Resolve (ec);
2384                         } 
2385
2386                         Expression orig_left = left;
2387                         Expression orig_right = right;
2388
2389                         //
2390                         // operator & (bool x, bool y)
2391                         // operator | (bool x, bool y)
2392                         // operator ^ (bool x, bool y)
2393                         //
2394                         if (oper == Operator.BitwiseAnd ||
2395                             oper == Operator.BitwiseOr ||
2396                             oper == Operator.ExclusiveOr) {
2397                                 if (OverloadResolve_PredefinedIntegral (ec)) {
2398                                         if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2399                                                 Error_OperatorAmbiguous (loc, oper, l, r);
2400                                                 return null;
2401                                         }
2402
2403                                         if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2404                                                 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2405                                                  r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2406                                                         Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2407                                                                 TypeManager.CSharpName (r));
2408                                         }
2409                                         
2410                                 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2411                                         Error_OperatorCannotBeApplied ();
2412                                         return null;
2413                                 }
2414                                 return this;
2415                         }
2416                         
2417                         //
2418                         // Pointer comparison
2419                         //
2420                         if (l.IsPointer && r.IsPointer){
2421                                 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2422                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2423                                         type = TypeManager.bool_type;
2424                                         return this;
2425                                 }
2426                         }
2427
2428                         if (OverloadResolve_PredefinedIntegral (ec)) {
2429                                 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2430                                         Error_OperatorAmbiguous (loc, oper, l, r);
2431                                         return null;
2432                                 }
2433                         } else if (OverloadResolve_PredefinedFloating (ec)) {
2434                                 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2435                                     IsApplicable_String (ec, orig_left, orig_right, oper)) {
2436                                         Error_OperatorAmbiguous (loc, oper, l, r);
2437                                         return null;
2438                                 }
2439                         } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2440                                 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2441                                         Error_OperatorAmbiguous (loc, oper, l, r);
2442                                         return null;
2443                                 }
2444                         } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2445                                 Error_OperatorCannotBeApplied ();
2446                                 return null;
2447                         }
2448
2449                         if (oper == Operator.Equality ||
2450                             oper == Operator.Inequality ||
2451                             oper == Operator.LessThanOrEqual ||
2452                             oper == Operator.LessThan ||
2453                             oper == Operator.GreaterThanOrEqual ||
2454                             oper == Operator.GreaterThan)
2455                                 type = TypeManager.bool_type;
2456
2457                         l = left.Type;
2458                         r = right.Type;
2459
2460                         if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2461                                 Type lookup = l;
2462                                 if (r == TypeManager.string_type)
2463                                         lookup = r;
2464                                 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2465                                         ec.ContainerType, lookup, oper_names [(int) oper],
2466                                         MemberTypes.Method, AllBindingFlags, loc);
2467                                 ArrayList args = new ArrayList (2);
2468                                 args.Add (new Argument (left, Argument.AType.Expression));
2469                                 args.Add (new Argument (right, Argument.AType.Expression));
2470                                 ops = ops.OverloadResolve (ec, ref args, true, Location.Null);
2471                                 return new BinaryMethod (type, (MethodInfo)ops, args);
2472                         }
2473
2474                         return this;
2475                 }
2476
2477                 Constant EnumLiftUp (Constant left, Constant right)
2478                 {
2479                         switch (oper) {
2480                                 case Operator.BitwiseOr:
2481                                 case Operator.BitwiseAnd:
2482                                 case Operator.ExclusiveOr:
2483                                 case Operator.Equality:
2484                                 case Operator.Inequality:
2485                                 case Operator.LessThan:
2486                                 case Operator.LessThanOrEqual:
2487                                 case Operator.GreaterThan:
2488                                 case Operator.GreaterThanOrEqual:
2489                                         if (left is EnumConstant)
2490                                                 return left;
2491
2492                                         if (left.IsZeroInteger)
2493                                                 return new EnumConstant (left, right.Type);
2494
2495                                         break;
2496
2497                                 case Operator.Addition:
2498                                 case Operator.Subtraction:
2499                                         return left;
2500
2501                                 case Operator.Multiply:
2502                                 case Operator.Division:
2503                                 case Operator.Modulus:
2504                                 case Operator.LeftShift:
2505                                 case Operator.RightShift:
2506                                         if (right is EnumConstant || left is EnumConstant)
2507                                                 break;
2508                                         return left;
2509                         }
2510                         Error_OperatorCannotBeApplied ();
2511                         return null;
2512                 }
2513
2514                 public override Expression DoResolve (EmitContext ec)
2515                 {
2516                         if (left == null)
2517                                 return null;
2518
2519                         if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2520                                 left = ((ParenthesizedExpression) left).Expr;
2521                                 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2522                                 if (left == null)
2523                                         return null;
2524
2525                                 if (left.eclass == ExprClass.Type) {
2526                                         Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2527                                         return null;
2528                                 }
2529                         } else
2530                                 left = left.Resolve (ec);
2531
2532                         if (left == null)
2533                                 return null;
2534
2535                         Constant lc = left as Constant;
2536                         if (lc != null && lc.Type == TypeManager.bool_type && 
2537                                 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2538                                  (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2539
2540                                 // TODO: make a sense to resolve unreachable expression as we do for statement
2541                                 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2542                                 return left;
2543                         }
2544
2545                         right = right.Resolve (ec);
2546                         if (right == null)
2547                                 return null;
2548
2549                         eclass = ExprClass.Value;
2550                         Constant rc = right as Constant;
2551
2552                         // The conversion rules are ignored in enum context but why
2553                         if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2554                                 left = lc = EnumLiftUp (lc, rc);
2555                                 if (lc == null)
2556                                         return null;
2557
2558                                 right = rc = EnumLiftUp (rc, lc);
2559                                 if (rc == null)
2560                                         return null;
2561                         }
2562
2563                         if (oper == Operator.BitwiseAnd) {
2564                                 if (rc != null && rc.IsZeroInteger) {
2565                                         return lc is EnumConstant ?
2566                                                 new EnumConstant (rc, lc.Type):
2567                                                 rc;
2568                                 }
2569
2570                                 if (lc != null && lc.IsZeroInteger) {
2571                                         return rc is EnumConstant ?
2572                                                 new EnumConstant (lc, rc.Type):
2573                                                 lc;
2574                                 }
2575                         }
2576                         else if (oper == Operator.BitwiseOr) {
2577                                 if (lc is EnumConstant &&
2578                                     rc != null && rc.IsZeroInteger)
2579                                         return lc;
2580                                 if (rc is EnumConstant &&
2581                                     lc != null && lc.IsZeroInteger)
2582                                         return rc;
2583                         } else if (oper == Operator.LogicalAnd) {
2584                                 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2585                                         return rc;
2586                                 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2587                                         return lc;
2588                         }
2589
2590                         if (rc != null && lc != null){
2591                                 int prev_e = Report.Errors;
2592                                 Expression e = ConstantFold.BinaryFold (
2593                                         ec, oper, lc, rc, loc);
2594                                 if (e != null || Report.Errors != prev_e)
2595                                         return e;
2596                         }
2597
2598 #if GMCS_SOURCE
2599                         if ((left is NullLiteral || left.Type.IsValueType) &&
2600                             (right is NullLiteral || right.Type.IsValueType) &&
2601                             !(left is NullLiteral && right is NullLiteral) &&
2602                             (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2603                                 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2604 #endif
2605
2606                         // Comparison warnings
2607                         if (oper == Operator.Equality || oper == Operator.Inequality ||
2608                             oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2609                             oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2610                                 if (left.Equals (right)) {
2611                                         Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2612                                 }
2613                                 CheckUselessComparison (lc, right.Type);
2614                                 CheckUselessComparison (rc, left.Type);
2615                         }
2616
2617                         return ResolveOperator (ec);
2618                 }
2619
2620                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2621                 {
2622                         return null;
2623                 }
2624
2625                 private void CheckUselessComparison (Constant c, Type type)
2626                 {
2627                         if (c == null || !IsTypeIntegral (type)
2628                                 || c is StringConstant
2629                                 || c is BoolConstant
2630                                 || c is FloatConstant
2631                                 || c is DoubleConstant
2632                                 || c is DecimalConstant
2633                                 )
2634                                 return;
2635
2636                         long value = 0;
2637
2638                         if (c is ULongConstant) {
2639                                 ulong uvalue = ((ULongConstant) c).Value;
2640                                 if (uvalue > long.MaxValue) {
2641                                         if (type == TypeManager.byte_type ||
2642                                             type == TypeManager.sbyte_type ||
2643                                             type == TypeManager.short_type ||
2644                                             type == TypeManager.ushort_type ||
2645                                             type == TypeManager.int32_type ||
2646                                             type == TypeManager.uint32_type ||
2647                                             type == TypeManager.int64_type ||
2648                                                 type == TypeManager.char_type)
2649                                                 WarnUselessComparison (type);
2650                                         return;
2651                                 }
2652                                 value = (long) uvalue;
2653                         }
2654                         else if (c is ByteConstant)
2655                                 value = ((ByteConstant) c).Value;
2656                         else if (c is SByteConstant)
2657                                 value = ((SByteConstant) c).Value;
2658                         else if (c is ShortConstant)
2659                                 value = ((ShortConstant) c).Value;
2660                         else if (c is UShortConstant)
2661                                 value = ((UShortConstant) c).Value;
2662                         else if (c is IntConstant)
2663                                 value = ((IntConstant) c).Value;
2664                         else if (c is UIntConstant)
2665                                 value = ((UIntConstant) c).Value;
2666                         else if (c is LongConstant)
2667                                 value = ((LongConstant) c).Value;
2668                         else if (c is CharConstant)
2669                                 value = ((CharConstant)c).Value;
2670
2671                         if (value == 0)
2672                                 return;
2673
2674                         if (IsValueOutOfRange (value, type))
2675                                 WarnUselessComparison (type);
2676                 }
2677
2678                 private bool IsValueOutOfRange (long value, Type type)
2679                 {
2680                         if (IsTypeUnsigned (type) && value < 0)
2681                                 return true;
2682                         return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2683                                 type == TypeManager.byte_type && value >= 0x100 ||
2684                                 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2685                                 type == TypeManager.ushort_type && value >= 0x10000 ||
2686                                 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2687                                 type == TypeManager.uint32_type && value >= 0x100000000;
2688                 }
2689
2690                 private static bool IsTypeIntegral (Type type)
2691                 {
2692                         return type == TypeManager.uint64_type ||
2693                                 type == TypeManager.int64_type ||
2694                                 type == TypeManager.uint32_type ||
2695                                 type == TypeManager.int32_type ||
2696                                 type == TypeManager.ushort_type ||
2697                                 type == TypeManager.short_type ||
2698                                 type == TypeManager.sbyte_type ||
2699                                 type == TypeManager.byte_type ||
2700                                 type == TypeManager.char_type;
2701                 }
2702
2703                 private static bool IsTypeUnsigned (Type type)
2704                 {
2705                         return type == TypeManager.uint64_type ||
2706                                 type == TypeManager.uint32_type ||
2707                                 type == TypeManager.ushort_type ||
2708                                 type == TypeManager.byte_type ||
2709                                 type == TypeManager.char_type;
2710                 }
2711
2712                 private void WarnUselessComparison (Type type)
2713                 {
2714                         Report.Warning (652, 2, loc, "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
2715                                 TypeManager.CSharpName (type));
2716                 }
2717
2718                 /// <remarks>
2719                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2720                 ///   context of a conditional bool expression.  This function will return
2721                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2722                 ///
2723                 ///   The expression's code is generated, and we will generate a branch to `target'
2724                 ///   if the resulting expression value is equal to isTrue
2725                 /// </remarks>
2726                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2727                 {
2728                         ILGenerator ig = ec.ig;
2729
2730                         //
2731                         // This is more complicated than it looks, but its just to avoid
2732                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2733                         // but on top of that we want for == and != to use a special path
2734                         // if we are comparing against null
2735                         //
2736                         if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2737                                 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
2738                                 
2739                                 //
2740                                 // put the constant on the rhs, for simplicity
2741                                 //
2742                                 if (left is Constant) {
2743                                         Expression swap = right;
2744                                         right = left;
2745                                         left = swap;
2746                                 }
2747                                 
2748                                 if (((Constant) right).IsZeroInteger) {
2749                                         left.Emit (ec);
2750                                         if (my_on_true)
2751                                                 ig.Emit (OpCodes.Brtrue, target);
2752                                         else
2753                                                 ig.Emit (OpCodes.Brfalse, target);
2754                                         
2755                                         return;
2756                                 } else if (right is BoolConstant) {
2757                                         left.Emit (ec);
2758                                         if (my_on_true != ((BoolConstant) right).Value)
2759                                                 ig.Emit (OpCodes.Brtrue, target);
2760                                         else
2761                                                 ig.Emit (OpCodes.Brfalse, target);
2762                                         
2763                                         return;
2764                                 }
2765
2766                         } else if (oper == Operator.LogicalAnd) {
2767
2768                                 if (on_true) {
2769                                         Label tests_end = ig.DefineLabel ();
2770                                         
2771                                         left.EmitBranchable (ec, tests_end, false);
2772                                         right.EmitBranchable (ec, target, true);
2773                                         ig.MarkLabel (tests_end);                                       
2774                                 } else {
2775                                         //
2776                                         // This optimizes code like this 
2777                                         // if (true && i > 4)
2778                                         //
2779                                         if (!(left is Constant))
2780                                                 left.EmitBranchable (ec, target, false);
2781
2782                                         if (!(right is Constant)) 
2783                                                 right.EmitBranchable (ec, target, false);
2784                                 }
2785                                 
2786                                 return;
2787                                 
2788                         } else if (oper == Operator.LogicalOr){
2789                                 if (on_true) {
2790                                         left.EmitBranchable (ec, target, true);
2791                                         right.EmitBranchable (ec, target, true);
2792                                         
2793                                 } else {
2794                                         Label tests_end = ig.DefineLabel ();
2795                                         left.EmitBranchable (ec, tests_end, true);
2796                                         right.EmitBranchable (ec, target, false);
2797                                         ig.MarkLabel (tests_end);
2798                                 }
2799                                 
2800                                 return;
2801                                 
2802                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
2803                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2804                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
2805                                 base.EmitBranchable (ec, target, on_true);
2806                                 return;
2807                         }
2808                         
2809                         left.Emit (ec);
2810                         right.Emit (ec);
2811
2812                         Type t = left.Type;
2813                         bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2814                         
2815                         switch (oper){
2816                         case Operator.Equality:
2817                                 if (on_true)
2818                                         ig.Emit (OpCodes.Beq, target);
2819                                 else
2820                                         ig.Emit (OpCodes.Bne_Un, target);
2821                                 break;
2822
2823                         case Operator.Inequality:
2824                                 if (on_true)
2825                                         ig.Emit (OpCodes.Bne_Un, target);
2826                                 else
2827                                         ig.Emit (OpCodes.Beq, target);
2828                                 break;
2829
2830                         case Operator.LessThan:
2831                                 if (on_true)
2832                                         if (is_unsigned)
2833                                                 ig.Emit (OpCodes.Blt_Un, target);
2834                                         else
2835                                                 ig.Emit (OpCodes.Blt, target);
2836                                 else
2837                                         if (is_unsigned)
2838                                                 ig.Emit (OpCodes.Bge_Un, target);
2839                                         else
2840                                                 ig.Emit (OpCodes.Bge, target);
2841                                 break;
2842
2843                         case Operator.GreaterThan:
2844                                 if (on_true)
2845                                         if (is_unsigned)
2846                                                 ig.Emit (OpCodes.Bgt_Un, target);
2847                                         else
2848                                                 ig.Emit (OpCodes.Bgt, target);
2849                                 else
2850                                         if (is_unsigned)
2851                                                 ig.Emit (OpCodes.Ble_Un, target);
2852                                         else
2853                                                 ig.Emit (OpCodes.Ble, target);
2854                                 break;
2855
2856                         case Operator.LessThanOrEqual:
2857                                 if (on_true)
2858                                         if (is_unsigned)
2859                                                 ig.Emit (OpCodes.Ble_Un, target);
2860                                         else
2861                                                 ig.Emit (OpCodes.Ble, target);
2862                                 else
2863                                         if (is_unsigned)
2864                                                 ig.Emit (OpCodes.Bgt_Un, target);
2865                                         else
2866                                                 ig.Emit (OpCodes.Bgt, target);
2867                                 break;
2868
2869
2870                         case Operator.GreaterThanOrEqual:
2871                                 if (on_true)
2872                                         if (is_unsigned)
2873                                                 ig.Emit (OpCodes.Bge_Un, target);
2874                                         else
2875                                                 ig.Emit (OpCodes.Bge, target);
2876                                 else
2877                                         if (is_unsigned)
2878                                                 ig.Emit (OpCodes.Blt_Un, target);
2879                                         else
2880                                                 ig.Emit (OpCodes.Blt, target);
2881                                 break;
2882                         default:
2883                                 Console.WriteLine (oper);
2884                                 throw new Exception ("what is THAT");
2885                         }
2886                 }
2887                 
2888                 public override void Emit (EmitContext ec)
2889                 {
2890                         ILGenerator ig = ec.ig;
2891                         Type l = left.Type;
2892                         OpCode opcode;
2893
2894                         //
2895                         // Handle short-circuit operators differently
2896                         // than the rest
2897                         //
2898                         if (oper == Operator.LogicalAnd) {
2899                                 Label load_zero = ig.DefineLabel ();
2900                                 Label end = ig.DefineLabel ();
2901                                                                 
2902                                 left.EmitBranchable (ec, load_zero, false);
2903                                 right.Emit (ec);
2904                                 ig.Emit (OpCodes.Br, end);
2905                                 
2906                                 ig.MarkLabel (load_zero);
2907                                 ig.Emit (OpCodes.Ldc_I4_0);
2908                                 ig.MarkLabel (end);
2909                                 return;
2910                         } else if (oper == Operator.LogicalOr) {
2911                                 Label load_one = ig.DefineLabel ();
2912                                 Label end = ig.DefineLabel ();
2913
2914                                 left.EmitBranchable (ec, load_one, true);
2915                                 right.Emit (ec);
2916                                 ig.Emit (OpCodes.Br, end);
2917                                 
2918                                 ig.MarkLabel (load_one);
2919                                 ig.Emit (OpCodes.Ldc_I4_1);
2920                                 ig.MarkLabel (end);
2921                                 return;
2922                         }
2923
2924                         left.Emit (ec);
2925                         right.Emit (ec);
2926
2927                         bool is_unsigned = IsUnsigned (left.Type);
2928                         
2929                         switch (oper){
2930                         case Operator.Multiply:
2931                                 if (ec.CheckState){
2932                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2933                                                 opcode = OpCodes.Mul_Ovf;
2934                                         else if (is_unsigned)
2935                                                 opcode = OpCodes.Mul_Ovf_Un;
2936                                         else
2937                                                 opcode = OpCodes.Mul;
2938                                 } else
2939                                         opcode = OpCodes.Mul;
2940                                 
2941                                 break;
2942                                 
2943                         case Operator.Division:
2944                                 if (is_unsigned)
2945                                         opcode = OpCodes.Div_Un;
2946                                 else
2947                                         opcode = OpCodes.Div;
2948                                 break;
2949                                 
2950                         case Operator.Modulus:
2951                                 if (is_unsigned)
2952                                         opcode = OpCodes.Rem_Un;
2953                                 else
2954                                         opcode = OpCodes.Rem;
2955                                 break;
2956
2957                         case Operator.Addition:
2958                                 if (ec.CheckState){
2959                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2960                                                 opcode = OpCodes.Add_Ovf;
2961                                         else if (is_unsigned)
2962                                                 opcode = OpCodes.Add_Ovf_Un;
2963                                         else
2964                                                 opcode = OpCodes.Add;
2965                                 } else
2966                                         opcode = OpCodes.Add;
2967                                 break;
2968
2969                         case Operator.Subtraction:
2970                                 if (ec.CheckState){
2971                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2972                                                 opcode = OpCodes.Sub_Ovf;
2973                                         else if (is_unsigned)
2974                                                 opcode = OpCodes.Sub_Ovf_Un;
2975                                         else
2976                                                 opcode = OpCodes.Sub;
2977                                 } else
2978                                         opcode = OpCodes.Sub;
2979                                 break;
2980
2981                         case Operator.RightShift:
2982                                 if (is_unsigned)
2983                                         opcode = OpCodes.Shr_Un;
2984                                 else
2985                                         opcode = OpCodes.Shr;
2986                                 break;
2987                                 
2988                         case Operator.LeftShift:
2989                                 opcode = OpCodes.Shl;
2990                                 break;
2991
2992                         case Operator.Equality:
2993                                 opcode = OpCodes.Ceq;
2994                                 break;
2995
2996                         case Operator.Inequality:
2997                                 ig.Emit (OpCodes.Ceq);
2998                                 ig.Emit (OpCodes.Ldc_I4_0);
2999                                 
3000                                 opcode = OpCodes.Ceq;
3001                                 break;
3002
3003                         case Operator.LessThan:
3004                                 if (is_unsigned)
3005                                         opcode = OpCodes.Clt_Un;
3006                                 else
3007                                         opcode = OpCodes.Clt;
3008                                 break;
3009
3010                         case Operator.GreaterThan:
3011                                 if (is_unsigned)
3012                                         opcode = OpCodes.Cgt_Un;
3013                                 else
3014                                         opcode = OpCodes.Cgt;
3015                                 break;
3016
3017                         case Operator.LessThanOrEqual:
3018                                 Type lt = left.Type;
3019                                 
3020                                 if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3021                                         ig.Emit (OpCodes.Cgt_Un);
3022                                 else
3023                                         ig.Emit (OpCodes.Cgt);
3024                                 ig.Emit (OpCodes.Ldc_I4_0);
3025                                 
3026                                 opcode = OpCodes.Ceq;
3027                                 break;
3028
3029                         case Operator.GreaterThanOrEqual:
3030                                 Type le = left.Type;
3031                                 
3032                                 if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3033                                         ig.Emit (OpCodes.Clt_Un);
3034                                 else
3035                                         ig.Emit (OpCodes.Clt);
3036                                 
3037                                 ig.Emit (OpCodes.Ldc_I4_0);
3038                                 
3039                                 opcode = OpCodes.Ceq;
3040                                 break;
3041
3042                         case Operator.BitwiseOr:
3043                                 opcode = OpCodes.Or;
3044                                 break;
3045
3046                         case Operator.BitwiseAnd:
3047                                 opcode = OpCodes.And;
3048                                 break;
3049
3050                         case Operator.ExclusiveOr:
3051                                 opcode = OpCodes.Xor;
3052                                 break;
3053
3054                         default:
3055                                 throw new Exception ("This should not happen: Operator = "
3056                                                      + oper.ToString ());
3057                         }
3058
3059                         ig.Emit (opcode);
3060                 }
3061
3062                 protected override void CloneTo (CloneContext clonectx, Expression t)
3063                 {
3064                         Binary target = (Binary) t;
3065
3066                         target.left = left.Clone (clonectx);
3067                         target.right = right.Clone (clonectx);
3068                 }
3069
3070                 public override Expression CreateExpressionTree (EmitContext ec)
3071                 {
3072                         string method_name;
3073                         switch (oper) {
3074                         case Operator.Addition:
3075                                 if (ec.CheckState)
3076                                         method_name = "AddChecked";
3077                                 else
3078                                         method_name = "Add";
3079                                 break;
3080                         case Operator.BitwiseAnd:
3081                                 method_name = "And";
3082                                 break;
3083                         case Operator.GreaterThan:
3084                                 method_name = "GreaterThan";
3085                                 break;
3086                         case Operator.LessThan:
3087                                 method_name = "LessThan";
3088                                 break;
3089                         case Operator.LogicalAnd:
3090                                 method_name = "AndAlso";
3091                                 break;
3092                                 
3093                         case Operator.BitwiseOr:
3094                                 method_name = "Or";
3095                                 break;
3096
3097                         case Operator.LogicalOr:
3098                                 method_name = "OrElse";
3099                                 break;
3100                         default:
3101                                 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3102                         }
3103
3104                         ArrayList args = new ArrayList (2);
3105                         args.Add (new Argument (left.CreateExpressionTree (ec)));
3106                         args.Add (new Argument (right.CreateExpressionTree (ec)));
3107                         return CreateExpressionFactoryCall (method_name, args);
3108                 }
3109         }
3110
3111         //
3112         // Object created by Binary when the binary operator uses an method instead of being
3113         // a binary operation that maps to a CIL binary operation.
3114         //
3115         public class BinaryMethod : Expression {
3116                 public MethodBase method;
3117                 public ArrayList  Arguments;
3118                 
3119                 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3120                 {
3121                         method = m;
3122                         Arguments = args;
3123                         type = t;
3124                         eclass = ExprClass.Value;
3125                 }
3126
3127                 public override Expression DoResolve (EmitContext ec)
3128                 {
3129                         return this;
3130                 }
3131
3132                 public override void Emit (EmitContext ec)
3133                 {
3134                         ILGenerator ig = ec.ig;
3135                         
3136                         Invocation.EmitArguments (ec, Arguments, false, null);
3137                         
3138                         if (method is MethodInfo)
3139                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
3140                         else
3141                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3142                 }
3143         }
3144         
3145         //
3146         // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3147         // b, c, d... may be strings or objects.
3148         //
3149         public class StringConcat : Expression {
3150                 ArrayList arguments;
3151                 
3152                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3153                 {
3154                         this.loc = loc;
3155                         type = TypeManager.string_type;
3156                         eclass = ExprClass.Value;
3157
3158                         arguments = new ArrayList (2);
3159                         Append (ec, left);
3160                         Append (ec, right);
3161                 }
3162                 
3163                 public override Expression DoResolve (EmitContext ec)
3164                 {
3165                         return this;
3166                 }
3167                 
3168                 public void Append (EmitContext ec, Expression operand)
3169                 {
3170                         //
3171                         // Constant folding
3172                         //
3173                         StringConstant sc = operand as StringConstant;
3174                         if (sc != null) {
3175                                 if (arguments.Count != 0) {
3176                                         Argument last_argument = (Argument) arguments [arguments.Count - 1];
3177                                         StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3178                                         if (last_expr_constant != null) {
3179                                                 last_argument.Expr = new StringConstant (
3180                                                         last_expr_constant.Value + sc.Value, sc.Location);
3181                                                 return;
3182                                         }
3183                                 }
3184                         } else {
3185                                 //
3186                                 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3187                                 //
3188                                 StringConcat concat_oper = operand as StringConcat;
3189                                 if (concat_oper != null) {
3190                                         arguments.AddRange (concat_oper.arguments);
3191                                         return;
3192                                 }
3193                         }
3194                         
3195                         //
3196                         // Conversion to object
3197                         //
3198                         if (operand.Type != TypeManager.string_type) {
3199                                 Expression expr = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3200                                 if (expr == null) {
3201                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3202                                         return;
3203                                 }
3204                                 operand = expr;
3205                         }
3206                         
3207                         arguments.Add (new Argument (operand));
3208                 }
3209
3210                 Expression CreateConcatInvocation ()
3211                 {
3212                         return new Invocation (
3213                                 new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
3214                                 arguments, true);
3215                 }
3216
3217                 public override void Emit (EmitContext ec)
3218                 {
3219                         Expression concat = CreateConcatInvocation ();
3220                         concat = concat.Resolve (ec);
3221                         if (concat != null)
3222                                 concat.Emit (ec);
3223                 }
3224         }
3225
3226         //
3227         // Object created with +/= on delegates
3228         //
3229         public class BinaryDelegate : Expression {
3230                 MethodInfo method;
3231                 ArrayList  args;
3232
3233                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3234                 {
3235                         method = mi;
3236                         this.args = args;
3237                         type = t;
3238                         eclass = ExprClass.Value;
3239                 }
3240
3241                 public override Expression DoResolve (EmitContext ec)
3242                 {
3243                         return this;
3244                 }
3245
3246                 public override void Emit (EmitContext ec)
3247                 {
3248                         ILGenerator ig = ec.ig;
3249                         
3250                         Invocation.EmitArguments (ec, args, false, null);
3251                         
3252                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3253                         ig.Emit (OpCodes.Castclass, type);
3254                 }
3255
3256                 public Expression Right {
3257                         get {
3258                                 Argument arg = (Argument) args [1];
3259                                 return arg.Expr;
3260                         }
3261                 }
3262
3263                 public bool IsAddition {
3264                         get {
3265                                 return method == TypeManager.delegate_combine_delegate_delegate;
3266                         }
3267                 }
3268         }
3269         
3270         //
3271         // User-defined conditional logical operator
3272         //
3273         public class ConditionalLogicalOperator : Expression {
3274                 Expression left, right;
3275                 bool is_and;
3276                 Expression op_true, op_false, op;
3277                 LocalTemporary left_temp;
3278
3279                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3280                 {
3281                         type = t;
3282                         eclass = ExprClass.Value;
3283                         this.loc = loc;
3284                         this.left = left;
3285                         this.right = right;
3286                         this.is_and = is_and;
3287                 }
3288
3289                 protected void Error19 ()
3290                 {
3291                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3292                 }
3293
3294                 protected void Error218 ()
3295                 {
3296                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3297                                "declarations of operator true and operator false");
3298                 }
3299
3300                 public override Expression DoResolve (EmitContext ec)
3301                 {
3302                         MethodGroupExpr operator_group;
3303
3304                         operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3305                         if (operator_group == null) {
3306                                 Error19 ();
3307                                 return null;
3308                         }
3309
3310                         left_temp = new LocalTemporary (type);
3311
3312                         ArrayList arguments = new ArrayList (2);
3313                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3314                         arguments.Add (new Argument (right, Argument.AType.Expression));
3315                         operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
3316                         if (operator_group == null) {
3317                                 Error19 ();
3318                                 return null;
3319                         }
3320
3321                         MethodInfo method = (MethodInfo)operator_group;
3322                         if (method.ReturnType != type) {
3323                                 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3324                                                 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3325                                 return null;
3326                         }
3327
3328                         op = new UserOperatorCall (operator_group, arguments, null, loc);
3329
3330                         op_true = GetOperatorTrue (ec, left_temp, loc);
3331                         op_false = GetOperatorFalse (ec, left_temp, loc);
3332                         if ((op_true == null) || (op_false == null)) {
3333                                 Error218 ();
3334                                 return null;
3335                         }
3336
3337                         return this;
3338                 }
3339
3340                 public override void Emit (EmitContext ec)
3341                 {
3342                         ILGenerator ig = ec.ig;
3343                         Label false_target = ig.DefineLabel ();
3344                         Label end_target = ig.DefineLabel ();
3345
3346                         left.Emit (ec);
3347                         left_temp.Store (ec);
3348
3349                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3350                         left_temp.Emit (ec);
3351                         ig.Emit (OpCodes.Br, end_target);
3352                         ig.MarkLabel (false_target);
3353                         op.Emit (ec);
3354                         ig.MarkLabel (end_target);
3355
3356                         // We release 'left_temp' here since 'op' may refer to it too
3357                         left_temp.Release (ec);
3358                 }
3359         }
3360
3361         public class PointerArithmetic : Expression {
3362                 Expression left, right;
3363                 bool is_add;
3364
3365                 //
3366                 // We assume that `l' is always a pointer
3367                 //
3368                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3369                 {
3370                         type = t;
3371                         this.loc = loc;
3372                         left = l;
3373                         right = r;
3374                         is_add = is_addition;
3375                 }
3376
3377                 public override Expression DoResolve (EmitContext ec)
3378                 {
3379                         eclass = ExprClass.Variable;
3380                         
3381                         if (left.Type == TypeManager.void_ptr_type) {
3382                                 Error (242, "The operation in question is undefined on void pointers");
3383                                 return null;
3384                         }
3385                         
3386                         return this;
3387                 }
3388
3389                 public override void Emit (EmitContext ec)
3390                 {
3391                         Type op_type = left.Type;
3392                         ILGenerator ig = ec.ig;
3393                         
3394                         // It must be either array or fixed buffer
3395                         Type element = TypeManager.HasElementType (op_type) ?
3396                                 element = TypeManager.GetElementType (op_type) :
3397                                 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3398
3399                         int size = GetTypeSize (element);
3400                         Type rtype = right.Type;
3401                         
3402                         if (rtype.IsPointer){
3403                                 //
3404                                 // handle (pointer - pointer)
3405                                 //
3406                                 left.Emit (ec);
3407                                 right.Emit (ec);
3408                                 ig.Emit (OpCodes.Sub);
3409
3410                                 if (size != 1){
3411                                         if (size == 0)
3412                                                 ig.Emit (OpCodes.Sizeof, element);
3413                                         else 
3414                                                 IntLiteral.EmitInt (ig, size);
3415                                         ig.Emit (OpCodes.Div);
3416                                 }
3417                                 ig.Emit (OpCodes.Conv_I8);
3418                         } else {
3419                                 //
3420                                 // handle + and - on (pointer op int)
3421                                 //
3422                                 left.Emit (ec);
3423                                 ig.Emit (OpCodes.Conv_I);
3424
3425                                 Constant right_const = right as Constant;
3426                                 if (right_const != null && size != 0) {
3427                                         Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3428                                         if (ex == null)
3429                                                 return;
3430                                         ex.Emit (ec);
3431                                 } else {
3432                                         right.Emit (ec);
3433                                         if (size != 1){
3434                                                 if (size == 0)
3435                                                         ig.Emit (OpCodes.Sizeof, element);
3436                                                 else 
3437                                                         IntLiteral.EmitInt (ig, size);
3438                                                 if (rtype == TypeManager.int64_type)
3439                                                         ig.Emit (OpCodes.Conv_I8);
3440                                                 else if (rtype == TypeManager.uint64_type)
3441                                                         ig.Emit (OpCodes.Conv_U8);
3442                                                 ig.Emit (OpCodes.Mul);
3443                                         }
3444                                 }
3445                                 
3446                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3447                                         ig.Emit (OpCodes.Conv_I);
3448                                 
3449                                 if (is_add)
3450                                         ig.Emit (OpCodes.Add);
3451                                 else
3452                                         ig.Emit (OpCodes.Sub);
3453                         }
3454                 }
3455         }
3456         
3457         /// <summary>
3458         ///   Implements the ternary conditional operator (?:)
3459         /// </summary>
3460         public class Conditional : Expression {
3461                 Expression expr, true_expr, false_expr;
3462                 
3463                 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3464                 {
3465                         this.expr = expr;
3466                         this.true_expr = true_expr;
3467                         this.false_expr = false_expr;
3468                         this.loc = expr.Location;
3469                 }
3470
3471                 public Expression Expr {
3472                         get {
3473                                 return expr;
3474                         }
3475                 }
3476
3477                 public Expression TrueExpr {
3478                         get {
3479                                 return true_expr;
3480                         }
3481                 }
3482
3483                 public Expression FalseExpr {
3484                         get {
3485                                 return false_expr;
3486                         }
3487                 }
3488
3489                 public override Expression CreateExpressionTree (EmitContext ec)
3490                 {
3491                         ArrayList args = new ArrayList (3);
3492                         args.Add (new Argument (expr.CreateExpressionTree (ec)));
3493                         args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3494                         args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3495                         return CreateExpressionFactoryCall ("Condition", args);
3496                 }
3497
3498                 public override Expression DoResolve (EmitContext ec)
3499                 {
3500                         expr = expr.Resolve (ec);
3501
3502                         if (expr == null)
3503                                 return null;
3504
3505                         if (expr.Type != TypeManager.bool_type){
3506                                 expr = Expression.ResolveBoolean (
3507                                         ec, expr, loc);
3508                                 
3509                                 if (expr == null)
3510                                         return null;
3511                         }
3512                         
3513                         Assign ass = expr as Assign;
3514                         if (ass != null && ass.Source is Constant) {
3515                                 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3516                         }
3517
3518                         true_expr = true_expr.Resolve (ec);
3519                         false_expr = false_expr.Resolve (ec);
3520
3521                         if (true_expr == null || false_expr == null)
3522                                 return null;
3523
3524                         eclass = ExprClass.Value;
3525                         if (true_expr.Type == false_expr.Type) {
3526                                 type = true_expr.Type;
3527                                 if (type == TypeManager.null_type) {
3528                                         // TODO: probably will have to implement ConditionalConstant
3529                                         // to call method without return constant as well
3530                                         Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3531                                         return true_expr;
3532                                 }
3533                         } else {
3534                                 Expression conv;
3535                                 Type true_type = true_expr.Type;
3536                                 Type false_type = false_expr.Type;
3537
3538                                 //
3539                                 // First, if an implicit conversion exists from true_expr
3540                                 // to false_expr, then the result type is of type false_expr.Type
3541                                 //
3542                                 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3543                                 if (conv != null){
3544                                         //
3545                                         // Check if both can convert implicitl to each other's type
3546                                         //
3547                                         if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3548                                                 Error (172,
3549                                                        "Can not compute type of conditional expression " +
3550                                                        "as `" + TypeManager.CSharpName (true_expr.Type) +
3551                                                        "' and `" + TypeManager.CSharpName (false_expr.Type) +
3552                                                        "' convert implicitly to each other");
3553                                                 return null;
3554                                         }
3555                                         type = false_type;
3556                                         true_expr = conv;
3557                                 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3558                                         type = true_type;
3559                                         false_expr = conv;
3560                                 } else {
3561                                         Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3562                                                 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3563                                         return null;
3564                                 }
3565                         }
3566
3567                         // Dead code optimalization
3568                         if (expr is BoolConstant){
3569                                 BoolConstant bc = (BoolConstant) expr;
3570
3571                                 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3572                                 return bc.Value ? true_expr : false_expr;
3573                         }
3574
3575                         return this;
3576                 }
3577
3578                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3579                 {
3580                         return null;
3581                 }
3582
3583                 public override void Emit (EmitContext ec)
3584                 {
3585                         ILGenerator ig = ec.ig;
3586                         Label false_target = ig.DefineLabel ();
3587                         Label end_target = ig.DefineLabel ();
3588
3589                         expr.EmitBranchable (ec, false_target, false);
3590                         true_expr.Emit (ec);
3591                         ig.Emit (OpCodes.Br, end_target);
3592                         ig.MarkLabel (false_target);
3593                         false_expr.Emit (ec);
3594                         ig.MarkLabel (end_target);
3595                 }
3596
3597                 protected override void CloneTo (CloneContext clonectx, Expression t)
3598                 {
3599                         Conditional target = (Conditional) t;
3600
3601                         target.expr = expr.Clone (clonectx);
3602                         target.true_expr = true_expr.Clone (clonectx);
3603                         target.false_expr = false_expr.Clone (clonectx);
3604                 }
3605         }
3606
3607         public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3608                 bool prepared;
3609                 LocalTemporary temp;
3610
3611                 public abstract Variable Variable {
3612                         get;
3613                 }
3614
3615                 public abstract bool IsRef {
3616                         get;
3617                 }
3618
3619                 public override void Emit (EmitContext ec)
3620                 {
3621                         Emit (ec, false);
3622                 }
3623
3624                 //
3625                 // This method is used by parameters that are references, that are
3626                 // being passed as references:  we only want to pass the pointer (that
3627                 // is already stored in the parameter, not the address of the pointer,
3628                 // and not the value of the variable).
3629                 //
3630                 public void EmitLoad (EmitContext ec)
3631                 {
3632                         Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3633                         if (!prepared)
3634                                 Variable.EmitInstance (ec);
3635                         Variable.Emit (ec);
3636                 }
3637                 
3638                 public void Emit (EmitContext ec, bool leave_copy)
3639                 {
3640                         Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3641
3642                         EmitLoad (ec);
3643
3644                         if (IsRef) {
3645                                 //
3646                                 // If we are a reference, we loaded on the stack a pointer
3647                                 // Now lets load the real value
3648                                 //
3649                                 LoadFromPtr (ec.ig, type);
3650                         }
3651
3652                         if (leave_copy) {
3653                                 ec.ig.Emit (OpCodes.Dup);
3654
3655                                 if (IsRef || Variable.NeedsTemporary) {
3656                                         temp = new LocalTemporary (Type);
3657                                         temp.Store (ec);
3658                                 }
3659                         }
3660                 }
3661
3662                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3663                                         bool prepare_for_load)
3664                 {
3665                         Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3666                                       source, loc);
3667
3668                         ILGenerator ig = ec.ig;
3669                         prepared = prepare_for_load;
3670
3671                         Variable.EmitInstance (ec);
3672                         if (prepare_for_load) {
3673                                 if (Variable.HasInstance)
3674                                         ig.Emit (OpCodes.Dup);
3675                         }
3676
3677                         if (IsRef)
3678                                 Variable.Emit (ec);
3679
3680                         source.Emit (ec);
3681
3682                         // HACK: variable is already emitted when source is an initializer 
3683                         if (source is NewInitialize)
3684                                 return;
3685
3686                         if (leave_copy) {
3687                                 ig.Emit (OpCodes.Dup);
3688                                 if (IsRef || Variable.NeedsTemporary) {
3689                                         temp = new LocalTemporary (Type);
3690                                         temp.Store (ec);
3691                                 }
3692                         }
3693
3694                         if (IsRef)
3695                                 StoreFromPtr (ig, type);
3696                         else
3697                                 Variable.EmitAssign (ec);
3698
3699                         if (temp != null) {
3700                                 temp.Emit (ec);
3701                                 temp.Release (ec);
3702                         }
3703                 }
3704                 
3705                 public void AddressOf (EmitContext ec, AddressOp mode)
3706                 {
3707                         Variable.EmitInstance (ec);
3708                         Variable.EmitAddressOf (ec);
3709                 }
3710         }
3711
3712         /// <summary>
3713         ///   Local variables
3714         /// </summary>
3715         public class LocalVariableReference : VariableReference, IVariable {
3716                 public readonly string Name;
3717                 public Block Block;
3718                 public LocalInfo local_info;
3719                 bool is_readonly;
3720                 Variable variable;
3721
3722                 public LocalVariableReference (Block block, string name, Location l)
3723                 {
3724                         Block = block;
3725                         Name = name;
3726                         loc = l;
3727                         eclass = ExprClass.Variable;
3728                 }
3729
3730                 //
3731                 // Setting `is_readonly' to false will allow you to create a writable
3732                 // reference to a read-only variable.  This is used by foreach and using.
3733                 //
3734                 public LocalVariableReference (Block block, string name, Location l,
3735                                                LocalInfo local_info, bool is_readonly)
3736                         : this (block, name, l)
3737                 {
3738                         this.local_info = local_info;
3739                         this.is_readonly = is_readonly;
3740                 }
3741
3742                 public VariableInfo VariableInfo {
3743                         get { return local_info.VariableInfo; }
3744                 }
3745
3746                 public override bool IsRef {
3747                         get { return false; }
3748                 }
3749
3750                 public bool IsReadOnly {
3751                         get { return is_readonly; }
3752                 }
3753
3754                 public bool VerifyAssigned (EmitContext ec)
3755                 {
3756                         VariableInfo variable_info = local_info.VariableInfo;
3757                         return variable_info == null || variable_info.IsAssigned (ec, loc);
3758                 }
3759
3760                 void ResolveLocalInfo ()
3761                 {
3762                         if (local_info == null) {
3763                                 local_info = Block.GetLocalInfo (Name);
3764                                 type = local_info.VariableType;
3765                                 is_readonly = local_info.ReadOnly;
3766                         }
3767                 }
3768
3769                 protected Expression DoResolveBase (EmitContext ec)
3770                 {
3771                         type = local_info.VariableType;
3772
3773                         Expression e = Block.GetConstantExpression (Name);
3774                         if (e != null)
3775                                 return e.Resolve (ec);
3776
3777                         if (!VerifyAssigned (ec))
3778                                 return null;
3779
3780                         //
3781                         // If we are referencing a variable from the external block
3782                         // flag it for capturing
3783                         //
3784                         if (ec.MustCaptureVariable (local_info)) {
3785                                 if (local_info.AddressTaken){
3786                                         AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3787                                         return null;
3788                                 }
3789
3790                                 if (!ec.IsInProbingMode)
3791                                 {
3792                                         ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3793                                         variable = scope.AddLocal (local_info);
3794                                         type = variable.Type;
3795                                 }
3796                         }
3797
3798                         return this;
3799                 }
3800
3801                 public override Expression DoResolve (EmitContext ec)
3802                 {
3803                         ResolveLocalInfo ();
3804                         local_info.Used = true;
3805
3806                         if (type == null && local_info.Type is VarExpr) {
3807                             local_info.VariableType = TypeManager.object_type;
3808                                 Error_VariableIsUsedBeforeItIsDeclared (Name);
3809                             return null;
3810                         }
3811                         
3812                         return DoResolveBase (ec);
3813                 }
3814
3815                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3816                 {
3817                         ResolveLocalInfo ();
3818
3819                         // is out param
3820                         if (right_side == EmptyExpression.OutAccess)
3821                                 local_info.Used = true;
3822
3823                         // Infer implicitly typed local variable
3824                         if (type == null) {
3825                                 VarExpr ve = local_info.Type as VarExpr;
3826                                 if (ve != null) {
3827                                         ve.DoResolveLValue (ec, right_side);
3828                                         type = local_info.VariableType = ve.Type;
3829                                 }
3830                         }
3831                                                 
3832                         if (is_readonly) {
3833                                 int code;
3834                                 string msg;
3835                                 if (right_side == EmptyExpression.OutAccess) {
3836                                         code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3837                                 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3838                                         code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3839                                 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3840                                         code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3841                                 } else {
3842                                         code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3843                                 }
3844                                 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3845                                 return null;
3846                         }
3847
3848                         if (VariableInfo != null)
3849                                 VariableInfo.SetAssigned (ec);
3850
3851                         return DoResolveBase (ec);
3852                 }
3853
3854                 public bool VerifyFixed ()
3855                 {
3856                         // A local Variable is always fixed.
3857                         return true;
3858                 }
3859
3860                 public override int GetHashCode ()
3861                 {
3862                         return Name.GetHashCode ();
3863                 }
3864
3865                 public override bool Equals (object obj)
3866                 {
3867                         LocalVariableReference lvr = obj as LocalVariableReference;
3868                         if (lvr == null)
3869                                 return false;
3870
3871                         return Name == lvr.Name && Block == lvr.Block;
3872                 }
3873
3874                 public override Variable Variable {
3875                         get { return variable != null ? variable : local_info.Variable; }
3876                 }
3877
3878                 public override string ToString ()
3879                 {
3880                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3881                 }
3882
3883                 protected override void CloneTo (CloneContext clonectx, Expression t)
3884                 {
3885                         LocalVariableReference target = (LocalVariableReference) t;
3886                         
3887                         target.Block = clonectx.LookupBlock (Block);
3888                         if (local_info != null)
3889                                 target.local_info = clonectx.LookupVariable (local_info);
3890                 }
3891         }
3892
3893         /// <summary>
3894         ///   This represents a reference to a parameter in the intermediate
3895         ///   representation.
3896         /// </summary>
3897         public class ParameterReference : VariableReference, IVariable {
3898                 readonly ToplevelParameterInfo pi;
3899                 readonly ToplevelBlock referenced;
3900                 Variable variable;
3901
3902                 public bool is_ref, is_out;
3903
3904                 public bool IsOut {
3905                         get { return is_out; }
3906                 }
3907
3908                 public override bool IsRef {
3909                         get { return is_ref; }
3910                 }
3911
3912                 public string Name {
3913                         get { return Parameter.Name; }
3914                 }
3915
3916                 public Parameter Parameter {
3917                         get { return pi.Parameter; }
3918                 }
3919
3920                 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3921                 {
3922                         this.pi = pi;
3923                         this.referenced = referenced;
3924                         this.loc = loc;
3925                         eclass = ExprClass.Variable;
3926                 }
3927
3928                 public VariableInfo VariableInfo {
3929                         get { return pi.VariableInfo; }
3930                 }
3931
3932                 public override Variable Variable {
3933                         get { return variable != null ? variable : Parameter.Variable; }
3934                 }
3935
3936                 public bool VerifyFixed ()
3937                 {
3938                         // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3939                         return Parameter.ModFlags == Parameter.Modifier.NONE;
3940                 }
3941
3942                 public bool IsAssigned (EmitContext ec, Location loc)
3943                 {
3944                         // HACK: Variables are not captured in probing mode
3945                         if (ec.IsInProbingMode)
3946                                 return true;
3947                         
3948                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3949                                 return true;
3950
3951                         Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3952                         return false;
3953                 }
3954
3955                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3956                 {
3957                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3958                                 return true;
3959
3960                         Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3961                         return false;
3962                 }
3963
3964                 public void SetAssigned (EmitContext ec)
3965                 {
3966                         if (is_out && ec.DoFlowAnalysis)
3967                                 ec.CurrentBranching.SetAssigned (VariableInfo);
3968                 }
3969
3970                 public void SetFieldAssigned (EmitContext ec, string field_name)
3971                 {
3972                         if (is_out && ec.DoFlowAnalysis)
3973                                 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3974                 }
3975
3976                 protected bool DoResolveBase (EmitContext ec)
3977                 {
3978                         Parameter par = Parameter;
3979                         if (!par.Resolve (ec)) {
3980                                 //TODO:
3981                         }
3982
3983                         type = par.ParameterType;
3984                         Parameter.Modifier mod = par.ModFlags;
3985                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3986                         is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3987                         eclass = ExprClass.Variable;
3988
3989                         AnonymousContainer am = ec.CurrentAnonymousMethod;
3990                         if (am == null)
3991                                 return true;
3992
3993                         ToplevelBlock declared = pi.Block;
3994                         if (is_ref && declared != referenced) {
3995                                 Report.Error (1628, Location,
3996                                               "Cannot use ref or out parameter `{0}' inside an " +
3997                                               "anonymous method block", par.Name);
3998                                 return false;
3999                         }
4000
4001                         if (!am.IsIterator && declared == referenced)
4002                                 return true;
4003
4004                         // Don't capture aruments when the probing is on
4005                         if (!ec.IsInProbingMode) {
4006                                 ScopeInfo scope = declared.CreateScopeInfo ();
4007                                 variable = scope.AddParameter (par, pi.Index);
4008                                 type = variable.Type;
4009                         }
4010                         return true;
4011                 }
4012
4013                 public override int GetHashCode ()
4014                 {
4015                         return Name.GetHashCode ();
4016                 }
4017
4018                 public override bool Equals (object obj)
4019                 {
4020                         ParameterReference pr = obj as ParameterReference;
4021                         if (pr == null)
4022                                 return false;
4023
4024                         return Name == pr.Name && referenced == pr.referenced;
4025                 }
4026
4027                 public override Expression CreateExpressionTree (EmitContext ec)
4028                 {
4029                         return Parameter.ExpressionTreeVariableReference ();
4030                 }
4031
4032                 //
4033                 // Notice that for ref/out parameters, the type exposed is not the
4034                 // same type exposed externally.
4035                 //
4036                 // for "ref int a":
4037                 //   externally we expose "int&"
4038                 //   here we expose       "int".
4039                 //
4040                 // We record this in "is_ref".  This means that the type system can treat
4041                 // the type as it is expected, but when we generate the code, we generate
4042                 // the alternate kind of code.
4043                 //
4044                 public override Expression DoResolve (EmitContext ec)
4045                 {
4046                         if (!DoResolveBase (ec))
4047                                 return null;
4048
4049                         if (is_out && ec.DoFlowAnalysis &&
4050                             (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4051                                 return null;
4052
4053                         return this;
4054                 }
4055
4056                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4057                 {
4058                         if (!DoResolveBase (ec))
4059                                 return null;
4060
4061                         // HACK: parameters are not captured when probing is on
4062                         if (!ec.IsInProbingMode)
4063                                 SetAssigned (ec);
4064
4065                         return this;
4066                 }
4067
4068                 static public void EmitLdArg (ILGenerator ig, int x)
4069                 {
4070                         if (x <= 255){
4071                                 switch (x){
4072                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4073                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4074                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4075                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4076                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4077                                 }
4078                         } else
4079                                 ig.Emit (OpCodes.Ldarg, x);
4080                 }
4081                 
4082                 public override string ToString ()
4083                 {
4084                         return "ParameterReference[" + Name + "]";
4085                 }
4086         }
4087         
4088         /// <summary>
4089         ///   Used for arguments to New(), Invocation()
4090         /// </summary>
4091         public class Argument {
4092                 public enum AType : byte {
4093                         Expression,
4094                         Ref,
4095                         Out,
4096                         ArgList
4097                 };
4098
4099                 public static readonly Argument[] Empty = new Argument [0];
4100
4101                 public readonly AType ArgType;
4102                 public Expression Expr;
4103                 
4104                 public Argument (Expression expr, AType type)
4105                 {
4106                         this.Expr = expr;
4107                         this.ArgType = type;
4108                 }
4109
4110                 public Argument (Expression expr)
4111                 {
4112                         this.Expr = expr;
4113                         this.ArgType = AType.Expression;
4114                 }
4115
4116                 public Type Type {
4117                         get {
4118                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4119                                         return TypeManager.GetReferenceType (Expr.Type);
4120                                 else
4121                                         return Expr.Type;
4122                         }
4123                 }
4124
4125                 public Parameter.Modifier Modifier
4126                 {
4127                         get {
4128                                 switch (ArgType) {
4129                                         case AType.Out:
4130                                                 return Parameter.Modifier.OUT;
4131
4132                                         case AType.Ref:
4133                                                 return Parameter.Modifier.REF;
4134
4135                                         default:
4136                                                 return Parameter.Modifier.NONE;
4137                                 }
4138                         }
4139                 }
4140
4141                 public string GetSignatureForError ()
4142                 {
4143                         if (Expr.eclass == ExprClass.MethodGroup)
4144                                 return Expr.ExprClassName;
4145
4146                         return Expr.GetSignatureForError ();
4147                 }               
4148
4149                 public bool ResolveMethodGroup (EmitContext ec)
4150                 {
4151                         SimpleName sn = Expr as SimpleName;
4152                         if (sn != null)
4153                                 Expr = sn.GetMethodGroup ();
4154
4155                         // FIXME: csc doesn't report any error if you try to use `ref' or
4156                         //        `out' in a delegate creation expression.
4157                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4158                         if (Expr == null)
4159                                 return false;
4160
4161                         return true;
4162                 }
4163
4164                 public bool Resolve (EmitContext ec, Location loc)
4165                 {
4166                         using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4167                                 // Verify that the argument is readable
4168                                 if (ArgType != AType.Out)
4169                                         Expr = Expr.Resolve (ec);
4170
4171                                 // Verify that the argument is writeable
4172                                 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4173                                         Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4174
4175                                 return Expr != null;
4176                         }
4177                 }
4178
4179                 public void Emit (EmitContext ec)
4180                 {
4181                         if (ArgType != AType.Ref && ArgType != AType.Out) {
4182                                 Expr.Emit (ec);
4183                                 return;
4184                         }
4185
4186                         AddressOp mode = AddressOp.Store;
4187                         if (ArgType == AType.Ref)
4188                                 mode |= AddressOp.Load;
4189                                 
4190                         IMemoryLocation ml = (IMemoryLocation) Expr;
4191                         ParameterReference pr = ml as ParameterReference;
4192
4193                         //
4194                         // ParameterReferences might already be references, so we want
4195                         // to pass just the value
4196                         //
4197                         if (pr != null && pr.IsRef)
4198                                 pr.EmitLoad (ec);
4199                         else
4200                                 ml.AddressOf (ec, mode);
4201                 }
4202
4203                 public Argument Clone (CloneContext clonectx)
4204                 {
4205                         return new Argument (Expr.Clone (clonectx), ArgType);
4206                 }
4207         }
4208
4209         /// <summary>
4210         ///   Invocation of methods or delegates.
4211         /// </summary>
4212         public class Invocation : ExpressionStatement {
4213                 protected ArrayList Arguments;
4214                 Expression expr;
4215                 protected MethodGroupExpr mg;
4216                 bool arguments_resolved;
4217                 
4218                 //
4219                 // arguments is an ArrayList, but we do not want to typecast,
4220                 // as it might be null.
4221                 //
4222                 public Invocation (Expression expr, ArrayList arguments)
4223                 {
4224                         SimpleName sn = expr as SimpleName;
4225                         if (sn != null)
4226                                 this.expr = sn.GetMethodGroup ();
4227                         else
4228                                 this.expr = expr;
4229                         
4230                         Arguments = arguments;
4231                         loc = expr.Location;
4232                 }
4233
4234                 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4235                         : this (expr, arguments)
4236                 {
4237                         this.arguments_resolved = arguments_resolved;
4238                 }
4239
4240                 public static string FullMethodDesc (MethodBase mb)
4241                 {
4242                         if (mb == null)
4243                                 return "";
4244
4245                         StringBuilder sb;
4246                         if (mb is MethodInfo) {
4247                                 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4248                                 sb.Append (" ");
4249                         }
4250                         else
4251                                 sb = new StringBuilder ();
4252
4253                         sb.Append (TypeManager.CSharpSignature (mb));
4254                         return sb.ToString ();
4255                 }
4256
4257                 public override Expression CreateExpressionTree (EmitContext ec)
4258                 {
4259                         ArrayList args = new ArrayList (Arguments.Count + 3);
4260                         if (mg.IsInstance)
4261                                 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4262                         else
4263                                 args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
4264
4265                         args.Add (new Argument (mg.CreateExpressionTree (ec)));
4266                         foreach (Argument a in Arguments) {
4267                                 Expression e = a.Expr.CreateExpressionTree (ec);
4268                                 if (e != null)
4269                                         args.Add (new Argument (e));
4270                         }
4271
4272                         return CreateExpressionFactoryCall ("Call", args);
4273                 }
4274
4275                 public override Expression DoResolve (EmitContext ec)
4276                 {
4277                         // Don't resolve already resolved expression
4278                         if (eclass != ExprClass.Invalid)
4279                                 return this;
4280                         
4281                         Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4282                         if (expr_resolved == null)
4283                                 return null;
4284
4285                         mg = expr_resolved as MethodGroupExpr;
4286                         if (mg == null) {
4287                                 Type expr_type = expr_resolved.Type;
4288
4289                                 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4290                                         return (new DelegateInvocation (
4291                                                 expr_resolved, Arguments, loc)).Resolve (ec);
4292                                 }
4293                                 
4294                                 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4295                                 return null;
4296                         }
4297
4298                         //
4299                         // Next, evaluate all the expressions in the argument list
4300                         //
4301                         if (Arguments != null && !arguments_resolved) {
4302                                 for (int i = 0; i < Arguments.Count; ++i)
4303                                 {
4304                                         if (!((Argument)Arguments[i]).Resolve(ec, loc))
4305                                                 return null;
4306                                 }
4307                         }
4308
4309                         mg = DoResolveOverload (ec);
4310                         if (mg == null)
4311                                 return null;
4312
4313                         MethodInfo method = (MethodInfo)mg;
4314                         if (method != null) {
4315                                 type = TypeManager.TypeToCoreType (method.ReturnType);
4316
4317                                 // TODO: this is a copy of mg.ResolveMemberAccess method
4318                                 Expression iexpr = mg.InstanceExpression;
4319                                 if (method.IsStatic) {
4320                                         if (iexpr == null ||
4321                                                 iexpr is This || iexpr is EmptyExpression ||
4322                                                 mg.IdenticalTypeName) {
4323                                                 mg.InstanceExpression = null;
4324                                         } else {
4325                                                 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4326                                                 return null;
4327                                         }
4328                                 }
4329                         }
4330
4331                         if (type.IsPointer){
4332                                 if (!ec.InUnsafe){
4333                                         UnsafeError (loc);
4334                                         return null;
4335                                 }
4336                         }
4337                         
4338                         //
4339                         // Only base will allow this invocation to happen.
4340                         //
4341                         if (mg.IsBase && method.IsAbstract){
4342                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4343                                 return null;
4344                         }
4345
4346                         if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4347                                 if (mg.IsBase)
4348                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4349                                 else
4350                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4351                                 return null;
4352                         }
4353
4354                         if (IsSpecialMethodInvocation (method)) {
4355                                 return null;
4356                         }
4357                         
4358                         if (mg.InstanceExpression != null)
4359                                 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4360
4361                         eclass = ExprClass.Value;
4362                         return this;
4363                 }
4364
4365                 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4366                 {
4367                         return mg.OverloadResolve (ec, ref Arguments, false, loc);
4368                 }
4369
4370                 bool IsSpecialMethodInvocation (MethodBase method)
4371                 {
4372                         if (!TypeManager.IsSpecialMethod (method))
4373                                 return false;
4374
4375                         Report.SymbolRelatedToPreviousError (method);
4376                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4377                                 TypeManager.CSharpSignature (method, true));
4378         
4379                         return true;
4380                 }
4381
4382                 /// <summary>
4383                 ///   Emits a list of resolved Arguments that are in the arguments
4384                 ///   ArrayList.
4385                 /// 
4386                 ///   The MethodBase argument might be null if the
4387                 ///   emission of the arguments is known not to contain
4388                 ///   a `params' field (for example in constructors or other routines
4389                 ///   that keep their arguments in this structure)
4390                 ///   
4391                 ///   if `dup_args' is true, a copy of the arguments will be left
4392                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
4393                 ///   which will be duplicated before any other args. Only EmitCall
4394                 ///   should be using this interface.
4395                 /// </summary>
4396                 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4397                 {
4398                         if (arguments == null)
4399                                 return;
4400
4401                         int top = arguments.Count;
4402                         LocalTemporary [] temps = null;
4403                         
4404                         if (dup_args && top != 0)
4405                                 temps = new LocalTemporary [top];
4406
4407                         int argument_index = 0;
4408                         Argument a;
4409                         for (int i = 0; i < top; i++) {
4410                                 a = (Argument) arguments [argument_index++];
4411                                 a.Emit (ec);
4412                                 if (dup_args) {
4413                                         ec.ig.Emit (OpCodes.Dup);
4414                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4415                                 }
4416                         }
4417                         
4418                         if (dup_args) {
4419                                 if (this_arg != null)
4420                                         this_arg.Emit (ec);
4421                                 
4422                                 for (int i = 0; i < top; i ++) {
4423                                         temps [i].Emit (ec);
4424                                         temps [i].Release (ec);
4425                                 }
4426                         }
4427                 }
4428
4429                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4430                 {
4431                         ParameterData pd = TypeManager.GetParameterData (mb);
4432
4433                         if (arguments == null)
4434                                 return new Type [0];
4435
4436                         Argument a = (Argument) arguments [pd.Count - 1];
4437                         Arglist list = (Arglist) a.Expr;
4438
4439                         return list.ArgumentTypes;
4440                 }
4441
4442                 /// <summary>
4443                 /// This checks the ConditionalAttribute on the method 
4444                 /// </summary>
4445                 public static bool IsMethodExcluded (MethodBase method)
4446                 {
4447                         if (method.IsConstructor)
4448                                 return false;
4449
4450                         method = TypeManager.DropGenericMethodArguments (method);
4451                         if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4452                                 IMethodData md = TypeManager.GetMethod (method);
4453                                 if (md != null)
4454                                         return md.IsExcluded ();
4455
4456                                 // For some methods (generated by delegate class) GetMethod returns null
4457                                 // because they are not included in builder_to_method table
4458                                 return false;
4459                         }
4460
4461                         return AttributeTester.IsConditionalMethodExcluded (method);
4462                 }
4463
4464                 /// <remarks>
4465                 ///   is_base tells whether we want to force the use of the `call'
4466                 ///   opcode instead of using callvirt.  Call is required to call
4467                 ///   a specific method, while callvirt will always use the most
4468                 ///   recent method in the vtable.
4469                 ///
4470                 ///   is_static tells whether this is an invocation on a static method
4471                 ///
4472                 ///   instance_expr is an expression that represents the instance
4473                 ///   it must be non-null if is_static is false.
4474                 ///
4475                 ///   method is the method to invoke.
4476                 ///
4477                 ///   Arguments is the list of arguments to pass to the method or constructor.
4478                 /// </remarks>
4479                 public static void EmitCall (EmitContext ec, bool is_base,
4480                                              Expression instance_expr,
4481                                              MethodBase method, ArrayList Arguments, Location loc)
4482                 {
4483                         EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4484                 }
4485                 
4486                 // `dup_args' leaves an extra copy of the arguments on the stack
4487                 // `omit_args' does not leave any arguments at all.
4488                 // So, basically, you could make one call with `dup_args' set to true,
4489                 // and then another with `omit_args' set to true, and the two calls
4490                 // would have the same set of arguments. However, each argument would
4491                 // only have been evaluated once.
4492                 public static void EmitCall (EmitContext ec, bool is_base,
4493                                              Expression instance_expr,
4494                                              MethodBase method, ArrayList Arguments, Location loc,
4495                                              bool dup_args, bool omit_args)
4496                 {
4497                         ILGenerator ig = ec.ig;
4498                         bool struct_call = false;
4499                         bool this_call = false;
4500                         LocalTemporary this_arg = null;
4501
4502                         Type decl_type = method.DeclaringType;
4503
4504                         if (!RootContext.StdLib) {
4505                                 // Replace any calls to the system's System.Array type with calls to
4506                                 // the newly created one.
4507                                 if (method == TypeManager.system_int_array_get_length)
4508                                         method = TypeManager.int_array_get_length;
4509                                 else if (method == TypeManager.system_int_array_get_rank)
4510                                         method = TypeManager.int_array_get_rank;
4511                                 else if (method == TypeManager.system_object_array_clone)
4512                                         method = TypeManager.object_array_clone;
4513                                 else if (method == TypeManager.system_int_array_get_length_int)
4514                                         method = TypeManager.int_array_get_length_int;
4515                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4516                                         method = TypeManager.int_array_get_lower_bound_int;
4517                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4518                                         method = TypeManager.int_array_get_upper_bound_int;
4519                                 else if (method == TypeManager.system_void_array_copyto_array_int)
4520                                         method = TypeManager.void_array_copyto_array_int;
4521                         }
4522
4523                         if (!ec.IsInObsoleteScope) {
4524                                 //
4525                                 // This checks ObsoleteAttribute on the method and on the declaring type
4526                                 //
4527                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4528                                 if (oa != null)
4529                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4530
4531                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4532                                 if (oa != null) {
4533                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4534                                 }
4535                         }
4536
4537                         if (IsMethodExcluded (method))
4538                                 return;
4539                         
4540                         bool is_static = method.IsStatic;
4541                         if (!is_static){
4542                                 if (instance_expr == EmptyExpression.Null) {
4543                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4544                                         return;
4545                                 }
4546
4547                                 this_call = instance_expr is This;
4548                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4549                                         struct_call = true;
4550
4551                                 //
4552                                 // If this is ourselves, push "this"
4553                                 //
4554                                 if (!omit_args) {
4555                                         Type t = null;
4556                                         Type iexpr_type = instance_expr.Type;
4557
4558                                         //
4559                                         // Push the instance expression
4560                                         //
4561                                         if (TypeManager.IsValueType (iexpr_type)) {
4562                                                 //
4563                                                 // Special case: calls to a function declared in a 
4564                                                 // reference-type with a value-type argument need
4565                                                 // to have their value boxed.
4566                                                 if (decl_type.IsValueType ||
4567                                                     TypeManager.IsGenericParameter (iexpr_type)) {
4568                                                         //
4569                                                         // If the expression implements IMemoryLocation, then
4570                                                         // we can optimize and use AddressOf on the
4571                                                         // return.
4572                                                         //
4573                                                         // If not we have to use some temporary storage for
4574                                                         // it.
4575                                                         if (instance_expr is IMemoryLocation) {
4576                                                                 ((IMemoryLocation)instance_expr).
4577                                                                         AddressOf (ec, AddressOp.LoadStore);
4578                                                         } else {
4579                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
4580                                                                 instance_expr.Emit (ec);
4581                                                                 temp.Store (ec);
4582                                                                 temp.AddressOf (ec, AddressOp.Load);
4583                                                         }
4584
4585                                                         // avoid the overhead of doing this all the time.
4586                                                         if (dup_args)
4587                                                                 t = TypeManager.GetReferenceType (iexpr_type);
4588                                                 } else {
4589                                                         instance_expr.Emit (ec);
4590                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
4591                                                         t = TypeManager.object_type;
4592                                                 }
4593                                         } else {
4594                                                 instance_expr.Emit (ec);
4595                                                 t = instance_expr.Type;
4596                                         }
4597
4598                                         if (dup_args) {
4599                                                 ig.Emit (OpCodes.Dup);
4600                                                 if (Arguments != null && Arguments.Count != 0) {
4601                                                         this_arg = new LocalTemporary (t);
4602                                                         this_arg.Store (ec);
4603                                                 }
4604                                         }
4605                                 }
4606                         }
4607
4608                         if (!omit_args)
4609                                 EmitArguments (ec, Arguments, dup_args, this_arg);
4610
4611 #if GMCS_SOURCE
4612                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4613                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4614 #endif
4615
4616                         OpCode call_op;
4617                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4618                                 call_op = OpCodes.Call;
4619                         else
4620                                 call_op = OpCodes.Callvirt;
4621
4622                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4623                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4624                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4625                                 return;
4626                         }
4627
4628                         //
4629                         // If you have:
4630                         // this.DoFoo ();
4631                         // and DoFoo is not virtual, you can omit the callvirt,
4632                         // because you don't need the null checking behavior.
4633                         //
4634                         if (method is MethodInfo)
4635                                 ig.Emit (call_op, (MethodInfo) method);
4636                         else
4637                                 ig.Emit (call_op, (ConstructorInfo) method);
4638                 }
4639                 
4640                 public override void Emit (EmitContext ec)
4641                 {
4642                         mg.EmitCall (ec, Arguments);
4643                 }
4644                 
4645                 public override void EmitStatement (EmitContext ec)
4646                 {
4647                         Emit (ec);
4648
4649                         // 
4650                         // Pop the return value if there is one
4651                         //
4652                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4653                                 ec.ig.Emit (OpCodes.Pop);
4654                 }
4655
4656                 protected override void CloneTo (CloneContext clonectx, Expression t)
4657                 {
4658                         Invocation target = (Invocation) t;
4659
4660                         if (Arguments != null) {
4661                                 target.Arguments = new ArrayList (Arguments.Count);
4662                                 foreach (Argument a in Arguments)
4663                                         target.Arguments.Add (a.Clone (clonectx));
4664                         }
4665
4666                         target.expr = expr.Clone (clonectx);
4667                 }
4668         }
4669
4670         public class InvocationOrCast : ExpressionStatement
4671         {
4672                 Expression expr;
4673                 Expression argument;
4674
4675                 public InvocationOrCast (Expression expr, Expression argument)
4676                 {
4677                         this.expr = expr;
4678                         this.argument = argument;
4679                         this.loc = expr.Location;
4680                 }
4681
4682                 public override Expression DoResolve (EmitContext ec)
4683                 {
4684                         //
4685                         // First try to resolve it as a cast.
4686                         //
4687                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4688                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4689                                 Cast cast = new Cast (te, argument, loc);
4690                                 return cast.Resolve (ec);
4691                         }
4692
4693                         //
4694                         // This can either be a type or a delegate invocation.
4695                         // Let's just resolve it and see what we'll get.
4696                         //
4697                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4698                         if (expr == null)
4699                                 return null;
4700
4701                         //
4702                         // Ok, so it's a Cast.
4703                         //
4704                         if (expr.eclass == ExprClass.Type) {
4705                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4706                                 return cast.Resolve (ec);
4707                         }
4708
4709                         //
4710                         // It's a delegate invocation.
4711                         //
4712                         if (!TypeManager.IsDelegateType (expr.Type)) {
4713                                 Error (149, "Method name expected");
4714                                 return null;
4715                         }
4716
4717                         ArrayList args = new ArrayList ();
4718                         args.Add (new Argument (argument, Argument.AType.Expression));
4719                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4720                         return invocation.Resolve (ec);
4721                 }
4722
4723                 public override ExpressionStatement ResolveStatement (EmitContext ec)
4724                 {
4725                         //
4726                         // First try to resolve it as a cast.
4727                         //
4728                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4729                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4730                                 Error_InvalidExpressionStatement ();
4731                                 return null;
4732                         }
4733
4734                         //
4735                         // This can either be a type or a delegate invocation.
4736                         // Let's just resolve it and see what we'll get.
4737                         //
4738                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4739                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4740                                 Error_InvalidExpressionStatement ();
4741                                 return null;
4742                         }
4743
4744                         //
4745                         // It's a delegate invocation.
4746                         //
4747                         if (!TypeManager.IsDelegateType (expr.Type)) {
4748                                 Error (149, "Method name expected");
4749                                 return null;
4750                         }
4751
4752                         ArrayList args = new ArrayList ();
4753                         args.Add (new Argument (argument, Argument.AType.Expression));
4754                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4755                         return invocation.ResolveStatement (ec);
4756                 }
4757
4758                 public override void Emit (EmitContext ec)
4759                 {
4760                         throw new Exception ("Cannot happen");
4761                 }
4762
4763                 public override void EmitStatement (EmitContext ec)
4764                 {
4765                         throw new Exception ("Cannot happen");
4766                 }
4767
4768                 protected override void CloneTo (CloneContext clonectx, Expression t)
4769                 {
4770                         InvocationOrCast target = (InvocationOrCast) t;
4771
4772                         target.expr = expr.Clone (clonectx);
4773                         target.argument = argument.Clone (clonectx);
4774                 }
4775         }
4776
4777         //
4778         // This class is used to "disable" the code generation for the
4779         // temporary variable when initializing value types.
4780         //
4781         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4782                 public void AddressOf (EmitContext ec, AddressOp Mode)
4783                 {
4784                         // nothing
4785                 }
4786         }
4787         
4788         /// <summary>
4789         ///    Implements the new expression 
4790         /// </summary>
4791         public class New : ExpressionStatement, IMemoryLocation {
4792                 ArrayList Arguments;
4793
4794                 //
4795                 // During bootstrap, it contains the RequestedType,
4796                 // but if `type' is not null, it *might* contain a NewDelegate
4797                 // (because of field multi-initialization)
4798                 //
4799                 public Expression RequestedType;
4800
4801                 MethodGroupExpr method;
4802
4803                 //
4804                 // If set, the new expression is for a value_target, and
4805                 // we will not leave anything on the stack.
4806                 //
4807                 protected Expression value_target;
4808                 protected bool value_target_set;
4809                 bool is_type_parameter = false;
4810                 
4811                 public New (Expression requested_type, ArrayList arguments, Location l)
4812                 {
4813                         RequestedType = requested_type;
4814                         Arguments = arguments;
4815                         loc = l;
4816                 }
4817
4818                 public bool SetTargetVariable (Expression value)
4819                 {
4820                         value_target = value;
4821                         value_target_set = true;
4822                         if (!(value_target is IMemoryLocation)){
4823                                 Error_UnexpectedKind (null, "variable", loc);
4824                                 return false;
4825                         }
4826                         return true;
4827                 }
4828
4829                 //
4830                 // This function is used to disable the following code sequence for
4831                 // value type initialization:
4832                 //
4833                 // AddressOf (temporary)
4834                 // Construct/Init
4835                 // LoadTemporary
4836                 //
4837                 // Instead the provide will have provided us with the address on the
4838                 // stack to store the results.
4839                 //
4840                 static Expression MyEmptyExpression;
4841                 
4842                 public void DisableTemporaryValueType ()
4843                 {
4844                         if (MyEmptyExpression == null)
4845                                 MyEmptyExpression = new EmptyAddressOf ();
4846
4847                         //
4848                         // To enable this, look into:
4849                         // test-34 and test-89 and self bootstrapping.
4850                         //
4851                         // For instance, we can avoid a copy by using `newobj'
4852                         // instead of Call + Push-temp on value types.
4853 //                      value_target = MyEmptyExpression;
4854                 }
4855
4856
4857                 /// <summary>
4858                 /// Converts complex core type syntax like 'new int ()' to simple constant
4859                 /// </summary>
4860                 public static Constant Constantify (Type t)
4861                 {
4862                         if (t == TypeManager.int32_type)
4863                                 return new IntConstant (0, Location.Null);
4864                         if (t == TypeManager.uint32_type)
4865                                 return new UIntConstant (0, Location.Null);
4866                         if (t == TypeManager.int64_type)
4867                                 return new LongConstant (0, Location.Null);
4868                         if (t == TypeManager.uint64_type)
4869                                 return new ULongConstant (0, Location.Null);
4870                         if (t == TypeManager.float_type)
4871                                 return new FloatConstant (0, Location.Null);
4872                         if (t == TypeManager.double_type)
4873                                 return new DoubleConstant (0, Location.Null);
4874                         if (t == TypeManager.short_type)
4875                                 return new ShortConstant (0, Location.Null);
4876                         if (t == TypeManager.ushort_type)
4877                                 return new UShortConstant (0, Location.Null);
4878                         if (t == TypeManager.sbyte_type)
4879                                 return new SByteConstant (0, Location.Null);
4880                         if (t == TypeManager.byte_type)
4881                                 return new ByteConstant (0, Location.Null);
4882                         if (t == TypeManager.char_type)
4883                                 return new CharConstant ('\0', Location.Null);
4884                         if (t == TypeManager.bool_type)
4885                                 return new BoolConstant (false, Location.Null);
4886                         if (t == TypeManager.decimal_type)
4887                                 return new DecimalConstant (0, Location.Null);
4888                         if (TypeManager.IsEnumType (t))
4889                                 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
4890
4891                         return null;
4892                 }
4893
4894                 //
4895                 // Checks whether the type is an interface that has the
4896                 // [ComImport, CoClass] attributes and must be treated
4897                 // specially
4898                 //
4899                 public Expression CheckComImport (EmitContext ec)
4900                 {
4901                         if (!type.IsInterface)
4902                                 return null;
4903
4904                         //
4905                         // Turn the call into:
4906                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
4907                         //
4908                         Type real_class = AttributeTester.GetCoClassAttribute (type);
4909                         if (real_class == null)
4910                                 return null;
4911
4912                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
4913                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
4914                         return cast.Resolve (ec);
4915                 }
4916                 
4917                 public override Expression DoResolve (EmitContext ec)
4918                 {
4919                         //
4920                         // The New DoResolve might be called twice when initializing field
4921                         // expressions (see EmitFieldInitializers, the call to
4922                         // GetInitializerExpression will perform a resolve on the expression,
4923                         // and later the assign will trigger another resolution
4924                         //
4925                         // This leads to bugs (#37014)
4926                         //
4927                         if (type != null){
4928                                 if (RequestedType is NewDelegate)
4929                                         return RequestedType;
4930                                 return this;
4931                         }
4932
4933                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
4934                         if (texpr == null)
4935                                 return null;
4936
4937                         type = texpr.Type;
4938
4939                         if (type == TypeManager.void_type) {
4940                                 Error_VoidInvalidInTheContext (loc);
4941                                 return null;
4942                         }
4943
4944                         if (type.IsPointer) {
4945                                 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
4946                                         TypeManager.CSharpName (type));
4947                                 return null;
4948                         }
4949
4950                         if (Arguments == null) {
4951                                 Expression c = Constantify (type);
4952                                 if (c != null)
4953                                         return c;
4954                         }
4955
4956                         if (TypeManager.IsDelegateType (type)) {
4957                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4958                                 if (RequestedType != null)
4959                                         if (!(RequestedType is DelegateCreation))
4960                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
4961                                 return RequestedType;
4962                         }
4963
4964 #if GMCS_SOURCE
4965                         if (type.IsGenericParameter) {
4966                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
4967
4968                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
4969                                         Error (304, String.Format (
4970                                                        "Cannot create an instance of the " +
4971                                                        "variable type '{0}' because it " +
4972                                                        "doesn't have the new() constraint",
4973                                                        type));
4974                                         return null;
4975                                 }
4976
4977                                 if ((Arguments != null) && (Arguments.Count != 0)) {
4978                                         Error (417, String.Format (
4979                                                        "`{0}': cannot provide arguments " +
4980                                                        "when creating an instance of a " +
4981                                                        "variable type.", type));
4982                                         return null;
4983                                 }
4984
4985                                 is_type_parameter = true;
4986                                 eclass = ExprClass.Value;
4987                                 return this;
4988                         }
4989 #endif
4990
4991                         if (type.IsAbstract && type.IsSealed) {
4992                                 Report.SymbolRelatedToPreviousError (type);
4993                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
4994                                 return null;
4995                         }
4996
4997                         if (type.IsInterface || type.IsAbstract){
4998                                 if (!TypeManager.IsGenericType (type)) {
4999                                         RequestedType = CheckComImport (ec);
5000                                         if (RequestedType != null)
5001                                                 return RequestedType;
5002                                 }
5003                                 
5004                                 Report.SymbolRelatedToPreviousError (type);
5005                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5006                                 return null;
5007                         }
5008
5009                         bool is_struct = type.IsValueType;
5010                         eclass = ExprClass.Value;
5011
5012                         //
5013                         // SRE returns a match for .ctor () on structs (the object constructor), 
5014                         // so we have to manually ignore it.
5015                         //
5016                         if (is_struct && Arguments == null)
5017                                 return this;
5018
5019                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5020                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5021                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5022
5023                         if (Arguments != null){
5024                                 foreach (Argument a in Arguments){
5025                                         if (!a.Resolve (ec, loc))
5026                                                 return null;
5027                                 }
5028                         }
5029
5030                         if (ml == null)
5031                                 return null;
5032
5033                         method = ml as MethodGroupExpr;
5034                         if (method == null) {
5035                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5036                                 return null;
5037                         }
5038
5039                         method = method.OverloadResolve (ec, ref Arguments, false, loc);
5040                         if (method == null)
5041                                 return null;
5042
5043                         return this;
5044                 }
5045
5046                 bool DoEmitTypeParameter (EmitContext ec)
5047                 {
5048 #if GMCS_SOURCE
5049                         ILGenerator ig = ec.ig;
5050 //                      IMemoryLocation ml;
5051
5052                         MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5053                                 new Type [] { type });
5054
5055                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5056                         if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5057                                 ig.Emit (OpCodes.Call, ci);
5058                                 return true;
5059                         }
5060
5061                         // Allow DoEmit() to be called multiple times.
5062                         // We need to create a new LocalTemporary each time since
5063                         // you can't share LocalBuilders among ILGeneators.
5064                         LocalTemporary temp = new LocalTemporary (type);
5065
5066                         Label label_activator = ig.DefineLabel ();
5067                         Label label_end = ig.DefineLabel ();
5068
5069                         temp.AddressOf (ec, AddressOp.Store);
5070                         ig.Emit (OpCodes.Initobj, type);
5071
5072                         temp.Emit (ec);
5073                         ig.Emit (OpCodes.Box, type);
5074                         ig.Emit (OpCodes.Brfalse, label_activator);
5075
5076                         temp.AddressOf (ec, AddressOp.Store);
5077                         ig.Emit (OpCodes.Initobj, type);
5078                         temp.Emit (ec);
5079                         ig.Emit (OpCodes.Br, label_end);
5080
5081                         ig.MarkLabel (label_activator);
5082
5083                         ig.Emit (OpCodes.Call, ci);
5084                         ig.MarkLabel (label_end);
5085                         return true;
5086 #else
5087                         throw new InternalErrorException ();
5088 #endif
5089                 }
5090
5091                 //
5092                 // This DoEmit can be invoked in two contexts:
5093                 //    * As a mechanism that will leave a value on the stack (new object)
5094                 //    * As one that wont (init struct)
5095                 //
5096                 // You can control whether a value is required on the stack by passing
5097                 // need_value_on_stack.  The code *might* leave a value on the stack
5098                 // so it must be popped manually
5099                 //
5100                 // If we are dealing with a ValueType, we have a few
5101                 // situations to deal with:
5102                 //
5103                 //    * The target is a ValueType, and we have been provided
5104                 //      the instance (this is easy, we are being assigned).
5105                 //
5106                 //    * The target of New is being passed as an argument,
5107                 //      to a boxing operation or a function that takes a
5108                 //      ValueType.
5109                 //
5110                 //      In this case, we need to create a temporary variable
5111                 //      that is the argument of New.
5112                 //
5113                 // Returns whether a value is left on the stack
5114                 //
5115                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5116                 {
5117                         bool is_value_type = TypeManager.IsValueType (type);
5118                         ILGenerator ig = ec.ig;
5119
5120                         if (is_value_type){
5121                                 IMemoryLocation ml;
5122
5123                                 // Allow DoEmit() to be called multiple times.
5124                                 // We need to create a new LocalTemporary each time since
5125                                 // you can't share LocalBuilders among ILGeneators.
5126                                 if (!value_target_set)
5127                                         value_target = new LocalTemporary (type);
5128
5129                                 ml = (IMemoryLocation) value_target;
5130                                 ml.AddressOf (ec, AddressOp.Store);
5131                         }
5132
5133                         if (method != null)
5134                                 method.EmitArguments (ec, Arguments);
5135
5136                         if (is_value_type){
5137                                 if (method == null)
5138                                         ig.Emit (OpCodes.Initobj, type);
5139                                 else
5140                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5141                                 if (need_value_on_stack){
5142                                         value_target.Emit (ec);
5143                                         return true;
5144                                 }
5145                                 return false;
5146                         } else {
5147                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5148                                 return true;
5149                         }
5150                 }
5151
5152                 public override void Emit (EmitContext ec)
5153                 {
5154                         if (is_type_parameter)
5155                                 DoEmitTypeParameter (ec);
5156                         else
5157                                 DoEmit (ec, true);
5158                 }
5159                 
5160                 public override void EmitStatement (EmitContext ec)
5161                 {
5162                         bool value_on_stack;
5163
5164                         if (is_type_parameter)
5165                                 value_on_stack = DoEmitTypeParameter (ec);
5166                         else
5167                                 value_on_stack = DoEmit (ec, false);
5168
5169                         if (value_on_stack)
5170                                 ec.ig.Emit (OpCodes.Pop);
5171
5172                 }
5173
5174                 public virtual bool HasInitializer {
5175                         get {
5176                                 return false;
5177                         }
5178                 }
5179
5180                 public void AddressOf (EmitContext ec, AddressOp Mode)
5181                 {
5182                         if (is_type_parameter) {
5183                                 LocalTemporary temp = new LocalTemporary (type);
5184                                 DoEmitTypeParameter (ec);
5185                                 temp.Store (ec);
5186                                 temp.AddressOf (ec, Mode);
5187                                 return;
5188                         }
5189
5190                         if (!type.IsValueType){
5191                                 //
5192                                 // We throw an exception.  So far, I believe we only need to support
5193                                 // value types:
5194                                 // foreach (int j in new StructType ())
5195                                 // see bug 42390
5196                                 //
5197                                 throw new Exception ("AddressOf should not be used for classes");
5198                         }
5199
5200                         if (!value_target_set)
5201                                 value_target = new LocalTemporary (type);
5202                         IMemoryLocation ml = (IMemoryLocation) value_target;
5203
5204                         ml.AddressOf (ec, AddressOp.Store);
5205                         if (method == null) {
5206                                 ec.ig.Emit (OpCodes.Initobj, type);
5207                         } else {
5208                                 method.EmitArguments (ec, Arguments);
5209                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5210                         }
5211                         
5212                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5213                 }
5214
5215                 protected override void CloneTo (CloneContext clonectx, Expression t)
5216                 {
5217                         New target = (New) t;
5218
5219                         target.RequestedType = RequestedType.Clone (clonectx);
5220                         if (Arguments != null){
5221                                 target.Arguments = new ArrayList ();
5222                                 foreach (Argument a in Arguments){
5223                                         target.Arguments.Add (a.Clone (clonectx));
5224                                 }
5225                         }
5226                 }
5227         }
5228
5229         /// <summary>
5230         ///   14.5.10.2: Represents an array creation expression.
5231         /// </summary>
5232         ///
5233         /// <remarks>
5234         ///   There are two possible scenarios here: one is an array creation
5235         ///   expression that specifies the dimensions and optionally the
5236         ///   initialization data and the other which does not need dimensions
5237         ///   specified but where initialization data is mandatory.
5238         /// </remarks>
5239         public class ArrayCreation : Expression {
5240                 Expression requested_base_type;
5241                 ArrayList initializers;
5242
5243                 //
5244                 // The list of Argument types.
5245                 // This is used to construct the `newarray' or constructor signature
5246                 //
5247                 protected ArrayList arguments;
5248                 
5249                 protected Type array_element_type;
5250                 bool expect_initializers = false;
5251                 int num_arguments = 0;
5252                 protected int dimensions;
5253                 protected readonly string rank;
5254
5255                 protected ArrayList array_data;
5256
5257                 IDictionary bounds;
5258
5259                 // The number of constants in array initializers
5260                 int const_initializers_count;
5261                 bool only_constant_initializers;
5262                 
5263                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5264                 {
5265                         this.requested_base_type = requested_base_type;
5266                         this.initializers = initializers;
5267                         this.rank = rank;
5268                         loc = l;
5269
5270                         arguments = new ArrayList ();
5271
5272                         foreach (Expression e in exprs) {
5273                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5274                                 num_arguments++;
5275                         }
5276                 }
5277
5278                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5279                 {
5280                         this.requested_base_type = requested_base_type;
5281                         this.initializers = initializers;
5282                         this.rank = rank;
5283                         loc = l;
5284
5285                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5286                         //
5287                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5288                         //
5289                         //dimensions = tmp.Length - 1;
5290                         expect_initializers = true;
5291                 }
5292
5293                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5294                 {
5295                         StringBuilder sb = new StringBuilder (rank);
5296                         
5297                         sb.Append ("[");
5298                         for (int i = 1; i < idx_count; i++)
5299                                 sb.Append (",");
5300                         
5301                         sb.Append ("]");
5302
5303                         return new ComposedCast (base_type, sb.ToString (), loc);
5304                 }
5305
5306                 void Error_IncorrectArrayInitializer ()
5307                 {
5308                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5309                 }
5310
5311                 protected override void Error_NegativeArrayIndex (Location loc)
5312                 {
5313                         Report.Error (248, loc, "Cannot create an array with a negative size");
5314                 }
5315                 
5316                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5317                 {
5318                         if (specified_dims) { 
5319                                 Argument a = (Argument) arguments [idx];
5320
5321                                 if (!a.Resolve (ec, loc))
5322                                         return false;
5323
5324                                 Constant c = a.Expr as Constant;
5325                                 if (c != null) {
5326                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5327                                 }
5328
5329                                 if (c == null) {
5330                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5331                                         return false;
5332                                 }
5333
5334                                 int value = (int) c.GetValue ();
5335                                 
5336                                 if (value != probe.Count) {
5337                                         Error_IncorrectArrayInitializer ();
5338                                         return false;
5339                                 }
5340                                 
5341                                 bounds [idx] = value;
5342                         }
5343
5344                         int child_bounds = -1;
5345                         only_constant_initializers = true;
5346                         for (int i = 0; i < probe.Count; ++i) {
5347                                 object o = probe [i];
5348                                 if (o is ArrayList) {
5349                                         ArrayList sub_probe = o as ArrayList;
5350                                         int current_bounds = sub_probe.Count;
5351                                         
5352                                         if (child_bounds == -1) 
5353                                                 child_bounds = current_bounds;
5354
5355                                         else if (child_bounds != current_bounds){
5356                                                 Error_IncorrectArrayInitializer ();
5357                                                 return false;
5358                                         }
5359                                         if (idx + 1 >= dimensions){
5360                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5361                                                 return false;
5362                                         }
5363                                         
5364                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5365                                         if (!ret)
5366                                                 return false;
5367                                 } else {
5368                                         if (child_bounds != -1){
5369                                                 Error_IncorrectArrayInitializer ();
5370                                                 return false;
5371                                         }
5372                                         
5373                                         Expression element = ResolveArrayElement (ec, (Expression) o);
5374                                         if (element == null)
5375                                                 continue;
5376
5377                                         // Initializers with the default values can be ignored
5378                                         Constant c = element as Constant;
5379                                         if (c != null) {
5380                                                 if (c.IsDefaultInitializer (array_element_type)) {
5381                                                         element = null;
5382                                                 }
5383                                                 else {
5384                                                         ++const_initializers_count;
5385                                                 }
5386                                         } else {
5387                                                 only_constant_initializers = false;
5388                                         }
5389                                         
5390                                         array_data.Add (element);
5391                                 }
5392                         }
5393
5394                         return true;
5395                 }
5396
5397                 public override Expression CreateExpressionTree (EmitContext ec)
5398                 {
5399                         if (dimensions != 1) {
5400                                 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5401                                 return null;
5402                         }
5403
5404                         ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5405                         args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5406                         if (array_data != null) {
5407                                 foreach (Expression e in array_data)
5408                                         args.Add (new Argument (e.CreateExpressionTree (ec)));
5409                         }
5410
5411                         return CreateExpressionFactoryCall ("NewArrayInit", args);
5412                 }               
5413                 
5414                 public void UpdateIndices ()
5415                 {
5416                         int i = 0;
5417                         for (ArrayList probe = initializers; probe != null;) {
5418                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5419                                         Expression e = new IntConstant (probe.Count, Location.Null);
5420                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5421
5422                                         bounds [i++] =  probe.Count;
5423                                         
5424                                         probe = (ArrayList) probe [0];
5425                                         
5426                                 } else {
5427                                         Expression e = new IntConstant (probe.Count, Location.Null);
5428                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5429
5430                                         bounds [i++] = probe.Count;
5431                                         return;
5432                                 }
5433                         }
5434
5435                 }
5436
5437                 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5438                 {
5439                         element = element.Resolve (ec);
5440                         if (element == null)
5441                                 return null;
5442
5443                         return Convert.ImplicitConversionRequired (
5444                                 ec, element, array_element_type, loc);
5445                 }
5446
5447                 protected bool ResolveInitializers (EmitContext ec)
5448                 {
5449                         if (initializers == null) {
5450                                 return !expect_initializers;
5451                         }
5452                                                 
5453                         //
5454                         // We use this to store all the date values in the order in which we
5455                         // will need to store them in the byte blob later
5456                         //
5457                         array_data = new ArrayList ();
5458                         bounds = new System.Collections.Specialized.HybridDictionary ();
5459                         
5460                         if (arguments != null)
5461                                 return CheckIndices (ec, initializers, 0, true);
5462
5463                         arguments = new ArrayList ();
5464
5465                         if (!CheckIndices (ec, initializers, 0, false))
5466                                 return false;
5467                                 
5468                         UpdateIndices ();
5469                                 
5470                         return true;
5471                 }
5472
5473                 //
5474                 // Resolved the type of the array
5475                 //
5476                 bool ResolveArrayType (EmitContext ec)
5477                 {
5478                         if (requested_base_type == null) {
5479                                 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5480                                 return false;
5481                         }
5482                         
5483                         StringBuilder array_qualifier = new StringBuilder (rank);
5484
5485                         //
5486                         // `In the first form allocates an array instace of the type that results
5487                         // from deleting each of the individual expression from the expression list'
5488                         //
5489                         if (num_arguments > 0) {
5490                                 array_qualifier.Append ("[");
5491                                 for (int i = num_arguments-1; i > 0; i--)
5492                                         array_qualifier.Append (",");
5493                                 array_qualifier.Append ("]");
5494                         }
5495
5496                         //
5497                         // Lookup the type
5498                         //
5499                         TypeExpr array_type_expr;
5500                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5501                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5502                         if (array_type_expr == null)
5503                                 return false;
5504
5505                         type = array_type_expr.Type;
5506                         array_element_type = TypeManager.GetElementType (type);
5507                         dimensions = type.GetArrayRank ();
5508
5509                         return true;
5510                 }
5511
5512                 public override Expression DoResolve (EmitContext ec)
5513                 {
5514                         if (type != null)
5515                                 return this;
5516
5517                         if (!ResolveArrayType (ec))
5518                                 return null;
5519                         
5520                         if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5521                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5522                                         TypeManager.CSharpName (array_element_type));
5523                         }
5524
5525                         //
5526                         // First step is to validate the initializers and fill
5527                         // in any missing bits
5528                         //
5529                         if (!ResolveInitializers (ec))
5530                                 return null;
5531
5532                         if (arguments.Count != dimensions) {
5533                                 Error_IncorrectArrayInitializer ();
5534                         }
5535
5536                         foreach (Argument a in arguments){
5537                                 if (!a.Resolve (ec, loc))
5538                                         continue;
5539
5540                                 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5541                         }
5542                                                         
5543                         eclass = ExprClass.Value;
5544                         return this;
5545                 }
5546
5547                 MethodInfo GetArrayMethod (int arguments)
5548                 {
5549                         ModuleBuilder mb = CodeGen.Module.Builder;
5550
5551                         Type[] arg_types = new Type[arguments];
5552                         for (int i = 0; i < arguments; i++)
5553                                 arg_types[i] = TypeManager.int32_type;
5554
5555                         MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5556                                                         arg_types);
5557
5558                         if (mi == null) {
5559                                 Report.Error (-6, "New invocation: Can not find a constructor for " +
5560                                                   "this argument list");
5561                                 return null;
5562                         }
5563
5564                         return mi; 
5565                 }
5566
5567                 byte [] MakeByteBlob ()
5568                 {
5569                         int factor;
5570                         byte [] data;
5571                         byte [] element;
5572                         int count = array_data.Count;
5573
5574                         if (array_element_type.IsEnum)
5575                                 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5576                         
5577                         factor = GetTypeSize (array_element_type);
5578                         if (factor == 0)
5579                                 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5580
5581                         data = new byte [(count * factor + 3) & ~3];
5582                         int idx = 0;
5583
5584                         for (int i = 0; i < count; ++i) {
5585                                 object v = array_data [i];
5586
5587                                 if (v is EnumConstant)
5588                                         v = ((EnumConstant) v).Child;
5589                                 
5590                                 if (v is Constant && !(v is StringConstant))
5591                                         v = ((Constant) v).GetValue ();
5592                                 else {
5593                                         idx += factor;
5594                                         continue;
5595                                 }
5596                                 
5597                                 if (array_element_type == TypeManager.int64_type){
5598                                         if (!(v is Expression)){
5599                                                 long val = (long) v;
5600                                                 
5601                                                 for (int j = 0; j < factor; ++j) {
5602                                                         data [idx + j] = (byte) (val & 0xFF);
5603                                                         val = (val >> 8);
5604                                                 }
5605                                         }
5606                                 } else if (array_element_type == TypeManager.uint64_type){
5607                                         if (!(v is Expression)){
5608                                                 ulong val = (ulong) v;
5609
5610                                                 for (int j = 0; j < factor; ++j) {
5611                                                         data [idx + j] = (byte) (val & 0xFF);
5612                                                         val = (val >> 8);
5613                                                 }
5614                                         }
5615                                 } else if (array_element_type == TypeManager.float_type) {
5616                                         if (!(v is Expression)){
5617                                                 element = BitConverter.GetBytes ((float) v);
5618                                                         
5619                                                 for (int j = 0; j < factor; ++j)
5620                                                         data [idx + j] = element [j];
5621                                                 if (!BitConverter.IsLittleEndian)
5622                                                         System.Array.Reverse (data, idx, 4);
5623                                         }
5624                                 } else if (array_element_type == TypeManager.double_type) {
5625                                         if (!(v is Expression)){
5626                                                 element = BitConverter.GetBytes ((double) v);
5627
5628                                                 for (int j = 0; j < factor; ++j)
5629                                                         data [idx + j] = element [j];
5630
5631                                                 // FIXME: Handle the ARM float format.
5632                                                 if (!BitConverter.IsLittleEndian)
5633                                                         System.Array.Reverse (data, idx, 8);
5634                                         }
5635                                 } else if (array_element_type == TypeManager.char_type){
5636                                         if (!(v is Expression)){
5637                                                 int val = (int) ((char) v);
5638                                                 
5639                                                 data [idx] = (byte) (val & 0xff);
5640                                                 data [idx+1] = (byte) (val >> 8);
5641                                         }
5642                                 } else if (array_element_type == TypeManager.short_type){
5643                                         if (!(v is Expression)){
5644                                                 int val = (int) ((short) v);
5645                                         
5646                                                 data [idx] = (byte) (val & 0xff);
5647                                                 data [idx+1] = (byte) (val >> 8);
5648                                         }
5649                                 } else if (array_element_type == TypeManager.ushort_type){
5650                                         if (!(v is Expression)){
5651                                                 int val = (int) ((ushort) v);
5652                                         
5653                                                 data [idx] = (byte) (val & 0xff);
5654                                                 data [idx+1] = (byte) (val >> 8);
5655                                         }
5656                                 } else if (array_element_type == TypeManager.int32_type) {
5657                                         if (!(v is Expression)){
5658                                                 int val = (int) v;
5659                                         
5660                                                 data [idx]   = (byte) (val & 0xff);
5661                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5662                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5663                                                 data [idx+3] = (byte) (val >> 24);
5664                                         }
5665                                 } else if (array_element_type == TypeManager.uint32_type) {
5666                                         if (!(v is Expression)){
5667                                                 uint val = (uint) v;
5668                                         
5669                                                 data [idx]   = (byte) (val & 0xff);
5670                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5671                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5672                                                 data [idx+3] = (byte) (val >> 24);
5673                                         }
5674                                 } else if (array_element_type == TypeManager.sbyte_type) {
5675                                         if (!(v is Expression)){
5676                                                 sbyte val = (sbyte) v;
5677                                                 data [idx] = (byte) val;
5678                                         }
5679                                 } else if (array_element_type == TypeManager.byte_type) {
5680                                         if (!(v is Expression)){
5681                                                 byte val = (byte) v;
5682                                                 data [idx] = (byte) val;
5683                                         }
5684                                 } else if (array_element_type == TypeManager.bool_type) {
5685                                         if (!(v is Expression)){
5686                                                 bool val = (bool) v;
5687                                                 data [idx] = (byte) (val ? 1 : 0);
5688                                         }
5689                                 } else if (array_element_type == TypeManager.decimal_type){
5690                                         if (!(v is Expression)){
5691                                                 int [] bits = Decimal.GetBits ((decimal) v);
5692                                                 int p = idx;
5693
5694                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
5695                                                 int [] nbits = new int [4];
5696                                                 nbits [0] = bits [3];
5697                                                 nbits [1] = bits [2];
5698                                                 nbits [2] = bits [0];
5699                                                 nbits [3] = bits [1];
5700                                                 
5701                                                 for (int j = 0; j < 4; j++){
5702                                                         data [p++] = (byte) (nbits [j] & 0xff);
5703                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5704                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5705                                                         data [p++] = (byte) (nbits [j] >> 24);
5706                                                 }
5707                                         }
5708                                 } else
5709                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5710
5711                                 idx += factor;
5712                         }
5713
5714                         return data;
5715                 }
5716
5717                 //
5718                 // Emits the initializers for the array
5719                 //
5720                 void EmitStaticInitializers (EmitContext ec)
5721                 {
5722                         //
5723                         // First, the static data
5724                         //
5725                         FieldBuilder fb;
5726                         ILGenerator ig = ec.ig;
5727                         
5728                         byte [] data = MakeByteBlob ();
5729
5730                         fb = RootContext.MakeStaticData (data);
5731
5732                         ig.Emit (OpCodes.Dup);
5733                         ig.Emit (OpCodes.Ldtoken, fb);
5734                         ig.Emit (OpCodes.Call,
5735                                  TypeManager.void_initializearray_array_fieldhandle);
5736                 }
5737
5738                 //
5739                 // Emits pieces of the array that can not be computed at compile
5740                 // time (variables and string locations).
5741                 //
5742                 // This always expect the top value on the stack to be the array
5743                 //
5744                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5745                 {
5746                         ILGenerator ig = ec.ig;
5747                         int dims = bounds.Count;
5748                         int [] current_pos = new int [dims];
5749
5750                         MethodInfo set = null;
5751
5752                         if (dims != 1){
5753                                 Type [] args = new Type [dims + 1];
5754
5755                                 for (int j = 0; j < dims; j++)
5756                                         args [j] = TypeManager.int32_type;
5757                                 args [dims] = array_element_type;
5758                                 
5759                                 set = CodeGen.Module.Builder.GetArrayMethod (
5760                                         type, "Set",
5761                                         CallingConventions.HasThis | CallingConventions.Standard,
5762                                         TypeManager.void_type, args);
5763                         }
5764
5765                         for (int i = 0; i < array_data.Count; i++){
5766
5767                                 Expression e = (Expression)array_data [i];
5768
5769                                 // Constant can be initialized via StaticInitializer
5770                                 if (e != null && !(!emitConstants && e is Constant)) {
5771                                         Type etype = e.Type;
5772
5773                                         ig.Emit (OpCodes.Dup);
5774
5775                                         for (int idx = 0; idx < dims; idx++) 
5776                                                 IntConstant.EmitInt (ig, current_pos [idx]);
5777
5778                                         //
5779                                         // If we are dealing with a struct, get the
5780                                         // address of it, so we can store it.
5781                                         //
5782                                         if ((dims == 1) && etype.IsValueType &&
5783                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
5784                                              etype == TypeManager.decimal_type)) {
5785                                                 if (e is New){
5786                                                         New n = (New) e;
5787
5788                                                         //
5789                                                         // Let new know that we are providing
5790                                                         // the address where to store the results
5791                                                         //
5792                                                         n.DisableTemporaryValueType ();
5793                                                 }
5794
5795                                                 ig.Emit (OpCodes.Ldelema, etype);
5796                                         }
5797
5798                                         e.Emit (ec);
5799
5800                                         if (dims == 1) {
5801                                                 bool is_stobj, has_type_arg;
5802                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5803                                                 if (is_stobj)
5804                                                         ig.Emit (OpCodes.Stobj, etype);
5805                                                 else if (has_type_arg)
5806                                                         ig.Emit (op, etype);
5807                                                 else
5808                                                         ig.Emit (op);
5809                                         } else 
5810                                                 ig.Emit (OpCodes.Call, set);
5811
5812                                 }
5813                                 
5814                                 //
5815                                 // Advance counter
5816                                 //
5817                                 for (int j = dims - 1; j >= 0; j--){
5818                                         current_pos [j]++;
5819                                         if (current_pos [j] < (int) bounds [j])
5820                                                 break;
5821                                         current_pos [j] = 0;
5822                                 }
5823                         }
5824                 }
5825
5826                 public override void Emit (EmitContext ec)
5827                 {
5828                         ILGenerator ig = ec.ig;
5829
5830                         foreach (Argument a in arguments)
5831                                 a.Emit (ec);
5832
5833                         if (arguments.Count == 1)
5834                                 ig.Emit (OpCodes.Newarr, array_element_type);
5835                         else {
5836                                 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5837                         }
5838                         
5839                         if (initializers == null)
5840                                 return;
5841
5842                         // Emit static initializer for arrays which have contain more than 4 items and
5843                         // the static initializer will initialize at least 25% of array values.
5844                         // NOTE: const_initializers_count does not contain default constant values.
5845                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5846                                 TypeManager.IsPrimitiveType (array_element_type)) {
5847                                 EmitStaticInitializers (ec);
5848
5849                                 if (!only_constant_initializers)
5850                                         EmitDynamicInitializers (ec, false);
5851                         } else {
5852                                 EmitDynamicInitializers (ec, true);
5853                         }                               
5854                 }
5855
5856                 public override bool GetAttributableValue (Type value_type, out object value)
5857                 {
5858                         if (arguments.Count != 1) {
5859                                 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
5860                                 return base.GetAttributableValue (null, out value);
5861                         }
5862
5863                         if (array_data == null) {
5864                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
5865                                 if (c.IsDefaultValue) {
5866                                         value = Array.CreateInstance (array_element_type, 0);
5867                                         return true;
5868                                 }
5869                                 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
5870                                 return base.GetAttributableValue (null, out value);
5871                         }
5872                         
5873                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
5874                         object element_value;
5875                         for (int i = 0; i < ret.Length; ++i)
5876                         {
5877                                 Expression e = (Expression)array_data [i];
5878
5879                                 // Is null when an initializer is optimized (value == predefined value)
5880                                 if (e == null) 
5881                                         continue;
5882
5883                                 if (!e.GetAttributableValue (array_element_type, out element_value)) {
5884                                         value = null;
5885                                         return false;
5886                                 }
5887                                 ret.SetValue (element_value, i);
5888                         }
5889                         value = ret;
5890                         return true;
5891                 }
5892                 
5893                 protected override void CloneTo (CloneContext clonectx, Expression t)
5894                 {
5895                         ArrayCreation target = (ArrayCreation) t;
5896
5897                         if (requested_base_type != null)
5898                                 target.requested_base_type = requested_base_type.Clone (clonectx);
5899
5900                         if (arguments != null){
5901                                 target.arguments = new ArrayList (arguments.Count);
5902                                 foreach (Argument a in arguments)
5903                                         target.arguments.Add (a.Clone (clonectx));
5904                         }
5905
5906                         if (initializers != null){
5907                                 target.initializers = new ArrayList (initializers.Count);
5908                                 foreach (Expression initializer in initializers)
5909                                         target.initializers.Add (initializer.Clone (clonectx));
5910                         }
5911                 }
5912         }
5913         
5914         //
5915         // Represents an implicitly typed array epxression
5916         //
5917         public class ImplicitlyTypedArrayCreation : ArrayCreation
5918         {
5919                 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
5920                         : base (null, rank, initializers, loc)
5921                 {
5922                         if (RootContext.Version <= LanguageVersion.ISO_2)
5923                                 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
5924                                 
5925                         if (rank.Length > 2) {
5926                                 while (rank [++dimensions] == ',');
5927                         } else {
5928                                 dimensions = 1;
5929                         }
5930                 }
5931
5932                 public override Expression DoResolve (EmitContext ec)
5933                 {
5934                         if (type != null)
5935                                 return this;
5936
5937                         if (!ResolveInitializers (ec))
5938                                 return null;
5939
5940                         if (array_element_type == null || array_element_type == TypeManager.null_type ||
5941                                 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
5942                                 arguments.Count != dimensions) {
5943                                 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
5944                                 return null;
5945                         }
5946
5947                         //
5948                         // At this point we found common base type for all initializer elements
5949                         // but we have to be sure that all static initializer elements are of
5950                         // same type
5951                         //
5952                         UnifyInitializerElement (ec);
5953
5954                         type = TypeManager.GetConstructedType (array_element_type, rank);
5955                         eclass = ExprClass.Value;
5956                         return this;
5957                 }
5958
5959                 //
5960                 // Converts static initializer only
5961                 //
5962                 void UnifyInitializerElement (EmitContext ec)
5963                 {
5964                         for (int i = 0; i < array_data.Count; ++i) {
5965                                 Expression e = (Expression)array_data[i];
5966                                 if (e != null)
5967                                         array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
5968                         }
5969                 }
5970
5971                 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
5972                 {
5973                         element = element.Resolve (ec);
5974                         if (element == null)
5975                                 return null;
5976                         
5977                         if (array_element_type == null) {
5978                                 array_element_type = element.Type;
5979                                 return element;
5980                         }
5981
5982                         if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
5983                                 return element;
5984                         }
5985
5986                         if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
5987                                 array_element_type = element.Type;
5988                                 return element;
5989                         }
5990
5991                         element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
5992                         return element;
5993                 }
5994         }       
5995         
5996         public sealed class CompilerGeneratedThis : This
5997         {
5998                 public static This Instance = new CompilerGeneratedThis ();
5999
6000                 private CompilerGeneratedThis ()
6001                         : base (Location.Null)
6002                 {
6003                 }
6004
6005                 public override Expression DoResolve (EmitContext ec)
6006                 {
6007                         eclass = ExprClass.Variable;
6008                         type = ec.ContainerType;
6009                         variable = new SimpleThis (type);
6010                         return this;
6011                 }
6012         }
6013         
6014         /// <summary>
6015         ///   Represents the `this' construct
6016         /// </summary>
6017
6018         public class This : VariableReference, IVariable
6019         {
6020                 Block block;
6021                 VariableInfo variable_info;
6022                 protected Variable variable;
6023                 bool is_struct;
6024
6025                 public This (Block block, Location loc)
6026                 {
6027                         this.loc = loc;
6028                         this.block = block;
6029                 }
6030
6031                 public This (Location loc)
6032                 {
6033                         this.loc = loc;
6034                 }
6035
6036                 public VariableInfo VariableInfo {
6037                         get { return variable_info; }
6038                 }
6039
6040                 public bool VerifyFixed ()
6041                 {
6042                         return !TypeManager.IsValueType (Type);
6043                 }
6044
6045                 public override bool IsRef {
6046                         get { return is_struct; }
6047                 }
6048
6049                 public override Variable Variable {
6050                         get { return variable; }
6051                 }
6052
6053                 public bool ResolveBase (EmitContext ec)
6054                 {
6055                         eclass = ExprClass.Variable;
6056
6057                         if (ec.TypeContainer.CurrentType != null)
6058                                 type = ec.TypeContainer.CurrentType;
6059                         else
6060                                 type = ec.ContainerType;
6061
6062                         is_struct = ec.TypeContainer is Struct;
6063
6064                         if (ec.IsStatic) {
6065                                 Error (26, "Keyword `this' is not valid in a static property, " +
6066                                        "static method, or static field initializer");
6067                                 return false;
6068                         }
6069
6070                         if (block != null) {
6071                                 if (block.Toplevel.ThisVariable != null)
6072                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6073
6074                                 AnonymousContainer am = ec.CurrentAnonymousMethod;
6075                                 if (is_struct && (am != null) && !am.IsIterator) {
6076                                         Report.Error (1673, loc, "Anonymous methods inside structs " +
6077                                                       "cannot access instance members of `this'. " +
6078                                                       "Consider copying `this' to a local variable " +
6079                                                       "outside the anonymous method and using the " +
6080                                                       "local instead.");
6081                                 }
6082
6083                                 RootScopeInfo host = block.Toplevel.RootScope;
6084                                 if ((host != null) && !ec.IsConstructor &&
6085                                     (!is_struct || host.IsIterator)) {
6086                                         variable = host.CaptureThis ();
6087                                         type = variable.Type;
6088                                         is_struct = false;
6089                                 }
6090                         }
6091
6092                         if (variable == null)
6093                                 variable = new SimpleThis (type);
6094                         
6095                         return true;
6096                 }
6097
6098                 //
6099                 // Called from Invocation to check if the invocation is correct
6100                 //
6101                 public override void CheckMarshalByRefAccess (EmitContext ec)
6102                 {
6103                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6104                             !variable_info.IsAssigned (ec)) {
6105                                 Error (188, "The `this' object cannot be used before all of its " +
6106                                        "fields are assigned to");
6107                                 variable_info.SetAssigned (ec);
6108                         }
6109                 }
6110
6111                 public override Expression CreateExpressionTree (EmitContext ec)
6112                 {
6113                         ArrayList args = new ArrayList (2);
6114                         args.Add (new Argument (this));
6115                         args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6116                         return CreateExpressionFactoryCall ("Constant", args);
6117                 }
6118                 
6119                 public override Expression DoResolve (EmitContext ec)
6120                 {
6121                         if (!ResolveBase (ec))
6122                                 return null;
6123
6124
6125                         if (ec.IsInFieldInitializer) {
6126                                 Error (27, "Keyword `this' is not available in the current context");
6127                                 return null;
6128                         }
6129                         
6130                         return this;
6131                 }
6132
6133                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6134                 {
6135                         if (!ResolveBase (ec))
6136                                 return null;
6137
6138                         if (variable_info != null)
6139                                 variable_info.SetAssigned (ec);
6140                         
6141                         if (ec.TypeContainer is Class){
6142                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6143                                 return null;
6144                         }
6145
6146                         return this;
6147                 }
6148                 public override int GetHashCode()
6149                 {
6150                         return block.GetHashCode ();
6151                 }
6152
6153                 public override bool Equals (object obj)
6154                 {
6155                         This t = obj as This;
6156                         if (t == null)
6157                                 return false;
6158
6159                         return block == t.block;
6160                 }
6161
6162                 protected class SimpleThis : Variable
6163                 {
6164                         Type type;
6165
6166                         public SimpleThis (Type type)
6167                         {
6168                                 this.type = type;
6169                         }
6170
6171                         public override Type Type {
6172                                 get { return type; }
6173                         }
6174
6175                         public override bool HasInstance {
6176                                 get { return false; }
6177                         }
6178
6179                         public override bool NeedsTemporary {
6180                                 get { return false; }
6181                         }
6182
6183                         public override void EmitInstance (EmitContext ec)
6184                         {
6185                                 // Do nothing.
6186                         }
6187
6188                         public override void Emit (EmitContext ec)
6189                         {
6190                                 ec.ig.Emit (OpCodes.Ldarg_0);
6191                         }
6192
6193                         public override void EmitAssign (EmitContext ec)
6194                         {
6195                                 throw new InvalidOperationException ();
6196                         }
6197
6198                         public override void EmitAddressOf (EmitContext ec)
6199                         {
6200                                 ec.ig.Emit (OpCodes.Ldarg_0);
6201                         }
6202                 }
6203
6204                 protected override void CloneTo (CloneContext clonectx, Expression t)
6205                 {
6206                         This target = (This) t;
6207
6208                         target.block = clonectx.LookupBlock (block);
6209                 }
6210         }
6211
6212         /// <summary>
6213         ///   Represents the `__arglist' construct
6214         /// </summary>
6215         public class ArglistAccess : Expression
6216         {
6217                 public ArglistAccess (Location loc)
6218                 {
6219                         this.loc = loc;
6220                 }
6221
6222                 public override Expression DoResolve (EmitContext ec)
6223                 {
6224                         eclass = ExprClass.Variable;
6225                         type = TypeManager.runtime_argument_handle_type;
6226
6227                         if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6228                         {
6229                                 Error (190, "The __arglist construct is valid only within " +
6230                                        "a variable argument method");
6231                                 return null;
6232                         }
6233
6234                         return this;
6235                 }
6236
6237                 public override void Emit (EmitContext ec)
6238                 {
6239                         ec.ig.Emit (OpCodes.Arglist);
6240                 }
6241
6242                 protected override void CloneTo (CloneContext clonectx, Expression target)
6243                 {
6244                         // nothing.
6245                 }
6246         }
6247
6248         /// <summary>
6249         ///   Represents the `__arglist (....)' construct
6250         /// </summary>
6251         public class Arglist : Expression
6252         {
6253                 Argument[] Arguments;
6254
6255                 public Arglist (Location loc)
6256                         : this (Argument.Empty, loc)
6257                 {
6258                 }
6259
6260                 public Arglist (Argument[] args, Location l)
6261                 {
6262                         Arguments = args;
6263                         loc = l;
6264                 }
6265
6266                 public Type[] ArgumentTypes {
6267                         get {
6268                                 Type[] retval = new Type [Arguments.Length];
6269                                 for (int i = 0; i < Arguments.Length; i++)
6270                                         retval [i] = Arguments [i].Type;
6271                                 return retval;
6272                         }
6273                 }
6274                 
6275                 public override Expression CreateExpressionTree (EmitContext ec)
6276                 {
6277                         Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6278                         return null;
6279                 }
6280
6281                 public override Expression DoResolve (EmitContext ec)
6282                 {
6283                         eclass = ExprClass.Variable;
6284                         type = TypeManager.runtime_argument_handle_type;
6285
6286                         foreach (Argument arg in Arguments) {
6287                                 if (!arg.Resolve (ec, loc))
6288                                         return null;
6289                         }
6290
6291                         return this;
6292                 }
6293
6294                 public override void Emit (EmitContext ec)
6295                 {
6296                         foreach (Argument arg in Arguments)
6297                                 arg.Emit (ec);
6298                 }
6299
6300                 protected override void CloneTo (CloneContext clonectx, Expression t)
6301                 {
6302                         Arglist target = (Arglist) t;
6303
6304                         target.Arguments = new Argument [Arguments.Length];
6305                         for (int i = 0; i < Arguments.Length; i++)
6306                                 target.Arguments [i] = Arguments [i].Clone (clonectx);
6307                 }
6308         }
6309
6310         //
6311         // This produces the value that renders an instance, used by the iterators code
6312         //
6313         public class ProxyInstance : Expression, IMemoryLocation  {
6314                 public override Expression DoResolve (EmitContext ec)
6315                 {
6316                         eclass = ExprClass.Variable;
6317                         type = ec.ContainerType;
6318                         return this;
6319                 }
6320                 
6321                 public override void Emit (EmitContext ec)
6322                 {
6323                         ec.ig.Emit (OpCodes.Ldarg_0);
6324
6325                 }
6326                 
6327                 public void AddressOf (EmitContext ec, AddressOp mode)
6328                 {
6329                         ec.ig.Emit (OpCodes.Ldarg_0);
6330                 }
6331         }
6332
6333         /// <summary>
6334         ///   Implements the typeof operator
6335         /// </summary>
6336         public class TypeOf : Expression {
6337                 Expression QueriedType;
6338                 protected Type typearg;
6339                 
6340                 public TypeOf (Expression queried_type, Location l)
6341                 {
6342                         QueriedType = queried_type;
6343                         loc = l;
6344                 }
6345
6346                 public override Expression DoResolve (EmitContext ec)
6347                 {
6348                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6349                         if (texpr == null)
6350                                 return null;
6351
6352                         typearg = texpr.Type;
6353
6354                         if (typearg == TypeManager.void_type) {
6355                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6356                                 return null;
6357                         }
6358
6359                         if (typearg.IsPointer && !ec.InUnsafe){
6360                                 UnsafeError (loc);
6361                                 return null;
6362                         }
6363
6364                         type = TypeManager.type_type;
6365                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6366                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6367                         eclass = ExprClass.Value;
6368                         return this;
6369                 }
6370
6371                 public override void Emit (EmitContext ec)
6372                 {
6373                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6374                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6375                 }
6376
6377                 public override bool GetAttributableValue (Type value_type, out object value)
6378                 {
6379                         if (TypeManager.ContainsGenericParameters (typearg) &&
6380                                 !TypeManager.IsGenericTypeDefinition (typearg)) {
6381                                 Report.SymbolRelatedToPreviousError (typearg);
6382                                 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6383                                              TypeManager.CSharpName (typearg));
6384                                 value = null;
6385                                 return false;
6386                         }
6387
6388                         if (value_type == TypeManager.object_type) {
6389                                 value = (object)typearg;
6390                                 return true;
6391                         }
6392                         value = typearg;
6393                         return true;
6394                 }
6395
6396                 public Type TypeArgument
6397                 {
6398                         get
6399                         {
6400                                 return typearg;
6401                         }
6402                 }
6403
6404                 protected override void CloneTo (CloneContext clonectx, Expression t)
6405                 {
6406                         TypeOf target = (TypeOf) t;
6407
6408                         target.QueriedType = QueriedType.Clone (clonectx);
6409                 }
6410         }
6411
6412         /// <summary>
6413         ///   Implements the `typeof (void)' operator
6414         /// </summary>
6415         public class TypeOfVoid : TypeOf {
6416                 public TypeOfVoid (Location l) : base (null, l)
6417                 {
6418                         loc = l;
6419                 }
6420
6421                 public override Expression DoResolve (EmitContext ec)
6422                 {
6423                         type = TypeManager.type_type;
6424                         typearg = TypeManager.void_type;
6425                         // See description in TypeOf.
6426                         eclass = ExprClass.Value;
6427                         return this;
6428                 }
6429         }
6430
6431         internal class TypeOfMethod : Expression
6432         {
6433                 readonly MethodGroupExpr method;
6434                 static MethodInfo get_type_from_handle;
6435
6436                 static TypeOfMethod ()
6437                 {
6438                         get_type_from_handle = typeof (MethodBase).GetMethod ("GetMethodFromHandle",
6439                                 new Type [] { TypeManager.runtime_method_handle_type });
6440                 }
6441
6442                 public TypeOfMethod (MethodGroupExpr method)
6443                 {
6444                         this.method = method;
6445                         loc = method.Location;
6446                 }
6447
6448                 public override Expression DoResolve (EmitContext ec)
6449                 {
6450                         type = typeof (MethodBase);
6451                         eclass = ExprClass.Value;
6452                         return this;
6453                 }
6454
6455                 public override void Emit (EmitContext ec)
6456                 {
6457                         ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
6458                         ec.ig.Emit (OpCodes.Call, get_type_from_handle);
6459                 }
6460         }
6461
6462         /// <summary>
6463         ///   Implements the sizeof expression
6464         /// </summary>
6465         public class SizeOf : Expression {
6466                 readonly Expression QueriedType;
6467                 Type type_queried;
6468                 
6469                 public SizeOf (Expression queried_type, Location l)
6470                 {
6471                         this.QueriedType = queried_type;
6472                         loc = l;
6473                 }
6474
6475                 public override Expression DoResolve (EmitContext ec)
6476                 {
6477                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6478                         if (texpr == null)
6479                                 return null;
6480
6481 #if GMCS_SOURCE
6482                         if (texpr is TypeParameterExpr){
6483                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6484                                 return null;
6485                         }
6486 #endif
6487
6488                         type_queried = texpr.Type;
6489                         if (type_queried.IsEnum)
6490                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
6491
6492                         if (type_queried == TypeManager.void_type) {
6493                                 Expression.Error_VoidInvalidInTheContext (loc);
6494                                 return null;
6495                         }
6496
6497                         int size_of = GetTypeSize (type_queried);
6498                         if (size_of > 0) {
6499                                 return new IntConstant (size_of, loc);
6500                         }
6501
6502                         if (!ec.InUnsafe) {
6503                                 Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
6504                                          TypeManager.CSharpName (type_queried));
6505                                 return null;
6506                         }
6507
6508                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6509                                 return null;
6510                         }
6511                         
6512                         type = TypeManager.int32_type;
6513                         eclass = ExprClass.Value;
6514                         return this;
6515                 }
6516
6517                 public override void Emit (EmitContext ec)
6518                 {
6519                         int size = GetTypeSize (type_queried);
6520
6521                         if (size == 0)
6522                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6523                         else
6524                                 IntConstant.EmitInt (ec.ig, size);
6525                 }
6526
6527                 protected override void CloneTo (CloneContext clonectx, Expression t)
6528                 {
6529                 }
6530         }
6531
6532         /// <summary>
6533         ///   Implements the qualified-alias-member (::) expression.
6534         /// </summary>
6535         public class QualifiedAliasMember : Expression
6536         {
6537                 string alias, identifier;
6538
6539                 public QualifiedAliasMember (string alias, string identifier, Location l)
6540                 {
6541                         this.alias = alias;
6542                         this.identifier = identifier;
6543                         loc = l;
6544                 }
6545
6546                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6547                 {
6548                         if (alias == "global")
6549                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6550
6551                         int errors = Report.Errors;
6552                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6553                         if (fne == null) {
6554                                 if (errors == Report.Errors)
6555                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
6556                                 return null;
6557                         }
6558                         if (fne.eclass != ExprClass.Namespace) {
6559                                 if (!silent)
6560                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6561                                 return null;
6562                         }
6563                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6564                 }
6565
6566                 public override Expression DoResolve (EmitContext ec)
6567                 {
6568                         FullNamedExpression fne;
6569                         if (alias == "global") {
6570                                 fne = RootNamespace.Global;
6571                         } else {
6572                                 int errors = Report.Errors;
6573                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6574                                 if (fne == null) {
6575                                         if (errors == Report.Errors)
6576                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
6577                                         return null;
6578                                 }
6579                         }
6580
6581                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6582                         if (retval == null)
6583                                 return null;
6584
6585                         if (!(retval is FullNamedExpression)) {
6586                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6587                                 return null;
6588                         }
6589
6590                         // We defer this check till the end to match the behaviour of CSC
6591                         if (fne.eclass != ExprClass.Namespace) {
6592                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6593                                 return null;
6594                         }
6595                         return retval;
6596                 }
6597
6598                 public override void Emit (EmitContext ec)
6599                 {
6600                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6601                 }
6602
6603
6604                 public override string ToString ()
6605                 {
6606                         return alias + "::" + identifier;
6607                 }
6608
6609                 public override string GetSignatureForError ()
6610                 {
6611                         return ToString ();
6612                 }
6613
6614                 protected override void CloneTo (CloneContext clonectx, Expression t)
6615                 {
6616                         // Nothing 
6617                 }
6618         }
6619
6620         /// <summary>
6621         ///   Implements the member access expression
6622         /// </summary>
6623         public class MemberAccess : Expression {
6624                 public readonly string Identifier;
6625                 Expression expr;
6626                 readonly TypeArguments args;
6627
6628                 public MemberAccess (Expression expr, string id)
6629                         : this (expr, id, expr.Location)
6630                 {
6631                 }
6632
6633                 public MemberAccess (Expression expr, string identifier, Location loc)
6634                 {
6635                         this.expr = expr;
6636                         Identifier = identifier;
6637                         this.loc = loc;
6638                 }
6639
6640                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6641                         : this (expr, identifier, loc)
6642                 {
6643                         this.args = args;
6644                 }
6645
6646                 protected string LookupIdentifier {
6647                         get { return MemberName.MakeName (Identifier, args); }
6648                 }
6649
6650                 // TODO: this method has very poor performace for Enum fields and
6651                 // probably for other constants as well
6652                 Expression DoResolve (EmitContext ec, Expression right_side)
6653                 {
6654                         if (type != null)
6655                                 throw new Exception ();
6656
6657                         //
6658                         // Resolve the expression with flow analysis turned off, we'll do the definite
6659                         // assignment checks later.  This is because we don't know yet what the expression
6660                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6661                         // definite assignment check on the actual field and not on the whole struct.
6662                         //
6663
6664                         SimpleName original = expr as SimpleName;
6665                         Expression expr_resolved = expr.Resolve (ec,
6666                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6667                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6668
6669                         if (expr_resolved == null)
6670                                 return null;
6671
6672                         if (expr_resolved is Namespace) {
6673                                 Namespace ns = (Namespace) expr_resolved;
6674                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6675 #if GMCS_SOURCE
6676                                 if ((retval != null) && (args != null))
6677                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6678 #endif
6679
6680                                 if (retval == null)
6681                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6682                                 return retval;
6683                         }
6684
6685                         Type expr_type = expr_resolved.Type;
6686                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6687                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6688                                 return null;
6689                         }
6690                         if (expr_type == TypeManager.anonymous_method_type){
6691                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6692                                 return null;
6693                         }
6694
6695                         Constant c = expr_resolved as Constant;
6696                         if (c != null && c.GetValue () == null) {
6697                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6698                                         "System.NullReferenceException");
6699                         }
6700
6701                         if (args != null) {
6702                                 if (!args.Resolve (ec))
6703                                         return null;
6704                         }
6705
6706                         Expression member_lookup;
6707                         member_lookup = MemberLookup (
6708                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6709 #if GMCS_SOURCE
6710                         if ((member_lookup == null) && (args != null)) {
6711                                 member_lookup = MemberLookup (
6712                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6713                         }
6714 #endif
6715                         if (member_lookup == null) {
6716                                 ExprClass expr_eclass = expr_resolved.eclass;
6717
6718                                 //
6719                                 // Extension methods are not allowed on all expression types
6720                                 //
6721                                 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
6722                                         expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
6723                                         expr_eclass == ExprClass.EventAccess) {
6724                                         ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
6725                                         if (ex_method_lookup != null) {
6726                                                 ex_method_lookup.ExtensionExpression = expr_resolved;
6727
6728                                                 if (args != null) {
6729                                                         ex_method_lookup.SetTypeArguments (args);
6730                                                 }
6731
6732                                                 return ex_method_lookup.DoResolve (ec);
6733                                         }
6734                                 }
6735
6736                                 expr = expr_resolved;
6737                                 Error_MemberLookupFailed (
6738                                         ec.ContainerType, expr_type, expr_type, Identifier, null,
6739                                         AllMemberTypes, AllBindingFlags);
6740                                 return null;
6741                         }
6742
6743                         TypeExpr texpr = member_lookup as TypeExpr;
6744                         if (texpr != null) {
6745                                 if (!(expr_resolved is TypeExpr) && 
6746                                     (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6747                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6748                                                 Identifier, member_lookup.GetSignatureForError ());
6749                                         return null;
6750                                 }
6751
6752                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6753                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
6754                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6755                                         return null;
6756                                 }
6757
6758 #if GMCS_SOURCE
6759                                 ConstructedType ct = expr_resolved as ConstructedType;
6760                                 if (ct != null) {
6761                                         //
6762                                         // When looking up a nested type in a generic instance
6763                                         // via reflection, we always get a generic type definition
6764                                         // and not a generic instance - so we have to do this here.
6765                                         //
6766                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
6767                                         //
6768                                         ct = new ConstructedType (
6769                                                 member_lookup.Type, ct.TypeArguments, loc);
6770
6771                                         return ct.ResolveAsTypeStep (ec, false);
6772                                 }
6773 #endif
6774                                 return member_lookup;
6775                         }
6776
6777                         MemberExpr me = (MemberExpr) member_lookup;
6778                         me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6779                         if (me == null)
6780                                 return null;
6781
6782                         if (args != null) {
6783                                 me.SetTypeArguments (args);
6784                         }
6785
6786                         if (original != null && !TypeManager.IsValueType (expr_type)) {
6787                                 if (me.IsInstance) {
6788                                         LocalVariableReference var = expr_resolved as LocalVariableReference;
6789                                         if (var != null && !var.VerifyAssigned (ec))
6790                                                 return null;
6791                                 }
6792                         }
6793
6794                         // The following DoResolve/DoResolveLValue will do the definite assignment
6795                         // check.
6796
6797                         if (right_side != null)
6798                                 return me.DoResolveLValue (ec, right_side);
6799                         else
6800                                 return me.DoResolve (ec);
6801                 }
6802
6803                 public override Expression DoResolve (EmitContext ec)
6804                 {
6805                         return DoResolve (ec, null);
6806                 }
6807
6808                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6809                 {
6810                         return DoResolve (ec, right_side);
6811                 }
6812
6813                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6814                 {
6815                         return ResolveNamespaceOrType (ec, silent);
6816                 }
6817
6818                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6819                 {
6820                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6821
6822                         if (new_expr == null)
6823                                 return null;
6824
6825                         if (new_expr is Namespace) {
6826                                 Namespace ns = (Namespace) new_expr;
6827                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6828 #if GMCS_SOURCE
6829                                 if ((retval != null) && (args != null))
6830                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6831 #endif
6832                                 if (!silent && retval == null)
6833                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6834                                 return retval;
6835                         }
6836
6837                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6838                         if (tnew_expr == null)
6839                                 return null;
6840
6841                         Type expr_type = tnew_expr.Type;
6842
6843                         if (expr_type.IsPointer){
6844                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6845                                        TypeManager.CSharpName (expr_type) + ")");
6846                                 return null;
6847                         }
6848
6849                         Expression member_lookup = MemberLookup (
6850                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6851                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6852                         if (member_lookup == null) {
6853                                 if (silent)
6854                                         return null;
6855
6856                                 member_lookup = MemberLookup (
6857                                         rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
6858                                         MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6859
6860                                 if (member_lookup != null) {
6861                                         tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
6862                                         if (tnew_expr == null)
6863                                                 return null;
6864
6865                                         Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
6866                                         return null;
6867                                 }
6868
6869                                 member_lookup = MemberLookup (
6870                                         rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6871                                                 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6872
6873                                 if (member_lookup == null) {
6874                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6875                                                           Identifier, new_expr.GetSignatureForError ());
6876                                 } else {
6877                                         // TODO: Report.SymbolRelatedToPreviousError
6878                                         member_lookup.Error_UnexpectedKind (null, "type", loc);
6879                                 }
6880                                 return null;
6881                         }
6882
6883                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6884                         if (texpr == null)
6885                                 return null;
6886
6887 #if GMCS_SOURCE
6888                         TypeArguments the_args = args;
6889                         Type declaring_type = texpr.Type.DeclaringType;
6890                         if (TypeManager.HasGenericArguments (declaring_type)) {
6891                                 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
6892                                         expr_type = expr_type.BaseType;
6893                                 }
6894                                 
6895                                 TypeArguments new_args = new TypeArguments (loc);
6896                                 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
6897                                         new_args.Add (new TypeExpression (decl, loc));
6898
6899                                 if (args != null)
6900                                         new_args.Add (args);
6901
6902                                 the_args = new_args;
6903                         }
6904
6905                         if (the_args != null) {
6906                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6907                                 return ctype.ResolveAsTypeStep (rc, false);
6908                         }
6909 #endif
6910
6911                         return texpr;
6912                 }
6913
6914                 public override void Emit (EmitContext ec)
6915                 {
6916                         throw new Exception ("Should not happen");
6917                 }
6918
6919                 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
6920                 {
6921                         if (RootContext.Version > LanguageVersion.ISO_2 &&
6922                                 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
6923                                 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
6924                                         "extension method `{1}' of type `{0}' could be found " +
6925                                         "(are you missing a using directive or an assembly reference?)",
6926                                         TypeManager.CSharpName (type), name);
6927                                 return;
6928                         }
6929
6930                         base.Error_TypeDoesNotContainDefinition (type, name);
6931                 }
6932
6933                 public override string ToString ()
6934                 {
6935                         return expr + "." + MemberName.MakeName (Identifier, args);
6936                 }
6937
6938                 public override string GetSignatureForError ()
6939                 {
6940                         return expr.GetSignatureForError () + "." + Identifier;
6941                 }
6942
6943                 protected override void CloneTo (CloneContext clonectx, Expression t)
6944                 {
6945                         MemberAccess target = (MemberAccess) t;
6946
6947                         target.expr = expr.Clone (clonectx);
6948                 }
6949         }
6950
6951         /// <summary>
6952         ///   Implements checked expressions
6953         /// </summary>
6954         public class CheckedExpr : Expression {
6955
6956                 public Expression Expr;
6957
6958                 public CheckedExpr (Expression e, Location l)
6959                 {
6960                         Expr = e;
6961                         loc = l;
6962                 }
6963
6964                 public override Expression DoResolve (EmitContext ec)
6965                 {
6966                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6967                                 Expr = Expr.Resolve (ec);
6968                         
6969                         if (Expr == null)
6970                                 return null;
6971
6972                         if (Expr is Constant)
6973                                 return Expr;
6974                         
6975                         eclass = Expr.eclass;
6976                         type = Expr.Type;
6977                         return this;
6978                 }
6979
6980                 public override void Emit (EmitContext ec)
6981                 {
6982                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6983                                 Expr.Emit (ec);
6984                 }
6985
6986                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
6987                 {
6988                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6989                                 Expr.EmitBranchable (ec, target, on_true);
6990                 }
6991
6992                 protected override void CloneTo (CloneContext clonectx, Expression t)
6993                 {
6994                         CheckedExpr target = (CheckedExpr) t;
6995
6996                         target.Expr = Expr.Clone (clonectx);
6997                 }
6998         }
6999
7000         /// <summary>
7001         ///   Implements the unchecked expression
7002         /// </summary>
7003         public class UnCheckedExpr : Expression {
7004
7005                 public Expression Expr;
7006
7007                 public UnCheckedExpr (Expression e, Location l)
7008                 {
7009                         Expr = e;
7010                         loc = l;
7011                 }
7012
7013                 public override Expression DoResolve (EmitContext ec)
7014                 {
7015                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7016                                 Expr = Expr.Resolve (ec);
7017
7018                         if (Expr == null)
7019                                 return null;
7020
7021                         if (Expr is Constant)
7022                                 return Expr;
7023                         
7024                         eclass = Expr.eclass;
7025                         type = Expr.Type;
7026                         return this;
7027                 }
7028
7029                 public override void Emit (EmitContext ec)
7030                 {
7031                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7032                                 Expr.Emit (ec);
7033                 }
7034                 
7035                 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7036                 {
7037                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7038                                 Expr.EmitBranchable (ec, target, on_true);
7039                 }
7040
7041                 protected override void CloneTo (CloneContext clonectx, Expression t)
7042                 {
7043                         UnCheckedExpr target = (UnCheckedExpr) t;
7044
7045                         target.Expr = Expr.Clone (clonectx);
7046                 }
7047         }
7048
7049         /// <summary>
7050         ///   An Element Access expression.
7051         ///
7052         ///   During semantic analysis these are transformed into 
7053         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7054         /// </summary>
7055         public class ElementAccess : Expression {
7056                 public ArrayList  Arguments;
7057                 public Expression Expr;
7058                 
7059                 public ElementAccess (Expression e, ArrayList e_list)
7060                 {
7061                         Expr = e;
7062
7063                         loc  = e.Location;
7064                         
7065                         if (e_list == null)
7066                                 return;
7067                         
7068                         Arguments = new ArrayList ();
7069                         foreach (Expression tmp in e_list)
7070                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7071                         
7072                 }
7073
7074                 bool CommonResolve (EmitContext ec)
7075                 {
7076                         Expr = Expr.Resolve (ec);
7077
7078                         if (Arguments == null)
7079                                 return false;
7080
7081                         foreach (Argument a in Arguments){
7082                                 if (!a.Resolve (ec, loc))
7083                                         return false;
7084                         }
7085
7086                         return Expr != null;
7087                 }
7088
7089                 public override Expression CreateExpressionTree (EmitContext ec)
7090                 {
7091                         ArrayList args = new ArrayList (Arguments.Count + 1);
7092                         args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7093                         foreach (Argument a in Arguments)
7094                                 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7095
7096                         return CreateExpressionFactoryCall ("ArrayIndex", args);
7097                 }
7098
7099                 Expression MakePointerAccess (EmitContext ec, Type t)
7100                 {
7101                         if (t == TypeManager.void_ptr_type){
7102                                 Error (242, "The array index operation is not valid on void pointers");
7103                                 return null;
7104                         }
7105                         if (Arguments.Count != 1){
7106                                 Error (196, "A pointer must be indexed by only one value");
7107                                 return null;
7108                         }
7109                         Expression p;
7110
7111                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7112                         if (p == null)
7113                                 return null;
7114                         return new Indirection (p, loc).Resolve (ec);
7115                 }
7116                 
7117                 public override Expression DoResolve (EmitContext ec)
7118                 {
7119                         if (!CommonResolve (ec))
7120                                 return null;
7121
7122                         //
7123                         // We perform some simple tests, and then to "split" the emit and store
7124                         // code we create an instance of a different class, and return that.
7125                         //
7126                         // I am experimenting with this pattern.
7127                         //
7128                         Type t = Expr.Type;
7129
7130                         if (t == TypeManager.array_type){
7131                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7132                                 return null;
7133                         }
7134                         
7135                         if (t.IsArray)
7136                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7137                         if (t.IsPointer)
7138                                 return MakePointerAccess (ec, t);
7139
7140                         FieldExpr fe = Expr as FieldExpr;
7141                         if (fe != null) {
7142                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7143                                 if (ff != null) {
7144                                         return MakePointerAccess (ec, ff.ElementType);
7145                                 }
7146                         }
7147                         return (new IndexerAccess (this, loc)).Resolve (ec);
7148                 }
7149
7150                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7151                 {
7152                         if (!CommonResolve (ec))
7153                                 return null;
7154
7155                         type = Expr.Type;
7156                         if (type.IsArray)
7157                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7158
7159                         if (type.IsPointer)
7160                                 return MakePointerAccess (ec, type);
7161
7162                         if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7163                                 Error_CannotModifyIntermediateExpressionValue (ec);
7164
7165                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7166                 }
7167                 
7168                 public override void Emit (EmitContext ec)
7169                 {
7170                         throw new Exception ("Should never be reached");
7171                 }
7172
7173                 public override string GetSignatureForError ()
7174                 {
7175                         return Expr.GetSignatureForError ();
7176                 }
7177
7178                 protected override void CloneTo (CloneContext clonectx, Expression t)
7179                 {
7180                         ElementAccess target = (ElementAccess) t;
7181
7182                         target.Expr = Expr.Clone (clonectx);
7183                         target.Arguments = new ArrayList (Arguments.Count);
7184                         foreach (Argument a in Arguments)
7185                                 target.Arguments.Add (a.Clone (clonectx));
7186                 }
7187         }
7188
7189         /// <summary>
7190         ///   Implements array access 
7191         /// </summary>
7192         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7193                 //
7194                 // Points to our "data" repository
7195                 //
7196                 ElementAccess ea;
7197
7198                 LocalTemporary temp;
7199                 LocalTemporary prepared_value;
7200
7201                 bool prepared;
7202                 
7203                 public ArrayAccess (ElementAccess ea_data, Location l)
7204                 {
7205                         ea = ea_data;
7206                         eclass = ExprClass.Variable;
7207                         loc = l;
7208                 }
7209
7210                 public override Expression CreateExpressionTree (EmitContext ec)
7211                 {
7212                         return ea.CreateExpressionTree (ec);
7213                 }
7214
7215                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7216                 {
7217                         return DoResolve (ec);
7218                 }
7219
7220                 public override Expression DoResolve (EmitContext ec)
7221                 {
7222 #if false
7223                         ExprClass eclass = ea.Expr.eclass;
7224
7225                         // As long as the type is valid
7226                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7227                               eclass == ExprClass.Value)) {
7228                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7229                                 return null;
7230                         }
7231 #endif
7232
7233                         Type t = ea.Expr.Type;
7234                         if (t.GetArrayRank () != ea.Arguments.Count) {
7235                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7236                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7237                                 return null;
7238                         }
7239
7240                         type = TypeManager.GetElementType (t);
7241                         if (type.IsPointer && !ec.InUnsafe) {
7242                                 UnsafeError (ea.Location);
7243                                 return null;
7244                         }
7245
7246                         foreach (Argument a in ea.Arguments) {
7247                                 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7248                         }
7249                         
7250                         eclass = ExprClass.Variable;
7251
7252                         return this;
7253                 }
7254
7255                 /// <summary>
7256                 ///    Emits the right opcode to load an object of Type `t'
7257                 ///    from an array of T
7258                 /// </summary>
7259                 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7260                 {
7261                         if (rank > 1) {
7262                                 MethodInfo get = FetchGetMethod ();
7263                                 ig.Emit (OpCodes.Call, get);
7264                                 return;
7265                         }
7266
7267                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7268                                 ig.Emit (OpCodes.Ldelem_U1);
7269                         else if (type == TypeManager.sbyte_type)
7270                                 ig.Emit (OpCodes.Ldelem_I1);
7271                         else if (type == TypeManager.short_type)
7272                                 ig.Emit (OpCodes.Ldelem_I2);
7273                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7274                                 ig.Emit (OpCodes.Ldelem_U2);
7275                         else if (type == TypeManager.int32_type)
7276                                 ig.Emit (OpCodes.Ldelem_I4);
7277                         else if (type == TypeManager.uint32_type)
7278                                 ig.Emit (OpCodes.Ldelem_U4);
7279                         else if (type == TypeManager.uint64_type)
7280                                 ig.Emit (OpCodes.Ldelem_I8);
7281                         else if (type == TypeManager.int64_type)
7282                                 ig.Emit (OpCodes.Ldelem_I8);
7283                         else if (type == TypeManager.float_type)
7284                                 ig.Emit (OpCodes.Ldelem_R4);
7285                         else if (type == TypeManager.double_type)
7286                                 ig.Emit (OpCodes.Ldelem_R8);
7287                         else if (type == TypeManager.intptr_type)
7288                                 ig.Emit (OpCodes.Ldelem_I);
7289                         else if (TypeManager.IsEnumType (type)){
7290                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
7291                         } else if (type.IsValueType){
7292                                 ig.Emit (OpCodes.Ldelema, type);
7293                                 ig.Emit (OpCodes.Ldobj, type);
7294 #if GMCS_SOURCE
7295                         } else if (type.IsGenericParameter) {
7296                                 ig.Emit (OpCodes.Ldelem, type);
7297 #endif
7298                         } else if (type.IsPointer)
7299                                 ig.Emit (OpCodes.Ldelem_I);
7300                         else
7301                                 ig.Emit (OpCodes.Ldelem_Ref);
7302                 }
7303
7304                 protected override void Error_NegativeArrayIndex (Location loc)
7305                 {
7306                         Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7307                 }
7308
7309                 /// <summary>
7310                 ///    Returns the right opcode to store an object of Type `t'
7311                 ///    from an array of T.  
7312                 /// </summary>
7313                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7314                 {
7315                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7316                         has_type_arg = false; is_stobj = false;
7317                         t = TypeManager.TypeToCoreType (t);
7318                         if (TypeManager.IsEnumType (t))
7319                                 t = TypeManager.EnumToUnderlying (t);
7320                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7321                             t == TypeManager.bool_type)
7322                                 return OpCodes.Stelem_I1;
7323                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7324                                  t == TypeManager.char_type)
7325                                 return OpCodes.Stelem_I2;
7326                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7327                                 return OpCodes.Stelem_I4;
7328                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7329                                 return OpCodes.Stelem_I8;
7330                         else if (t == TypeManager.float_type)
7331                                 return OpCodes.Stelem_R4;
7332                         else if (t == TypeManager.double_type)
7333                                 return OpCodes.Stelem_R8;
7334                         else if (t == TypeManager.intptr_type) {
7335                                 has_type_arg = true;
7336                                 is_stobj = true;
7337                                 return OpCodes.Stobj;
7338                         } else if (t.IsValueType) {
7339                                 has_type_arg = true;
7340                                 is_stobj = true;
7341                                 return OpCodes.Stobj;
7342 #if GMCS_SOURCE
7343                         } else if (t.IsGenericParameter) {
7344                                 has_type_arg = true;
7345                                 return OpCodes.Stelem;
7346 #endif
7347
7348                         } else if (t.IsPointer)
7349                                 return OpCodes.Stelem_I;
7350                         else
7351                                 return OpCodes.Stelem_Ref;
7352                 }
7353
7354                 MethodInfo FetchGetMethod ()
7355                 {
7356                         ModuleBuilder mb = CodeGen.Module.Builder;
7357                         int arg_count = ea.Arguments.Count;
7358                         Type [] args = new Type [arg_count];
7359                         MethodInfo get;
7360                         
7361                         for (int i = 0; i < arg_count; i++){
7362                                 //args [i++] = a.Type;
7363                                 args [i] = TypeManager.int32_type;
7364                         }
7365                         
7366                         get = mb.GetArrayMethod (
7367                                 ea.Expr.Type, "Get",
7368                                 CallingConventions.HasThis |
7369                                 CallingConventions.Standard,
7370                                 type, args);
7371                         return get;
7372                 }
7373                                 
7374
7375                 MethodInfo FetchAddressMethod ()
7376                 {
7377                         ModuleBuilder mb = CodeGen.Module.Builder;
7378                         int arg_count = ea.Arguments.Count;
7379                         Type [] args = new Type [arg_count];
7380                         MethodInfo address;
7381                         Type ret_type;
7382                         
7383                         ret_type = TypeManager.GetReferenceType (type);
7384                         
7385                         for (int i = 0; i < arg_count; i++){
7386                                 //args [i++] = a.Type;
7387                                 args [i] = TypeManager.int32_type;
7388                         }
7389                         
7390                         address = mb.GetArrayMethod (
7391                                 ea.Expr.Type, "Address",
7392                                 CallingConventions.HasThis |
7393                                 CallingConventions.Standard,
7394                                 ret_type, args);
7395
7396                         return address;
7397                 }
7398
7399                 //
7400                 // Load the array arguments into the stack.
7401                 //
7402                 // If we have been requested to cache the values (cached_locations array
7403                 // initialized), then load the arguments the first time and store them
7404                 // in locals.  otherwise load from local variables.
7405                 //
7406                 // prepare_for_load is used in compound assignments to cache original index
7407                 // values ( label[idx++] += s )
7408                 //
7409                 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
7410                 {
7411                         ea.Expr.Emit (ec);
7412
7413                         LocalTemporary[] indexes = null;
7414                         if (prepare_for_load) {
7415                                 ec.ig.Emit (OpCodes.Dup);
7416                                 indexes = new LocalTemporary [ea.Arguments.Count];
7417                         }
7418
7419                         for (int i = 0; i < ea.Arguments.Count; ++i) {
7420                                 ((Argument)ea.Arguments [i]).Emit (ec);
7421                                 if (!prepare_for_load)
7422                                         continue;
7423
7424                                 // Keep original array index value on the stack
7425                                 ec.ig.Emit (OpCodes.Dup);
7426
7427                                 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7428                                 indexes [i].Store (ec);
7429                         }
7430
7431                         return indexes;
7432                 }
7433
7434                 public void Emit (EmitContext ec, bool leave_copy)
7435                 {
7436                         int rank = ea.Expr.Type.GetArrayRank ();
7437                         ILGenerator ig = ec.ig;
7438
7439                         if (prepared_value != null) {
7440                                 prepared_value.Emit (ec);
7441                         } else if (prepared) {
7442                                 LoadFromPtr (ig, this.type);
7443                         } else {
7444                                 LoadArrayAndArguments (ec, false);
7445                                 EmitLoadOpcode (ig, type, rank);
7446                         }       
7447
7448                         if (leave_copy) {
7449                                 ig.Emit (OpCodes.Dup);
7450                                 temp = new LocalTemporary (this.type);
7451                                 temp.Store (ec);
7452                         }
7453                 }
7454                 
7455                 public override void Emit (EmitContext ec)
7456                 {
7457                         Emit (ec, false);
7458                 }
7459
7460                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7461                 {
7462                         int rank = ea.Expr.Type.GetArrayRank ();
7463                         ILGenerator ig = ec.ig;
7464                         Type t = source.Type;
7465                         prepared = prepare_for_load && !(source is StringConcat);
7466
7467                         if (prepared) {
7468                                 AddressOf (ec, AddressOp.LoadStore);
7469                                 ec.ig.Emit (OpCodes.Dup);
7470                         } else {
7471                                 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7472                                         prepare_for_load && (source is StringConcat));
7473
7474                                 if (original_indexes_values != null) {
7475                                         prepared_value = new LocalTemporary (type);
7476                                         EmitLoadOpcode (ig, type, rank);
7477                                         prepared_value.Store (ec);
7478                                         foreach (LocalTemporary lt in original_indexes_values) {
7479                                                 lt.Emit (ec);
7480                                                 lt.Release (ec);
7481                                         }
7482                                 }
7483                         }
7484
7485                         if (rank == 1) {
7486                                 bool is_stobj, has_type_arg;
7487                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7488
7489                                 if (!prepared) {
7490                                         //
7491                                         // The stobj opcode used by value types will need
7492                                         // an address on the stack, not really an array/array
7493                                         // pair
7494                                         //
7495                                         if (is_stobj)
7496                                                 ig.Emit (OpCodes.Ldelema, t);
7497                                 }
7498                                 
7499                                 source.Emit (ec);
7500                                 if (leave_copy) {
7501                                         ec.ig.Emit (OpCodes.Dup);
7502                                         temp = new LocalTemporary (this.type);
7503                                         temp.Store (ec);
7504                                 }
7505                                 
7506                                 if (prepared)
7507                                         StoreFromPtr (ig, t);
7508                                 else if (is_stobj)
7509                                         ig.Emit (OpCodes.Stobj, t);
7510                                 else if (has_type_arg)
7511                                         ig.Emit (op, t);
7512                                 else
7513                                         ig.Emit (op);
7514                         } else {
7515                                 source.Emit (ec);
7516                                 if (leave_copy) {
7517                                         ec.ig.Emit (OpCodes.Dup);
7518                                         temp = new LocalTemporary (this.type);
7519                                         temp.Store (ec);
7520                                 }
7521
7522                                 if (prepared) {
7523                                         StoreFromPtr (ig, t);
7524                                 } else {
7525                                         int arg_count = ea.Arguments.Count;
7526                                         Type [] args = new Type [arg_count + 1];
7527                                         for (int i = 0; i < arg_count; i++) {
7528                                                 //args [i++] = a.Type;
7529                                                 args [i] = TypeManager.int32_type;
7530                                         }
7531                                         args [arg_count] = type;
7532
7533                                         MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7534                                                 ea.Expr.Type, "Set",
7535                                                 CallingConventions.HasThis |
7536                                                 CallingConventions.Standard,
7537                                                 TypeManager.void_type, args);
7538
7539                                         ig.Emit (OpCodes.Call, set);
7540                                 }
7541                         }
7542                         
7543                         if (temp != null) {
7544                                 temp.Emit (ec);
7545                                 temp.Release (ec);
7546                         }
7547                 }
7548
7549                 public void AddressOf (EmitContext ec, AddressOp mode)
7550                 {
7551                         int rank = ea.Expr.Type.GetArrayRank ();
7552                         ILGenerator ig = ec.ig;
7553
7554                         LoadArrayAndArguments (ec, false);
7555
7556                         if (rank == 1){
7557                                 ig.Emit (OpCodes.Ldelema, type);
7558                         } else {
7559                                 MethodInfo address = FetchAddressMethod ();
7560                                 ig.Emit (OpCodes.Call, address);
7561                         }
7562                 }
7563
7564                 public void EmitGetLength (EmitContext ec, int dim)
7565                 {
7566                         int rank = ea.Expr.Type.GetArrayRank ();
7567                         ILGenerator ig = ec.ig;
7568
7569                         ea.Expr.Emit (ec);
7570                         if (rank == 1) {
7571                                 ig.Emit (OpCodes.Ldlen);
7572                                 ig.Emit (OpCodes.Conv_I4);
7573                         } else {
7574                                 IntLiteral.EmitInt (ig, dim);
7575                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7576                         }
7577                 }
7578         }
7579
7580         /// <summary>
7581         ///   Expressions that represent an indexer call.
7582         /// </summary>
7583         public class IndexerAccess : Expression, IAssignMethod
7584         {
7585                 class IndexerMethodGroupExpr : MethodGroupExpr
7586                 {
7587                         public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7588                                 : base (null, loc)
7589                         {
7590                                 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7591                         }
7592
7593                         public override string Name {
7594                                 get {
7595                                         return "this";
7596                                 }
7597                         }
7598
7599                         protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7600                         {
7601                                 //
7602                                 // Here is the trick, decrease number of arguments by 1 when only
7603                                 // available property method is setter. This makes overload resolution
7604                                 // work correctly for indexers.
7605                                 //
7606                                 
7607                                 if (method.Name [0] == 'g')
7608                                         return parameters.Count;
7609
7610                                 return parameters.Count - 1;
7611                         }
7612                 }
7613
7614                 class Indexers
7615                 {
7616                         // Contains either property getter or setter
7617                         public ArrayList Methods;
7618                         public ArrayList Properties;
7619
7620                         Indexers ()
7621                         {
7622                         }
7623
7624                         void Append (Type caller_type, MemberInfo [] mi)
7625                         {
7626                                 if (mi == null)
7627                                         return;
7628
7629                                 foreach (PropertyInfo property in mi) {
7630                                         MethodInfo accessor = property.GetGetMethod (true);
7631                                         if (accessor == null)
7632                                                 accessor = property.GetSetMethod (true);
7633
7634                                         if (Methods == null) {
7635                                                 Methods = new ArrayList ();
7636                                                 Properties = new ArrayList ();
7637                                         }
7638
7639                                         Methods.Add (accessor);
7640                                         Properties.Add (property);
7641                                 }
7642                         }
7643
7644                         static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7645                         {
7646                                 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7647
7648                                 return TypeManager.MemberLookup (
7649                                         caller_type, caller_type, lookup_type, MemberTypes.Property,
7650                                         BindingFlags.Public | BindingFlags.Instance |
7651                                         BindingFlags.DeclaredOnly, p_name, null);
7652                         }
7653                         
7654                         public static Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
7655                         {
7656                                 Indexers ix = new Indexers ();
7657
7658         #if GMCS_SOURCE
7659                                 if (lookup_type.IsGenericParameter) {
7660                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7661                                         if (gc == null)
7662                                                 return ix;
7663
7664                                         if (gc.HasClassConstraint)
7665                                                 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7666
7667                                         Type[] ifaces = gc.InterfaceConstraints;
7668                                         foreach (Type itype in ifaces)
7669                                                 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7670
7671                                         return ix;
7672                                 }
7673         #endif
7674
7675                                 Type copy = lookup_type;
7676                                 while (copy != TypeManager.object_type && copy != null){
7677                                         ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7678                                         copy = copy.BaseType;
7679                                 }
7680
7681                                 if (lookup_type.IsInterface) {
7682                                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7683                                         if (ifaces != null) {
7684                                                 foreach (Type itype in ifaces)
7685                                                         ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7686                                         }
7687                                 }
7688
7689                                 return ix;
7690                         }
7691                 }
7692
7693                 enum AccessorType
7694                 {
7695                         Get,
7696                         Set
7697                 }
7698
7699                 //
7700                 // Points to our "data" repository
7701                 //
7702                 MethodInfo get, set;
7703                 bool is_base_indexer;
7704                 bool prepared;
7705                 LocalTemporary temp;
7706                 LocalTemporary prepared_value;
7707                 Expression set_expr;
7708
7709                 protected Type indexer_type;
7710                 protected Type current_type;
7711                 protected Expression instance_expr;
7712                 protected ArrayList arguments;
7713                 
7714                 public IndexerAccess (ElementAccess ea, Location loc)
7715                         : this (ea.Expr, false, loc)
7716                 {
7717                         this.arguments = ea.Arguments;
7718                 }
7719
7720                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7721                                          Location loc)
7722                 {
7723                         this.instance_expr = instance_expr;
7724                         this.is_base_indexer = is_base_indexer;
7725                         this.eclass = ExprClass.Value;
7726                         this.loc = loc;
7727                 }
7728
7729                 static string GetAccessorName (AccessorType at)
7730                 {
7731                         if (at == AccessorType.Set)
7732                                 return "set";
7733
7734                         if (at == AccessorType.Get)
7735                                 return "get";
7736
7737                         throw new NotImplementedException (at.ToString ());
7738                 }
7739
7740                 protected virtual bool CommonResolve (EmitContext ec)
7741                 {
7742                         indexer_type = instance_expr.Type;
7743                         current_type = ec.ContainerType;
7744
7745                         return true;
7746                 }
7747
7748                 public override Expression DoResolve (EmitContext ec)
7749                 {
7750                         return ResolveAccessor (ec, AccessorType.Get);
7751                 }
7752
7753                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7754                 {
7755                         if (right_side == EmptyExpression.OutAccess) {
7756                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7757                                               GetSignatureForError ());
7758                                 return null;
7759                         }
7760
7761                         // if the indexer returns a value type, and we try to set a field in it
7762                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7763                                 Error_CannotModifyIntermediateExpressionValue (ec);
7764                         }
7765
7766                         Expression e = ResolveAccessor (ec, AccessorType.Set);
7767                         if (e == null)
7768                                 return null;
7769
7770                         set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
7771                         return e;
7772                 }
7773
7774                 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
7775                 {
7776                         if (!CommonResolve (ec))
7777                                 return null;
7778
7779                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7780                         if (ilist.Methods == null) {
7781                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7782                                                   TypeManager.CSharpName (indexer_type));
7783                                 return null;
7784                         }
7785
7786                         MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
7787                         mg = mg.OverloadResolve (ec, ref arguments, false, loc);
7788                         if (mg == null)
7789                                 return null;
7790
7791                         MethodInfo mi = (MethodInfo) mg;
7792                         PropertyInfo pi = null;
7793                         for (int i = 0; i < ilist.Methods.Count; ++i) {
7794                                 if (ilist.Methods [i] == mi) {
7795                                         pi = (PropertyInfo) ilist.Properties [i];
7796                                         break;
7797                                 }
7798                         }
7799
7800                         type = pi.PropertyType;
7801                         if (type.IsPointer && !ec.InUnsafe)
7802                                 UnsafeError (loc);
7803
7804                         MethodInfo accessor;
7805                         if (accessorType == AccessorType.Get) {
7806                                 accessor = get = pi.GetGetMethod (true);
7807                         } else {
7808                                 accessor = set = pi.GetSetMethod (true);
7809                                 if (accessor == null && pi.GetGetMethod (true) != null) {
7810                                         Report.SymbolRelatedToPreviousError (pi);
7811                                         Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
7812                                                 TypeManager.GetFullNameSignature (pi));
7813                                         return null;
7814                                 }
7815                         }
7816
7817                         if (accessor == null) {
7818                                 Report.SymbolRelatedToPreviousError (pi);
7819                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
7820                                         TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7821                                 return null;
7822                         }
7823
7824                         //
7825                         // Only base will allow this invocation to happen.
7826                         //
7827                         if (accessor.IsAbstract && this is BaseIndexerAccess) {
7828                                 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
7829                         }
7830
7831                         bool must_do_cs1540_check;
7832                         if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
7833                                 if (set == null)
7834                                         set = pi.GetSetMethod (true);
7835                                 else
7836                                         get = pi.GetGetMethod (true);
7837
7838                                 if (set != null && get != null &&
7839                                         (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
7840                                         Report.SymbolRelatedToPreviousError (accessor);
7841                                         Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
7842                                                 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7843                                 } else {
7844                                         Report.SymbolRelatedToPreviousError (pi);
7845                                         ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
7846                                 }
7847                         }
7848
7849                         instance_expr.CheckMarshalByRefAccess (ec);
7850                         eclass = ExprClass.IndexerAccess;
7851                         return this;
7852                 }
7853                 
7854                 public void Emit (EmitContext ec, bool leave_copy)
7855                 {
7856                         if (prepared) {
7857                                 prepared_value.Emit (ec);
7858                         } else {
7859                                 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7860                                         arguments, loc, false, false);
7861                         }
7862
7863                         if (leave_copy) {
7864                                 ec.ig.Emit (OpCodes.Dup);
7865                                 temp = new LocalTemporary (Type);
7866                                 temp.Store (ec);
7867                         }
7868                 }
7869                 
7870                 //
7871                 // source is ignored, because we already have a copy of it from the
7872                 // LValue resolution and we have already constructed a pre-cached
7873                 // version of the arguments (ea.set_arguments);
7874                 //
7875                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7876                 {
7877                         prepared = prepare_for_load;
7878                         Expression value = set_expr;
7879
7880                         if (prepared) {
7881                                 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7882                                         arguments, loc, true, false);
7883
7884                                 prepared_value = new LocalTemporary (type);
7885                                 prepared_value.Store (ec);
7886                                 source.Emit (ec);
7887                                 prepared_value.Release (ec);
7888
7889                                 if (leave_copy) {
7890                                         ec.ig.Emit (OpCodes.Dup);
7891                                         temp = new LocalTemporary (Type);
7892                                         temp.Store (ec);
7893                                 }
7894                         } else if (leave_copy) {
7895                                 temp = new LocalTemporary (Type);
7896                                 source.Emit (ec);
7897                                 temp.Store (ec);
7898                                 value = temp;
7899                         }
7900                         
7901                         arguments.Add (new Argument (value, Argument.AType.Expression));
7902                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
7903                         
7904                         if (temp != null) {
7905                                 temp.Emit (ec);
7906                                 temp.Release (ec);
7907                         }
7908                 }
7909                 
7910                 public override void Emit (EmitContext ec)
7911                 {
7912                         Emit (ec, false);
7913                 }
7914
7915                 public override string GetSignatureForError ()
7916                 {
7917                         return TypeManager.CSharpSignature (get != null ? get : set, false);
7918                 }
7919
7920                 protected override void CloneTo (CloneContext clonectx, Expression t)
7921                 {
7922                         IndexerAccess target = (IndexerAccess) t;
7923
7924                         if (arguments != null){
7925                                 target.arguments = new ArrayList ();
7926                                 foreach (Argument a in arguments)
7927                                         target.arguments.Add (a.Clone (clonectx));
7928                         }
7929                         if (instance_expr != null)
7930                                 target.instance_expr = instance_expr.Clone (clonectx);
7931                 }
7932         }
7933
7934         /// <summary>
7935         ///   The base operator for method names
7936         /// </summary>
7937         public class BaseAccess : Expression {
7938                 public readonly string Identifier;
7939                 TypeArguments args;
7940
7941                 public BaseAccess (string member, Location l)
7942                 {
7943                         this.Identifier = member;
7944                         loc = l;
7945                 }
7946
7947                 public BaseAccess (string member, TypeArguments args, Location l)
7948                         : this (member, l)
7949                 {
7950                         this.args = args;
7951                 }
7952
7953                 public override Expression DoResolve (EmitContext ec)
7954                 {
7955                         Expression c = CommonResolve (ec);
7956
7957                         if (c == null)
7958                                 return null;
7959
7960                         //
7961                         // MethodGroups use this opportunity to flag an error on lacking ()
7962                         //
7963                         if (!(c is MethodGroupExpr))
7964                                 return c.Resolve (ec);
7965                         return c;
7966                 }
7967
7968                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7969                 {
7970                         Expression c = CommonResolve (ec);
7971
7972                         if (c == null)
7973                                 return null;
7974
7975                         //
7976                         // MethodGroups use this opportunity to flag an error on lacking ()
7977                         //
7978                         if (! (c is MethodGroupExpr))
7979                                 return c.DoResolveLValue (ec, right_side);
7980
7981                         return c;
7982                 }
7983
7984                 Expression CommonResolve (EmitContext ec)
7985                 {
7986                         Expression member_lookup;
7987                         Type current_type = ec.ContainerType;
7988                         Type base_type = current_type.BaseType;
7989
7990                         if (ec.IsStatic){
7991                                 Error (1511, "Keyword `base' is not available in a static method");
7992                                 return null;
7993                         }
7994
7995                         if (ec.IsInFieldInitializer){
7996                                 Error (1512, "Keyword `base' is not available in the current context");
7997                                 return null;
7998                         }
7999                         
8000                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8001                                                       AllMemberTypes, AllBindingFlags, loc);
8002                         if (member_lookup == null) {
8003                                 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8004                                         null, AllMemberTypes, AllBindingFlags);
8005                                 return null;
8006                         }
8007
8008                         Expression left;
8009                         
8010                         if (ec.IsStatic)
8011                                 left = new TypeExpression (base_type, loc);
8012                         else
8013                                 left = ec.GetThis (loc);
8014
8015                         MemberExpr me = (MemberExpr) member_lookup;
8016                         me = me.ResolveMemberAccess (ec, left, loc, null);
8017                         if (me == null)
8018                                 return null;
8019
8020                         me.IsBase = true;
8021                         if (args != null) {
8022                                 args.Resolve (ec);
8023                                 me.SetTypeArguments (args);
8024                         }
8025
8026                         return me;
8027                 }
8028
8029                 public override void Emit (EmitContext ec)
8030                 {
8031                         throw new Exception ("Should never be called"); 
8032                 }
8033
8034                 protected override void CloneTo (CloneContext clonectx, Expression t)
8035                 {
8036                         BaseAccess target = (BaseAccess) t;
8037
8038                         if (args != null)
8039                                 target.args = args.Clone ();
8040                 }
8041         }
8042
8043         /// <summary>
8044         ///   The base indexer operator
8045         /// </summary>
8046         public class BaseIndexerAccess : IndexerAccess {
8047                 public BaseIndexerAccess (ArrayList args, Location loc)
8048                         : base (null, true, loc)
8049                 {
8050                         arguments = new ArrayList ();
8051                         foreach (Expression tmp in args)
8052                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8053                 }
8054
8055                 protected override bool CommonResolve (EmitContext ec)
8056                 {
8057                         instance_expr = ec.GetThis (loc);
8058
8059                         current_type = ec.ContainerType.BaseType;
8060                         indexer_type = current_type;
8061
8062                         foreach (Argument a in arguments){
8063                                 if (!a.Resolve (ec, loc))
8064                                         return false;
8065                         }
8066
8067                         return true;
8068                 }
8069         }
8070         
8071         /// <summary>
8072         ///   This class exists solely to pass the Type around and to be a dummy
8073         ///   that can be passed to the conversion functions (this is used by
8074         ///   foreach implementation to typecast the object return value from
8075         ///   get_Current into the proper type.  All code has been generated and
8076         ///   we only care about the side effect conversions to be performed
8077         ///
8078         ///   This is also now used as a placeholder where a no-action expression
8079         ///   is needed (the `New' class).
8080         /// </summary>
8081         public class EmptyExpression : Expression {
8082                 public static readonly EmptyExpression Null = new EmptyExpression ();
8083
8084                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8085                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8086                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8087
8088                 static EmptyExpression temp = new EmptyExpression ();
8089                 public static EmptyExpression Grab ()
8090                 {
8091                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8092                         temp = null;
8093                         return retval;
8094                 }
8095
8096                 public static void Release (EmptyExpression e)
8097                 {
8098                         temp = e;
8099                 }
8100
8101                 // TODO: should be protected
8102                 public EmptyExpression ()
8103                 {
8104                         type = TypeManager.object_type;
8105                         eclass = ExprClass.Value;
8106                         loc = Location.Null;
8107                 }
8108
8109                 public EmptyExpression (Type t)
8110                 {
8111                         type = t;
8112                         eclass = ExprClass.Value;
8113                         loc = Location.Null;
8114                 }
8115                 
8116                 public override Expression DoResolve (EmitContext ec)
8117                 {
8118                         return this;
8119                 }
8120
8121                 public override void Emit (EmitContext ec)
8122                 {
8123                         // nothing, as we only exist to not do anything.
8124                 }
8125
8126                 //
8127                 // This is just because we might want to reuse this bad boy
8128                 // instead of creating gazillions of EmptyExpressions.
8129                 // (CanImplicitConversion uses it)
8130                 //
8131                 public void SetType (Type t)
8132                 {
8133                         type = t;
8134                 }
8135         }
8136         
8137         //
8138         // Empty statement expression
8139         //
8140         public sealed class EmptyExpressionStatement : ExpressionStatement
8141         {
8142                 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8143
8144                 private EmptyExpressionStatement ()
8145                 {
8146                         type = TypeManager.object_type;
8147                         eclass = ExprClass.Value;
8148                         loc = Location.Null;
8149                 }
8150
8151                 public override void EmitStatement (EmitContext ec)
8152                 {
8153                         // Do nothing
8154                 }
8155
8156                 public override Expression DoResolve (EmitContext ec)
8157                 {
8158                         return this;
8159                 }
8160
8161                 public override void Emit (EmitContext ec)
8162                 {
8163                         // Do nothing
8164                 }
8165         }       
8166
8167         public class UserCast : Expression {
8168                 MethodBase method;
8169                 Expression source;
8170                 
8171                 public UserCast (MethodInfo method, Expression source, Location l)
8172                 {
8173                         this.method = method;
8174                         this.source = source;
8175                         type = method.ReturnType;
8176                         eclass = ExprClass.Value;
8177                         loc = l;
8178                 }
8179
8180                 public Expression Source {
8181                         get {
8182                                 return source;
8183                         }
8184                 }
8185                         
8186                 public override Expression DoResolve (EmitContext ec)
8187                 {
8188                         //
8189                         // We are born fully resolved
8190                         //
8191                         return this;
8192                 }
8193
8194                 public override void Emit (EmitContext ec)
8195                 {
8196                         ILGenerator ig = ec.ig;
8197
8198                         source.Emit (ec);
8199                         
8200                         if (method is MethodInfo)
8201                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8202                         else
8203                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8204
8205                 }
8206         }
8207
8208         // <summary>
8209         //   This class is used to "construct" the type during a typecast
8210         //   operation.  Since the Type.GetType class in .NET can parse
8211         //   the type specification, we just use this to construct the type
8212         //   one bit at a time.
8213         // </summary>
8214         public class ComposedCast : TypeExpr {
8215                 Expression left;
8216                 string dim;
8217                 
8218                 public ComposedCast (Expression left, string dim)
8219                         : this (left, dim, left.Location)
8220                 {
8221                 }
8222
8223                 public ComposedCast (Expression left, string dim, Location l)
8224                 {
8225                         this.left = left;
8226                         this.dim = dim;
8227                         loc = l;
8228                 }
8229
8230                 public Expression RemoveNullable ()
8231                 {
8232                         if (dim.EndsWith ("?")) {
8233                                 dim = dim.Substring (0, dim.Length - 1);
8234                                 if (dim.Length == 0)
8235                                         return left;
8236                         }
8237
8238                         return this;
8239                 }
8240
8241                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8242                 {
8243                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8244                         if (lexpr == null)
8245                                 return null;
8246
8247                         Type ltype = lexpr.Type;
8248                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8249                                 Error_VoidInvalidInTheContext (loc);
8250                                 return null;
8251                         }
8252
8253 #if GMCS_SOURCE
8254                         if ((dim.Length > 0) && (dim [0] == '?')) {
8255                                 TypeExpr nullable = new NullableType (left, loc);
8256                                 if (dim.Length > 1)
8257                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8258                                 return nullable.ResolveAsTypeTerminal (ec, false);
8259                         }
8260 #endif
8261
8262                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8263                                 return null;
8264
8265                         if (dim != "" && dim [0] == '[' &&
8266                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8267                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8268                                 return null;
8269                         }
8270
8271                         if (dim != "")
8272                                 type = TypeManager.GetConstructedType (ltype, dim);
8273                         else
8274                                 type = ltype;
8275
8276                         if (type == null)
8277                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8278
8279                         if (type.IsPointer && !ec.IsInUnsafeScope){
8280                                 UnsafeError (loc);
8281                                 return null;
8282                         }
8283
8284                         eclass = ExprClass.Type;
8285                         return this;
8286                 }
8287
8288                 public override string Name {
8289                         get { return left + dim; }
8290                 }
8291
8292                 public override string FullName {
8293                         get { return type.FullName; }
8294                 }
8295
8296                 public override string GetSignatureForError ()
8297                 {
8298                         return left.GetSignatureForError () + dim;
8299                 }
8300
8301                 protected override void CloneTo (CloneContext clonectx, Expression t)
8302                 {
8303                         ComposedCast target = (ComposedCast) t;
8304
8305                         target.left = left.Clone (clonectx);
8306                 }
8307         }
8308
8309         public class FixedBufferPtr : Expression {
8310                 Expression array;
8311
8312                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8313                 {
8314                         this.array = array;
8315                         this.loc = l;
8316
8317                         type = TypeManager.GetPointerType (array_type);
8318                         eclass = ExprClass.Value;
8319                 }
8320
8321                 public override void Emit(EmitContext ec)
8322                 {
8323                         array.Emit (ec);
8324                 }
8325
8326                 public override Expression DoResolve (EmitContext ec)
8327                 {
8328                         //
8329                         // We are born fully resolved
8330                         //
8331                         return this;
8332                 }
8333         }
8334
8335
8336         //
8337         // This class is used to represent the address of an array, used
8338         // only by the Fixed statement, this generates "&a [0]" construct
8339         // for fixed (char *pa = a)
8340         //
8341         public class ArrayPtr : FixedBufferPtr {
8342                 Type array_type;
8343                 
8344                 public ArrayPtr (Expression array, Type array_type, Location l):
8345                         base (array, array_type, l)
8346                 {
8347                         this.array_type = array_type;
8348                 }
8349
8350                 public override void Emit (EmitContext ec)
8351                 {
8352                         base.Emit (ec);
8353                         
8354                         ILGenerator ig = ec.ig;
8355                         IntLiteral.EmitInt (ig, 0);
8356                         ig.Emit (OpCodes.Ldelema, array_type);
8357                 }
8358         }
8359
8360         //
8361         // Encapsulates a conversion rules required for array indexes
8362         //
8363         public class ArrayIndexCast : Expression
8364         {
8365                 Expression expr;
8366
8367                 public ArrayIndexCast (Expression expr)
8368                 {
8369                         this.expr = expr;
8370                         this.loc = expr.Location;
8371                 }
8372
8373                 public override Expression CreateExpressionTree (EmitContext ec)
8374                 {
8375                         ArrayList args = new ArrayList (2);
8376                         args.Add (new Argument (expr.CreateExpressionTree (ec)));
8377                         args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8378                         return CreateExpressionFactoryCall ("ConvertChecked", args);
8379                 }
8380
8381                 public override Expression DoResolve (EmitContext ec)
8382                 {
8383                         type = expr.Type;
8384                         eclass = expr.eclass;
8385                         return this;
8386                 }
8387
8388                 public override void Emit (EmitContext ec)
8389                 {
8390                         expr.Emit (ec);
8391                                 
8392                         if (type == TypeManager.int32_type)
8393                                 return;
8394
8395                         if (type == TypeManager.uint32_type)
8396                                 ec.ig.Emit (OpCodes.Conv_U);
8397                         else if (type == TypeManager.int64_type)
8398                                 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8399                         else if (type == TypeManager.uint64_type)
8400                                 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8401                         else
8402                                 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8403                 }
8404         }
8405
8406         //
8407         // Used by the fixed statement
8408         //
8409         public class StringPtr : Expression {
8410                 LocalBuilder b;
8411                 
8412                 public StringPtr (LocalBuilder b, Location l)
8413                 {
8414                         this.b = b;
8415                         eclass = ExprClass.Value;
8416                         type = TypeManager.char_ptr_type;
8417                         loc = l;
8418                 }
8419
8420                 public override Expression DoResolve (EmitContext ec)
8421                 {
8422                         // This should never be invoked, we are born in fully
8423                         // initialized state.
8424
8425                         return this;
8426                 }
8427
8428                 public override void Emit (EmitContext ec)
8429                 {
8430                         ILGenerator ig = ec.ig;
8431
8432                         ig.Emit (OpCodes.Ldloc, b);
8433                         ig.Emit (OpCodes.Conv_I);
8434                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8435                         ig.Emit (OpCodes.Add);
8436                 }
8437         }
8438         
8439         //
8440         // Implements the `stackalloc' keyword
8441         //
8442         public class StackAlloc : Expression {
8443                 Type otype;
8444                 Expression t;
8445                 Expression count;
8446                 
8447                 public StackAlloc (Expression type, Expression count, Location l)
8448                 {
8449                         t = type;
8450                         this.count = count;
8451                         loc = l;
8452                 }
8453
8454                 public override Expression DoResolve (EmitContext ec)
8455                 {
8456                         count = count.Resolve (ec);
8457                         if (count == null)
8458                                 return null;
8459                         
8460                         if (count.Type != TypeManager.int32_type){
8461                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8462                                 if (count == null)
8463                                         return null;
8464                         }
8465
8466                         Constant c = count as Constant;
8467                         if (c != null && c.IsNegative) {
8468                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8469                                 return null;
8470                         }
8471
8472                         if (ec.InCatch || ec.InFinally) {
8473                                 Error (255, "Cannot use stackalloc in finally or catch");
8474                                 return null;
8475                         }
8476
8477                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8478                         if (texpr == null)
8479                                 return null;
8480
8481                         otype = texpr.Type;
8482
8483                         if (!TypeManager.VerifyUnManaged (otype, loc))
8484                                 return null;
8485
8486                         type = TypeManager.GetPointerType (otype);
8487                         eclass = ExprClass.Value;
8488
8489                         return this;
8490                 }
8491
8492                 public override void Emit (EmitContext ec)
8493                 {
8494                         int size = GetTypeSize (otype);
8495                         ILGenerator ig = ec.ig;
8496                                 
8497                         if (size == 0)
8498                                 ig.Emit (OpCodes.Sizeof, otype);
8499                         else
8500                                 IntConstant.EmitInt (ig, size);
8501                         count.Emit (ec);
8502                         ig.Emit (OpCodes.Mul);
8503                         ig.Emit (OpCodes.Localloc);
8504                 }
8505
8506                 protected override void CloneTo (CloneContext clonectx, Expression t)
8507                 {
8508                         StackAlloc target = (StackAlloc) t;
8509                         target.count = count.Clone (clonectx);
8510                         target.t = t.Clone (clonectx);
8511                 }
8512         }
8513
8514         //
8515         // An object initializer expression
8516         //
8517         public class ElementInitializer : Expression
8518         {
8519                 Expression initializer;
8520                 public readonly string Name;
8521
8522                 public ElementInitializer (string name, Expression initializer, Location loc)
8523                 {
8524                         this.Name = name;
8525                         this.initializer = initializer;
8526                         this.loc = loc;
8527                 }
8528
8529                 protected override void CloneTo (CloneContext clonectx, Expression t)
8530                 {
8531                         if (initializer == null)
8532                                 return;
8533
8534                         ElementInitializer target = (ElementInitializer) t;
8535                         target.initializer = initializer.Clone (clonectx);
8536                 }
8537
8538                 public override Expression DoResolve (EmitContext ec)
8539                 {
8540                         if (initializer == null)
8541                                 return EmptyExpressionStatement.Instance;
8542                         
8543                         MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8544                                 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8545
8546                         if (element_member == null)
8547                                 return null;
8548
8549                         element_member.InstanceExpression = ec.CurrentInitializerVariable;
8550
8551                         if (initializer is CollectionOrObjectInitializers) {
8552                                 Expression previous = ec.CurrentInitializerVariable;
8553                                 ec.CurrentInitializerVariable = element_member;
8554                                 initializer = initializer.Resolve (ec);
8555                                 ec.CurrentInitializerVariable = previous;
8556                                 return initializer;
8557                         }
8558
8559                         Assign a = new Assign (element_member, initializer, loc);
8560                         if (a.Resolve (ec) == null)
8561                                 return null;
8562
8563                         //
8564                         // Ignore field initializers with default value
8565                         //
8566                         Constant c = a.Source as Constant;
8567                         if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
8568                                 return EmptyExpressionStatement.Instance;
8569
8570                         return a;
8571                 }
8572
8573                 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8574                 {
8575                         MemberInfo member = members [0];
8576                         if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8577                                 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8578                                         "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8579                         else
8580                                 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8581                                         TypeManager.GetFullNameSignature (member));
8582
8583                         return null;
8584                 }
8585
8586                 public override void Emit (EmitContext ec)
8587                 {
8588                         throw new NotSupportedException ("Should not be reached");
8589                 }
8590         }
8591         
8592         //
8593         // A collection initializer expression
8594         //
8595         public class CollectionElementInitializer : Expression
8596         {
8597                 public class ElementInitializerArgument : Argument
8598                 {
8599                         public ElementInitializerArgument (Expression e)
8600                                 : base (e)
8601                         {
8602                         }
8603                 }
8604
8605                 ArrayList arguments;
8606
8607                 public CollectionElementInitializer (Expression argument)
8608                 {
8609                         arguments = new ArrayList (1);
8610                         arguments.Add (argument);
8611                         this.loc = argument.Location;
8612                 }
8613
8614                 public CollectionElementInitializer (ArrayList arguments, Location loc)
8615                 {
8616                         this.arguments = arguments;
8617                         this.loc = loc;
8618                 }
8619
8620                 protected override void CloneTo (CloneContext clonectx, Expression t)
8621                 {
8622                         CollectionElementInitializer target = (CollectionElementInitializer) t;
8623                         ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8624                         foreach (Expression e in arguments)
8625                                 t_arguments.Add (e.Clone (clonectx));
8626                 }
8627
8628                 public override Expression DoResolve (EmitContext ec)
8629                 {
8630                         // TODO: We should call a constructor which takes element counts argument,
8631                         // for know types like List<T>, Dictionary<T, U>
8632                         
8633                         for (int i = 0; i < arguments.Count; ++i)
8634                                 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8635
8636                         Expression add_method = new Invocation (
8637                                 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8638                                 arguments);
8639
8640                         add_method = add_method.Resolve (ec);
8641
8642                         return add_method;
8643                 }
8644                 
8645                 public override void Emit (EmitContext ec)
8646                 {
8647                         throw new NotSupportedException ("Should not be reached");
8648                 }
8649         }
8650         
8651         //
8652         // A block of object or collection initializers
8653         //
8654         public class CollectionOrObjectInitializers : ExpressionStatement
8655         {
8656                 ArrayList initializers;
8657                 
8658                 public static readonly CollectionOrObjectInitializers Empty = 
8659                         new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8660
8661                 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8662                 {
8663                         this.initializers = initializers;
8664                         this.loc = loc;
8665                 }
8666                 
8667                 public bool IsEmpty {
8668                         get {
8669                                 return initializers.Count == 0;
8670                         }
8671                 }
8672
8673                 protected override void CloneTo (CloneContext clonectx, Expression target)
8674                 {
8675                         CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8676
8677                         t.initializers = new ArrayList (initializers.Count);
8678                         foreach (Expression e in initializers)
8679                                 t.initializers.Add (e.Clone (clonectx));
8680                 }
8681                 
8682                 public override Expression DoResolve (EmitContext ec)
8683                 {
8684                         bool is_elements_initialization = false;
8685                         ArrayList element_names = null;
8686                         for (int i = 0; i < initializers.Count; ++i) {
8687                                 Expression initializer = (Expression) initializers [i];
8688                                 ElementInitializer element_initializer = initializer as ElementInitializer;
8689
8690                                 if (i == 0) {
8691                                         if (element_initializer != null) {
8692                                                 is_elements_initialization = true;
8693                                                 element_names = new ArrayList (initializers.Count);
8694                                                 element_names.Add (element_initializer.Name);
8695                                         } else {
8696                                                 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8697                                                         TypeManager.ienumerable_type)) {
8698                                                         Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8699                                                                 "object initializer because type `{1}' does not implement `{2}' interface",
8700                                                                 ec.CurrentInitializerVariable.GetSignatureForError (),
8701                                                                 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8702                                                                 TypeManager.CSharpName (TypeManager.ienumerable_type));
8703                                                         return null;
8704                                                 }
8705                                         }
8706                                 } else {
8707                                         if (is_elements_initialization == (element_initializer == null)) {
8708                                                 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8709                                                         is_elements_initialization ? "object initializer" : "collection initializer");
8710                                                 continue;
8711                                         }
8712                                         
8713                                         if (is_elements_initialization) {
8714                                                 if (element_names.Contains (element_initializer.Name)) {
8715                                                         Report.Error (1912, element_initializer.Location,
8716                                                                 "An object initializer includes more than one member `{0}' initialization",
8717                                                                 element_initializer.Name);
8718                                                 } else {
8719                                                         element_names.Add (element_initializer.Name);
8720                                                 }
8721                                         }
8722                                 }
8723
8724                                 Expression e = initializer.Resolve (ec);
8725                                 if (e == EmptyExpressionStatement.Instance)
8726                                         initializers.RemoveAt (i--);
8727                                 else
8728                                         initializers [i] = e;                           
8729                         }
8730
8731                         type = typeof (CollectionOrObjectInitializers);
8732                         eclass = ExprClass.Variable;
8733                         return this;
8734                 }
8735
8736                 public override void Emit (EmitContext ec)
8737                 {
8738                         EmitStatement (ec);
8739                 }
8740
8741                 public override void EmitStatement (EmitContext ec)
8742                 {
8743                         foreach (ExpressionStatement e in initializers)
8744                                 e.EmitStatement (ec);
8745                 }
8746         }
8747         
8748         //
8749         // New expression with element/object initializers
8750         //
8751         public class NewInitialize : New
8752         {
8753                 //
8754                 // This class serves as a proxy for variable initializer target instances.
8755                 // A real variable is assigned later when we resolve left side of an
8756                 // assignment
8757                 //
8758                 sealed class InitializerTargetExpression : Expression, IMemoryLocation
8759                 {
8760                         NewInitialize new_instance;
8761
8762                         public InitializerTargetExpression (NewInitialize newInstance)
8763                         {
8764                                 this.type = newInstance.type;
8765                                 this.loc = newInstance.loc;
8766                                 this.eclass = newInstance.eclass;
8767                                 this.new_instance = newInstance;
8768                         }
8769
8770                         public override Expression DoResolve (EmitContext ec)
8771                         {
8772                                 return this;
8773                         }
8774
8775                         public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8776                         {
8777                                 return this;
8778                         }
8779
8780                         public override void Emit (EmitContext ec)
8781                         {
8782                                 new_instance.value_target.Emit (ec);
8783                         }
8784
8785                         #region IMemoryLocation Members
8786
8787                         public void AddressOf (EmitContext ec, AddressOp mode)
8788                         {
8789                                 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
8790                         }
8791
8792                         #endregion
8793                 }
8794
8795                 CollectionOrObjectInitializers initializers;
8796
8797                 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8798                         : base (requested_type, arguments, l)
8799                 {
8800                         this.initializers = initializers;
8801                 }
8802
8803                 protected override void CloneTo (CloneContext clonectx, Expression t)
8804                 {
8805                         base.CloneTo (clonectx, t);
8806
8807                         NewInitialize target = (NewInitialize) t;
8808                         target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
8809                 }
8810
8811                 public override Expression DoResolve (EmitContext ec)
8812                 {
8813                         if (eclass != ExprClass.Invalid)
8814                                 return this;
8815                         
8816                         Expression e = base.DoResolve (ec);
8817                         if (type == null)
8818                                 return null;
8819
8820                         // Empty initializer can be optimized to simple new
8821                         if (initializers.IsEmpty)
8822                                 return e;
8823
8824                         Expression previous = ec.CurrentInitializerVariable;
8825                         ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
8826                         initializers.Resolve (ec);
8827                         ec.CurrentInitializerVariable = previous;
8828                         return this;
8829                 }
8830
8831                 public override void Emit (EmitContext ec)
8832                 {
8833                         base.Emit (ec);
8834
8835                         //
8836                         // If target is a value, let's use it
8837                         //
8838                         VariableReference variable = value_target as VariableReference;
8839                         if (variable != null) {
8840                                 if (variable.IsRef)
8841                                         StoreFromPtr (ec.ig, type);
8842                                 else
8843                                         variable.Variable.EmitAssign (ec);
8844                         } else {
8845                                 if (value_target == null || value_target_set)
8846                                         value_target = new LocalTemporary (type);
8847
8848                                 ((LocalTemporary) value_target).Store (ec);
8849                         }
8850
8851                         initializers.Emit (ec);
8852
8853                         if (variable == null)
8854                                 value_target.Emit (ec);
8855                 }
8856
8857                 public override void EmitStatement (EmitContext ec)
8858                 {
8859                         if (initializers.IsEmpty) {
8860                                 base.EmitStatement (ec);
8861                                 return;
8862                         }
8863
8864                         base.Emit (ec);
8865
8866                         if (value_target == null) {
8867                                 LocalTemporary variable = new LocalTemporary (type);
8868                                 variable.Store (ec);
8869                                 value_target = variable;
8870                         }
8871
8872                         initializers.EmitStatement (ec);
8873                 }
8874
8875                 public override bool HasInitializer {
8876                         get {
8877                                 return !initializers.IsEmpty;
8878                         }
8879                 }
8880         }
8881
8882         public class AnonymousTypeDeclaration : Expression
8883         {
8884                 ArrayList parameters;
8885                 readonly TypeContainer parent;
8886                 static readonly ArrayList EmptyParameters = new ArrayList (0);
8887
8888                 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8889                 {
8890                         this.parameters = parameters;
8891                         this.parent = parent;
8892                         this.loc = loc;
8893                 }
8894
8895                 protected override void CloneTo (CloneContext clonectx, Expression target)
8896                 {
8897                         if (parameters == null)
8898                                 return;
8899
8900                         AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
8901                         t.parameters = new ArrayList (parameters.Count);
8902                         foreach (AnonymousTypeParameter atp in parameters)
8903                                 t.parameters.Add (atp.Clone (clonectx));
8904                 }
8905
8906                 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
8907                 {
8908                         AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8909                         if (type != null)
8910                                 return type;
8911
8912                         type = AnonymousTypeClass.Create (parent, parameters, loc);
8913                         if (type == null)
8914                                 return null;
8915
8916                         type.DefineType ();
8917                         type.DefineMembers ();
8918                         type.Define ();
8919                         type.EmitType ();
8920
8921                         RootContext.ToplevelTypes.AddAnonymousType (type);
8922                         return type;
8923                 }
8924
8925                 public override Expression DoResolve (EmitContext ec)
8926                 {
8927                         AnonymousTypeClass anonymous_type;
8928
8929                         if (parameters == null) {
8930                                 anonymous_type = CreateAnonymousType (EmptyParameters);
8931                                 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
8932                                         null, loc).Resolve (ec);
8933                         }
8934
8935                         bool error = false;
8936                         ArrayList arguments = new ArrayList (parameters.Count);
8937                         TypeExpression [] t_args = new TypeExpression [parameters.Count];
8938                         for (int i = 0; i < parameters.Count; ++i) {
8939                                 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
8940                                 if (e == null) {
8941                                         error = true;
8942                                         continue;
8943                                 }
8944
8945                                 arguments.Add (new Argument (e));
8946                                 t_args [i] = new TypeExpression (e.Type, e.Location);
8947                         }
8948
8949                         if (error)
8950                                 return null;
8951
8952                         anonymous_type = CreateAnonymousType (parameters);
8953                         if (anonymous_type == null)
8954                                 return null;
8955
8956                         ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8957                                 new TypeArguments (loc, t_args), loc);
8958
8959                         return new New (te, arguments, loc).Resolve (ec);
8960                 }
8961
8962                 public override void Emit (EmitContext ec)
8963                 {
8964                         throw new InternalErrorException ("Should not be reached");
8965                 }
8966         }
8967
8968         public class AnonymousTypeParameter : Expression
8969         {
8970                 public readonly string Name;
8971                 Expression initializer;
8972
8973                 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8974                 {
8975                         this.Name = name;
8976                         this.loc = loc;
8977                         this.initializer = initializer;
8978                 }
8979                 
8980                 public AnonymousTypeParameter (Parameter parameter)
8981                 {
8982                         this.Name = parameter.Name;
8983                         this.loc = parameter.Location;
8984                         this.initializer = new SimpleName (Name, loc);
8985                 }               
8986
8987                 protected override void CloneTo (CloneContext clonectx, Expression target)
8988                 {
8989                         AnonymousTypeParameter t = (AnonymousTypeParameter) target;
8990                         t.initializer = initializer.Clone (clonectx);
8991                 }
8992
8993                 public override bool Equals (object o)
8994                 {
8995                         AnonymousTypeParameter other = o as AnonymousTypeParameter;
8996                         return other != null && Name == other.Name;
8997                 }
8998
8999                 public override int GetHashCode ()
9000                 {
9001                         return Name.GetHashCode ();
9002                 }
9003
9004                 public override Expression DoResolve (EmitContext ec)
9005                 {
9006                         Expression e = initializer.Resolve (ec);
9007                         if (e == null)
9008                                 return null;
9009
9010                         type = e.Type;
9011                         if (type == TypeManager.void_type || type == TypeManager.null_type ||
9012                                 type == TypeManager.anonymous_method_type || type.IsPointer) {
9013                                 Error_InvalidInitializer (e);
9014                                 return null;
9015                         }
9016
9017                         return e;
9018                 }
9019
9020                 protected virtual void Error_InvalidInitializer (Expression initializer)
9021                 {
9022                         Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9023                                 Name, initializer.GetSignatureForError ());
9024                 }
9025
9026                 public override void Emit (EmitContext ec)
9027                 {
9028                         throw new InternalErrorException ("Should not be reached");
9029                 }
9030         }
9031 }