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