2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / expression.cs
blob84980efd5f599e287b40d3b870acd2b1e9f83c56
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.
11 #define USE_OLD
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections.Generic;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
19 using System.Linq;
20 using SLE = System.Linq.Expressions;
23 // This is an user operator expression, automatically created during
24 // resolve phase
26 public class UserOperatorCall : Expression {
27 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
29 protected readonly Arguments arguments;
30 protected readonly MethodGroupExpr mg;
31 readonly ExpressionTreeExpression expr_tree;
33 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
35 this.mg = mg;
36 this.arguments = args;
37 this.expr_tree = expr_tree;
39 type = TypeManager.TypeToCoreType (((MethodSpec) mg).ReturnType);
40 eclass = ExprClass.Value;
41 this.loc = loc;
44 public override Expression CreateExpressionTree (ResolveContext ec)
46 if (expr_tree != null)
47 return expr_tree (ec, mg);
49 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
50 new NullLiteral (loc),
51 mg.CreateExpressionTree (ec));
53 return CreateExpressionFactoryCall (ec, "Call", args);
56 protected override void CloneTo (CloneContext context, Expression target)
58 // Nothing to clone
61 protected override Expression DoResolve (ResolveContext ec)
64 // We are born fully resolved
66 return this;
69 public override void Emit (EmitContext ec)
71 mg.EmitCall (ec, arguments);
74 public override SLE.Expression MakeExpression (BuilderContext ctx)
76 var method = ((MethodSpec) mg).MetaInfo as MethodInfo;
77 return SLE.Expression.Call (method, Arguments.MakeExpression (arguments, ctx));
80 public MethodGroupExpr Method {
81 get { return mg; }
84 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
86 arguments.MutateHoistedGenericType (storey);
87 mg.MutateHoistedGenericType (storey);
91 public class ParenthesizedExpression : ShimExpression
93 public ParenthesizedExpression (Expression expr)
94 : base (expr)
96 loc = expr.Location;
99 protected override Expression DoResolve (ResolveContext ec)
101 return expr.Resolve (ec);
104 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
106 return expr.DoResolveLValue (ec, right_side);
111 // Unary implements unary expressions.
113 public class Unary : Expression
115 public enum Operator : byte {
116 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
117 AddressOf, TOP
120 static Type [] [] predefined_operators;
122 public readonly Operator Oper;
123 public Expression Expr;
124 Expression enum_conversion;
126 public Unary (Operator op, Expression expr, Location loc)
128 Oper = op;
129 Expr = expr;
130 this.loc = loc;
133 // <summary>
134 // This routine will attempt to simplify the unary expression when the
135 // argument is a constant.
136 // </summary>
137 Constant TryReduceConstant (ResolveContext ec, Constant e)
139 if (e is EmptyConstantCast)
140 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
142 if (e is SideEffectConstant) {
143 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
144 return r == null ? null : new SideEffectConstant (r, e, r.Location);
147 Type expr_type = e.Type;
149 switch (Oper){
150 case Operator.UnaryPlus:
151 // Unary numeric promotions
152 if (expr_type == TypeManager.byte_type)
153 return new IntConstant (((ByteConstant)e).Value, e.Location);
154 if (expr_type == TypeManager.sbyte_type)
155 return new IntConstant (((SByteConstant)e).Value, e.Location);
156 if (expr_type == TypeManager.short_type)
157 return new IntConstant (((ShortConstant)e).Value, e.Location);
158 if (expr_type == TypeManager.ushort_type)
159 return new IntConstant (((UShortConstant)e).Value, e.Location);
160 if (expr_type == TypeManager.char_type)
161 return new IntConstant (((CharConstant)e).Value, e.Location);
163 // Predefined operators
164 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
165 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
166 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
167 expr_type == TypeManager.decimal_type) {
168 return e;
171 return null;
173 case Operator.UnaryNegation:
174 // Unary numeric promotions
175 if (expr_type == TypeManager.byte_type)
176 return new IntConstant (-((ByteConstant)e).Value, e.Location);
177 if (expr_type == TypeManager.sbyte_type)
178 return new IntConstant (-((SByteConstant)e).Value, e.Location);
179 if (expr_type == TypeManager.short_type)
180 return new IntConstant (-((ShortConstant)e).Value, e.Location);
181 if (expr_type == TypeManager.ushort_type)
182 return new IntConstant (-((UShortConstant)e).Value, e.Location);
183 if (expr_type == TypeManager.char_type)
184 return new IntConstant (-((CharConstant)e).Value, e.Location);
186 // Predefined operators
187 if (expr_type == TypeManager.int32_type) {
188 int value = ((IntConstant)e).Value;
189 if (value == int.MinValue) {
190 if (ec.ConstantCheckState) {
191 ConstantFold.Error_CompileTimeOverflow (ec, loc);
192 return null;
194 return e;
196 return new IntConstant (-value, e.Location);
198 if (expr_type == TypeManager.int64_type) {
199 long value = ((LongConstant)e).Value;
200 if (value == long.MinValue) {
201 if (ec.ConstantCheckState) {
202 ConstantFold.Error_CompileTimeOverflow (ec, loc);
203 return null;
205 return e;
207 return new LongConstant (-value, e.Location);
210 if (expr_type == TypeManager.uint32_type) {
211 UIntLiteral uil = e as UIntLiteral;
212 if (uil != null) {
213 if (uil.Value == int.MaxValue + (uint) 1)
214 return new IntLiteral (int.MinValue, e.Location);
215 return new LongLiteral (-uil.Value, e.Location);
217 return new LongConstant (-((UIntConstant)e).Value, e.Location);
220 if (expr_type == TypeManager.uint64_type) {
221 ULongLiteral ull = e as ULongLiteral;
222 if (ull != null && ull.Value == 9223372036854775808)
223 return new LongLiteral (long.MinValue, e.Location);
224 return null;
227 if (expr_type == TypeManager.float_type) {
228 FloatLiteral fl = e as FloatLiteral;
229 // For better error reporting
230 if (fl != null)
231 return new FloatLiteral (-fl.Value, e.Location);
233 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
235 if (expr_type == TypeManager.double_type) {
236 DoubleLiteral dl = e as DoubleLiteral;
237 // For better error reporting
238 if (dl != null)
239 return new DoubleLiteral (-dl.Value, e.Location);
241 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.decimal_type)
244 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
246 return null;
248 case Operator.LogicalNot:
249 if (expr_type != TypeManager.bool_type)
250 return null;
252 bool b = (bool)e.GetValue ();
253 return new BoolConstant (!b, e.Location);
255 case Operator.OnesComplement:
256 // Unary numeric promotions
257 if (expr_type == TypeManager.byte_type)
258 return new IntConstant (~((ByteConstant)e).Value, e.Location);
259 if (expr_type == TypeManager.sbyte_type)
260 return new IntConstant (~((SByteConstant)e).Value, e.Location);
261 if (expr_type == TypeManager.short_type)
262 return new IntConstant (~((ShortConstant)e).Value, e.Location);
263 if (expr_type == TypeManager.ushort_type)
264 return new IntConstant (~((UShortConstant)e).Value, e.Location);
265 if (expr_type == TypeManager.char_type)
266 return new IntConstant (~((CharConstant)e).Value, e.Location);
268 // Predefined operators
269 if (expr_type == TypeManager.int32_type)
270 return new IntConstant (~((IntConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.uint32_type)
272 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.int64_type)
274 return new LongConstant (~((LongConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.uint64_type){
276 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
278 if (e is EnumConstant) {
279 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
280 if (e != null)
281 e = new EnumConstant (e, expr_type);
282 return e;
284 return null;
286 throw new Exception ("Can not constant fold: " + Oper.ToString());
289 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
291 eclass = ExprClass.Value;
293 if (predefined_operators == null)
294 CreatePredefinedOperatorsTable ();
296 Type expr_type = expr.Type;
297 Expression best_expr;
300 // Primitive types first
302 if (TypeManager.IsPrimitiveType (expr_type)) {
303 best_expr = ResolvePrimitivePredefinedType (expr);
304 if (best_expr == null)
305 return null;
307 type = best_expr.Type;
308 Expr = best_expr;
309 return this;
313 // E operator ~(E x);
315 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
316 return ResolveEnumOperator (ec, expr);
318 return ResolveUserType (ec, expr);
321 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
323 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
324 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
325 if (best_expr == null)
326 return null;
328 Expr = best_expr;
329 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
330 type = expr.Type;
331 return EmptyCast.Create (this, type);
334 public override Expression CreateExpressionTree (ResolveContext ec)
336 return CreateExpressionTree (ec, null);
339 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
341 string method_name;
342 switch (Oper) {
343 case Operator.AddressOf:
344 Error_PointerInsideExpressionTree (ec);
345 return null;
346 case Operator.UnaryNegation:
347 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
348 method_name = "NegateChecked";
349 else
350 method_name = "Negate";
351 break;
352 case Operator.OnesComplement:
353 case Operator.LogicalNot:
354 method_name = "Not";
355 break;
356 case Operator.UnaryPlus:
357 method_name = "UnaryPlus";
358 break;
359 default:
360 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
363 Arguments args = new Arguments (2);
364 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
365 if (user_op != null)
366 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
367 return CreateExpressionFactoryCall (ec, method_name, args);
370 static void CreatePredefinedOperatorsTable ()
372 predefined_operators = new Type [(int) Operator.TOP] [];
375 // 7.6.1 Unary plus operator
377 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
378 TypeManager.int32_type, TypeManager.uint32_type,
379 TypeManager.int64_type, TypeManager.uint64_type,
380 TypeManager.float_type, TypeManager.double_type,
381 TypeManager.decimal_type
385 // 7.6.2 Unary minus operator
387 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
388 TypeManager.int32_type,
389 TypeManager.int64_type,
390 TypeManager.float_type, TypeManager.double_type,
391 TypeManager.decimal_type
395 // 7.6.3 Logical negation operator
397 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
398 TypeManager.bool_type
402 // 7.6.4 Bitwise complement operator
404 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
405 TypeManager.int32_type, TypeManager.uint32_type,
406 TypeManager.int64_type, TypeManager.uint64_type
411 // Unary numeric promotions
413 static Expression DoNumericPromotion (Operator op, Expression expr)
415 Type expr_type = expr.Type;
416 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
417 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
418 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
419 expr_type == TypeManager.char_type)
420 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
422 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
423 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
425 return expr;
428 protected override Expression DoResolve (ResolveContext ec)
430 if (Oper == Operator.AddressOf) {
431 return ResolveAddressOf (ec);
434 Expr = Expr.Resolve (ec);
435 if (Expr == null)
436 return null;
438 if (TypeManager.IsDynamicType (Expr.Type)) {
439 Arguments args = new Arguments (1);
440 args.Add (new Argument (Expr));
441 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
444 if (TypeManager.IsNullableType (Expr.Type))
445 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
448 // Attempt to use a constant folding operation.
450 Constant cexpr = Expr as Constant;
451 if (cexpr != null) {
452 cexpr = TryReduceConstant (ec, cexpr);
453 if (cexpr != null)
454 return cexpr.Resolve (ec);
457 Expression expr = ResolveOperator (ec, Expr);
458 if (expr == null)
459 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
462 // Reduce unary operator on predefined types
464 if (expr == this && Oper == Operator.UnaryPlus)
465 return Expr;
467 return expr;
470 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
472 return null;
475 public override void Emit (EmitContext ec)
477 EmitOperator (ec, type);
480 protected void EmitOperator (EmitContext ec, Type type)
482 ILGenerator ig = ec.ig;
484 switch (Oper) {
485 case Operator.UnaryPlus:
486 Expr.Emit (ec);
487 break;
489 case Operator.UnaryNegation:
490 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
491 ig.Emit (OpCodes.Ldc_I4_0);
492 if (type == TypeManager.int64_type)
493 ig.Emit (OpCodes.Conv_U8);
494 Expr.Emit (ec);
495 ig.Emit (OpCodes.Sub_Ovf);
496 } else {
497 Expr.Emit (ec);
498 ig.Emit (OpCodes.Neg);
501 break;
503 case Operator.LogicalNot:
504 Expr.Emit (ec);
505 ig.Emit (OpCodes.Ldc_I4_0);
506 ig.Emit (OpCodes.Ceq);
507 break;
509 case Operator.OnesComplement:
510 Expr.Emit (ec);
511 ig.Emit (OpCodes.Not);
512 break;
514 case Operator.AddressOf:
515 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
516 break;
518 default:
519 throw new Exception ("This should not happen: Operator = "
520 + Oper.ToString ());
524 // Same trick as in Binary expression
526 if (enum_conversion != null)
527 enum_conversion.Emit (ec);
530 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
532 if (Oper == Operator.LogicalNot)
533 Expr.EmitBranchable (ec, target, !on_true);
534 else
535 base.EmitBranchable (ec, target, on_true);
538 public override void EmitSideEffect (EmitContext ec)
540 Expr.EmitSideEffect (ec);
543 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, Type t)
545 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
546 oper, TypeManager.CSharpName (t));
550 // Converts operator to System.Linq.Expressions.ExpressionType enum name
552 string GetOperatorExpressionTypeName ()
554 switch (Oper) {
555 case Operator.OnesComplement:
556 return "OnesComplement";
557 case Operator.LogicalNot:
558 return "Not";
559 case Operator.UnaryNegation:
560 return "Negate";
561 case Operator.UnaryPlus:
562 return "UnaryPlus";
563 default:
564 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
568 static bool IsFloat (Type t)
570 return t == TypeManager.float_type || t == TypeManager.double_type;
574 // Returns a stringified representation of the Operator
576 public static string OperName (Operator oper)
578 switch (oper) {
579 case Operator.UnaryPlus:
580 return "+";
581 case Operator.UnaryNegation:
582 return "-";
583 case Operator.LogicalNot:
584 return "!";
585 case Operator.OnesComplement:
586 return "~";
587 case Operator.AddressOf:
588 return "&";
591 throw new NotImplementedException (oper.ToString ());
594 public override SLE.Expression MakeExpression (BuilderContext ctx)
596 var expr = Expr.MakeExpression (ctx);
597 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
599 switch (Oper) {
600 case Operator.UnaryNegation:
601 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
602 case Operator.LogicalNot:
603 return SLE.Expression.Not (expr);
604 #if NET_4_0
605 case Operator.OnesComplement:
606 return SLE.Expression.OnesComplement (expr);
607 #endif
608 default:
609 throw new NotImplementedException (Oper.ToString ());
613 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
615 type = storey.MutateType (type);
616 Expr.MutateHoistedGenericType (storey);
619 Expression ResolveAddressOf (ResolveContext ec)
621 if (!ec.IsUnsafe)
622 UnsafeError (ec, loc);
624 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
625 if (Expr == null || Expr.eclass != ExprClass.Variable) {
626 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
627 return null;
630 if (!TypeManager.VerifyUnmanaged (ec.Compiler, Expr.Type, loc)) {
631 return null;
634 IVariableReference vr = Expr as IVariableReference;
635 bool is_fixed;
636 if (vr != null) {
637 VariableInfo vi = vr.VariableInfo;
638 if (vi != null) {
639 if (vi.LocalInfo != null)
640 vi.LocalInfo.Used = true;
643 // A variable is considered definitely assigned if you take its address.
645 vi.SetAssigned (ec);
648 is_fixed = vr.IsFixed;
649 vr.SetHasAddressTaken ();
651 if (vr.IsHoisted) {
652 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
654 } else {
655 IFixedExpression fe = Expr as IFixedExpression;
656 is_fixed = fe != null && fe.IsFixed;
659 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
660 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
663 type = TypeManager.GetPointerType (Expr.Type);
664 eclass = ExprClass.Value;
665 return this;
668 Expression ResolvePrimitivePredefinedType (Expression expr)
670 expr = DoNumericPromotion (Oper, expr);
671 Type expr_type = expr.Type;
672 Type[] predefined = predefined_operators [(int) Oper];
673 foreach (Type t in predefined) {
674 if (t == expr_type)
675 return expr;
677 return null;
681 // Perform user-operator overload resolution
683 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
685 CSharp.Operator.OpType op_type;
686 switch (Oper) {
687 case Operator.LogicalNot:
688 op_type = CSharp.Operator.OpType.LogicalNot; break;
689 case Operator.OnesComplement:
690 op_type = CSharp.Operator.OpType.OnesComplement; break;
691 case Operator.UnaryNegation:
692 op_type = CSharp.Operator.OpType.UnaryNegation; break;
693 case Operator.UnaryPlus:
694 op_type = CSharp.Operator.OpType.UnaryPlus; break;
695 default:
696 throw new InternalErrorException (Oper.ToString ());
699 string op_name = CSharp.Operator.GetMetadataName (op_type);
700 MethodGroupExpr user_op = MemberLookup (ec.Compiler, ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
701 if (user_op == null)
702 return null;
704 Arguments args = new Arguments (1);
705 args.Add (new Argument (expr));
706 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
708 if (user_op == null)
709 return null;
711 Expr = args [0].Expr;
712 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
716 // Unary user type overload resolution
718 Expression ResolveUserType (ResolveContext ec, Expression expr)
720 Expression best_expr = ResolveUserOperator (ec, expr);
721 if (best_expr != null)
722 return best_expr;
724 Type[] predefined = predefined_operators [(int) Oper];
725 foreach (Type t in predefined) {
726 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
727 if (oper_expr == null)
728 continue;
731 // decimal type is predefined but has user-operators
733 if (oper_expr.Type == TypeManager.decimal_type)
734 oper_expr = ResolveUserType (ec, oper_expr);
735 else
736 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
738 if (oper_expr == null)
739 continue;
741 if (best_expr == null) {
742 best_expr = oper_expr;
743 continue;
746 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
747 if (result == 0) {
748 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
749 OperName (Oper), TypeManager.CSharpName (expr.Type));
750 break;
753 if (result == 2)
754 best_expr = oper_expr;
757 if (best_expr == null)
758 return null;
761 // HACK: Decimal user-operator is included in standard operators
763 if (best_expr.Type == TypeManager.decimal_type)
764 return best_expr;
766 Expr = best_expr;
767 type = best_expr.Type;
768 return this;
771 protected override void CloneTo (CloneContext clonectx, Expression t)
773 Unary target = (Unary) t;
775 target.Expr = Expr.Clone (clonectx);
780 // Unary operators are turned into Indirection expressions
781 // after semantic analysis (this is so we can take the address
782 // of an indirection).
784 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
785 Expression expr;
786 LocalTemporary temporary;
787 bool prepared;
789 public Indirection (Expression expr, Location l)
791 this.expr = expr;
792 loc = l;
795 public override Expression CreateExpressionTree (ResolveContext ec)
797 Error_PointerInsideExpressionTree (ec);
798 return null;
801 protected override void CloneTo (CloneContext clonectx, Expression t)
803 Indirection target = (Indirection) t;
804 target.expr = expr.Clone (clonectx);
807 public override void Emit (EmitContext ec)
809 if (!prepared)
810 expr.Emit (ec);
812 LoadFromPtr (ec.ig, Type);
815 public void Emit (EmitContext ec, bool leave_copy)
817 Emit (ec);
818 if (leave_copy) {
819 ec.ig.Emit (OpCodes.Dup);
820 temporary = new LocalTemporary (expr.Type);
821 temporary.Store (ec);
825 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
827 prepared = prepare_for_load;
829 expr.Emit (ec);
831 if (prepare_for_load)
832 ec.ig.Emit (OpCodes.Dup);
834 source.Emit (ec);
835 if (leave_copy) {
836 ec.ig.Emit (OpCodes.Dup);
837 temporary = new LocalTemporary (expr.Type);
838 temporary.Store (ec);
841 StoreFromPtr (ec.ig, type);
843 if (temporary != null) {
844 temporary.Emit (ec);
845 temporary.Release (ec);
849 public void AddressOf (EmitContext ec, AddressOp Mode)
851 expr.Emit (ec);
854 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
856 return DoResolve (ec);
859 protected override Expression DoResolve (ResolveContext ec)
861 expr = expr.Resolve (ec);
862 if (expr == null)
863 return null;
865 if (!ec.IsUnsafe)
866 UnsafeError (ec, loc);
868 if (!expr.Type.IsPointer) {
869 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
870 return null;
873 if (expr.Type == TypeManager.void_ptr_type) {
874 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
875 return null;
878 type = TypeManager.GetElementType (expr.Type);
879 eclass = ExprClass.Variable;
880 return this;
883 public bool IsFixed {
884 get { return true; }
887 public override string ToString ()
889 return "*(" + expr + ")";
893 /// <summary>
894 /// Unary Mutator expressions (pre and post ++ and --)
895 /// </summary>
897 /// <remarks>
898 /// UnaryMutator implements ++ and -- expressions. It derives from
899 /// ExpressionStatement becuase the pre/post increment/decrement
900 /// operators can be used in a statement context.
902 /// FIXME: Idea, we could split this up in two classes, one simpler
903 /// for the common case, and one with the extra fields for more complex
904 /// classes (indexers require temporary access; overloaded require method)
906 /// </remarks>
907 public class UnaryMutator : ExpressionStatement
909 class DynamicPostMutator : Expression, IAssignMethod
911 LocalTemporary temp;
912 Expression expr;
914 public DynamicPostMutator (Expression expr)
916 this.expr = expr;
917 this.type = expr.Type;
918 this.loc = expr.Location;
921 public override Expression CreateExpressionTree (ResolveContext ec)
923 throw new NotImplementedException ("ET");
926 protected override Expression DoResolve (ResolveContext rc)
928 eclass = expr.eclass;
929 return this;
932 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
934 expr.DoResolveLValue (ec, right_side);
935 return DoResolve (ec);
938 public override void Emit (EmitContext ec)
940 temp.Emit (ec);
943 public void Emit (EmitContext ec, bool leave_copy)
945 throw new NotImplementedException ();
949 // Emits target assignment using unmodified source value
951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
954 // Allocate temporary variable to keep original value before it's modified
956 temp = new LocalTemporary (type);
957 expr.Emit (ec);
958 temp.Store (ec);
960 ((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
962 if (leave_copy)
963 Emit (ec);
965 temp.Release (ec);
966 temp = null;
970 [Flags]
971 public enum Mode : byte {
972 IsIncrement = 0,
973 IsDecrement = 1,
974 IsPre = 0,
975 IsPost = 2,
977 PreIncrement = 0,
978 PreDecrement = IsDecrement,
979 PostIncrement = IsPost,
980 PostDecrement = IsPost | IsDecrement
983 Mode mode;
984 bool is_expr, recurse;
986 Expression expr;
988 // Holds the real operation
989 Expression operation;
991 public UnaryMutator (Mode m, Expression e, Location loc)
993 mode = m;
994 this.loc = loc;
995 expr = e;
998 public override Expression CreateExpressionTree (ResolveContext ec)
1000 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1003 protected override Expression DoResolve (ResolveContext ec)
1005 expr = expr.Resolve (ec);
1007 if (expr == null)
1008 return null;
1010 if (TypeManager.IsDynamicType (expr.Type)) {
1012 // Handle postfix unary operators using local
1013 // temporary variable
1015 if ((mode & Mode.IsPost) != 0)
1016 expr = new DynamicPostMutator (expr);
1018 Arguments args = new Arguments (1);
1019 args.Add (new Argument (expr));
1020 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1023 if (TypeManager.IsNullableType (expr.Type))
1024 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1026 eclass = ExprClass.Value;
1027 type = expr.Type;
1028 return ResolveOperator (ec);
1031 void EmitCode (EmitContext ec, bool is_expr)
1033 recurse = true;
1034 this.is_expr = is_expr;
1035 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1038 public override void Emit (EmitContext ec)
1041 // We use recurse to allow ourselfs to be the source
1042 // of an assignment. This little hack prevents us from
1043 // having to allocate another expression
1045 if (recurse) {
1046 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1048 operation.Emit (ec);
1050 recurse = false;
1051 return;
1054 EmitCode (ec, true);
1057 public override void EmitStatement (EmitContext ec)
1059 EmitCode (ec, false);
1063 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1065 string GetOperatorExpressionTypeName ()
1067 return IsDecrement ? "Decrement" : "Increment";
1070 bool IsDecrement {
1071 get { return (mode & Mode.IsDecrement) != 0; }
1075 // Returns whether an object of type `t' can be incremented
1076 // or decremented with add/sub (ie, basically whether we can
1077 // use pre-post incr-decr operations on it, but it is not a
1078 // System.Decimal, which we require operator overloading to catch)
1080 static bool IsPredefinedOperator (Type t)
1082 return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
1083 TypeManager.IsEnumType (t) ||
1084 t.IsPointer && t != TypeManager.void_ptr_type;
1087 #if NET_4_0
1088 public override SLE.Expression MakeExpression (BuilderContext ctx)
1090 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1091 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1092 return SLE.Expression.Assign (target, source);
1094 #endif
1096 protected override void CloneTo (CloneContext clonectx, Expression t)
1098 UnaryMutator target = (UnaryMutator) t;
1100 target.expr = expr.Clone (clonectx);
1103 Expression ResolveOperator (ResolveContext ec)
1105 if (expr is RuntimeValueExpression) {
1106 operation = expr;
1107 } else {
1108 // Use itself at the top of the stack
1109 operation = new EmptyExpression (type);
1113 // The operand of the prefix/postfix increment decrement operators
1114 // should be an expression that is classified as a variable,
1115 // a property access or an indexer access
1117 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1118 expr = expr.ResolveLValue (ec, expr);
1119 } else {
1120 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1124 // 1. Check predefined types
1126 if (IsPredefinedOperator (type)) {
1127 // TODO: Move to IntConstant once I get rid of int32_type
1128 var one = new IntConstant (1, loc);
1130 // TODO: Cache this based on type when using EmptyExpression in
1131 // context cache
1132 Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1133 operation = new Binary (op, operation, one, loc);
1134 operation = operation.Resolve (ec);
1135 if (operation != null && operation.Type != type)
1136 operation = Convert.ExplicitNumericConversion (operation, type);
1138 return this;
1142 // Step 2: Perform Operator Overload location
1144 MethodGroupExpr mg;
1145 string op_name;
1147 if (IsDecrement)
1148 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
1149 else
1150 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
1152 mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1154 if (mg != null) {
1155 Arguments args = new Arguments (1);
1156 args.Add (new Argument (expr));
1157 mg = mg.OverloadResolve (ec, ref args, false, loc);
1158 if (mg == null)
1159 return null;
1161 args[0].Expr = operation;
1162 operation = new UserOperatorCall (mg, args, null, loc);
1163 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1164 return this;
1167 string name = IsDecrement ?
1168 Operator.GetName (Operator.OpType.Decrement) :
1169 Operator.GetName (Operator.OpType.Increment);
1171 Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
1172 return null;
1176 /// <summary>
1177 /// Base class for the `Is' and `As' classes.
1178 /// </summary>
1180 /// <remarks>
1181 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1182 /// size.
1183 /// </remarks>
1184 public abstract class Probe : Expression {
1185 public Expression ProbeType;
1186 protected Expression expr;
1187 protected TypeExpr probe_type_expr;
1189 public Probe (Expression expr, Expression probe_type, Location l)
1191 ProbeType = probe_type;
1192 loc = l;
1193 this.expr = expr;
1196 public Expression Expr {
1197 get {
1198 return expr;
1202 protected override Expression DoResolve (ResolveContext ec)
1204 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1205 if (probe_type_expr == null)
1206 return null;
1208 expr = expr.Resolve (ec);
1209 if (expr == null)
1210 return null;
1212 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1213 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1214 OperatorName);
1217 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1218 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1219 OperatorName);
1220 return null;
1223 if (expr.Type == InternalType.AnonymousMethod) {
1224 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1225 OperatorName);
1226 return null;
1229 return this;
1232 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1234 expr.MutateHoistedGenericType (storey);
1235 probe_type_expr.MutateHoistedGenericType (storey);
1238 protected abstract string OperatorName { get; }
1240 protected override void CloneTo (CloneContext clonectx, Expression t)
1242 Probe target = (Probe) t;
1244 target.expr = expr.Clone (clonectx);
1245 target.ProbeType = ProbeType.Clone (clonectx);
1250 /// <summary>
1251 /// Implementation of the `is' operator.
1252 /// </summary>
1253 public class Is : Probe {
1254 Nullable.Unwrap expr_unwrap;
1256 public Is (Expression expr, Expression probe_type, Location l)
1257 : base (expr, probe_type, l)
1261 public override Expression CreateExpressionTree (ResolveContext ec)
1263 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1264 expr.CreateExpressionTree (ec),
1265 new TypeOf (probe_type_expr, loc));
1267 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1270 public override void Emit (EmitContext ec)
1272 ILGenerator ig = ec.ig;
1273 if (expr_unwrap != null) {
1274 expr_unwrap.EmitCheck (ec);
1275 return;
1278 expr.Emit (ec);
1279 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1280 ig.Emit (OpCodes.Ldnull);
1281 ig.Emit (OpCodes.Cgt_Un);
1284 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1286 ILGenerator ig = ec.ig;
1287 if (expr_unwrap != null) {
1288 expr_unwrap.EmitCheck (ec);
1289 } else {
1290 expr.Emit (ec);
1291 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1293 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1296 Expression CreateConstantResult (ResolveContext ec, bool result)
1298 if (result)
1299 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1300 TypeManager.CSharpName (probe_type_expr.Type));
1301 else
1302 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1303 TypeManager.CSharpName (probe_type_expr.Type));
1305 return ReducedExpression.Create (new BoolConstant (result, loc).Resolve (ec), this);
1308 protected override Expression DoResolve (ResolveContext ec)
1310 if (base.DoResolve (ec) == null)
1311 return null;
1313 Type d = expr.Type;
1314 bool d_is_nullable = false;
1317 // If E is a method group or the null literal, or if the type of E is a reference
1318 // type or a nullable type and the value of E is null, the result is false
1320 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1321 return CreateConstantResult (ec, false);
1323 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1324 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1325 d_is_nullable = true;
1328 type = TypeManager.bool_type;
1329 eclass = ExprClass.Value;
1330 Type t = probe_type_expr.Type;
1331 bool t_is_nullable = false;
1332 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1333 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1334 t_is_nullable = true;
1337 if (TypeManager.IsStruct (t)) {
1338 if (d == t) {
1340 // D and T are the same value types but D can be null
1342 if (d_is_nullable && !t_is_nullable) {
1343 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1344 return this;
1348 // The result is true if D and T are the same value types
1350 return CreateConstantResult (ec, true);
1353 if (TypeManager.IsGenericParameter (d))
1354 return ResolveGenericParameter (ec, t, d);
1357 // An unboxing conversion exists
1359 if (Convert.ExplicitReferenceConversionExists (d, t))
1360 return this;
1361 } else {
1362 if (TypeManager.IsGenericParameter (t))
1363 return ResolveGenericParameter (ec, d, t);
1365 if (TypeManager.IsStruct (d)) {
1366 bool temp;
1367 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1368 return CreateConstantResult (ec, true);
1369 } else {
1370 if (TypeManager.IsGenericParameter (d))
1371 return ResolveGenericParameter (ec, t, d);
1373 if (TypeManager.ContainsGenericParameters (d))
1374 return this;
1376 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1377 Convert.ExplicitReferenceConversionExists (d, t)) {
1378 return this;
1383 return CreateConstantResult (ec, false);
1386 Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
1388 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1389 if (constraints != null) {
1390 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1391 return CreateConstantResult (ec, false);
1394 if (TypeManager.IsGenericParameter (expr.Type)) {
1395 if (constraints != null && constraints.IsValueType && expr.Type == t)
1396 return CreateConstantResult (ec, true);
1398 expr = new BoxedCast (expr, d);
1401 return this;
1404 protected override string OperatorName {
1405 get { return "is"; }
1409 /// <summary>
1410 /// Implementation of the `as' operator.
1411 /// </summary>
1412 public class As : Probe {
1413 bool do_isinst;
1414 Expression resolved_type;
1416 public As (Expression expr, Expression probe_type, Location l)
1417 : base (expr, probe_type, l)
1421 public override Expression CreateExpressionTree (ResolveContext ec)
1423 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1424 expr.CreateExpressionTree (ec),
1425 new TypeOf (probe_type_expr, loc));
1427 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1430 public override void Emit (EmitContext ec)
1432 ILGenerator ig = ec.ig;
1434 expr.Emit (ec);
1436 if (do_isinst)
1437 ig.Emit (OpCodes.Isinst, type);
1439 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1440 ig.Emit (OpCodes.Unbox_Any, type);
1443 protected override Expression DoResolve (ResolveContext ec)
1445 if (resolved_type == null) {
1446 resolved_type = base.DoResolve (ec);
1448 if (resolved_type == null)
1449 return null;
1452 type = probe_type_expr.Type;
1453 eclass = ExprClass.Value;
1454 Type etype = expr.Type;
1456 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1457 if (TypeManager.IsGenericParameter (type)) {
1458 ec.Report.Error (413, loc,
1459 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1460 probe_type_expr.GetSignatureForError ());
1461 } else {
1462 ec.Report.Error (77, loc,
1463 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1464 TypeManager.CSharpName (type));
1466 return null;
1469 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1470 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1473 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1474 if (e != null){
1475 expr = e;
1476 do_isinst = false;
1477 return this;
1480 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1481 if (TypeManager.IsGenericParameter (etype))
1482 expr = new BoxedCast (expr, etype);
1484 do_isinst = true;
1485 return this;
1488 if (TypeManager.ContainsGenericParameters (etype) ||
1489 TypeManager.ContainsGenericParameters (type)) {
1490 expr = new BoxedCast (expr, etype);
1491 do_isinst = true;
1492 return this;
1495 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1496 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1498 return null;
1501 protected override string OperatorName {
1502 get { return "as"; }
1505 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1507 type = storey.MutateType (type);
1508 base.MutateHoistedGenericType (storey);
1511 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1513 return expr.GetAttributableValue (ec, value_type, out value);
1517 /// <summary>
1518 /// This represents a typecast in the source language.
1520 /// FIXME: Cast expressions have an unusual set of parsing
1521 /// rules, we need to figure those out.
1522 /// </summary>
1523 public class Cast : ShimExpression {
1524 Expression target_type;
1526 public Cast (Expression cast_type, Expression expr)
1527 : this (cast_type, expr, cast_type.Location)
1531 public Cast (Expression cast_type, Expression expr, Location loc)
1532 : base (expr)
1534 this.target_type = cast_type;
1535 this.loc = loc;
1538 public Expression TargetType {
1539 get { return target_type; }
1542 protected override Expression DoResolve (ResolveContext ec)
1544 expr = expr.Resolve (ec);
1545 if (expr == null)
1546 return null;
1548 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1549 if (target == null)
1550 return null;
1552 type = target.Type;
1554 if (type.IsAbstract && type.IsSealed) {
1555 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1556 return null;
1559 eclass = ExprClass.Value;
1561 Constant c = expr as Constant;
1562 if (c != null) {
1563 c = c.TryReduce (ec, type, loc);
1564 if (c != null)
1565 return c;
1568 if (type.IsPointer && !ec.IsUnsafe) {
1569 UnsafeError (ec, loc);
1570 } else if (TypeManager.IsDynamicType (expr.Type)) {
1571 Arguments arg = new Arguments (1);
1572 arg.Add (new Argument (expr));
1573 return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
1576 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1577 return expr;
1580 protected override void CloneTo (CloneContext clonectx, Expression t)
1582 Cast target = (Cast) t;
1584 target.target_type = target_type.Clone (clonectx);
1585 target.expr = expr.Clone (clonectx);
1589 public class ImplicitCast : ShimExpression
1591 bool arrayAccess;
1593 public ImplicitCast (Expression expr, Type target, bool arrayAccess)
1594 : base (expr)
1596 this.loc = expr.Location;
1597 this.type = target;
1598 this.arrayAccess = arrayAccess;
1601 protected override Expression DoResolve (ResolveContext ec)
1603 expr = expr.Resolve (ec);
1604 if (expr == null)
1605 return null;
1607 if (arrayAccess)
1608 expr = ConvertExpressionToArrayIndex (ec, expr);
1609 else
1610 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1612 return expr;
1617 // C# 2.0 Default value expression
1619 public class DefaultValueExpression : Expression
1621 Expression expr;
1623 public DefaultValueExpression (Expression expr, Location loc)
1625 this.expr = expr;
1626 this.loc = loc;
1629 public override Expression CreateExpressionTree (ResolveContext ec)
1631 Arguments args = new Arguments (2);
1632 args.Add (new Argument (this));
1633 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1634 return CreateExpressionFactoryCall (ec, "Constant", args);
1637 protected override Expression DoResolve (ResolveContext ec)
1639 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1640 if (texpr == null)
1641 return null;
1643 type = texpr.Type;
1645 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1646 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1649 if (type.IsPointer)
1650 return new NullLiteral (Location).ConvertImplicitly (ec, type);
1652 if (TypeManager.IsReferenceType (type))
1653 return new NullConstant (type, loc);
1655 Constant c = New.Constantify (type);
1656 if (c != null)
1657 return c.Resolve (ec);
1659 eclass = ExprClass.Variable;
1660 return this;
1663 public override void Emit (EmitContext ec)
1665 LocalTemporary temp_storage = new LocalTemporary(type);
1667 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1668 ec.ig.Emit(OpCodes.Initobj, type);
1669 temp_storage.Emit(ec);
1672 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1674 type = storey.MutateType (type);
1677 protected override void CloneTo (CloneContext clonectx, Expression t)
1679 DefaultValueExpression target = (DefaultValueExpression) t;
1681 target.expr = expr.Clone (clonectx);
1685 /// <summary>
1686 /// Binary operators
1687 /// </summary>
1688 public class Binary : Expression, IDynamicBinder
1690 protected class PredefinedOperator {
1691 protected readonly Type left;
1692 protected readonly Type right;
1693 public readonly Operator OperatorsMask;
1694 public Type ReturnType;
1696 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1697 : this (ltype, rtype, op_mask, ltype)
1701 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1702 : this (type, type, op_mask, return_type)
1706 public PredefinedOperator (Type type, Operator op_mask)
1707 : this (type, type, op_mask, type)
1711 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1713 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1714 throw new InternalErrorException ("Only masked values can be used");
1716 this.left = ltype;
1717 this.right = rtype;
1718 this.OperatorsMask = op_mask;
1719 this.ReturnType = return_type;
1722 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1724 b.type = ReturnType;
1726 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1727 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1730 // A user operators does not support multiple user conversions, but decimal type
1731 // is considered to be predefined type therefore we apply predefined operators rules
1732 // and then look for decimal user-operator implementation
1734 if (left == TypeManager.decimal_type)
1735 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1737 var c = b.right as Constant;
1738 if (c != null) {
1739 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
1740 return ReducedExpression.Create (b.left, b).Resolve (ec);
1741 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
1742 return ReducedExpression.Create (b.left, b).Resolve (ec);
1743 return b;
1746 c = b.left as Constant;
1747 if (c != null) {
1748 if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
1749 return ReducedExpression.Create (b.right, b).Resolve (ec);
1750 if (b.oper == Operator.Multiply && c.IsOneInteger)
1751 return ReducedExpression.Create (b.right, b).Resolve (ec);
1752 return b;
1755 return b;
1758 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1761 // We are dealing with primitive types only
1763 return left == ltype && ltype == rtype;
1766 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1768 if (TypeManager.IsEqual (left, lexpr.Type) &&
1769 TypeManager.IsEqual (right, rexpr.Type))
1770 return true;
1772 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1773 Convert.ImplicitConversionExists (ec, rexpr, right);
1776 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1778 int result = 0;
1779 if (left != null && best_operator.left != null) {
1780 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1784 // When second arguments are same as the first one, the result is same
1786 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1787 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1790 if (result == 0 || result > 2)
1791 return null;
1793 return result == 1 ? best_operator : this;
1797 class PredefinedStringOperator : PredefinedOperator {
1798 public PredefinedStringOperator (Type type, Operator op_mask)
1799 : base (type, op_mask, type)
1801 ReturnType = TypeManager.string_type;
1804 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1805 : base (ltype, rtype, op_mask)
1807 ReturnType = TypeManager.string_type;
1810 public override Expression ConvertResult (ResolveContext ec, Binary b)
1813 // Use original expression for nullable arguments
1815 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1816 if (unwrap != null)
1817 b.left = unwrap.Original;
1819 unwrap = b.right as Nullable.Unwrap;
1820 if (unwrap != null)
1821 b.right = unwrap.Original;
1823 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1824 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1827 // Start a new concat expression using converted expression
1829 return StringConcat.Create (ec, b.left, b.right, b.loc);
1833 class PredefinedShiftOperator : PredefinedOperator {
1834 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1835 base (ltype, TypeManager.int32_type, op_mask)
1839 public override Expression ConvertResult (ResolveContext ec, Binary b)
1841 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1843 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1845 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1848 // b = b.left >> b.right & (0x1f|0x3f)
1850 b.right = new Binary (Operator.BitwiseAnd,
1851 b.right, new IntConstant (right_mask, b.right.Location), b.loc).Resolve (ec);
1854 // Expression tree representation does not use & mask
1856 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1857 b.type = ReturnType;
1860 // Optimize shift by 0
1862 var c = b.right as Constant;
1863 if (c != null && c.IsDefaultValue)
1864 return ReducedExpression.Create (b.left, b).Resolve (ec);
1866 return b;
1870 class PredefinedPointerOperator : PredefinedOperator {
1871 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1872 : base (ltype, rtype, op_mask)
1876 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1877 : base (ltype, rtype, op_mask, retType)
1881 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1882 : base (type, op_mask, return_type)
1886 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1888 if (left == null) {
1889 if (!lexpr.Type.IsPointer)
1890 return false;
1891 } else {
1892 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1893 return false;
1896 if (right == null) {
1897 if (!rexpr.Type.IsPointer)
1898 return false;
1899 } else {
1900 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1901 return false;
1904 return true;
1907 public override Expression ConvertResult (ResolveContext ec, Binary b)
1909 if (left != null) {
1910 b.left = EmptyCast.Create (b.left, left);
1911 } else if (right != null) {
1912 b.right = EmptyCast.Create (b.right, right);
1915 Type r_type = ReturnType;
1916 Expression left_arg, right_arg;
1917 if (r_type == null) {
1918 if (left == null) {
1919 left_arg = b.left;
1920 right_arg = b.right;
1921 r_type = b.left.Type;
1922 } else {
1923 left_arg = b.right;
1924 right_arg = b.left;
1925 r_type = b.right.Type;
1927 } else {
1928 left_arg = b.left;
1929 right_arg = b.right;
1932 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1936 [Flags]
1937 public enum Operator {
1938 Multiply = 0 | ArithmeticMask,
1939 Division = 1 | ArithmeticMask,
1940 Modulus = 2 | ArithmeticMask,
1941 Addition = 3 | ArithmeticMask | AdditionMask,
1942 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1944 LeftShift = 5 | ShiftMask,
1945 RightShift = 6 | ShiftMask,
1947 LessThan = 7 | ComparisonMask | RelationalMask,
1948 GreaterThan = 8 | ComparisonMask | RelationalMask,
1949 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1950 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1951 Equality = 11 | ComparisonMask | EqualityMask,
1952 Inequality = 12 | ComparisonMask | EqualityMask,
1954 BitwiseAnd = 13 | BitwiseMask,
1955 ExclusiveOr = 14 | BitwiseMask,
1956 BitwiseOr = 15 | BitwiseMask,
1958 LogicalAnd = 16 | LogicalMask,
1959 LogicalOr = 17 | LogicalMask,
1962 // Operator masks
1964 ValuesOnlyMask = ArithmeticMask - 1,
1965 ArithmeticMask = 1 << 5,
1966 ShiftMask = 1 << 6,
1967 ComparisonMask = 1 << 7,
1968 EqualityMask = 1 << 8,
1969 BitwiseMask = 1 << 9,
1970 LogicalMask = 1 << 10,
1971 AdditionMask = 1 << 11,
1972 SubtractionMask = 1 << 12,
1973 RelationalMask = 1 << 13
1976 readonly Operator oper;
1977 protected Expression left, right;
1978 readonly bool is_compound;
1979 Expression enum_conversion;
1981 static PredefinedOperator [] standard_operators;
1982 static PredefinedOperator [] pointer_operators;
1984 public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
1985 : this (oper, left, right, loc)
1987 this.is_compound = isCompound;
1990 public Binary (Operator oper, Expression left, Expression right, Location loc)
1992 this.oper = oper;
1993 this.left = left;
1994 this.right = right;
1995 this.loc = loc;
1998 public Operator Oper {
1999 get {
2000 return oper;
2004 /// <summary>
2005 /// Returns a stringified representation of the Operator
2006 /// </summary>
2007 string OperName (Operator oper)
2009 string s;
2010 switch (oper){
2011 case Operator.Multiply:
2012 s = "*";
2013 break;
2014 case Operator.Division:
2015 s = "/";
2016 break;
2017 case Operator.Modulus:
2018 s = "%";
2019 break;
2020 case Operator.Addition:
2021 s = "+";
2022 break;
2023 case Operator.Subtraction:
2024 s = "-";
2025 break;
2026 case Operator.LeftShift:
2027 s = "<<";
2028 break;
2029 case Operator.RightShift:
2030 s = ">>";
2031 break;
2032 case Operator.LessThan:
2033 s = "<";
2034 break;
2035 case Operator.GreaterThan:
2036 s = ">";
2037 break;
2038 case Operator.LessThanOrEqual:
2039 s = "<=";
2040 break;
2041 case Operator.GreaterThanOrEqual:
2042 s = ">=";
2043 break;
2044 case Operator.Equality:
2045 s = "==";
2046 break;
2047 case Operator.Inequality:
2048 s = "!=";
2049 break;
2050 case Operator.BitwiseAnd:
2051 s = "&";
2052 break;
2053 case Operator.BitwiseOr:
2054 s = "|";
2055 break;
2056 case Operator.ExclusiveOr:
2057 s = "^";
2058 break;
2059 case Operator.LogicalOr:
2060 s = "||";
2061 break;
2062 case Operator.LogicalAnd:
2063 s = "&&";
2064 break;
2065 default:
2066 s = oper.ToString ();
2067 break;
2070 if (is_compound)
2071 return s + "=";
2073 return s;
2076 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2078 new Binary (oper, left, right, loc).Error_OperatorCannotBeApplied (ec, left, right);
2081 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2083 string l, r;
2084 l = TypeManager.CSharpName (left.Type);
2085 r = TypeManager.CSharpName (right.Type);
2087 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2088 oper, l, r);
2091 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2093 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2097 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2099 string GetOperatorExpressionTypeName ()
2101 switch (oper) {
2102 case Operator.Addition:
2103 return is_compound ? "AddAssign" : "Add";
2104 case Operator.BitwiseAnd:
2105 return is_compound ? "AndAssign" : "And";
2106 case Operator.BitwiseOr:
2107 return is_compound ? "OrAssign" : "Or";
2108 case Operator.Division:
2109 return is_compound ? "DivideAssign" : "Divide";
2110 case Operator.ExclusiveOr:
2111 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2112 case Operator.Equality:
2113 return "Equal";
2114 case Operator.GreaterThan:
2115 return "GreaterThan";
2116 case Operator.GreaterThanOrEqual:
2117 return "GreaterThanOrEqual";
2118 case Operator.Inequality:
2119 return "NotEqual";
2120 case Operator.LeftShift:
2121 return is_compound ? "LeftShiftAssign" : "LeftShift";
2122 case Operator.LessThan:
2123 return "LessThan";
2124 case Operator.LessThanOrEqual:
2125 return "LessThanOrEqual";
2126 case Operator.LogicalAnd:
2127 return "And";
2128 case Operator.LogicalOr:
2129 return "Or";
2130 case Operator.Modulus:
2131 return is_compound ? "ModuloAssign" : "Modulo";
2132 case Operator.Multiply:
2133 return is_compound ? "MultiplyAssign" : "Multiply";
2134 case Operator.RightShift:
2135 return is_compound ? "RightShiftAssign" : "RightShift";
2136 case Operator.Subtraction:
2137 return is_compound ? "SubtractAssign" : "Subtract";
2138 default:
2139 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2143 static string GetOperatorMetadataName (Operator op)
2145 CSharp.Operator.OpType op_type;
2146 switch (op) {
2147 case Operator.Addition:
2148 op_type = CSharp.Operator.OpType.Addition; break;
2149 case Operator.BitwiseAnd:
2150 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2151 case Operator.BitwiseOr:
2152 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2153 case Operator.Division:
2154 op_type = CSharp.Operator.OpType.Division; break;
2155 case Operator.Equality:
2156 op_type = CSharp.Operator.OpType.Equality; break;
2157 case Operator.ExclusiveOr:
2158 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2159 case Operator.GreaterThan:
2160 op_type = CSharp.Operator.OpType.GreaterThan; break;
2161 case Operator.GreaterThanOrEqual:
2162 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2163 case Operator.Inequality:
2164 op_type = CSharp.Operator.OpType.Inequality; break;
2165 case Operator.LeftShift:
2166 op_type = CSharp.Operator.OpType.LeftShift; break;
2167 case Operator.LessThan:
2168 op_type = CSharp.Operator.OpType.LessThan; break;
2169 case Operator.LessThanOrEqual:
2170 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2171 case Operator.Modulus:
2172 op_type = CSharp.Operator.OpType.Modulus; break;
2173 case Operator.Multiply:
2174 op_type = CSharp.Operator.OpType.Multiply; break;
2175 case Operator.RightShift:
2176 op_type = CSharp.Operator.OpType.RightShift; break;
2177 case Operator.Subtraction:
2178 op_type = CSharp.Operator.OpType.Subtraction; break;
2179 default:
2180 throw new InternalErrorException (op.ToString ());
2183 return CSharp.Operator.GetMetadataName (op_type);
2186 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2188 OpCode opcode;
2189 ILGenerator ig = ec.ig;
2191 switch (oper){
2192 case Operator.Multiply:
2193 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2194 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2195 opcode = OpCodes.Mul_Ovf;
2196 else if (!IsFloat (l))
2197 opcode = OpCodes.Mul_Ovf_Un;
2198 else
2199 opcode = OpCodes.Mul;
2200 } else
2201 opcode = OpCodes.Mul;
2203 break;
2205 case Operator.Division:
2206 if (IsUnsigned (l))
2207 opcode = OpCodes.Div_Un;
2208 else
2209 opcode = OpCodes.Div;
2210 break;
2212 case Operator.Modulus:
2213 if (IsUnsigned (l))
2214 opcode = OpCodes.Rem_Un;
2215 else
2216 opcode = OpCodes.Rem;
2217 break;
2219 case Operator.Addition:
2220 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2221 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2222 opcode = OpCodes.Add_Ovf;
2223 else if (!IsFloat (l))
2224 opcode = OpCodes.Add_Ovf_Un;
2225 else
2226 opcode = OpCodes.Add;
2227 } else
2228 opcode = OpCodes.Add;
2229 break;
2231 case Operator.Subtraction:
2232 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2233 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2234 opcode = OpCodes.Sub_Ovf;
2235 else if (!IsFloat (l))
2236 opcode = OpCodes.Sub_Ovf_Un;
2237 else
2238 opcode = OpCodes.Sub;
2239 } else
2240 opcode = OpCodes.Sub;
2241 break;
2243 case Operator.RightShift:
2244 if (IsUnsigned (l))
2245 opcode = OpCodes.Shr_Un;
2246 else
2247 opcode = OpCodes.Shr;
2248 break;
2250 case Operator.LeftShift:
2251 opcode = OpCodes.Shl;
2252 break;
2254 case Operator.Equality:
2255 opcode = OpCodes.Ceq;
2256 break;
2258 case Operator.Inequality:
2259 ig.Emit (OpCodes.Ceq);
2260 ig.Emit (OpCodes.Ldc_I4_0);
2262 opcode = OpCodes.Ceq;
2263 break;
2265 case Operator.LessThan:
2266 if (IsUnsigned (l))
2267 opcode = OpCodes.Clt_Un;
2268 else
2269 opcode = OpCodes.Clt;
2270 break;
2272 case Operator.GreaterThan:
2273 if (IsUnsigned (l))
2274 opcode = OpCodes.Cgt_Un;
2275 else
2276 opcode = OpCodes.Cgt;
2277 break;
2279 case Operator.LessThanOrEqual:
2280 if (IsUnsigned (l) || IsFloat (l))
2281 ig.Emit (OpCodes.Cgt_Un);
2282 else
2283 ig.Emit (OpCodes.Cgt);
2284 ig.Emit (OpCodes.Ldc_I4_0);
2286 opcode = OpCodes.Ceq;
2287 break;
2289 case Operator.GreaterThanOrEqual:
2290 if (IsUnsigned (l) || IsFloat (l))
2291 ig.Emit (OpCodes.Clt_Un);
2292 else
2293 ig.Emit (OpCodes.Clt);
2295 ig.Emit (OpCodes.Ldc_I4_0);
2297 opcode = OpCodes.Ceq;
2298 break;
2300 case Operator.BitwiseOr:
2301 opcode = OpCodes.Or;
2302 break;
2304 case Operator.BitwiseAnd:
2305 opcode = OpCodes.And;
2306 break;
2308 case Operator.ExclusiveOr:
2309 opcode = OpCodes.Xor;
2310 break;
2312 default:
2313 throw new InternalErrorException (oper.ToString ());
2316 ig.Emit (opcode);
2319 static bool IsUnsigned (Type t)
2321 if (t.IsPointer)
2322 return true;
2324 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2325 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2328 static bool IsFloat (Type t)
2330 return t == TypeManager.float_type || t == TypeManager.double_type;
2333 Expression ResolveOperator (ResolveContext ec)
2335 Type l = left.Type;
2336 Type r = right.Type;
2337 Expression expr;
2338 bool primitives_only = false;
2340 if (standard_operators == null)
2341 CreateStandardOperatorsTable ();
2344 // Handles predefined primitive types
2346 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2347 if ((oper & Operator.ShiftMask) == 0) {
2348 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2349 return null;
2351 primitives_only = true;
2353 } else {
2354 // Pointers
2355 if (l.IsPointer || r.IsPointer)
2356 return ResolveOperatorPointer (ec, l, r);
2358 // Enums
2359 bool lenum = TypeManager.IsEnumType (l);
2360 bool renum = TypeManager.IsEnumType (r);
2361 if (lenum || renum) {
2362 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2364 // TODO: Can this be ambiguous
2365 if (expr != null)
2366 return expr;
2369 // Delegates
2370 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2371 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2373 expr = ResolveOperatorDelegate (ec, l, r);
2375 // TODO: Can this be ambiguous
2376 if (expr != null)
2377 return expr;
2380 // User operators
2381 expr = ResolveUserOperator (ec, l, r);
2382 if (expr != null)
2383 return expr;
2385 // Predefined reference types equality
2386 if ((oper & Operator.EqualityMask) != 0) {
2387 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2388 if (expr != null)
2389 return expr;
2393 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2396 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2397 // if 'left' is not an enumeration constant, create one from the type of 'right'
2398 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2400 switch (oper) {
2401 case Operator.BitwiseOr:
2402 case Operator.BitwiseAnd:
2403 case Operator.ExclusiveOr:
2404 case Operator.Equality:
2405 case Operator.Inequality:
2406 case Operator.LessThan:
2407 case Operator.LessThanOrEqual:
2408 case Operator.GreaterThan:
2409 case Operator.GreaterThanOrEqual:
2410 if (TypeManager.IsEnumType (left.Type))
2411 return left;
2413 if (left.IsZeroInteger)
2414 return left.TryReduce (ec, right.Type, loc);
2416 break;
2418 case Operator.Addition:
2419 case Operator.Subtraction:
2420 return left;
2422 case Operator.Multiply:
2423 case Operator.Division:
2424 case Operator.Modulus:
2425 case Operator.LeftShift:
2426 case Operator.RightShift:
2427 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2428 break;
2429 return left;
2431 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2432 return null;
2436 // The `|' operator used on types which were extended is dangerous
2438 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2440 OpcodeCast lcast = left as OpcodeCast;
2441 if (lcast != null) {
2442 if (IsUnsigned (lcast.UnderlyingType))
2443 lcast = null;
2446 OpcodeCast rcast = right as OpcodeCast;
2447 if (rcast != null) {
2448 if (IsUnsigned (rcast.UnderlyingType))
2449 rcast = null;
2452 if (lcast == null && rcast == null)
2453 return;
2455 // FIXME: consider constants
2457 ec.Report.Warning (675, 3, loc,
2458 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2459 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2462 static void CreatePointerOperatorsTable ()
2464 var temp = new List<PredefinedPointerOperator> ();
2467 // Pointer arithmetic:
2469 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2470 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2471 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2472 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2474 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2475 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2476 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2477 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2480 // T* operator + (int y, T* x);
2481 // T* operator + (uint y, T *x);
2482 // T* operator + (long y, T *x);
2483 // T* operator + (ulong y, T *x);
2485 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2486 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2487 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2488 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2491 // long operator - (T* x, T *y)
2493 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2495 pointer_operators = temp.ToArray ();
2498 static void CreateStandardOperatorsTable ()
2500 var temp = new List<PredefinedOperator> ();
2501 Type bool_type = TypeManager.bool_type;
2503 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2504 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2505 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2506 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2507 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2508 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2509 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2511 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2512 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2513 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2514 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2515 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2516 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2517 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2519 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2521 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2522 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2523 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2525 temp.Add (new PredefinedOperator (bool_type,
2526 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2528 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2529 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2530 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2531 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2533 standard_operators = temp.ToArray ();
2537 // Rules used during binary numeric promotion
2539 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, Type type)
2541 Expression temp;
2542 Type etype;
2544 Constant c = prim_expr as Constant;
2545 if (c != null) {
2546 temp = c.ConvertImplicitly (rc, type);
2547 if (temp != null) {
2548 prim_expr = temp;
2549 return true;
2553 if (type == TypeManager.uint32_type) {
2554 etype = prim_expr.Type;
2555 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2556 type = TypeManager.int64_type;
2558 if (type != second_expr.Type) {
2559 c = second_expr as Constant;
2560 if (c != null)
2561 temp = c.ConvertImplicitly (rc, type);
2562 else
2563 temp = Convert.ImplicitNumericConversion (second_expr, type);
2564 if (temp == null)
2565 return false;
2566 second_expr = temp;
2569 } else if (type == TypeManager.uint64_type) {
2571 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2573 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2574 type == TypeManager.short_type || type == TypeManager.sbyte_type)
2575 return false;
2578 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2579 if (temp == null)
2580 return false;
2582 prim_expr = temp;
2583 return true;
2587 // 7.2.6.2 Binary numeric promotions
2589 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2591 Type ltype = left.Type;
2592 Type rtype = right.Type;
2593 Expression temp;
2595 foreach (Type t in ConstantFold.binary_promotions) {
2596 if (t == ltype)
2597 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2599 if (t == rtype)
2600 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2603 Type int32 = TypeManager.int32_type;
2604 if (ltype != int32) {
2605 Constant c = left as Constant;
2606 if (c != null)
2607 temp = c.ConvertImplicitly (ec, int32);
2608 else
2609 temp = Convert.ImplicitNumericConversion (left, int32);
2611 if (temp == null)
2612 return false;
2613 left = temp;
2616 if (rtype != int32) {
2617 Constant c = right as Constant;
2618 if (c != null)
2619 temp = c.ConvertImplicitly (ec, int32);
2620 else
2621 temp = Convert.ImplicitNumericConversion (right, int32);
2623 if (temp == null)
2624 return false;
2625 right = temp;
2628 return true;
2631 protected override Expression DoResolve (ResolveContext ec)
2633 if (left == null)
2634 return null;
2636 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2637 left = ((ParenthesizedExpression) left).Expr;
2638 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2639 if (left == null)
2640 return null;
2642 if (left.eclass == ExprClass.Type) {
2643 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2644 return null;
2646 } else
2647 left = left.Resolve (ec);
2649 if (left == null)
2650 return null;
2652 Constant lc = left as Constant;
2654 if (lc != null && lc.Type == TypeManager.bool_type &&
2655 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2656 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2658 // FIXME: resolve right expression as unreachable
2659 // right.Resolve (ec);
2661 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2662 return left;
2665 right = right.Resolve (ec);
2666 if (right == null)
2667 return null;
2669 eclass = ExprClass.Value;
2670 Constant rc = right as Constant;
2672 // The conversion rules are ignored in enum context but why
2673 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2674 lc = EnumLiftUp (ec, lc, rc, loc);
2675 if (lc != null)
2676 rc = EnumLiftUp (ec, rc, lc, loc);
2679 if (rc != null && lc != null) {
2680 int prev_e = ec.Report.Errors;
2681 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2682 if (e != null)
2683 e = e.Resolve (ec);
2685 if (e != null || ec.Report.Errors != prev_e)
2686 return e;
2689 // Comparison warnings
2690 if ((oper & Operator.ComparisonMask) != 0) {
2691 if (left.Equals (right)) {
2692 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2694 CheckUselessComparison (ec, lc, right.Type);
2695 CheckUselessComparison (ec, rc, left.Type);
2698 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2699 Arguments args = new Arguments (2);
2700 args.Add (new Argument (left));
2701 args.Add (new Argument (right));
2702 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2705 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2706 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2707 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2708 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2709 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2710 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2712 return DoResolveCore (ec, left, right);
2715 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2717 Expression expr = ResolveOperator (ec);
2718 if (expr == null)
2719 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2721 if (left == null || right == null)
2722 throw new InternalErrorException ("Invalid conversion");
2724 if (oper == Operator.BitwiseOr)
2725 CheckBitwiseOrOnSignExtended (ec);
2727 return expr;
2730 public override SLE.Expression MakeExpression (BuilderContext ctx)
2732 var le = left.MakeExpression (ctx);
2733 var re = right.MakeExpression (ctx);
2734 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2736 switch (oper) {
2737 case Operator.Addition:
2738 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2739 case Operator.BitwiseAnd:
2740 return SLE.Expression.And (le, re);
2741 case Operator.BitwiseOr:
2742 return SLE.Expression.Or (le, re);
2743 case Operator.Division:
2744 return SLE.Expression.Divide (le, re);
2745 case Operator.Equality:
2746 return SLE.Expression.Equal (le, re);
2747 case Operator.ExclusiveOr:
2748 return SLE.Expression.ExclusiveOr (le, re);
2749 case Operator.GreaterThan:
2750 return SLE.Expression.GreaterThan (le, re);
2751 case Operator.GreaterThanOrEqual:
2752 return SLE.Expression.GreaterThanOrEqual (le, re);
2753 case Operator.Inequality:
2754 return SLE.Expression.NotEqual (le, re);
2755 case Operator.LeftShift:
2756 return SLE.Expression.LeftShift (le, re);
2757 case Operator.LessThan:
2758 return SLE.Expression.LessThan (le, re);
2759 case Operator.LessThanOrEqual:
2760 return SLE.Expression.LessThanOrEqual (le, re);
2761 case Operator.LogicalAnd:
2762 return SLE.Expression.AndAlso (le, re);
2763 case Operator.LogicalOr:
2764 return SLE.Expression.OrElse (le, re);
2765 case Operator.Modulus:
2766 return SLE.Expression.Modulo (le, re);
2767 case Operator.Multiply:
2768 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2769 case Operator.RightShift:
2770 return SLE.Expression.RightShift (le, re);
2771 case Operator.Subtraction:
2772 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2773 default:
2774 throw new NotImplementedException (oper.ToString ());
2778 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2780 left.MutateHoistedGenericType (storey);
2781 right.MutateHoistedGenericType (storey);
2785 // D operator + (D x, D y)
2786 // D operator - (D x, D y)
2787 // bool operator == (D x, D y)
2788 // bool operator != (D x, D y)
2790 Expression ResolveOperatorDelegate (ResolveContext ec, Type l, Type r)
2792 bool is_equality = (oper & Operator.EqualityMask) != 0;
2793 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2794 Expression tmp;
2795 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2796 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2797 if (tmp == null)
2798 return null;
2799 right = tmp;
2800 r = right.Type;
2801 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2802 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2803 if (tmp == null)
2804 return null;
2805 left = tmp;
2806 l = left.Type;
2807 } else {
2808 return null;
2813 // Resolve delegate equality as a user operator
2815 if (is_equality)
2816 return ResolveUserOperator (ec, l, r);
2818 MethodSpec method;
2819 Arguments args = new Arguments (2);
2820 args.Add (new Argument (left));
2821 args.Add (new Argument (right));
2823 if (oper == Operator.Addition) {
2824 if (TypeManager.delegate_combine_delegate_delegate == null) {
2825 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2826 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2829 method = TypeManager.delegate_combine_delegate_delegate;
2830 } else {
2831 if (TypeManager.delegate_remove_delegate_delegate == null) {
2832 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2833 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2836 method = TypeManager.delegate_remove_delegate_delegate;
2839 MethodGroupExpr mg = new MethodGroupExpr (new [] { method }, TypeManager.delegate_type, loc);
2840 mg = mg.OverloadResolve (ec, ref args, false, loc);
2842 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2846 // Enumeration operators
2848 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2851 // bool operator == (E x, E y);
2852 // bool operator != (E x, E y);
2853 // bool operator < (E x, E y);
2854 // bool operator > (E x, E y);
2855 // bool operator <= (E x, E y);
2856 // bool operator >= (E x, E y);
2858 // E operator & (E x, E y);
2859 // E operator | (E x, E y);
2860 // E operator ^ (E x, E y);
2862 // U operator - (E e, E f)
2863 // E operator - (E e, U x)
2865 // E operator + (U x, E e)
2866 // E operator + (E e, U x)
2868 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2869 (oper == Operator.Subtraction && lenum) ||
2870 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2871 return null;
2873 Expression ltemp = left;
2874 Expression rtemp = right;
2875 Type underlying_type;
2876 Expression expr;
2878 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2879 if (renum) {
2880 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2881 if (expr != null) {
2882 left = expr;
2883 ltype = expr.Type;
2885 } else if (lenum) {
2886 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2887 if (expr != null) {
2888 right = expr;
2889 rtype = expr.Type;
2894 if (TypeManager.IsEqual (ltype, rtype)) {
2895 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2897 if (left is Constant)
2898 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2899 else
2900 left = EmptyCast.Create (left, underlying_type);
2902 if (right is Constant)
2903 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2904 else
2905 right = EmptyCast.Create (right, underlying_type);
2906 } else if (lenum) {
2907 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2909 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2910 Constant c = right as Constant;
2911 if (c == null || !c.IsDefaultValue)
2912 return null;
2913 } else {
2914 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2915 return null;
2917 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2920 if (left is Constant)
2921 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2922 else
2923 left = EmptyCast.Create (left, underlying_type);
2925 } else if (renum) {
2926 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2928 if (oper != Operator.Addition) {
2929 Constant c = left as Constant;
2930 if (c == null || !c.IsDefaultValue)
2931 return null;
2932 } else {
2933 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2934 return null;
2936 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2939 if (right is Constant)
2940 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2941 else
2942 right = EmptyCast.Create (right, underlying_type);
2944 } else {
2945 return null;
2949 // C# specification uses explicit cast syntax which means binary promotion
2950 // should happen, however it seems that csc does not do that
2952 if (!DoBinaryOperatorPromotion (ec)) {
2953 left = ltemp;
2954 right = rtemp;
2955 return null;
2958 Type res_type = null;
2959 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2960 Type promoted_type = lenum ? left.Type : right.Type;
2961 enum_conversion = Convert.ExplicitNumericConversion (
2962 new EmptyExpression (promoted_type), underlying_type);
2964 if (oper == Operator.Subtraction && renum && lenum)
2965 res_type = underlying_type;
2966 else if (oper == Operator.Addition && renum)
2967 res_type = rtype;
2968 else
2969 res_type = ltype;
2972 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2973 if (!is_compound || expr == null)
2974 return expr;
2977 // Section: 7.16.2
2981 // If the return type of the selected operator is implicitly convertible to the type of x
2983 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2984 return expr;
2987 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2988 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2989 // convertible to the type of x or the operator is a shift operator, then the operation
2990 // is evaluated as x = (T)(x op y), where T is the type of x
2992 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
2993 if (expr == null)
2994 return null;
2996 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
2997 return expr;
2999 return null;
3003 // 7.9.6 Reference type equality operators
3005 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
3008 // operator != (object a, object b)
3009 // operator == (object a, object b)
3012 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
3014 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
3015 return null;
3017 type = TypeManager.bool_type;
3018 GenericConstraints constraints;
3020 bool lgen = TypeManager.IsGenericParameter (l);
3022 if (TypeManager.IsEqual (l, r)) {
3023 if (lgen) {
3025 // Only allow to compare same reference type parameter
3027 if (TypeManager.IsReferenceType (l)) {
3028 left = new BoxedCast (left, TypeManager.object_type);
3029 right = new BoxedCast (right, TypeManager.object_type);
3030 return this;
3033 return null;
3036 if (l == InternalType.AnonymousMethod)
3037 return null;
3039 if (TypeManager.IsValueType (l))
3040 return null;
3042 return this;
3045 bool rgen = TypeManager.IsGenericParameter (r);
3048 // a, Both operands are reference-type values or the value null
3049 // b, One operand is a value of type T where T is a type-parameter and
3050 // the other operand is the value null. Furthermore T does not have the
3051 // value type constrain
3053 if (left is NullLiteral || right is NullLiteral) {
3054 if (lgen) {
3055 constraints = TypeManager.GetTypeParameterConstraints (l);
3056 if (constraints != null && constraints.HasValueTypeConstraint)
3057 return null;
3059 left = new BoxedCast (left, TypeManager.object_type);
3060 return this;
3063 if (rgen) {
3064 constraints = TypeManager.GetTypeParameterConstraints (r);
3065 if (constraints != null && constraints.HasValueTypeConstraint)
3066 return null;
3068 right = new BoxedCast (right, TypeManager.object_type);
3069 return this;
3074 // An interface is converted to the object before the
3075 // standard conversion is applied. It's not clear from the
3076 // standard but it looks like it works like that.
3078 if (lgen) {
3079 if (!TypeManager.IsReferenceType (l))
3080 return null;
3082 l = TypeManager.object_type;
3083 left = new BoxedCast (left, l);
3084 } else if (l.IsInterface) {
3085 l = TypeManager.object_type;
3086 } else if (TypeManager.IsStruct (l)) {
3087 return null;
3090 if (rgen) {
3091 if (!TypeManager.IsReferenceType (r))
3092 return null;
3094 r = TypeManager.object_type;
3095 right = new BoxedCast (right, r);
3096 } else if (r.IsInterface) {
3097 r = TypeManager.object_type;
3098 } else if (TypeManager.IsStruct (r)) {
3099 return null;
3103 const string ref_comparison = "Possible unintended reference comparison. " +
3104 "Consider casting the {0} side of the expression to `string' to compare the values";
3107 // A standard implicit conversion exists from the type of either
3108 // operand to the type of the other operand
3110 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3111 if (l == TypeManager.string_type)
3112 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3114 return this;
3117 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3118 if (r == TypeManager.string_type)
3119 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3121 return this;
3124 return null;
3128 Expression ResolveOperatorPointer (ResolveContext ec, Type l, Type r)
3131 // bool operator == (void* x, void* y);
3132 // bool operator != (void* x, void* y);
3133 // bool operator < (void* x, void* y);
3134 // bool operator > (void* x, void* y);
3135 // bool operator <= (void* x, void* y);
3136 // bool operator >= (void* x, void* y);
3138 if ((oper & Operator.ComparisonMask) != 0) {
3139 Expression temp;
3140 if (!l.IsPointer) {
3141 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3142 if (temp == null)
3143 return null;
3144 left = temp;
3147 if (!r.IsPointer) {
3148 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3149 if (temp == null)
3150 return null;
3151 right = temp;
3154 type = TypeManager.bool_type;
3155 return this;
3158 if (pointer_operators == null)
3159 CreatePointerOperatorsTable ();
3161 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3165 // Build-in operators method overloading
3167 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3169 PredefinedOperator best_operator = null;
3170 Type l = left.Type;
3171 Type r = right.Type;
3172 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3174 foreach (PredefinedOperator po in operators) {
3175 if ((po.OperatorsMask & oper_mask) == 0)
3176 continue;
3178 if (primitives_only) {
3179 if (!po.IsPrimitiveApplicable (l, r))
3180 continue;
3181 } else {
3182 if (!po.IsApplicable (ec, left, right))
3183 continue;
3186 if (best_operator == null) {
3187 best_operator = po;
3188 if (primitives_only)
3189 break;
3191 continue;
3194 best_operator = po.ResolveBetterOperator (ec, best_operator);
3196 if (best_operator == null) {
3197 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3198 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3200 best_operator = po;
3201 break;
3205 if (best_operator == null)
3206 return null;
3208 Expression expr = best_operator.ConvertResult (ec, this);
3211 // Optimize &/&& constant expressions with 0 value
3213 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3214 Constant rc = right as Constant;
3215 Constant lc = left as Constant;
3216 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
3218 // The result is a constant with side-effect
3220 Constant side_effect = rc == null ?
3221 new SideEffectConstant (lc, right, loc) :
3222 new SideEffectConstant (rc, left, loc);
3224 return ReducedExpression.Create (side_effect.Resolve (ec), expr);
3228 if (enum_type == null)
3229 return expr;
3232 // HACK: required by enum_conversion
3234 expr.Type = enum_type;
3235 return EmptyCast.Create (expr, enum_type);
3239 // Performs user-operator overloading
3241 protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r)
3243 Operator user_oper;
3244 if (oper == Operator.LogicalAnd)
3245 user_oper = Operator.BitwiseAnd;
3246 else if (oper == Operator.LogicalOr)
3247 user_oper = Operator.BitwiseOr;
3248 else
3249 user_oper = oper;
3251 string op = GetOperatorMetadataName (user_oper);
3253 MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3254 MethodGroupExpr right_operators = null;
3256 if (!TypeManager.IsEqual (r, l)) {
3257 right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3258 if (right_operators == null && left_operators == null)
3259 return null;
3260 } else if (left_operators == null) {
3261 return null;
3264 Arguments args = new Arguments (2);
3265 Argument larg = new Argument (left);
3266 args.Add (larg);
3267 Argument rarg = new Argument (right);
3268 args.Add (rarg);
3270 MethodGroupExpr union;
3273 // User-defined operator implementations always take precedence
3274 // over predefined operator implementations
3276 if (left_operators != null && right_operators != null) {
3277 if (IsPredefinedUserOperator (l, user_oper)) {
3278 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3279 if (union == null)
3280 union = left_operators;
3281 } else if (IsPredefinedUserOperator (r, user_oper)) {
3282 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3283 if (union == null)
3284 union = right_operators;
3285 } else {
3286 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3288 } else if (left_operators != null) {
3289 union = left_operators;
3290 } else {
3291 union = right_operators;
3294 union = union.OverloadResolve (ec, ref args, true, loc);
3295 if (union == null)
3296 return null;
3298 Expression oper_expr;
3300 // TODO: CreateExpressionTree is allocated every time
3301 if (user_oper != oper) {
3302 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3303 oper == Operator.LogicalAnd, loc).Resolve (ec);
3304 } else {
3305 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3308 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3309 // and not invoke user operator
3311 if ((oper & Operator.EqualityMask) != 0) {
3312 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3313 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3314 type = TypeManager.bool_type;
3315 if (left is NullLiteral || right is NullLiteral)
3316 oper_expr = ReducedExpression.Create (this, oper_expr);
3317 } else if (l != r) {
3318 var mi = union.BestCandidate;
3321 // Two System.Delegate(s) are never equal
3323 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3324 return null;
3329 left = larg.Expr;
3330 right = rarg.Expr;
3331 return oper_expr;
3334 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3336 return null;
3339 private void CheckUselessComparison (ResolveContext ec, Constant c, Type type)
3341 if (c == null || !IsTypeIntegral (type)
3342 || c is StringConstant
3343 || c is BoolConstant
3344 || c is FloatConstant
3345 || c is DoubleConstant
3346 || c is DecimalConstant
3348 return;
3350 long value = 0;
3352 if (c is ULongConstant) {
3353 ulong uvalue = ((ULongConstant) c).Value;
3354 if (uvalue > long.MaxValue) {
3355 if (type == TypeManager.byte_type ||
3356 type == TypeManager.sbyte_type ||
3357 type == TypeManager.short_type ||
3358 type == TypeManager.ushort_type ||
3359 type == TypeManager.int32_type ||
3360 type == TypeManager.uint32_type ||
3361 type == TypeManager.int64_type ||
3362 type == TypeManager.char_type)
3363 WarnUselessComparison (ec, type);
3364 return;
3366 value = (long) uvalue;
3368 else if (c is ByteConstant)
3369 value = ((ByteConstant) c).Value;
3370 else if (c is SByteConstant)
3371 value = ((SByteConstant) c).Value;
3372 else if (c is ShortConstant)
3373 value = ((ShortConstant) c).Value;
3374 else if (c is UShortConstant)
3375 value = ((UShortConstant) c).Value;
3376 else if (c is IntConstant)
3377 value = ((IntConstant) c).Value;
3378 else if (c is UIntConstant)
3379 value = ((UIntConstant) c).Value;
3380 else if (c is LongConstant)
3381 value = ((LongConstant) c).Value;
3382 else if (c is CharConstant)
3383 value = ((CharConstant)c).Value;
3385 if (value == 0)
3386 return;
3388 if (IsValueOutOfRange (value, type))
3389 WarnUselessComparison (ec, type);
3392 static bool IsValueOutOfRange (long value, Type type)
3394 if (IsTypeUnsigned (type) && value < 0)
3395 return true;
3396 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3397 type == TypeManager.byte_type && value >= 0x100 ||
3398 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3399 type == TypeManager.ushort_type && value >= 0x10000 ||
3400 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3401 type == TypeManager.uint32_type && value >= 0x100000000;
3404 static bool IsBuildInEqualityOperator (Type t)
3406 return t == TypeManager.object_type || t == TypeManager.string_type ||
3407 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3410 static bool IsPredefinedUserOperator (Type t, Operator op)
3413 // Some predefined types have user operators
3415 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3418 private static bool IsTypeIntegral (Type type)
3420 return type == TypeManager.uint64_type ||
3421 type == TypeManager.int64_type ||
3422 type == TypeManager.uint32_type ||
3423 type == TypeManager.int32_type ||
3424 type == TypeManager.ushort_type ||
3425 type == TypeManager.short_type ||
3426 type == TypeManager.sbyte_type ||
3427 type == TypeManager.byte_type ||
3428 type == TypeManager.char_type;
3431 private static bool IsTypeUnsigned (Type type)
3433 return type == TypeManager.uint64_type ||
3434 type == TypeManager.uint32_type ||
3435 type == TypeManager.ushort_type ||
3436 type == TypeManager.byte_type ||
3437 type == TypeManager.char_type;
3440 private void WarnUselessComparison (ResolveContext ec, Type type)
3442 ec.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}'",
3443 TypeManager.CSharpName (type));
3446 /// <remarks>
3447 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3448 /// context of a conditional bool expression. This function will return
3449 /// false if it is was possible to use EmitBranchable, or true if it was.
3451 /// The expression's code is generated, and we will generate a branch to `target'
3452 /// if the resulting expression value is equal to isTrue
3453 /// </remarks>
3454 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3456 ILGenerator ig = ec.ig;
3459 // This is more complicated than it looks, but its just to avoid
3460 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3461 // but on top of that we want for == and != to use a special path
3462 // if we are comparing against null
3464 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3465 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3468 // put the constant on the rhs, for simplicity
3470 if (left is Constant) {
3471 Expression swap = right;
3472 right = left;
3473 left = swap;
3476 if (((Constant) right).IsZeroInteger) {
3477 left.EmitBranchable (ec, target, my_on_true);
3478 return;
3480 if (right.Type == TypeManager.bool_type) {
3481 // right is a boolean, and it's not 'false' => it is 'true'
3482 left.EmitBranchable (ec, target, !my_on_true);
3483 return;
3486 } else if (oper == Operator.LogicalAnd) {
3488 if (on_true) {
3489 Label tests_end = ig.DefineLabel ();
3491 left.EmitBranchable (ec, tests_end, false);
3492 right.EmitBranchable (ec, target, true);
3493 ig.MarkLabel (tests_end);
3494 } else {
3496 // This optimizes code like this
3497 // if (true && i > 4)
3499 if (!(left is Constant))
3500 left.EmitBranchable (ec, target, false);
3502 if (!(right is Constant))
3503 right.EmitBranchable (ec, target, false);
3506 return;
3508 } else if (oper == Operator.LogicalOr){
3509 if (on_true) {
3510 left.EmitBranchable (ec, target, true);
3511 right.EmitBranchable (ec, target, true);
3513 } else {
3514 Label tests_end = ig.DefineLabel ();
3515 left.EmitBranchable (ec, tests_end, true);
3516 right.EmitBranchable (ec, target, false);
3517 ig.MarkLabel (tests_end);
3520 return;
3522 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3523 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3524 oper == Operator.Equality || oper == Operator.Inequality)) {
3525 base.EmitBranchable (ec, target, on_true);
3526 return;
3529 left.Emit (ec);
3530 right.Emit (ec);
3532 Type t = left.Type;
3533 bool is_float = IsFloat (t);
3534 bool is_unsigned = is_float || IsUnsigned (t);
3536 switch (oper){
3537 case Operator.Equality:
3538 if (on_true)
3539 ig.Emit (OpCodes.Beq, target);
3540 else
3541 ig.Emit (OpCodes.Bne_Un, target);
3542 break;
3544 case Operator.Inequality:
3545 if (on_true)
3546 ig.Emit (OpCodes.Bne_Un, target);
3547 else
3548 ig.Emit (OpCodes.Beq, target);
3549 break;
3551 case Operator.LessThan:
3552 if (on_true)
3553 if (is_unsigned && !is_float)
3554 ig.Emit (OpCodes.Blt_Un, target);
3555 else
3556 ig.Emit (OpCodes.Blt, target);
3557 else
3558 if (is_unsigned)
3559 ig.Emit (OpCodes.Bge_Un, target);
3560 else
3561 ig.Emit (OpCodes.Bge, target);
3562 break;
3564 case Operator.GreaterThan:
3565 if (on_true)
3566 if (is_unsigned && !is_float)
3567 ig.Emit (OpCodes.Bgt_Un, target);
3568 else
3569 ig.Emit (OpCodes.Bgt, target);
3570 else
3571 if (is_unsigned)
3572 ig.Emit (OpCodes.Ble_Un, target);
3573 else
3574 ig.Emit (OpCodes.Ble, target);
3575 break;
3577 case Operator.LessThanOrEqual:
3578 if (on_true)
3579 if (is_unsigned && !is_float)
3580 ig.Emit (OpCodes.Ble_Un, target);
3581 else
3582 ig.Emit (OpCodes.Ble, target);
3583 else
3584 if (is_unsigned)
3585 ig.Emit (OpCodes.Bgt_Un, target);
3586 else
3587 ig.Emit (OpCodes.Bgt, target);
3588 break;
3591 case Operator.GreaterThanOrEqual:
3592 if (on_true)
3593 if (is_unsigned && !is_float)
3594 ig.Emit (OpCodes.Bge_Un, target);
3595 else
3596 ig.Emit (OpCodes.Bge, target);
3597 else
3598 if (is_unsigned)
3599 ig.Emit (OpCodes.Blt_Un, target);
3600 else
3601 ig.Emit (OpCodes.Blt, target);
3602 break;
3603 default:
3604 throw new InternalErrorException (oper.ToString ());
3608 public override void Emit (EmitContext ec)
3610 EmitOperator (ec, left.Type);
3613 protected virtual void EmitOperator (EmitContext ec, Type l)
3615 ILGenerator ig = ec.ig;
3618 // Handle short-circuit operators differently
3619 // than the rest
3621 if ((oper & Operator.LogicalMask) != 0) {
3622 Label load_result = ig.DefineLabel ();
3623 Label end = ig.DefineLabel ();
3625 bool is_or = oper == Operator.LogicalOr;
3626 left.EmitBranchable (ec, load_result, is_or);
3627 right.Emit (ec);
3628 ig.Emit (OpCodes.Br_S, end);
3630 ig.MarkLabel (load_result);
3631 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3632 ig.MarkLabel (end);
3633 return;
3637 // Optimize zero-based operations which cannot be optimized at expression level
3639 if (oper == Operator.Subtraction) {
3640 var lc = left as IntegralConstant;
3641 if (lc != null && lc.IsDefaultValue) {
3642 right.Emit (ec);
3643 ig.Emit (OpCodes.Neg);
3644 return;
3648 left.Emit (ec);
3649 right.Emit (ec);
3650 EmitOperatorOpcode (ec, oper, l);
3653 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3654 // expression because that would wrap lifted binary operation
3656 if (enum_conversion != null)
3657 enum_conversion.Emit (ec);
3660 public override void EmitSideEffect (EmitContext ec)
3662 if ((oper & Operator.LogicalMask) != 0 ||
3663 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3664 base.EmitSideEffect (ec);
3665 } else {
3666 left.EmitSideEffect (ec);
3667 right.EmitSideEffect (ec);
3671 protected override void CloneTo (CloneContext clonectx, Expression t)
3673 Binary target = (Binary) t;
3675 target.left = left.Clone (clonectx);
3676 target.right = right.Clone (clonectx);
3679 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3681 Arguments binder_args = new Arguments (4);
3683 MemberAccess sle = new MemberAccess (new MemberAccess (
3684 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3686 CSharpBinderFlags flags = 0;
3687 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3688 flags = CSharpBinderFlags.CheckedContext;
3690 if ((oper & Operator.LogicalMask) != 0)
3691 flags |= CSharpBinderFlags.BinaryOperationLogical;
3693 binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
3694 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3695 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
3696 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (ec), loc)));
3698 return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
3701 public override Expression CreateExpressionTree (ResolveContext ec)
3703 return CreateExpressionTree (ec, null);
3706 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3708 string method_name;
3709 bool lift_arg = false;
3711 switch (oper) {
3712 case Operator.Addition:
3713 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3714 method_name = "AddChecked";
3715 else
3716 method_name = "Add";
3717 break;
3718 case Operator.BitwiseAnd:
3719 method_name = "And";
3720 break;
3721 case Operator.BitwiseOr:
3722 method_name = "Or";
3723 break;
3724 case Operator.Division:
3725 method_name = "Divide";
3726 break;
3727 case Operator.Equality:
3728 method_name = "Equal";
3729 lift_arg = true;
3730 break;
3731 case Operator.ExclusiveOr:
3732 method_name = "ExclusiveOr";
3733 break;
3734 case Operator.GreaterThan:
3735 method_name = "GreaterThan";
3736 lift_arg = true;
3737 break;
3738 case Operator.GreaterThanOrEqual:
3739 method_name = "GreaterThanOrEqual";
3740 lift_arg = true;
3741 break;
3742 case Operator.Inequality:
3743 method_name = "NotEqual";
3744 lift_arg = true;
3745 break;
3746 case Operator.LeftShift:
3747 method_name = "LeftShift";
3748 break;
3749 case Operator.LessThan:
3750 method_name = "LessThan";
3751 lift_arg = true;
3752 break;
3753 case Operator.LessThanOrEqual:
3754 method_name = "LessThanOrEqual";
3755 lift_arg = true;
3756 break;
3757 case Operator.LogicalAnd:
3758 method_name = "AndAlso";
3759 break;
3760 case Operator.LogicalOr:
3761 method_name = "OrElse";
3762 break;
3763 case Operator.Modulus:
3764 method_name = "Modulo";
3765 break;
3766 case Operator.Multiply:
3767 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3768 method_name = "MultiplyChecked";
3769 else
3770 method_name = "Multiply";
3771 break;
3772 case Operator.RightShift:
3773 method_name = "RightShift";
3774 break;
3775 case Operator.Subtraction:
3776 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3777 method_name = "SubtractChecked";
3778 else
3779 method_name = "Subtract";
3780 break;
3782 default:
3783 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3786 Arguments args = new Arguments (2);
3787 args.Add (new Argument (left.CreateExpressionTree (ec)));
3788 args.Add (new Argument (right.CreateExpressionTree (ec)));
3789 if (method != null) {
3790 if (lift_arg)
3791 args.Add (new Argument (new BoolConstant (false, loc)));
3793 args.Add (new Argument (method.CreateExpressionTree (ec)));
3796 return CreateExpressionFactoryCall (ec, method_name, args);
3801 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3802 // b, c, d... may be strings or objects.
3804 public class StringConcat : Expression {
3805 Arguments arguments;
3807 public StringConcat (Expression left, Expression right, Location loc)
3809 this.loc = loc;
3810 type = TypeManager.string_type;
3811 eclass = ExprClass.Value;
3813 arguments = new Arguments (2);
3816 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
3818 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
3819 throw new ArgumentException ();
3821 var s = new StringConcat (left, right, loc);
3822 s.Append (rc, left);
3823 s.Append (rc, right);
3824 return s;
3827 public override Expression CreateExpressionTree (ResolveContext ec)
3829 Argument arg = arguments [0];
3830 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3834 // Creates nested calls tree from an array of arguments used for IL emit
3836 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3838 Arguments concat_args = new Arguments (2);
3839 Arguments add_args = new Arguments (3);
3841 concat_args.Add (left);
3842 add_args.Add (new Argument (left_etree));
3844 concat_args.Add (arguments [pos]);
3845 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3847 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3848 if (method == null)
3849 return null;
3851 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3852 if (method == null)
3853 return null;
3855 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3857 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3858 if (++pos == arguments.Count)
3859 return expr;
3861 left = new Argument (new EmptyExpression (method.BestCandidate.ReturnType));
3862 return CreateExpressionAddCall (ec, left, expr, pos);
3865 protected override Expression DoResolve (ResolveContext ec)
3867 return this;
3870 void Append (ResolveContext rc, Expression operand)
3873 // Constant folding
3875 StringConstant sc = operand as StringConstant;
3876 if (sc != null) {
3877 if (arguments.Count != 0) {
3878 Argument last_argument = arguments [arguments.Count - 1];
3879 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3880 if (last_expr_constant != null) {
3881 last_argument.Expr = new StringConstant (
3882 last_expr_constant.Value + sc.Value, sc.Location).Resolve (rc);
3883 return;
3886 } else {
3888 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3890 StringConcat concat_oper = operand as StringConcat;
3891 if (concat_oper != null) {
3892 arguments.AddRange (concat_oper.arguments);
3893 return;
3897 arguments.Add (new Argument (operand));
3900 Expression CreateConcatMemberExpression ()
3902 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3905 public override void Emit (EmitContext ec)
3907 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3908 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3909 if (concat != null)
3910 concat.Emit (ec);
3913 public override SLE.Expression MakeExpression (BuilderContext ctx)
3915 if (arguments.Count != 2)
3916 throw new NotImplementedException ("arguments.Count != 2");
3918 var concat = TypeManager.string_type.GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3919 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3922 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3924 arguments.MutateHoistedGenericType (storey);
3929 // User-defined conditional logical operator
3931 public class ConditionalLogicalOperator : UserOperatorCall {
3932 readonly bool is_and;
3933 Expression oper;
3935 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3936 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3937 : base (oper_method, arguments, expr_tree, loc)
3939 this.is_and = is_and;
3940 eclass = ExprClass.Unresolved;
3943 protected override Expression DoResolve (ResolveContext ec)
3945 var method = mg.BestCandidate;
3946 type = TypeManager.TypeToCoreType (method.ReturnType);
3947 AParametersCollection pd = method.Parameters;
3948 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3949 ec.Report.Error (217, loc,
3950 "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",
3951 TypeManager.CSharpSignature (method.MetaInfo));
3952 return null;
3955 Expression left_dup = new EmptyExpression (type);
3956 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3957 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3958 if (op_true == null || op_false == null) {
3959 ec.Report.Error (218, loc,
3960 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3961 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method.MetaInfo));
3962 return null;
3965 oper = is_and ? op_false : op_true;
3966 eclass = ExprClass.Value;
3967 return this;
3970 public override void Emit (EmitContext ec)
3972 ILGenerator ig = ec.ig;
3973 Label end_target = ig.DefineLabel ();
3976 // Emit and duplicate left argument
3978 arguments [0].Expr.Emit (ec);
3979 ig.Emit (OpCodes.Dup);
3980 arguments.RemoveAt (0);
3982 oper.EmitBranchable (ec, end_target, true);
3983 base.Emit (ec);
3984 ig.MarkLabel (end_target);
3988 public class PointerArithmetic : Expression {
3989 Expression left, right;
3990 Binary.Operator op;
3993 // We assume that `l' is always a pointer
3995 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3997 type = t;
3998 this.loc = loc;
3999 left = l;
4000 right = r;
4001 this.op = op;
4004 public override Expression CreateExpressionTree (ResolveContext ec)
4006 Error_PointerInsideExpressionTree (ec);
4007 return null;
4010 protected override Expression DoResolve (ResolveContext ec)
4012 eclass = ExprClass.Variable;
4014 if (left.Type == TypeManager.void_ptr_type) {
4015 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
4016 return null;
4019 return this;
4022 public override void Emit (EmitContext ec)
4024 Type op_type = left.Type;
4025 ILGenerator ig = ec.ig;
4027 // It must be either array or fixed buffer
4028 Type element;
4029 if (TypeManager.HasElementType (op_type)) {
4030 element = TypeManager.GetElementType (op_type);
4031 } else {
4032 FieldExpr fe = left as FieldExpr;
4033 if (fe != null)
4034 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
4035 else
4036 element = op_type;
4039 int size = GetTypeSize (element);
4040 Type rtype = right.Type;
4042 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4044 // handle (pointer - pointer)
4046 left.Emit (ec);
4047 right.Emit (ec);
4048 ig.Emit (OpCodes.Sub);
4050 if (size != 1){
4051 if (size == 0)
4052 ig.Emit (OpCodes.Sizeof, element);
4053 else
4054 IntLiteral.EmitInt (ig, size);
4055 ig.Emit (OpCodes.Div);
4057 ig.Emit (OpCodes.Conv_I8);
4058 } else {
4060 // handle + and - on (pointer op int)
4062 Constant left_const = left as Constant;
4063 if (left_const != null) {
4065 // Optimize ((T*)null) pointer operations
4067 if (left_const.IsDefaultValue) {
4068 left = EmptyExpression.Null;
4069 } else {
4070 left_const = null;
4074 left.Emit (ec);
4076 var right_const = right as Constant;
4077 if (right_const != null) {
4079 // Optimize 0-based arithmetic
4081 if (right_const.IsDefaultValue)
4082 return;
4084 if (size != 0)
4085 right = new IntConstant (size, right.Location);
4086 else
4087 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
4089 // TODO: Should be the checks resolve context sensitive?
4090 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
4091 right = new Binary (Binary.Operator.Multiply, right, right_const, loc).Resolve (rc);
4092 if (right == null)
4093 return;
4096 right.Emit (ec);
4097 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4098 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4099 ig.Emit (OpCodes.Conv_I);
4100 } else if (rtype == TypeManager.uint32_type) {
4101 ig.Emit (OpCodes.Conv_U);
4104 if (right_const == null && size != 1){
4105 if (size == 0)
4106 ig.Emit (OpCodes.Sizeof, element);
4107 else
4108 IntLiteral.EmitInt (ig, size);
4109 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4110 ig.Emit (OpCodes.Conv_I8);
4112 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4115 if (left_const == null) {
4116 if (rtype == TypeManager.int64_type)
4117 ig.Emit (OpCodes.Conv_I);
4118 else if (rtype == TypeManager.uint64_type)
4119 ig.Emit (OpCodes.Conv_U);
4121 Binary.EmitOperatorOpcode (ec, op, op_type);
4128 // A boolean-expression is an expression that yields a result
4129 // of type bool
4131 public class BooleanExpression : ShimExpression
4133 public BooleanExpression (Expression expr)
4134 : base (expr)
4136 this.loc = expr.Location;
4139 public override Expression CreateExpressionTree (ResolveContext ec)
4141 // TODO: We should emit IsTrue (v4) instead of direct user operator
4142 // call but that would break csc compatibility
4143 return base.CreateExpressionTree (ec);
4146 protected override Expression DoResolve (ResolveContext ec)
4148 // A boolean-expression is required to be of a type
4149 // that can be implicitly converted to bool or of
4150 // a type that implements operator true
4152 expr = expr.Resolve (ec);
4153 if (expr == null)
4154 return null;
4156 Assign ass = expr as Assign;
4157 if (ass != null && ass.Source is Constant) {
4158 ec.Report.Warning (665, 3, loc,
4159 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4162 if (expr.Type == TypeManager.bool_type)
4163 return expr;
4165 if (TypeManager.IsDynamicType (expr.Type)) {
4166 Arguments args = new Arguments (1);
4167 args.Add (new Argument (expr));
4168 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4171 type = TypeManager.bool_type;
4172 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4173 if (converted != null)
4174 return converted;
4177 // If no implicit conversion to bool exists, try using `operator true'
4179 converted = GetOperatorTrue (ec, expr, loc);
4180 if (converted == null) {
4181 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4182 return null;
4185 return converted;
4189 /// <summary>
4190 /// Implements the ternary conditional operator (?:)
4191 /// </summary>
4192 public class Conditional : Expression {
4193 Expression expr, true_expr, false_expr;
4195 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
4197 this.expr = expr;
4198 this.true_expr = true_expr;
4199 this.false_expr = false_expr;
4200 this.loc = expr.Location;
4203 public Expression Expr {
4204 get {
4205 return expr;
4209 public Expression TrueExpr {
4210 get {
4211 return true_expr;
4215 public Expression FalseExpr {
4216 get {
4217 return false_expr;
4221 public override Expression CreateExpressionTree (ResolveContext ec)
4223 Arguments args = new Arguments (3);
4224 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4225 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4226 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4227 return CreateExpressionFactoryCall (ec, "Condition", args);
4230 protected override Expression DoResolve (ResolveContext ec)
4232 expr = expr.Resolve (ec);
4233 true_expr = true_expr.Resolve (ec);
4234 false_expr = false_expr.Resolve (ec);
4236 if (true_expr == null || false_expr == null || expr == null)
4237 return null;
4239 eclass = ExprClass.Value;
4240 Type true_type = true_expr.Type;
4241 Type false_type = false_expr.Type;
4242 type = true_type;
4245 // First, if an implicit conversion exists from true_expr
4246 // to false_expr, then the result type is of type false_expr.Type
4248 if (!TypeManager.IsEqual (true_type, false_type)) {
4249 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4250 if (conv != null) {
4252 // Check if both can convert implicitly to each other's type
4254 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4255 ec.Report.Error (172, true_expr.Location,
4256 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
4257 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4258 return null;
4260 type = false_type;
4261 true_expr = conv;
4262 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4263 false_expr = conv;
4264 } else {
4265 ec.Report.Error (173, true_expr.Location,
4266 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4267 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4268 return null;
4272 // Dead code optimalization
4273 Constant c = expr as Constant;
4274 if (c != null){
4275 bool is_false = c.IsDefaultValue;
4276 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4277 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4280 return this;
4283 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4285 expr.MutateHoistedGenericType (storey);
4286 true_expr.MutateHoistedGenericType (storey);
4287 false_expr.MutateHoistedGenericType (storey);
4288 type = storey.MutateType (type);
4291 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4293 return null;
4296 public override void Emit (EmitContext ec)
4298 ILGenerator ig = ec.ig;
4299 Label false_target = ig.DefineLabel ();
4300 Label end_target = ig.DefineLabel ();
4302 expr.EmitBranchable (ec, false_target, false);
4303 true_expr.Emit (ec);
4305 if (type.IsInterface) {
4306 LocalBuilder temp = ec.GetTemporaryLocal (type);
4307 ig.Emit (OpCodes.Stloc, temp);
4308 ig.Emit (OpCodes.Ldloc, temp);
4309 ec.FreeTemporaryLocal (temp, type);
4312 ig.Emit (OpCodes.Br, end_target);
4313 ig.MarkLabel (false_target);
4314 false_expr.Emit (ec);
4315 ig.MarkLabel (end_target);
4318 protected override void CloneTo (CloneContext clonectx, Expression t)
4320 Conditional target = (Conditional) t;
4322 target.expr = expr.Clone (clonectx);
4323 target.true_expr = true_expr.Clone (clonectx);
4324 target.false_expr = false_expr.Clone (clonectx);
4328 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4329 LocalTemporary temp;
4331 #region Abstract
4332 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4333 public abstract bool IsFixed { get; }
4334 public abstract bool IsRef { get; }
4335 public abstract string Name { get; }
4336 public abstract void SetHasAddressTaken ();
4339 // Variable IL data, it has to be protected to encapsulate hoisted variables
4341 protected abstract ILocalVariable Variable { get; }
4344 // Variable flow-analysis data
4346 public abstract VariableInfo VariableInfo { get; }
4347 #endregion
4349 public virtual void AddressOf (EmitContext ec, AddressOp mode)
4351 HoistedVariable hv = GetHoistedVariable (ec);
4352 if (hv != null) {
4353 hv.AddressOf (ec, mode);
4354 return;
4357 Variable.EmitAddressOf (ec);
4360 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4362 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4365 public HoistedVariable GetHoistedVariable (EmitContext ec)
4367 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4370 public override string GetSignatureForError ()
4372 return Name;
4375 public override void Emit (EmitContext ec)
4377 Emit (ec, false);
4380 public override void EmitSideEffect (EmitContext ec)
4382 // do nothing
4386 // This method is used by parameters that are references, that are
4387 // being passed as references: we only want to pass the pointer (that
4388 // is already stored in the parameter, not the address of the pointer,
4389 // and not the value of the variable).
4391 public void EmitLoad (EmitContext ec)
4393 Variable.Emit (ec);
4396 public void Emit (EmitContext ec, bool leave_copy)
4398 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4400 HoistedVariable hv = GetHoistedVariable (ec);
4401 if (hv != null) {
4402 hv.Emit (ec, leave_copy);
4403 return;
4406 EmitLoad (ec);
4408 if (IsRef) {
4410 // If we are a reference, we loaded on the stack a pointer
4411 // Now lets load the real value
4413 LoadFromPtr (ec.ig, type);
4416 if (leave_copy) {
4417 ec.ig.Emit (OpCodes.Dup);
4419 if (IsRef) {
4420 temp = new LocalTemporary (Type);
4421 temp.Store (ec);
4426 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4427 bool prepare_for_load)
4429 HoistedVariable hv = GetHoistedVariable (ec);
4430 if (hv != null) {
4431 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4432 return;
4435 New n_source = source as New;
4436 if (n_source != null) {
4437 if (!n_source.Emit (ec, this)) {
4438 if (leave_copy)
4439 EmitLoad (ec);
4440 return;
4442 } else {
4443 if (IsRef)
4444 EmitLoad (ec);
4446 source.Emit (ec);
4449 if (leave_copy) {
4450 ec.ig.Emit (OpCodes.Dup);
4451 if (IsRef) {
4452 temp = new LocalTemporary (Type);
4453 temp.Store (ec);
4457 if (IsRef)
4458 StoreFromPtr (ec.ig, type);
4459 else
4460 Variable.EmitAssign (ec);
4462 if (temp != null) {
4463 temp.Emit (ec);
4464 temp.Release (ec);
4468 public bool IsHoisted {
4469 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4472 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4474 type = storey.MutateType (type);
4478 /// <summary>
4479 /// Local variables
4480 /// </summary>
4481 public class LocalVariableReference : VariableReference {
4482 readonly string name;
4483 public Block Block;
4484 public LocalInfo local_info;
4485 bool is_readonly;
4487 public LocalVariableReference (Block block, string name, Location l)
4489 Block = block;
4490 this.name = name;
4491 loc = l;
4495 // Setting `is_readonly' to false will allow you to create a writable
4496 // reference to a read-only variable. This is used by foreach and using.
4498 public LocalVariableReference (Block block, string name, Location l,
4499 LocalInfo local_info, bool is_readonly)
4500 : this (block, name, l)
4502 this.local_info = local_info;
4503 this.is_readonly = is_readonly;
4506 public override VariableInfo VariableInfo {
4507 get { return local_info.VariableInfo; }
4510 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4512 return local_info.HoistedVariant;
4516 // A local variable is always fixed
4518 public override bool IsFixed {
4519 get { return true; }
4522 public override bool IsRef {
4523 get { return false; }
4526 public bool IsReadOnly {
4527 get { return is_readonly; }
4530 public override string Name {
4531 get { return name; }
4534 public bool VerifyAssigned (ResolveContext ec)
4536 VariableInfo variable_info = local_info.VariableInfo;
4537 return variable_info == null || variable_info.IsAssigned (ec, loc);
4540 void ResolveLocalInfo ()
4542 if (local_info == null) {
4543 local_info = Block.GetLocalInfo (Name);
4544 type = local_info.VariableType;
4545 is_readonly = local_info.ReadOnly;
4549 public override void SetHasAddressTaken ()
4551 local_info.AddressTaken = true;
4554 public override Expression CreateExpressionTree (ResolveContext ec)
4556 HoistedVariable hv = GetHoistedVariable (ec);
4557 if (hv != null)
4558 return hv.CreateExpressionTree ();
4560 Arguments arg = new Arguments (1);
4561 arg.Add (new Argument (this));
4562 return CreateExpressionFactoryCall (ec, "Constant", arg);
4565 Expression DoResolveBase (ResolveContext ec)
4567 Expression e = Block.GetConstantExpression (Name);
4568 if (e != null)
4569 return e.Resolve (ec);
4571 VerifyAssigned (ec);
4574 // If we are referencing a variable from the external block
4575 // flag it for capturing
4577 if (ec.MustCaptureVariable (local_info)) {
4578 if (local_info.AddressTaken)
4579 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4581 if (ec.IsVariableCapturingRequired) {
4582 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4583 storey.CaptureLocalVariable (ec, local_info);
4587 eclass = ExprClass.Variable;
4588 type = local_info.VariableType;
4589 return this;
4592 protected override Expression DoResolve (ResolveContext ec)
4594 ResolveLocalInfo ();
4595 local_info.Used = true;
4597 if (type == null && local_info.Type is VarExpr) {
4598 local_info.VariableType = TypeManager.object_type;
4599 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4600 return null;
4603 return DoResolveBase (ec);
4606 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4608 ResolveLocalInfo ();
4610 // is out param
4611 if (right_side == EmptyExpression.OutAccess.Instance)
4612 local_info.Used = true;
4614 // Infer implicitly typed local variable
4615 if (type == null) {
4616 VarExpr ve = local_info.Type as VarExpr;
4617 if (ve != null) {
4618 if (!ve.InferType (ec, right_side))
4619 return null;
4620 type = local_info.VariableType = ve.Type;
4624 if (is_readonly) {
4625 int code;
4626 string msg;
4627 if (right_side == EmptyExpression.OutAccess.Instance) {
4628 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4629 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4630 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4631 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4632 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4633 } else if (right_side == EmptyExpression.UnaryAddress) {
4634 code = 459; msg = "Cannot take the address of {1} `{0}'";
4635 } else {
4636 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4638 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4639 } else if (VariableInfo != null) {
4640 VariableInfo.SetAssigned (ec);
4643 return DoResolveBase (ec);
4646 public override int GetHashCode ()
4648 return Name.GetHashCode ();
4651 public override bool Equals (object obj)
4653 LocalVariableReference lvr = obj as LocalVariableReference;
4654 if (lvr == null)
4655 return false;
4657 return Name == lvr.Name && Block == lvr.Block;
4660 protected override ILocalVariable Variable {
4661 get { return local_info; }
4664 public override string ToString ()
4666 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4669 protected override void CloneTo (CloneContext clonectx, Expression t)
4671 LocalVariableReference target = (LocalVariableReference) t;
4673 target.Block = clonectx.LookupBlock (Block);
4674 if (local_info != null)
4675 target.local_info = clonectx.LookupVariable (local_info);
4679 /// <summary>
4680 /// This represents a reference to a parameter in the intermediate
4681 /// representation.
4682 /// </summary>
4683 public class ParameterReference : VariableReference {
4684 readonly ToplevelParameterInfo pi;
4686 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4688 this.pi = pi;
4689 this.loc = loc;
4692 public override bool IsRef {
4693 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4696 bool HasOutModifier {
4697 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4700 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4702 return pi.Parameter.HoistedVariant;
4706 // A ref or out parameter is classified as a moveable variable, even
4707 // if the argument given for the parameter is a fixed variable
4709 public override bool IsFixed {
4710 get { return !IsRef; }
4713 public override string Name {
4714 get { return Parameter.Name; }
4717 public Parameter Parameter {
4718 get { return pi.Parameter; }
4721 public override VariableInfo VariableInfo {
4722 get { return pi.VariableInfo; }
4725 protected override ILocalVariable Variable {
4726 get { return Parameter; }
4729 public bool IsAssigned (ResolveContext ec, Location loc)
4731 // HACK: Variables are not captured in probing mode
4732 if (ec.IsInProbingMode)
4733 return true;
4735 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4736 return true;
4738 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4739 return false;
4742 public override void SetHasAddressTaken ()
4744 Parameter.HasAddressTaken = true;
4747 void SetAssigned (ResolveContext ec)
4749 if (HasOutModifier && ec.DoFlowAnalysis)
4750 ec.CurrentBranching.SetAssigned (VariableInfo);
4753 bool DoResolveBase (ResolveContext ec)
4755 type = pi.ParameterType;
4756 eclass = ExprClass.Variable;
4758 AnonymousExpression am = ec.CurrentAnonymousMethod;
4759 if (am == null)
4760 return true;
4762 Block b = ec.CurrentBlock;
4763 while (b != null) {
4764 b = b.Toplevel;
4765 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4766 for (int i = 0; i < p.Length; ++i) {
4767 if (p [i] != Parameter)
4768 continue;
4771 // Don't capture local parameters
4773 if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
4774 return true;
4776 if (IsRef) {
4777 ec.Report.Error (1628, loc,
4778 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4779 Name, am.ContainerType);
4782 if (pi.Parameter.HasAddressTaken)
4783 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4785 if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
4786 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4787 storey.CaptureParameter (ec, this);
4790 return true;
4793 b = b.Parent;
4796 return true;
4799 public override int GetHashCode ()
4801 return Name.GetHashCode ();
4804 public override bool Equals (object obj)
4806 ParameterReference pr = obj as ParameterReference;
4807 if (pr == null)
4808 return false;
4810 return Name == pr.Name;
4813 public override void AddressOf (EmitContext ec, AddressOp mode)
4816 // ParameterReferences might already be a reference
4818 if (IsRef) {
4819 EmitLoad (ec);
4820 return;
4823 base.AddressOf (ec, mode);
4826 protected override void CloneTo (CloneContext clonectx, Expression target)
4828 // Nothing to clone
4831 public override Expression CreateExpressionTree (ResolveContext ec)
4833 HoistedVariable hv = GetHoistedVariable (ec);
4834 if (hv != null)
4835 return hv.CreateExpressionTree ();
4837 return Parameter.ExpressionTreeVariableReference ();
4841 // Notice that for ref/out parameters, the type exposed is not the
4842 // same type exposed externally.
4844 // for "ref int a":
4845 // externally we expose "int&"
4846 // here we expose "int".
4848 // We record this in "is_ref". This means that the type system can treat
4849 // the type as it is expected, but when we generate the code, we generate
4850 // the alternate kind of code.
4852 protected override Expression DoResolve (ResolveContext ec)
4854 if (!DoResolveBase (ec))
4855 return null;
4857 // HACK: Variables are not captured in probing mode
4858 if (ec.IsInProbingMode)
4859 return this;
4861 if (HasOutModifier && ec.DoFlowAnalysis &&
4862 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4863 return null;
4865 return this;
4868 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4870 if (!DoResolveBase (ec))
4871 return null;
4873 // HACK: parameters are not captured when probing is on
4874 if (!ec.IsInProbingMode)
4875 SetAssigned (ec);
4877 return this;
4880 static public void EmitLdArg (ILGenerator ig, int x)
4882 switch (x) {
4883 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4884 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4885 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4886 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4887 default:
4888 if (x > byte.MaxValue)
4889 ig.Emit (OpCodes.Ldarg, x);
4890 else
4891 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4892 break;
4897 /// <summary>
4898 /// Invocation of methods or delegates.
4899 /// </summary>
4900 public class Invocation : ExpressionStatement
4902 protected Arguments arguments;
4903 protected Expression expr;
4904 protected MethodGroupExpr mg;
4905 bool arguments_resolved;
4908 // arguments is an ArrayList, but we do not want to typecast,
4909 // as it might be null.
4911 public Invocation (Expression expr, Arguments arguments)
4913 SimpleName sn = expr as SimpleName;
4914 if (sn != null)
4915 this.expr = sn.GetMethodGroup ();
4916 else
4917 this.expr = expr;
4919 this.arguments = arguments;
4920 if (expr != null)
4921 loc = expr.Location;
4924 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4925 : this (expr, arguments)
4927 this.arguments_resolved = arguments_resolved;
4930 public override Expression CreateExpressionTree (ResolveContext ec)
4932 Expression instance = mg.IsInstance ?
4933 mg.InstanceExpression.CreateExpressionTree (ec) :
4934 new NullLiteral (loc);
4936 var args = Arguments.CreateForExpressionTree (ec, arguments,
4937 instance,
4938 mg.CreateExpressionTree (ec));
4940 if (mg.IsBase)
4941 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4943 return CreateExpressionFactoryCall (ec, "Call", args);
4946 protected override Expression DoResolve (ResolveContext ec)
4948 Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4949 if (member_expr == null)
4950 return null;
4953 // Next, evaluate all the expressions in the argument list
4955 bool dynamic_arg = false;
4956 if (arguments != null && !arguments_resolved)
4957 arguments.Resolve (ec, out dynamic_arg);
4959 Type expr_type = member_expr.Type;
4960 mg = member_expr as MethodGroupExpr;
4962 bool dynamic_member = TypeManager.IsDynamicType (expr_type);
4964 if (!dynamic_member) {
4965 Expression invoke = null;
4967 if (mg == null) {
4968 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
4969 invoke = new DelegateInvocation (member_expr, arguments, loc);
4970 invoke = invoke.Resolve (ec);
4971 if (invoke == null || !dynamic_arg)
4972 return invoke;
4973 } else {
4974 MemberExpr me = member_expr as MemberExpr;
4975 if (me == null) {
4976 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
4977 return null;
4980 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
4981 if (mg == null) {
4982 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4983 member_expr.GetSignatureForError ());
4984 return null;
4987 ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
4991 if (invoke == null) {
4992 mg = DoResolveOverload (ec);
4993 if (mg == null)
4994 return null;
4998 if (dynamic_arg || dynamic_member)
4999 return DoResolveDynamic (ec, member_expr);
5001 var method = mg.BestCandidate;
5002 if (method != null) {
5003 type = TypeManager.TypeToCoreType (method.ReturnType);
5005 // TODO: this is a copy of mg.ResolveMemberAccess method
5006 Expression iexpr = mg.InstanceExpression;
5007 if (method.IsStatic) {
5008 if (iexpr == null ||
5009 iexpr is This || iexpr is EmptyExpression ||
5010 mg.IdenticalTypeName) {
5011 mg.InstanceExpression = null;
5012 } else {
5013 MemberExpr.error176 (ec, loc, mg.GetSignatureForError ());
5014 return null;
5016 } else {
5017 if (iexpr == null || iexpr == EmptyExpression.Null) {
5018 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
5024 // Only base will allow this invocation to happen.
5026 if (mg.IsBase && method.IsAbstract){
5027 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
5028 return null;
5031 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5032 if (mg.IsBase)
5033 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5034 else
5035 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5036 return null;
5039 IsSpecialMethodInvocation (ec, method, loc);
5041 if (mg.InstanceExpression != null)
5042 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
5044 eclass = ExprClass.Value;
5045 return this;
5048 Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5050 Arguments args;
5051 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5052 if (dmb != null) {
5053 args = dmb.Arguments;
5054 if (arguments != null)
5055 args.AddRange (arguments);
5056 } else if (mg == null) {
5057 if (arguments == null)
5058 args = new Arguments (1);
5059 else
5060 args = arguments;
5062 args.Insert (0, new Argument (memberExpr));
5063 this.expr = null;
5064 } else {
5065 if (mg.IsBase) {
5066 ec.Report.Error (1971, loc,
5067 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5068 mg.Name);
5069 return null;
5072 args = arguments;
5074 if (mg.IsStatic != mg.IsInstance) {
5075 if (args == null)
5076 args = new Arguments (1);
5078 if (mg.IsStatic) {
5079 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5080 } else {
5081 MemberAccess ma = expr as MemberAccess;
5082 if (ma != null)
5083 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
5084 else
5085 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5090 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5093 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5095 return mg.OverloadResolve (ec, ref arguments, false, loc);
5098 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
5100 if (!TypeManager.IsSpecialMethod (method.MetaInfo))
5101 return false;
5103 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
5104 return false;
5106 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
5107 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5108 TypeManager.CSharpSignature (method.MetaInfo, true));
5110 return true;
5113 static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
5115 AParametersCollection pd = mb.Parameters;
5117 Argument a = arguments [pd.Count - 1];
5118 Arglist list = (Arglist) a.Expr;
5120 return list.ArgumentTypes;
5123 /// <summary>
5124 /// This checks the ConditionalAttribute on the method
5125 /// </summary>
5126 public static bool IsMethodExcluded (MethodSpec method, Location loc)
5128 if (method.IsConstructor)
5129 return false;
5131 var mb = TypeManager.DropGenericMethodArguments (method.MetaInfo);
5132 if (TypeManager.IsBeingCompiled (mb)) {
5133 IMethodData md = TypeManager.GetMethod (mb);
5134 if (md != null)
5135 return md.IsExcluded ();
5137 // For some methods (generated by delegate class) GetMethod returns null
5138 // because they are not included in builder_to_method table
5139 return false;
5142 return AttributeTester.IsConditionalMethodExcluded (mb, loc);
5145 /// <remarks>
5146 /// is_base tells whether we want to force the use of the `call'
5147 /// opcode instead of using callvirt. Call is required to call
5148 /// a specific method, while callvirt will always use the most
5149 /// recent method in the vtable.
5151 /// is_static tells whether this is an invocation on a static method
5153 /// instance_expr is an expression that represents the instance
5154 /// it must be non-null if is_static is false.
5156 /// method is the method to invoke.
5158 /// Arguments is the list of arguments to pass to the method or constructor.
5159 /// </remarks>
5160 public static void EmitCall (EmitContext ec, bool is_base,
5161 Expression instance_expr,
5162 MethodSpec method, Arguments Arguments, Location loc)
5164 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5167 // `dup_args' leaves an extra copy of the arguments on the stack
5168 // `omit_args' does not leave any arguments at all.
5169 // So, basically, you could make one call with `dup_args' set to true,
5170 // and then another with `omit_args' set to true, and the two calls
5171 // would have the same set of arguments. However, each argument would
5172 // only have been evaluated once.
5173 public static void EmitCall (EmitContext ec, bool is_base,
5174 Expression instance_expr,
5175 MethodSpec method, Arguments Arguments, Location loc,
5176 bool dup_args, bool omit_args)
5178 ILGenerator ig = ec.ig;
5179 bool struct_call = false;
5180 bool this_call = false;
5181 LocalTemporary this_arg = null;
5183 Type decl_type = method.DeclaringType;
5185 if (IsMethodExcluded (method, loc))
5186 return;
5188 bool is_static = method.IsStatic;
5189 if (!is_static){
5190 this_call = instance_expr is This;
5191 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5192 struct_call = true;
5195 // If this is ourselves, push "this"
5197 if (!omit_args) {
5198 Type t = null;
5199 Type iexpr_type = instance_expr.Type;
5202 // Push the instance expression
5204 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5206 // Special case: calls to a function declared in a
5207 // reference-type with a value-type argument need
5208 // to have their value boxed.
5209 if (TypeManager.IsStruct (decl_type) ||
5210 TypeManager.IsGenericParameter (iexpr_type)) {
5212 // If the expression implements IMemoryLocation, then
5213 // we can optimize and use AddressOf on the
5214 // return.
5216 // If not we have to use some temporary storage for
5217 // it.
5218 if (instance_expr is IMemoryLocation) {
5219 ((IMemoryLocation)instance_expr).
5220 AddressOf (ec, AddressOp.LoadStore);
5221 } else {
5222 LocalTemporary temp = new LocalTemporary (iexpr_type);
5223 instance_expr.Emit (ec);
5224 temp.Store (ec);
5225 temp.AddressOf (ec, AddressOp.Load);
5228 // avoid the overhead of doing this all the time.
5229 if (dup_args)
5230 t = TypeManager.GetReferenceType (iexpr_type);
5231 } else {
5232 instance_expr.Emit (ec);
5234 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5235 // to help JIT to produce better code
5236 ig.Emit (OpCodes.Box, instance_expr.Type);
5237 t = TypeManager.object_type;
5239 } else {
5240 instance_expr.Emit (ec);
5241 t = instance_expr.Type;
5244 if (dup_args) {
5245 ig.Emit (OpCodes.Dup);
5246 if (Arguments != null && Arguments.Count != 0) {
5247 this_arg = new LocalTemporary (t);
5248 this_arg.Store (ec);
5254 if (!omit_args && Arguments != null)
5255 Arguments.Emit (ec, dup_args, this_arg);
5257 OpCode call_op;
5258 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5259 call_op = OpCodes.Call;
5260 } else {
5261 call_op = OpCodes.Callvirt;
5263 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5264 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5267 if ((method.MetaInfo.CallingConvention & CallingConventions.VarArgs) != 0) {
5268 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5269 ig.EmitCall (call_op, (MethodInfo) method.MetaInfo, varargs_types);
5270 return;
5274 // If you have:
5275 // this.DoFoo ();
5276 // and DoFoo is not virtual, you can omit the callvirt,
5277 // because you don't need the null checking behavior.
5279 if (method.IsConstructor)
5280 ig.Emit (call_op, (ConstructorInfo) method.MetaInfo);
5281 else
5282 ig.Emit (call_op, (MethodInfo) method.MetaInfo);
5285 public override void Emit (EmitContext ec)
5287 mg.EmitCall (ec, arguments);
5290 public override void EmitStatement (EmitContext ec)
5292 Emit (ec);
5295 // Pop the return value if there is one
5297 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5298 ec.ig.Emit (OpCodes.Pop);
5301 protected override void CloneTo (CloneContext clonectx, Expression t)
5303 Invocation target = (Invocation) t;
5305 if (arguments != null)
5306 target.arguments = arguments.Clone (clonectx);
5308 target.expr = expr.Clone (clonectx);
5311 public override SLE.Expression MakeExpression (BuilderContext ctx)
5313 return MakeExpression (ctx, mg.InstanceExpression, (MethodSpec) mg, arguments);
5316 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
5318 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5319 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.MetaInfo, Arguments.MakeExpression (args, ctx));
5322 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5324 mg.MutateHoistedGenericType (storey);
5325 type = storey.MutateType (type);
5326 if (arguments != null) {
5327 arguments.MutateHoistedGenericType (storey);
5332 /// <summary>
5333 /// Implements the new expression
5334 /// </summary>
5335 public class New : ExpressionStatement, IMemoryLocation {
5336 protected Arguments Arguments;
5339 // During bootstrap, it contains the RequestedType,
5340 // but if `type' is not null, it *might* contain a NewDelegate
5341 // (because of field multi-initialization)
5343 protected Expression RequestedType;
5345 protected MethodGroupExpr method;
5347 bool is_type_parameter;
5349 public New (Expression requested_type, Arguments arguments, Location l)
5351 RequestedType = requested_type;
5352 Arguments = arguments;
5353 loc = l;
5356 /// <summary>
5357 /// Converts complex core type syntax like 'new int ()' to simple constant
5358 /// </summary>
5359 public static Constant Constantify (Type t)
5361 if (t == TypeManager.int32_type)
5362 return new IntConstant (0, Location.Null);
5363 if (t == TypeManager.uint32_type)
5364 return new UIntConstant (0, Location.Null);
5365 if (t == TypeManager.int64_type)
5366 return new LongConstant (0, Location.Null);
5367 if (t == TypeManager.uint64_type)
5368 return new ULongConstant (0, Location.Null);
5369 if (t == TypeManager.float_type)
5370 return new FloatConstant (0, Location.Null);
5371 if (t == TypeManager.double_type)
5372 return new DoubleConstant (0, Location.Null);
5373 if (t == TypeManager.short_type)
5374 return new ShortConstant (0, Location.Null);
5375 if (t == TypeManager.ushort_type)
5376 return new UShortConstant (0, Location.Null);
5377 if (t == TypeManager.sbyte_type)
5378 return new SByteConstant (0, Location.Null);
5379 if (t == TypeManager.byte_type)
5380 return new ByteConstant (0, Location.Null);
5381 if (t == TypeManager.char_type)
5382 return new CharConstant ('\0', Location.Null);
5383 if (t == TypeManager.bool_type)
5384 return new BoolConstant (false, Location.Null);
5385 if (t == TypeManager.decimal_type)
5386 return new DecimalConstant (0, Location.Null);
5387 if (TypeManager.IsEnumType (t))
5388 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5389 if (TypeManager.IsNullableType (t))
5390 return Nullable.LiftedNull.Create (t, Location.Null);
5392 return null;
5396 // Checks whether the type is an interface that has the
5397 // [ComImport, CoClass] attributes and must be treated
5398 // specially
5400 public Expression CheckComImport (ResolveContext ec)
5402 if (!type.IsInterface)
5403 return null;
5406 // Turn the call into:
5407 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5409 Type real_class = AttributeTester.GetCoClassAttribute (type);
5410 if (real_class == null)
5411 return null;
5413 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5414 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5415 return cast.Resolve (ec);
5418 public override Expression CreateExpressionTree (ResolveContext ec)
5420 Arguments args;
5421 if (method == null) {
5422 args = new Arguments (1);
5423 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5424 } else {
5425 args = Arguments.CreateForExpressionTree (ec,
5426 Arguments,
5427 method.CreateExpressionTree (ec));
5430 return CreateExpressionFactoryCall (ec, "New", args);
5433 protected override Expression DoResolve (ResolveContext ec)
5436 // The New DoResolve might be called twice when initializing field
5437 // expressions (see EmitFieldInitializers, the call to
5438 // GetInitializerExpression will perform a resolve on the expression,
5439 // and later the assign will trigger another resolution
5441 // This leads to bugs (#37014)
5443 if (type != null){
5444 if (RequestedType is NewDelegate)
5445 return RequestedType;
5446 return this;
5449 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5450 if (texpr == null)
5451 return null;
5453 type = texpr.Type;
5455 if (type.IsPointer) {
5456 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5457 TypeManager.CSharpName (type));
5458 return null;
5461 if (Arguments == null) {
5462 Constant c = Constantify (type);
5463 if (c != null)
5464 return ReducedExpression.Create (c.Resolve (ec), this);
5467 if (TypeManager.IsDelegateType (type)) {
5468 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5471 if (TypeManager.IsGenericParameter (type)) {
5472 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5474 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5475 ec.Report.Error (304, loc,
5476 "Cannot create an instance of the variable type '{0}' because it doesn't have the new() constraint",
5477 TypeManager.CSharpName (type));
5478 return null;
5481 if ((Arguments != null) && (Arguments.Count != 0)) {
5482 ec.Report.Error (417, loc,
5483 "`{0}': cannot provide arguments when creating an instance of a variable type",
5484 TypeManager.CSharpName (type));
5485 return null;
5488 if (TypeManager.activator_create_instance == null) {
5489 Type activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", MemberKind.Class, true);
5490 if (activator_type != null) {
5491 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5492 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5496 is_type_parameter = true;
5497 eclass = ExprClass.Value;
5498 return this;
5501 if (type.IsAbstract && type.IsSealed) {
5502 ec.Report.SymbolRelatedToPreviousError (type);
5503 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5504 return null;
5507 if (type.IsInterface || type.IsAbstract){
5508 if (!TypeManager.IsGenericType (type)) {
5509 RequestedType = CheckComImport (ec);
5510 if (RequestedType != null)
5511 return RequestedType;
5514 ec.Report.SymbolRelatedToPreviousError (type);
5515 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5516 return null;
5519 bool is_struct = TypeManager.IsStruct (type);
5520 eclass = ExprClass.Value;
5523 // SRE returns a match for .ctor () on structs (the object constructor),
5524 // so we have to manually ignore it.
5526 if (is_struct && Arguments == null)
5527 return this;
5529 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5530 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5531 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5533 bool dynamic;
5534 if (Arguments != null) {
5535 Arguments.Resolve (ec, out dynamic);
5536 } else {
5537 dynamic = false;
5540 if (ml == null)
5541 return null;
5543 method = ml as MethodGroupExpr;
5544 if (method == null) {
5545 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5546 return null;
5549 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5550 if (method == null)
5551 return null;
5553 if (dynamic) {
5554 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5555 return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
5558 return this;
5561 bool DoEmitTypeParameter (EmitContext ec)
5563 ILGenerator ig = ec.ig;
5565 MethodInfo ci = (MethodInfo) TypeManager.activator_create_instance.MetaInfo;
5566 ci = ci.MakeGenericMethod (new Type [] { type });
5568 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5569 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5570 ig.Emit (OpCodes.Call, ci);
5571 return true;
5574 // Allow DoEmit() to be called multiple times.
5575 // We need to create a new LocalTemporary each time since
5576 // you can't share LocalBuilders among ILGeneators.
5577 LocalTemporary temp = new LocalTemporary (type);
5579 Label label_activator = ig.DefineLabel ();
5580 Label label_end = ig.DefineLabel ();
5582 temp.AddressOf (ec, AddressOp.Store);
5583 ig.Emit (OpCodes.Initobj, type);
5585 temp.Emit (ec);
5586 ig.Emit (OpCodes.Box, type);
5587 ig.Emit (OpCodes.Brfalse, label_activator);
5589 temp.AddressOf (ec, AddressOp.Store);
5590 ig.Emit (OpCodes.Initobj, type);
5591 temp.Emit (ec);
5592 ig.Emit (OpCodes.Br_S, label_end);
5594 ig.MarkLabel (label_activator);
5596 ig.Emit (OpCodes.Call, ci);
5597 ig.MarkLabel (label_end);
5598 return true;
5602 // This Emit can be invoked in two contexts:
5603 // * As a mechanism that will leave a value on the stack (new object)
5604 // * As one that wont (init struct)
5606 // If we are dealing with a ValueType, we have a few
5607 // situations to deal with:
5609 // * The target is a ValueType, and we have been provided
5610 // the instance (this is easy, we are being assigned).
5612 // * The target of New is being passed as an argument,
5613 // to a boxing operation or a function that takes a
5614 // ValueType.
5616 // In this case, we need to create a temporary variable
5617 // that is the argument of New.
5619 // Returns whether a value is left on the stack
5621 // *** Implementation note ***
5623 // To benefit from this optimization, each assignable expression
5624 // has to manually cast to New and call this Emit.
5626 // TODO: It's worth to implement it for arrays and fields
5628 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5630 bool is_value_type = TypeManager.IsValueType (type);
5631 ILGenerator ig = ec.ig;
5632 VariableReference vr = target as VariableReference;
5634 if (target != null && is_value_type && (vr != null || method == null)) {
5635 target.AddressOf (ec, AddressOp.Store);
5636 } else if (vr != null && vr.IsRef) {
5637 vr.EmitLoad (ec);
5640 if (Arguments != null)
5641 Arguments.Emit (ec);
5643 if (is_value_type) {
5644 if (method == null) {
5645 ig.Emit (OpCodes.Initobj, type);
5646 return false;
5649 if (vr != null) {
5650 ig.Emit (OpCodes.Call, (ConstructorInfo) method.BestCandidate.MetaInfo);
5651 return false;
5655 if (is_type_parameter)
5656 return DoEmitTypeParameter (ec);
5658 ConstructorInfo ci = (ConstructorInfo) method.BestCandidate.MetaInfo;
5659 #if MS_COMPATIBLE
5660 if (TypeManager.IsGenericType (type) && type.IsGenericTypeDefinition)
5661 ci = TypeBuilder.GetConstructor (type, ci);
5662 #endif
5664 ig.Emit (OpCodes.Newobj, ci);
5665 return true;
5668 public override void Emit (EmitContext ec)
5670 LocalTemporary v = null;
5671 if (method == null && TypeManager.IsValueType (type)) {
5672 // TODO: Use temporary variable from pool
5673 v = new LocalTemporary (type);
5676 if (!Emit (ec, v))
5677 v.Emit (ec);
5680 public override void EmitStatement (EmitContext ec)
5682 LocalTemporary v = null;
5683 if (method == null && TypeManager.IsValueType (type)) {
5684 // TODO: Use temporary variable from pool
5685 v = new LocalTemporary (type);
5688 if (Emit (ec, v))
5689 ec.ig.Emit (OpCodes.Pop);
5692 public virtual bool HasInitializer {
5693 get {
5694 return false;
5698 public void AddressOf (EmitContext ec, AddressOp mode)
5700 EmitAddressOf (ec, mode);
5703 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5705 LocalTemporary value_target = new LocalTemporary (type);
5707 if (is_type_parameter) {
5708 DoEmitTypeParameter (ec);
5709 value_target.Store (ec);
5710 value_target.AddressOf (ec, mode);
5711 return value_target;
5714 if (!TypeManager.IsStruct (type)){
5716 // We throw an exception. So far, I believe we only need to support
5717 // value types:
5718 // foreach (int j in new StructType ())
5719 // see bug 42390
5721 throw new Exception ("AddressOf should not be used for classes");
5724 value_target.AddressOf (ec, AddressOp.Store);
5726 if (method == null) {
5727 ec.ig.Emit (OpCodes.Initobj, type);
5728 } else {
5729 if (Arguments != null)
5730 Arguments.Emit (ec);
5732 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method.BestCandidate.MetaInfo);
5735 value_target.AddressOf (ec, mode);
5736 return value_target;
5739 protected override void CloneTo (CloneContext clonectx, Expression t)
5741 New target = (New) t;
5743 target.RequestedType = RequestedType.Clone (clonectx);
5744 if (Arguments != null){
5745 target.Arguments = Arguments.Clone (clonectx);
5749 public override SLE.Expression MakeExpression (BuilderContext ctx)
5751 return SLE.Expression.New ((ConstructorInfo) method.BestCandidate.MetaInfo, Arguments.MakeExpression (Arguments, ctx));
5754 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5756 if (method != null) {
5757 method.MutateHoistedGenericType (storey);
5758 if (Arguments != null) {
5759 Arguments.MutateHoistedGenericType (storey);
5763 type = storey.MutateType (type);
5767 public class ArrayInitializer : ShimExpression
5769 List<Expression> elements;
5771 public ArrayInitializer (List<Expression> init, Location loc)
5772 : base (null)
5774 elements = init;
5777 public ArrayInitializer (int count, Location loc)
5778 : base (null)
5780 elements = new List<Expression> (count);
5783 public ArrayInitializer (Location loc)
5784 : this (4, loc)
5788 public void Add (Expression expr)
5790 elements.Add (expr);
5793 protected override void CloneTo (CloneContext clonectx, Expression t)
5795 var target = (ArrayInitializer) t;
5797 target.elements = new List<Expression> (elements.Count);
5798 foreach (var element in elements)
5799 target.elements.Add (element.Clone (clonectx));
5801 base.CloneTo (clonectx, t);
5804 public int Count {
5805 get { return elements.Count; }
5808 protected override Expression DoResolve (ResolveContext rc)
5810 throw new NotImplementedException ();
5813 public Expression this [int index] {
5814 get { return elements [index]; }
5818 /// <summary>
5819 /// 14.5.10.2: Represents an array creation expression.
5820 /// </summary>
5822 /// <remarks>
5823 /// There are two possible scenarios here: one is an array creation
5824 /// expression that specifies the dimensions and optionally the
5825 /// initialization data and the other which does not need dimensions
5826 /// specified but where initialization data is mandatory.
5827 /// </remarks>
5828 class ArrayCreation : Expression
5830 FullNamedExpression requested_base_type;
5831 ArrayInitializer initializers;
5834 // The list of Argument types.
5835 // This is used to construct the `newarray' or constructor signature
5837 protected List<Expression> arguments;
5839 protected Type array_element_type;
5840 bool expect_initializers = false;
5841 int num_arguments = 0;
5842 protected int dimensions;
5843 protected readonly string rank;
5844 Expression first_emit;
5845 LocalTemporary first_emit_temp;
5847 protected List<Expression> array_data;
5849 Dictionary<int, int> bounds;
5851 // The number of constants in array initializers
5852 int const_initializers_count;
5853 bool only_constant_initializers;
5855 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, string rank, ArrayInitializer initializers, Location l)
5857 this.requested_base_type = requested_base_type;
5858 this.initializers = initializers;
5859 this.rank = rank;
5860 loc = l;
5862 arguments = new List<Expression> (exprs);
5863 num_arguments = arguments.Count;
5866 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayInitializer initializers, Location l)
5868 this.requested_base_type = requested_base_type;
5869 this.initializers = initializers;
5870 this.rank = rank;
5871 loc = l;
5873 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5875 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5877 //dimensions = tmp.Length - 1;
5878 expect_initializers = true;
5881 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5883 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5886 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
5888 if (specified_dims) {
5889 Expression a = arguments [idx];
5890 a = a.Resolve (ec);
5891 if (a == null)
5892 return false;
5894 Constant c = a as Constant;
5895 if (c != null) {
5896 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5899 if (c == null) {
5900 ec.Report.Error (150, a.Location, "A constant value is expected");
5901 return false;
5904 int value = (int) c.GetValue ();
5906 if (value != probe.Count) {
5907 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5908 return false;
5911 bounds [idx] = value;
5914 only_constant_initializers = true;
5915 for (int i = 0; i < probe.Count; ++i) {
5916 var o = probe [i];
5917 if (o is ArrayInitializer) {
5918 var sub_probe = o as ArrayInitializer;
5919 if (idx + 1 >= dimensions){
5920 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5921 return false;
5924 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5925 if (!ret)
5926 return false;
5927 } else if (child_bounds > 1) {
5928 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
5929 } else {
5930 Expression element = ResolveArrayElement (ec, o);
5931 if (element == null)
5932 continue;
5934 // Initializers with the default values can be ignored
5935 Constant c = element as Constant;
5936 if (c != null) {
5937 if (c.IsDefaultInitializer (array_element_type)) {
5938 element = null;
5940 else {
5941 ++const_initializers_count;
5943 } else {
5944 only_constant_initializers = false;
5947 array_data.Add (element);
5951 return true;
5954 public override Expression CreateExpressionTree (ResolveContext ec)
5956 Arguments args;
5958 if (array_data == null) {
5959 args = new Arguments (arguments.Count + 1);
5960 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5961 foreach (Expression a in arguments)
5962 args.Add (new Argument (a.CreateExpressionTree (ec)));
5964 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
5967 if (dimensions > 1) {
5968 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5969 return null;
5972 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5973 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5974 if (array_data != null) {
5975 for (int i = 0; i < array_data.Count; ++i) {
5976 Expression e = array_data [i];
5977 if (e == null)
5978 e = Convert.ImplicitConversion (ec, initializers [i], array_element_type, loc);
5980 args.Add (new Argument (e.CreateExpressionTree (ec)));
5984 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
5987 public void UpdateIndices ()
5989 int i = 0;
5990 for (var probe = initializers; probe != null;) {
5991 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
5992 Expression e = new IntConstant (probe.Count, Location.Null);
5993 arguments.Add (e);
5995 bounds [i++] = probe.Count;
5997 probe = (ArrayInitializer) probe[0];
5999 } else {
6000 Expression e = new IntConstant (probe.Count, Location.Null);
6001 arguments.Add (e);
6003 bounds [i++] = probe.Count;
6004 return;
6009 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
6011 element = element.Resolve (ec);
6012 if (element == null)
6013 return null;
6015 if (element is CompoundAssign.TargetExpression) {
6016 if (first_emit != null)
6017 throw new InternalErrorException ("Can only handle one mutator at a time");
6018 first_emit = element;
6019 element = first_emit_temp = new LocalTemporary (element.Type);
6022 return Convert.ImplicitConversionRequired (
6023 ec, element, array_element_type, loc);
6026 protected bool ResolveInitializers (ResolveContext ec)
6028 if (initializers == null) {
6029 return !expect_initializers;
6033 // We use this to store all the date values in the order in which we
6034 // will need to store them in the byte blob later
6036 array_data = new List<Expression> ();
6037 bounds = new Dictionary<int, int> ();
6039 if (arguments != null)
6040 return CheckIndices (ec, initializers, 0, true, dimensions);
6042 arguments = new List<Expression> ();
6044 if (!CheckIndices (ec, initializers, 0, false, dimensions))
6045 return false;
6047 UpdateIndices ();
6049 return true;
6053 // Resolved the type of the array
6055 bool ResolveArrayType (ResolveContext ec)
6057 if (requested_base_type is VarExpr) {
6058 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6059 return false;
6062 StringBuilder array_qualifier = new StringBuilder (rank);
6065 // `In the first form allocates an array instace of the type that results
6066 // from deleting each of the individual expression from the expression list'
6068 if (num_arguments > 0) {
6069 array_qualifier.Append ("[");
6070 for (int i = num_arguments-1; i > 0; i--)
6071 array_qualifier.Append (",");
6072 array_qualifier.Append ("]");
6076 // Lookup the type
6078 TypeExpr array_type_expr;
6079 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6080 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6081 if (array_type_expr == null)
6082 return false;
6084 type = array_type_expr.Type;
6085 if (!type.IsArray) {
6086 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6087 return false;
6090 array_element_type = TypeManager.GetElementType (type);
6091 dimensions = type.GetArrayRank ();
6093 return true;
6096 protected override Expression DoResolve (ResolveContext ec)
6098 if (type != null)
6099 return this;
6101 if (!ResolveArrayType (ec))
6102 return null;
6105 // First step is to validate the initializers and fill
6106 // in any missing bits
6108 if (!ResolveInitializers (ec))
6109 return null;
6111 for (int i = 0; i < arguments.Count; ++i) {
6112 Expression e = arguments[i].Resolve (ec);
6113 if (e == null)
6114 continue;
6116 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
6119 eclass = ExprClass.Value;
6120 return this;
6123 MethodInfo GetArrayMethod (EmitContext ec, int arguments)
6125 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6127 Type[] arg_types = new Type[arguments];
6128 for (int i = 0; i < arguments; i++)
6129 arg_types[i] = TypeManager.int32_type;
6131 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6132 arg_types);
6134 if (mi == null) {
6135 ec.Report.Error (-6, "New invocation: Can not find a constructor for " +
6136 "this argument list");
6137 return null;
6140 return mi;
6143 byte [] MakeByteBlob ()
6145 int factor;
6146 byte [] data;
6147 byte [] element;
6148 int count = array_data.Count;
6150 Type element_type = array_element_type;
6151 if (TypeManager.IsEnumType (element_type))
6152 element_type = TypeManager.GetEnumUnderlyingType (element_type);
6154 factor = GetTypeSize (element_type);
6155 if (factor == 0)
6156 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6158 data = new byte [(count * factor + 3) & ~3];
6159 int idx = 0;
6161 for (int i = 0; i < count; ++i) {
6162 object v = array_data [i];
6164 if (v is EnumConstant)
6165 v = ((EnumConstant) v).Child;
6167 if (v is Constant && !(v is StringConstant))
6168 v = ((Constant) v).GetValue ();
6169 else {
6170 idx += factor;
6171 continue;
6174 if (element_type == TypeManager.int64_type){
6175 if (!(v is Expression)){
6176 long val = (long) v;
6178 for (int j = 0; j < factor; ++j) {
6179 data [idx + j] = (byte) (val & 0xFF);
6180 val = (val >> 8);
6183 } else if (element_type == TypeManager.uint64_type){
6184 if (!(v is Expression)){
6185 ulong val = (ulong) v;
6187 for (int j = 0; j < factor; ++j) {
6188 data [idx + j] = (byte) (val & 0xFF);
6189 val = (val >> 8);
6192 } else if (element_type == TypeManager.float_type) {
6193 if (!(v is Expression)){
6194 element = BitConverter.GetBytes ((float) v);
6196 for (int j = 0; j < factor; ++j)
6197 data [idx + j] = element [j];
6198 if (!BitConverter.IsLittleEndian)
6199 System.Array.Reverse (data, idx, 4);
6201 } else if (element_type == TypeManager.double_type) {
6202 if (!(v is Expression)){
6203 element = BitConverter.GetBytes ((double) v);
6205 for (int j = 0; j < factor; ++j)
6206 data [idx + j] = element [j];
6208 // FIXME: Handle the ARM float format.
6209 if (!BitConverter.IsLittleEndian)
6210 System.Array.Reverse (data, idx, 8);
6212 } else if (element_type == TypeManager.char_type){
6213 if (!(v is Expression)){
6214 int val = (int) ((char) v);
6216 data [idx] = (byte) (val & 0xff);
6217 data [idx+1] = (byte) (val >> 8);
6219 } else if (element_type == TypeManager.short_type){
6220 if (!(v is Expression)){
6221 int val = (int) ((short) v);
6223 data [idx] = (byte) (val & 0xff);
6224 data [idx+1] = (byte) (val >> 8);
6226 } else if (element_type == TypeManager.ushort_type){
6227 if (!(v is Expression)){
6228 int val = (int) ((ushort) v);
6230 data [idx] = (byte) (val & 0xff);
6231 data [idx+1] = (byte) (val >> 8);
6233 } else if (element_type == TypeManager.int32_type) {
6234 if (!(v is Expression)){
6235 int val = (int) v;
6237 data [idx] = (byte) (val & 0xff);
6238 data [idx+1] = (byte) ((val >> 8) & 0xff);
6239 data [idx+2] = (byte) ((val >> 16) & 0xff);
6240 data [idx+3] = (byte) (val >> 24);
6242 } else if (element_type == TypeManager.uint32_type) {
6243 if (!(v is Expression)){
6244 uint val = (uint) v;
6246 data [idx] = (byte) (val & 0xff);
6247 data [idx+1] = (byte) ((val >> 8) & 0xff);
6248 data [idx+2] = (byte) ((val >> 16) & 0xff);
6249 data [idx+3] = (byte) (val >> 24);
6251 } else if (element_type == TypeManager.sbyte_type) {
6252 if (!(v is Expression)){
6253 sbyte val = (sbyte) v;
6254 data [idx] = (byte) val;
6256 } else if (element_type == TypeManager.byte_type) {
6257 if (!(v is Expression)){
6258 byte val = (byte) v;
6259 data [idx] = (byte) val;
6261 } else if (element_type == TypeManager.bool_type) {
6262 if (!(v is Expression)){
6263 bool val = (bool) v;
6264 data [idx] = (byte) (val ? 1 : 0);
6266 } else if (element_type == TypeManager.decimal_type){
6267 if (!(v is Expression)){
6268 int [] bits = Decimal.GetBits ((decimal) v);
6269 int p = idx;
6271 // FIXME: For some reason, this doesn't work on the MS runtime.
6272 int [] nbits = new int [4];
6273 nbits [0] = bits [3];
6274 nbits [1] = bits [2];
6275 nbits [2] = bits [0];
6276 nbits [3] = bits [1];
6278 for (int j = 0; j < 4; j++){
6279 data [p++] = (byte) (nbits [j] & 0xff);
6280 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6281 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6282 data [p++] = (byte) (nbits [j] >> 24);
6285 } else {
6286 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6289 idx += factor;
6292 return data;
6295 #if NET_4_0
6296 public override SLE.Expression MakeExpression (BuilderContext ctx)
6298 var initializers = new SLE.Expression [array_data.Count];
6299 for (var i = 0; i < initializers.Length; i++) {
6300 if (array_data [i] == null)
6301 initializers [i] = SLE.Expression.Default (array_element_type);
6302 else
6303 initializers [i] = array_data [i].MakeExpression (ctx);
6306 return SLE.Expression.NewArrayInit (array_element_type, initializers);
6308 #endif
6310 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6312 array_element_type = storey.MutateType (array_element_type);
6313 type = storey.MutateType (type);
6314 if (arguments != null) {
6315 foreach (Expression e in arguments)
6316 e.MutateHoistedGenericType (storey);
6319 if (array_data != null) {
6320 foreach (Expression e in array_data) {
6321 // Don't mutate values optimized away
6322 if (e == null)
6323 continue;
6325 e.MutateHoistedGenericType (storey);
6331 // Emits the initializers for the array
6333 void EmitStaticInitializers (EmitContext ec)
6335 // FIXME: This should go to Resolve !
6336 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6337 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6338 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6339 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6340 if (TypeManager.void_initializearray_array_fieldhandle == null)
6341 return;
6345 // First, the static data
6347 FieldBuilder fb;
6348 ILGenerator ig = ec.ig;
6350 byte [] data = MakeByteBlob ();
6352 fb = RootContext.MakeStaticData (data);
6354 ig.Emit (OpCodes.Dup);
6355 ig.Emit (OpCodes.Ldtoken, fb);
6356 ig.Emit (OpCodes.Call, (MethodInfo) TypeManager.void_initializearray_array_fieldhandle.MetaInfo);
6360 // Emits pieces of the array that can not be computed at compile
6361 // time (variables and string locations).
6363 // This always expect the top value on the stack to be the array
6365 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6367 ILGenerator ig = ec.ig;
6368 int dims = bounds.Count;
6369 int [] current_pos = new int [dims];
6371 MethodInfo set = null;
6373 if (dims != 1){
6374 Type [] args = new Type [dims + 1];
6376 for (int j = 0; j < dims; j++)
6377 args [j] = TypeManager.int32_type;
6378 args [dims] = array_element_type;
6380 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6381 type, "Set",
6382 CallingConventions.HasThis | CallingConventions.Standard,
6383 TypeManager.void_type, args);
6386 for (int i = 0; i < array_data.Count; i++){
6388 Expression e = array_data [i];
6390 // Constant can be initialized via StaticInitializer
6391 if (e != null && !(!emitConstants && e is Constant)) {
6392 Type etype = e.Type;
6394 ig.Emit (OpCodes.Dup);
6396 for (int idx = 0; idx < dims; idx++)
6397 IntConstant.EmitInt (ig, current_pos [idx]);
6400 // If we are dealing with a struct, get the
6401 // address of it, so we can store it.
6403 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6404 (!TypeManager.IsBuiltinOrEnum (etype) ||
6405 etype == TypeManager.decimal_type)) {
6407 ig.Emit (OpCodes.Ldelema, etype);
6410 e.Emit (ec);
6412 if (dims == 1) {
6413 bool is_stobj, has_type_arg;
6414 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6415 if (is_stobj)
6416 ig.Emit (OpCodes.Stobj, etype);
6417 else if (has_type_arg)
6418 ig.Emit (op, etype);
6419 else
6420 ig.Emit (op);
6421 } else
6422 ig.Emit (OpCodes.Call, set);
6427 // Advance counter
6429 for (int j = dims - 1; j >= 0; j--){
6430 current_pos [j]++;
6431 if (current_pos [j] < bounds [j])
6432 break;
6433 current_pos [j] = 0;
6438 public override void Emit (EmitContext ec)
6440 ILGenerator ig = ec.ig;
6442 if (first_emit != null) {
6443 first_emit.Emit (ec);
6444 first_emit_temp.Store (ec);
6447 foreach (Expression e in arguments)
6448 e.Emit (ec);
6450 if (arguments.Count == 1)
6451 ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
6452 else {
6453 ig.Emit (OpCodes.Newobj, GetArrayMethod (ec, arguments.Count));
6456 if (initializers == null)
6457 return;
6459 // Emit static initializer for arrays which have contain more than 2 items and
6460 // the static initializer will initialize at least 25% of array values.
6461 // NOTE: const_initializers_count does not contain default constant values.
6462 if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
6463 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6464 EmitStaticInitializers (ec);
6466 if (!only_constant_initializers)
6467 EmitDynamicInitializers (ec, false);
6468 } else {
6469 EmitDynamicInitializers (ec, true);
6472 if (first_emit_temp != null)
6473 first_emit_temp.Release (ec);
6476 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6478 if (arguments.Count != 1) {
6479 // ec.Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6480 return base.GetAttributableValue (ec, null, out value);
6483 if (array_data == null) {
6484 Expression arg = arguments [0];
6485 object arg_value;
6486 if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
6487 value = Array.CreateInstance (array_element_type, 0);
6488 return true;
6491 // ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6492 return base.GetAttributableValue (ec, null, out value);
6495 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6496 object element_value;
6497 for (int i = 0; i < ret.Length; ++i)
6499 Expression e = array_data [i];
6501 // Is null when an initializer is optimized (value == predefined value)
6502 if (e == null)
6503 continue;
6505 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6506 value = null;
6507 return false;
6509 ret.SetValue (element_value, i);
6511 value = ret;
6512 return true;
6515 protected override void CloneTo (CloneContext clonectx, Expression t)
6517 ArrayCreation target = (ArrayCreation) t;
6519 if (requested_base_type != null)
6520 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6522 if (arguments != null){
6523 target.arguments = new List<Expression> (arguments.Count);
6524 foreach (Expression e in arguments)
6525 target.arguments.Add (e.Clone (clonectx));
6528 if (initializers != null)
6529 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
6534 // Represents an implicitly typed array epxression
6536 class ImplicitlyTypedArrayCreation : ArrayCreation
6538 public ImplicitlyTypedArrayCreation (string rank, ArrayInitializer initializers, Location loc)
6539 : base (null, rank, initializers, loc)
6541 if (rank.Length > 2) {
6542 while (rank [++dimensions] == ',');
6543 } else {
6544 dimensions = 1;
6548 protected override Expression DoResolve (ResolveContext ec)
6550 if (type != null)
6551 return this;
6553 if (!ResolveInitializers (ec))
6554 return null;
6556 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6557 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6558 array_element_type == InternalType.MethodGroup ||
6559 arguments.Count != dimensions) {
6560 Error_NoBestType (ec);
6561 return null;
6565 // At this point we found common base type for all initializer elements
6566 // but we have to be sure that all static initializer elements are of
6567 // same type
6569 UnifyInitializerElement (ec);
6571 type = TypeManager.GetConstructedType (array_element_type, rank);
6572 eclass = ExprClass.Value;
6573 return this;
6576 void Error_NoBestType (ResolveContext ec)
6578 ec.Report.Error (826, loc,
6579 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6583 // Converts static initializer only
6585 void UnifyInitializerElement (ResolveContext ec)
6587 for (int i = 0; i < array_data.Count; ++i) {
6588 Expression e = (Expression)array_data[i];
6589 if (e != null)
6590 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6594 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6596 element = element.Resolve (ec);
6597 if (element == null)
6598 return null;
6600 if (array_element_type == null) {
6601 if (element.Type != TypeManager.null_type)
6602 array_element_type = element.Type;
6604 return element;
6607 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6608 return element;
6611 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6612 array_element_type = element.Type;
6613 return element;
6616 Error_NoBestType (ec);
6617 return null;
6621 public sealed class CompilerGeneratedThis : This
6623 public static This Instance = new CompilerGeneratedThis ();
6625 private CompilerGeneratedThis ()
6626 : base (Location.Null)
6630 public CompilerGeneratedThis (Type type, Location loc)
6631 : base (loc)
6633 this.type = type;
6636 protected override Expression DoResolve (ResolveContext ec)
6638 eclass = ExprClass.Variable;
6639 if (type == null)
6640 type = ec.CurrentType;
6642 is_struct = type.IsValueType;
6643 return this;
6646 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6648 return null;
6652 /// <summary>
6653 /// Represents the `this' construct
6654 /// </summary>
6656 public class This : VariableReference
6658 sealed class ThisVariable : ILocalVariable
6660 public static readonly ILocalVariable Instance = new ThisVariable ();
6662 public void Emit (EmitContext ec)
6664 ec.ig.Emit (OpCodes.Ldarg_0);
6667 public void EmitAssign (EmitContext ec)
6669 throw new InvalidOperationException ();
6672 public void EmitAddressOf (EmitContext ec)
6674 ec.ig.Emit (OpCodes.Ldarg_0);
6678 Block block;
6679 VariableInfo variable_info;
6680 protected bool is_struct;
6682 public This (Block block, Location loc)
6684 this.loc = loc;
6685 this.block = block;
6688 public This (Location loc)
6690 this.loc = loc;
6693 public override VariableInfo VariableInfo {
6694 get { return variable_info; }
6697 public override bool IsFixed {
6698 get { return false; }
6701 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6703 if (ae == null)
6704 return null;
6706 AnonymousMethodStorey storey = ae.Storey;
6707 while (storey != null) {
6708 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6709 if (temp == null)
6710 return storey.HoistedThis;
6712 storey = temp;
6715 return null;
6718 public override bool IsRef {
6719 get { return is_struct; }
6722 protected override ILocalVariable Variable {
6723 get { return ThisVariable.Instance; }
6726 public static bool IsThisAvailable (ResolveContext ec)
6728 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6729 return false;
6731 if (ec.CurrentAnonymousMethod == null)
6732 return true;
6734 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6735 return false;
6737 return true;
6740 public bool ResolveBase (ResolveContext ec)
6742 eclass = ExprClass.Variable;
6743 type = ec.CurrentType;
6745 if (!IsThisAvailable (ec)) {
6746 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6747 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6748 } else if (ec.CurrentAnonymousMethod != null) {
6749 ec.Report.Error (1673, loc,
6750 "Anonymous methods inside structs cannot access instance members of `this'. " +
6751 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6752 } else {
6753 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6757 is_struct = type.IsValueType;
6759 if (block != null) {
6760 if (block.Toplevel.ThisVariable != null)
6761 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6763 AnonymousExpression am = ec.CurrentAnonymousMethod;
6764 if (am != null && ec.IsVariableCapturingRequired) {
6765 am.SetHasThisAccess ();
6769 return true;
6773 // Called from Invocation to check if the invocation is correct
6775 public override void CheckMarshalByRefAccess (ResolveContext ec)
6777 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6778 !variable_info.IsAssigned (ec)) {
6779 ec.Report.Error (188, loc,
6780 "The `this' object cannot be used before all of its fields are assigned to");
6781 variable_info.SetAssigned (ec);
6785 public override Expression CreateExpressionTree (ResolveContext ec)
6787 Arguments args = new Arguments (1);
6788 args.Add (new Argument (this));
6790 // Use typeless constant for ldarg.0 to save some
6791 // space and avoid problems with anonymous stories
6792 return CreateExpressionFactoryCall (ec, "Constant", args);
6795 protected override Expression DoResolve (ResolveContext ec)
6797 ResolveBase (ec);
6798 return this;
6801 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6803 if (!ResolveBase (ec))
6804 return null;
6806 if (variable_info != null)
6807 variable_info.SetAssigned (ec);
6809 if (ec.CurrentType.IsClass){
6810 if (right_side == EmptyExpression.UnaryAddress)
6811 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6812 else if (right_side == EmptyExpression.OutAccess.Instance)
6813 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6814 else
6815 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6818 return this;
6821 public override int GetHashCode()
6823 return block.GetHashCode ();
6826 public override string Name {
6827 get { return "this"; }
6830 public override bool Equals (object obj)
6832 This t = obj as This;
6833 if (t == null)
6834 return false;
6836 return block == t.block;
6839 protected override void CloneTo (CloneContext clonectx, Expression t)
6841 This target = (This) t;
6843 target.block = clonectx.LookupBlock (block);
6846 public override void SetHasAddressTaken ()
6848 // Nothing
6852 /// <summary>
6853 /// Represents the `__arglist' construct
6854 /// </summary>
6855 public class ArglistAccess : Expression
6857 public ArglistAccess (Location loc)
6859 this.loc = loc;
6862 public override Expression CreateExpressionTree (ResolveContext ec)
6864 throw new NotSupportedException ("ET");
6867 protected override Expression DoResolve (ResolveContext ec)
6869 eclass = ExprClass.Variable;
6870 type = TypeManager.runtime_argument_handle_type;
6872 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6873 ec.Report.Error (190, loc,
6874 "The __arglist construct is valid only within a variable argument method");
6877 return this;
6880 public override void Emit (EmitContext ec)
6882 ec.ig.Emit (OpCodes.Arglist);
6885 protected override void CloneTo (CloneContext clonectx, Expression target)
6887 // nothing.
6891 /// <summary>
6892 /// Represents the `__arglist (....)' construct
6893 /// </summary>
6894 class Arglist : Expression
6896 Arguments Arguments;
6898 public Arglist (Location loc)
6899 : this (null, loc)
6903 public Arglist (Arguments args, Location l)
6905 Arguments = args;
6906 loc = l;
6909 public Type[] ArgumentTypes {
6910 get {
6911 if (Arguments == null)
6912 return Type.EmptyTypes;
6914 Type[] retval = new Type [Arguments.Count];
6915 for (int i = 0; i < retval.Length; i++)
6916 retval [i] = Arguments [i].Expr.Type;
6918 return retval;
6922 public override Expression CreateExpressionTree (ResolveContext ec)
6924 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6925 return null;
6928 protected override Expression DoResolve (ResolveContext ec)
6930 eclass = ExprClass.Variable;
6931 type = InternalType.Arglist;
6932 if (Arguments != null) {
6933 bool dynamic; // Can be ignored as there is always only 1 overload
6934 Arguments.Resolve (ec, out dynamic);
6937 return this;
6940 public override void Emit (EmitContext ec)
6942 if (Arguments != null)
6943 Arguments.Emit (ec);
6946 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6948 if (Arguments != null)
6949 Arguments.MutateHoistedGenericType (storey);
6952 protected override void CloneTo (CloneContext clonectx, Expression t)
6954 Arglist target = (Arglist) t;
6956 if (Arguments != null)
6957 target.Arguments = Arguments.Clone (clonectx);
6961 /// <summary>
6962 /// Implements the typeof operator
6963 /// </summary>
6964 public class TypeOf : Expression {
6965 Expression QueriedType;
6966 protected Type typearg;
6968 public TypeOf (Expression queried_type, Location l)
6970 QueriedType = queried_type;
6971 loc = l;
6974 public override Expression CreateExpressionTree (ResolveContext ec)
6976 Arguments args = new Arguments (2);
6977 args.Add (new Argument (this));
6978 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6979 return CreateExpressionFactoryCall (ec, "Constant", args);
6982 protected override Expression DoResolve (ResolveContext ec)
6984 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6985 if (texpr == null)
6986 return null;
6988 typearg = texpr.Type;
6990 if (typearg == TypeManager.void_type) {
6991 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6992 } else if (typearg.IsPointer && !ec.IsUnsafe){
6993 UnsafeError (ec, loc);
6994 } else if (texpr is DynamicTypeExpr) {
6995 ec.Report.Error (1962, QueriedType.Location,
6996 "The typeof operator cannot be used on the dynamic type");
6999 type = TypeManager.type_type;
7001 return DoResolveBase ();
7004 protected Expression DoResolveBase ()
7006 if (TypeManager.system_type_get_type_from_handle == null) {
7007 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
7008 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
7011 // Even though what is returned is a type object, it's treated as a value by the compiler.
7012 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7013 eclass = ExprClass.Value;
7014 return this;
7017 public override void Emit (EmitContext ec)
7019 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
7020 ec.ig.Emit (OpCodes.Call, (MethodInfo) TypeManager.system_type_get_type_from_handle.MetaInfo);
7023 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
7025 if (TypeManager.ContainsGenericParameters (typearg) &&
7026 !TypeManager.IsGenericTypeDefinition (typearg)) {
7027 ec.Report.SymbolRelatedToPreviousError (typearg);
7028 ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7029 TypeManager.CSharpName (typearg));
7030 value = null;
7031 return false;
7034 if (value_type == TypeManager.object_type) {
7035 value = (object)typearg;
7036 return true;
7038 value = typearg;
7039 return true;
7042 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7044 if (!TypeManager.IsGenericTypeDefinition (typearg))
7045 typearg = storey.MutateType (typearg);
7048 public Type TypeArgument {
7049 get {
7050 return typearg;
7054 protected override void CloneTo (CloneContext clonectx, Expression t)
7056 TypeOf target = (TypeOf) t;
7057 if (QueriedType != null)
7058 target.QueriedType = QueriedType.Clone (clonectx);
7062 /// <summary>
7063 /// Implements the `typeof (void)' operator
7064 /// </summary>
7065 public class TypeOfVoid : TypeOf {
7066 public TypeOfVoid (Location l) : base (null, l)
7068 loc = l;
7071 protected override Expression DoResolve (ResolveContext ec)
7073 type = TypeManager.type_type;
7074 typearg = TypeManager.void_type;
7076 return DoResolveBase ();
7080 class TypeOfMethod : TypeOfMember<MethodSpec>
7082 public TypeOfMethod (MethodSpec method, Location loc)
7083 : base (method, loc)
7087 protected override Expression DoResolve (ResolveContext ec)
7089 if (member.IsConstructor) {
7090 type = TypeManager.ctorinfo_type;
7091 if (type == null)
7092 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", MemberKind.Class, true);
7093 } else {
7094 type = TypeManager.methodinfo_type;
7095 if (type == null)
7096 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", MemberKind.Class, true);
7099 return base.DoResolve (ec);
7102 public override void Emit (EmitContext ec)
7104 if (member.IsConstructor)
7105 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member.MetaInfo);
7106 else
7107 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member.MetaInfo);
7109 base.Emit (ec);
7110 ec.ig.Emit (OpCodes.Castclass, type);
7113 protected override string GetMethodName {
7114 get { return "GetMethodFromHandle"; }
7117 protected override string RuntimeHandleName {
7118 get { return "RuntimeMethodHandle"; }
7121 protected override MethodSpec TypeFromHandle {
7122 get {
7123 return TypeManager.methodbase_get_type_from_handle;
7125 set {
7126 TypeManager.methodbase_get_type_from_handle = value;
7130 protected override MethodSpec TypeFromHandleGeneric {
7131 get {
7132 return TypeManager.methodbase_get_type_from_handle_generic;
7134 set {
7135 TypeManager.methodbase_get_type_from_handle_generic = value;
7139 protected override string TypeName {
7140 get { return "MethodBase"; }
7144 abstract class TypeOfMember<T> : Expression where T : MemberSpec
7146 protected readonly T member;
7148 protected TypeOfMember (T member, Location loc)
7150 this.member = member;
7151 this.loc = loc;
7154 public override Expression CreateExpressionTree (ResolveContext ec)
7156 Arguments args = new Arguments (2);
7157 args.Add (new Argument (this));
7158 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7159 return CreateExpressionFactoryCall (ec, "Constant", args);
7162 protected override Expression DoResolve (ResolveContext ec)
7164 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7165 var mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7167 if (mi == null) {
7168 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
7169 Type handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, MemberKind.Class, true);
7171 if (t == null || handle_type == null)
7172 return null;
7174 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7175 is_generic ?
7176 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7177 new Type[] { handle_type } );
7179 if (is_generic)
7180 TypeFromHandleGeneric = mi;
7181 else
7182 TypeFromHandle = mi;
7185 eclass = ExprClass.Value;
7186 return this;
7189 public override void Emit (EmitContext ec)
7191 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7192 MethodSpec mi;
7193 if (is_generic) {
7194 mi = TypeFromHandleGeneric;
7195 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7196 } else {
7197 mi = TypeFromHandle;
7200 ec.ig.Emit (OpCodes.Call, (MethodInfo) mi.MetaInfo);
7203 protected abstract string GetMethodName { get; }
7204 protected abstract string RuntimeHandleName { get; }
7205 protected abstract MethodSpec TypeFromHandle { get; set; }
7206 protected abstract MethodSpec TypeFromHandleGeneric { get; set; }
7207 protected abstract string TypeName { get; }
7210 class TypeOfField : TypeOfMember<FieldSpec>
7212 public TypeOfField (FieldSpec field, Location loc)
7213 : base (field, loc)
7217 protected override Expression DoResolve (ResolveContext ec)
7219 if (TypeManager.fieldinfo_type == null)
7220 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, MemberKind.Class, true);
7222 type = TypeManager.fieldinfo_type;
7223 return base.DoResolve (ec);
7226 public override void Emit (EmitContext ec)
7228 ec.ig.Emit (OpCodes.Ldtoken, member.MetaInfo);
7229 base.Emit (ec);
7232 protected override string GetMethodName {
7233 get { return "GetFieldFromHandle"; }
7236 protected override string RuntimeHandleName {
7237 get { return "RuntimeFieldHandle"; }
7240 protected override MethodSpec TypeFromHandle {
7241 get {
7242 return TypeManager.fieldinfo_get_field_from_handle;
7244 set {
7245 TypeManager.fieldinfo_get_field_from_handle = value;
7249 protected override MethodSpec TypeFromHandleGeneric {
7250 get {
7251 return TypeManager.fieldinfo_get_field_from_handle_generic;
7253 set {
7254 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7258 protected override string TypeName {
7259 get { return "FieldInfo"; }
7263 /// <summary>
7264 /// Implements the sizeof expression
7265 /// </summary>
7266 public class SizeOf : Expression {
7267 readonly Expression QueriedType;
7268 Type type_queried;
7270 public SizeOf (Expression queried_type, Location l)
7272 this.QueriedType = queried_type;
7273 loc = l;
7276 public override Expression CreateExpressionTree (ResolveContext ec)
7278 Error_PointerInsideExpressionTree (ec);
7279 return null;
7282 protected override Expression DoResolve (ResolveContext ec)
7284 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7285 if (texpr == null)
7286 return null;
7288 type_queried = texpr.Type;
7289 if (TypeManager.IsEnumType (type_queried))
7290 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7292 int size_of = GetTypeSize (type_queried);
7293 if (size_of > 0) {
7294 return new IntConstant (size_of, loc).Resolve (ec);
7297 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type_queried, loc)){
7298 return null;
7301 if (!ec.IsUnsafe) {
7302 ec.Report.Error (233, loc,
7303 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7304 TypeManager.CSharpName (type_queried));
7307 type = TypeManager.int32_type;
7308 eclass = ExprClass.Value;
7309 return this;
7312 public override void Emit (EmitContext ec)
7314 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7317 protected override void CloneTo (CloneContext clonectx, Expression t)
7322 /// <summary>
7323 /// Implements the qualified-alias-member (::) expression.
7324 /// </summary>
7325 public class QualifiedAliasMember : MemberAccess
7327 readonly string alias;
7328 public static readonly string GlobalAlias = "global";
7330 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7331 : base (null, identifier, targs, l)
7333 this.alias = alias;
7336 public QualifiedAliasMember (string alias, string identifier, Location l)
7337 : base (null, identifier, l)
7339 this.alias = alias;
7342 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7344 if (alias == GlobalAlias) {
7345 expr = GlobalRootNamespace.Instance;
7346 return base.ResolveAsTypeStep (ec, silent);
7349 int errors = ec.Compiler.Report.Errors;
7350 expr = ec.LookupNamespaceAlias (alias);
7351 if (expr == null) {
7352 if (errors == ec.Compiler.Report.Errors)
7353 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7354 return null;
7357 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7358 if (fne == null)
7359 return null;
7361 if (expr.eclass == ExprClass.Type) {
7362 if (!silent) {
7363 ec.Compiler.Report.Error (431, loc,
7364 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7366 return null;
7369 return fne;
7372 protected override Expression DoResolve (ResolveContext ec)
7374 return ResolveAsTypeStep (ec, false);
7377 protected override void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7379 rc.Compiler.Report.Error (687, loc,
7380 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7381 GetSignatureForError ());
7384 public override string GetSignatureForError ()
7386 string name = Name;
7387 if (targs != null) {
7388 name = TypeManager.RemoveGenericArity (Name) + "<" +
7389 targs.GetSignatureForError () + ">";
7392 return alias + "::" + name;
7395 protected override void CloneTo (CloneContext clonectx, Expression t)
7397 // Nothing
7401 /// <summary>
7402 /// Implements the member access expression
7403 /// </summary>
7404 public class MemberAccess : ATypeNameExpression {
7405 protected Expression expr;
7407 public MemberAccess (Expression expr, string id)
7408 : base (id, expr.Location)
7410 this.expr = expr;
7413 public MemberAccess (Expression expr, string identifier, Location loc)
7414 : base (identifier, loc)
7416 this.expr = expr;
7419 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7420 : base (identifier, args, loc)
7422 this.expr = expr;
7425 Expression DoResolve (ResolveContext ec, Expression right_side)
7427 if (type != null)
7428 throw new Exception ();
7431 // Resolve the expression with flow analysis turned off, we'll do the definite
7432 // assignment checks later. This is because we don't know yet what the expression
7433 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7434 // definite assignment check on the actual field and not on the whole struct.
7437 SimpleName original = expr as SimpleName;
7438 Expression expr_resolved;
7439 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7440 expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.Intermediate);
7443 if (expr_resolved == null)
7444 return null;
7446 string LookupIdentifier = MemberName.MakeName (Name, targs);
7448 Namespace ns = expr_resolved as Namespace;
7449 if (ns != null) {
7450 FullNamedExpression retval = ns.Lookup (ec.Compiler, LookupIdentifier, loc);
7452 if (retval == null)
7453 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, ec);
7454 else if (targs != null)
7455 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7457 return retval;
7460 Type expr_type = expr_resolved.Type;
7461 if (TypeManager.IsDynamicType (expr_type)) {
7462 Arguments args = new Arguments (1);
7463 args.Add (new Argument (expr_resolved.Resolve (ec)));
7464 expr = new DynamicMemberBinder (Name, args, loc);
7465 if (right_side != null)
7466 return expr.DoResolveLValue (ec, right_side);
7468 return expr.Resolve (ec);
7471 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7472 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7473 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7474 return null;
7477 Constant c = expr_resolved as Constant;
7478 if (c != null && c.GetValue () == null) {
7479 ec.Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7480 "System.NullReferenceException");
7483 if (targs != null) {
7484 if (!targs.Resolve (ec))
7485 return null;
7488 Expression member_lookup;
7489 member_lookup = MemberLookup (ec.Compiler,
7490 ec.CurrentType, expr_type, expr_type, Name, loc);
7492 if (member_lookup == null && targs != null) {
7493 member_lookup = MemberLookup (ec.Compiler,
7494 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7497 if (member_lookup == null) {
7498 ExprClass expr_eclass = expr_resolved.eclass;
7501 // Extension methods are not allowed on all expression types
7503 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7504 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7505 expr_eclass == ExprClass.EventAccess) {
7506 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7507 if (ex_method_lookup != null) {
7508 ex_method_lookup.ExtensionExpression = expr_resolved;
7510 if (targs != null) {
7511 ex_method_lookup.SetTypeArguments (ec, targs);
7514 return ex_method_lookup.Resolve (ec);
7518 expr = expr_resolved;
7519 member_lookup = Error_MemberLookupFailed (ec,
7520 ec.CurrentType, expr_type, expr_type, Name, null,
7521 AllMemberTypes, AllBindingFlags);
7522 if (member_lookup == null)
7523 return null;
7526 TypeExpr texpr = member_lookup as TypeExpr;
7527 if (texpr != null) {
7528 if (!(expr_resolved is TypeExpr) &&
7529 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7530 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7531 Name, member_lookup.GetSignatureForError ());
7532 return null;
7535 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7536 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7537 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7538 return null;
7541 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7542 if (ct != null) {
7544 // When looking up a nested type in a generic instance
7545 // via reflection, we always get a generic type definition
7546 // and not a generic instance - so we have to do this here.
7548 // See gtest-172-lib.cs and gtest-172.cs for an example.
7551 TypeArguments nested_targs;
7552 if (HasTypeArguments) {
7553 nested_targs = ct.TypeArguments.Clone ();
7554 nested_targs.Add (targs);
7555 } else {
7556 nested_targs = ct.TypeArguments;
7559 ct = new GenericTypeExpr (member_lookup.Type, nested_targs, loc);
7561 return ct.ResolveAsTypeStep (ec, false);
7564 return member_lookup;
7567 MemberExpr me = (MemberExpr) member_lookup;
7568 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7569 if (me == null)
7570 return null;
7572 if (targs != null) {
7573 me.SetTypeArguments (ec, targs);
7576 if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7577 if (me.IsInstance) {
7578 LocalVariableReference var = expr_resolved as LocalVariableReference;
7579 if (var != null && !var.VerifyAssigned (ec))
7580 return null;
7584 // The following DoResolve/DoResolveLValue will do the definite assignment
7585 // check.
7587 if (right_side != null)
7588 return me.DoResolveLValue (ec, right_side);
7589 else
7590 return me.Resolve (ec);
7593 protected override Expression DoResolve (ResolveContext ec)
7595 return DoResolve (ec, null);
7598 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7600 return DoResolve (ec, right_side);
7603 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7605 return ResolveNamespaceOrType (ec, silent);
7608 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7610 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7612 if (expr_resolved == null)
7613 return null;
7615 string LookupIdentifier = MemberName.MakeName (Name, targs);
7617 Namespace ns = expr_resolved as Namespace;
7618 if (ns != null) {
7619 FullNamedExpression retval = ns.Lookup (rc.Compiler, LookupIdentifier, loc);
7621 if (retval == null && !silent)
7622 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, rc);
7623 else if (targs != null)
7624 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7626 return retval;
7629 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7630 if (tnew_expr == null)
7631 return null;
7633 Type expr_type = tnew_expr.Type;
7634 if (TypeManager.IsGenericParameter (expr_type)) {
7635 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7636 tnew_expr.GetSignatureForError ());
7637 return null;
7640 Expression member_lookup = MemberLookup (rc.Compiler,
7641 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7642 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7643 if (member_lookup == null) {
7644 if (silent)
7645 return null;
7647 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7648 return null;
7651 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7652 if (texpr == null)
7653 return null;
7655 TypeArguments the_args = targs;
7656 Type declaring_type = texpr.Type.DeclaringType;
7657 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7658 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7659 expr_type = expr_type.BaseType;
7662 TypeArguments new_args = new TypeArguments ();
7663 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7664 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7666 if (targs != null)
7667 new_args.Add (targs);
7669 the_args = new_args;
7672 if (the_args != null) {
7673 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7674 return ctype.ResolveAsTypeStep (rc, false);
7677 return texpr;
7680 protected virtual void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7682 Expression member_lookup = MemberLookup (rc.Compiler,
7683 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7684 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7686 if (member_lookup != null) {
7687 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7688 if (expr_type == null)
7689 return;
7691 expr_type.Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, loc);
7692 return;
7695 member_lookup = MemberLookup (rc.Compiler,
7696 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7697 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7699 if (member_lookup == null) {
7700 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7701 Name, expr_type.GetSignatureForError ());
7702 } else {
7703 // TODO: Report.SymbolRelatedToPreviousError
7704 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7708 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
7710 if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
7711 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7712 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7713 "extension method `{1}' of type `{0}' could be found " +
7714 "(are you missing a using directive or an assembly reference?)",
7715 TypeManager.CSharpName (type), name);
7716 return;
7719 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7722 public override string GetSignatureForError ()
7724 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7727 public Expression Left {
7728 get {
7729 return expr;
7733 protected override void CloneTo (CloneContext clonectx, Expression t)
7735 MemberAccess target = (MemberAccess) t;
7737 target.expr = expr.Clone (clonectx);
7741 /// <summary>
7742 /// Implements checked expressions
7743 /// </summary>
7744 public class CheckedExpr : Expression {
7746 public Expression Expr;
7748 public CheckedExpr (Expression e, Location l)
7750 Expr = e;
7751 loc = l;
7754 public override Expression CreateExpressionTree (ResolveContext ec)
7756 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7757 return Expr.CreateExpressionTree (ec);
7760 protected override Expression DoResolve (ResolveContext ec)
7762 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7763 Expr = Expr.Resolve (ec);
7765 if (Expr == null)
7766 return null;
7768 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7769 return Expr;
7771 eclass = Expr.eclass;
7772 type = Expr.Type;
7773 return this;
7776 public override void Emit (EmitContext ec)
7778 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7779 Expr.Emit (ec);
7782 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7784 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7785 Expr.EmitBranchable (ec, target, on_true);
7788 public override SLE.Expression MakeExpression (BuilderContext ctx)
7790 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7791 return Expr.MakeExpression (ctx);
7795 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7797 Expr.MutateHoistedGenericType (storey);
7800 protected override void CloneTo (CloneContext clonectx, Expression t)
7802 CheckedExpr target = (CheckedExpr) t;
7804 target.Expr = Expr.Clone (clonectx);
7808 /// <summary>
7809 /// Implements the unchecked expression
7810 /// </summary>
7811 public class UnCheckedExpr : Expression {
7813 public Expression Expr;
7815 public UnCheckedExpr (Expression e, Location l)
7817 Expr = e;
7818 loc = l;
7821 public override Expression CreateExpressionTree (ResolveContext ec)
7823 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7824 return Expr.CreateExpressionTree (ec);
7827 protected override Expression DoResolve (ResolveContext ec)
7829 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7830 Expr = Expr.Resolve (ec);
7832 if (Expr == null)
7833 return null;
7835 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7836 return Expr;
7838 eclass = Expr.eclass;
7839 type = Expr.Type;
7840 return this;
7843 public override void Emit (EmitContext ec)
7845 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7846 Expr.Emit (ec);
7849 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7851 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7852 Expr.EmitBranchable (ec, target, on_true);
7855 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7857 Expr.MutateHoistedGenericType (storey);
7860 protected override void CloneTo (CloneContext clonectx, Expression t)
7862 UnCheckedExpr target = (UnCheckedExpr) t;
7864 target.Expr = Expr.Clone (clonectx);
7868 /// <summary>
7869 /// An Element Access expression.
7871 /// During semantic analysis these are transformed into
7872 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7873 /// </summary>
7874 public class ElementAccess : Expression {
7875 public Arguments Arguments;
7876 public Expression Expr;
7878 public ElementAccess (Expression e, Arguments args)
7880 Expr = e;
7881 loc = e.Location;
7882 this.Arguments = args;
7885 public override Expression CreateExpressionTree (ResolveContext ec)
7887 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7888 Expr.CreateExpressionTree (ec));
7890 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7893 Expression MakePointerAccess (ResolveContext ec, Type t)
7895 if (Arguments.Count != 1){
7896 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7897 return null;
7900 if (Arguments [0] is NamedArgument)
7901 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7903 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7904 return new Indirection (p, loc).Resolve (ec);
7907 protected override Expression DoResolve (ResolveContext ec)
7909 Expr = Expr.Resolve (ec);
7910 if (Expr == null)
7911 return null;
7914 // We perform some simple tests, and then to "split" the emit and store
7915 // code we create an instance of a different class, and return that.
7917 // I am experimenting with this pattern.
7919 Type t = Expr.Type;
7921 if (t == TypeManager.array_type){
7922 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7923 return null;
7926 if (t.IsArray)
7927 return (new ArrayAccess (this, loc)).Resolve (ec);
7928 if (t.IsPointer)
7929 return MakePointerAccess (ec, t);
7931 FieldExpr fe = Expr as FieldExpr;
7932 if (fe != null) {
7933 var ff = fe.Spec as FixedFieldSpec;
7934 if (ff != null) {
7935 return MakePointerAccess (ec, ff.ElementType);
7938 return (new IndexerAccess (this, loc)).Resolve (ec);
7941 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7943 Expr = Expr.Resolve (ec);
7944 if (Expr == null)
7945 return null;
7947 type = Expr.Type;
7948 if (type.IsArray)
7949 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7951 if (type.IsPointer)
7952 return MakePointerAccess (ec, type);
7954 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7955 Error_CannotModifyIntermediateExpressionValue (ec);
7957 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7960 public override void Emit (EmitContext ec)
7962 throw new Exception ("Should never be reached");
7965 public static void Error_NamedArgument (NamedArgument na, Report Report)
7967 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
7970 public override string GetSignatureForError ()
7972 return Expr.GetSignatureForError ();
7975 protected override void CloneTo (CloneContext clonectx, Expression t)
7977 ElementAccess target = (ElementAccess) t;
7979 target.Expr = Expr.Clone (clonectx);
7980 if (Arguments != null)
7981 target.Arguments = Arguments.Clone (clonectx);
7985 /// <summary>
7986 /// Implements array access
7987 /// </summary>
7988 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
7990 // Points to our "data" repository
7992 ElementAccess ea;
7994 LocalTemporary temp;
7996 bool prepared;
7998 public ArrayAccess (ElementAccess ea_data, Location l)
8000 ea = ea_data;
8001 loc = l;
8004 public override Expression CreateExpressionTree (ResolveContext ec)
8006 return ea.CreateExpressionTree (ec);
8009 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8011 return DoResolve (ec);
8014 protected override Expression DoResolve (ResolveContext ec)
8016 // dynamic is used per argument in ConvertExpressionToArrayIndex case
8017 bool dynamic;
8018 ea.Arguments.Resolve (ec, out dynamic);
8020 Type t = ea.Expr.Type;
8021 int rank = ea.Arguments.Count;
8022 if (t.GetArrayRank () != rank) {
8023 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8024 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
8025 return null;
8028 type = TypeManager.GetElementType (t);
8029 if (type.IsPointer && !ec.IsUnsafe) {
8030 UnsafeError (ec, ea.Location);
8033 foreach (Argument a in ea.Arguments) {
8034 if (a is NamedArgument)
8035 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
8037 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
8040 eclass = ExprClass.Variable;
8042 return this;
8045 /// <summary>
8046 /// Emits the right opcode to load an object of Type `t'
8047 /// from an array of T
8048 /// </summary>
8049 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
8051 if (rank > 1) {
8052 MethodInfo get = FetchGetMethod ();
8053 ig.Emit (OpCodes.Call, get);
8054 return;
8057 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8058 ig.Emit (OpCodes.Ldelem_U1);
8059 else if (type == TypeManager.sbyte_type)
8060 ig.Emit (OpCodes.Ldelem_I1);
8061 else if (type == TypeManager.short_type)
8062 ig.Emit (OpCodes.Ldelem_I2);
8063 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8064 ig.Emit (OpCodes.Ldelem_U2);
8065 else if (type == TypeManager.int32_type)
8066 ig.Emit (OpCodes.Ldelem_I4);
8067 else if (type == TypeManager.uint32_type)
8068 ig.Emit (OpCodes.Ldelem_U4);
8069 else if (type == TypeManager.uint64_type)
8070 ig.Emit (OpCodes.Ldelem_I8);
8071 else if (type == TypeManager.int64_type)
8072 ig.Emit (OpCodes.Ldelem_I8);
8073 else if (type == TypeManager.float_type)
8074 ig.Emit (OpCodes.Ldelem_R4);
8075 else if (type == TypeManager.double_type)
8076 ig.Emit (OpCodes.Ldelem_R8);
8077 else if (type == TypeManager.intptr_type)
8078 ig.Emit (OpCodes.Ldelem_I);
8079 else if (TypeManager.IsEnumType (type)){
8080 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8081 } else if (TypeManager.IsStruct (type)){
8082 ig.Emit (OpCodes.Ldelema, type);
8083 ig.Emit (OpCodes.Ldobj, type);
8084 } else if (type.IsGenericParameter) {
8085 ig.Emit (OpCodes.Ldelem, type);
8086 } else if (type.IsPointer)
8087 ig.Emit (OpCodes.Ldelem_I);
8088 else
8089 ig.Emit (OpCodes.Ldelem_Ref);
8092 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8094 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8097 /// <summary>
8098 /// Returns the right opcode to store an object of Type `t'
8099 /// from an array of T.
8100 /// </summary>
8101 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8103 has_type_arg = false; is_stobj = false;
8104 t = TypeManager.TypeToCoreType (t);
8105 if (TypeManager.IsEnumType (t))
8106 t = TypeManager.GetEnumUnderlyingType (t);
8107 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8108 t == TypeManager.bool_type)
8109 return OpCodes.Stelem_I1;
8110 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8111 t == TypeManager.char_type)
8112 return OpCodes.Stelem_I2;
8113 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8114 return OpCodes.Stelem_I4;
8115 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8116 return OpCodes.Stelem_I8;
8117 else if (t == TypeManager.float_type)
8118 return OpCodes.Stelem_R4;
8119 else if (t == TypeManager.double_type)
8120 return OpCodes.Stelem_R8;
8121 else if (t == TypeManager.intptr_type) {
8122 has_type_arg = true;
8123 is_stobj = true;
8124 return OpCodes.Stobj;
8125 } else if (TypeManager.IsStruct (t)) {
8126 has_type_arg = true;
8127 is_stobj = true;
8128 return OpCodes.Stobj;
8129 } else if (t.IsGenericParameter) {
8130 has_type_arg = true;
8131 return OpCodes.Stelem;
8132 } else if (t.IsPointer)
8133 return OpCodes.Stelem_I;
8134 else
8135 return OpCodes.Stelem_Ref;
8138 MethodInfo FetchGetMethod ()
8140 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8141 int arg_count = ea.Arguments.Count;
8142 Type [] args = new Type [arg_count];
8143 MethodInfo get;
8145 for (int i = 0; i < arg_count; i++){
8146 //args [i++] = a.Type;
8147 args [i] = TypeManager.int32_type;
8150 get = mb.GetArrayMethod (
8151 ea.Expr.Type, "Get",
8152 CallingConventions.HasThis |
8153 CallingConventions.Standard,
8154 type, args);
8155 return get;
8159 MethodInfo FetchAddressMethod ()
8161 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8162 int arg_count = ea.Arguments.Count;
8163 Type [] args = new Type [arg_count];
8164 MethodInfo address;
8165 Type ret_type;
8167 ret_type = TypeManager.GetReferenceType (type);
8169 for (int i = 0; i < arg_count; i++){
8170 //args [i++] = a.Type;
8171 args [i] = TypeManager.int32_type;
8174 address = mb.GetArrayMethod (
8175 ea.Expr.Type, "Address",
8176 CallingConventions.HasThis |
8177 CallingConventions.Standard,
8178 ret_type, args);
8180 return address;
8184 // Load the array arguments into the stack.
8186 void LoadArrayAndArguments (EmitContext ec)
8188 ea.Expr.Emit (ec);
8190 for (int i = 0; i < ea.Arguments.Count; ++i) {
8191 ea.Arguments [i].Emit (ec);
8195 public void Emit (EmitContext ec, bool leave_copy)
8197 int rank = ea.Expr.Type.GetArrayRank ();
8198 ILGenerator ig = ec.ig;
8200 if (prepared) {
8201 LoadFromPtr (ig, this.type);
8202 } else {
8203 LoadArrayAndArguments (ec);
8204 EmitLoadOpcode (ig, type, rank);
8207 if (leave_copy) {
8208 ig.Emit (OpCodes.Dup);
8209 temp = new LocalTemporary (this.type);
8210 temp.Store (ec);
8214 public override void Emit (EmitContext ec)
8216 Emit (ec, false);
8219 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8221 int rank = ea.Expr.Type.GetArrayRank ();
8222 ILGenerator ig = ec.ig;
8223 Type t = source.Type;
8224 prepared = prepare_for_load;
8226 if (prepared) {
8227 AddressOf (ec, AddressOp.LoadStore);
8228 ec.ig.Emit (OpCodes.Dup);
8229 } else {
8230 LoadArrayAndArguments (ec);
8233 if (rank == 1) {
8234 bool is_stobj, has_type_arg;
8235 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8237 if (!prepared) {
8239 // The stobj opcode used by value types will need
8240 // an address on the stack, not really an array/array
8241 // pair
8243 if (is_stobj)
8244 ig.Emit (OpCodes.Ldelema, t);
8247 source.Emit (ec);
8248 if (leave_copy) {
8249 ec.ig.Emit (OpCodes.Dup);
8250 temp = new LocalTemporary (this.type);
8251 temp.Store (ec);
8254 if (prepared)
8255 StoreFromPtr (ig, t);
8256 else if (is_stobj)
8257 ig.Emit (OpCodes.Stobj, t);
8258 else if (has_type_arg)
8259 ig.Emit (op, t);
8260 else
8261 ig.Emit (op);
8262 } else {
8263 source.Emit (ec);
8264 if (leave_copy) {
8265 ec.ig.Emit (OpCodes.Dup);
8266 temp = new LocalTemporary (this.type);
8267 temp.Store (ec);
8270 if (prepared) {
8271 StoreFromPtr (ig, t);
8272 } else {
8273 int arg_count = ea.Arguments.Count;
8274 Type [] args = new Type [arg_count + 1];
8275 for (int i = 0; i < arg_count; i++) {
8276 //args [i++] = a.Type;
8277 args [i] = TypeManager.int32_type;
8279 args [arg_count] = type;
8281 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8282 ea.Expr.Type, "Set",
8283 CallingConventions.HasThis |
8284 CallingConventions.Standard,
8285 TypeManager.void_type, args);
8287 ig.Emit (OpCodes.Call, set);
8291 if (temp != null) {
8292 temp.Emit (ec);
8293 temp.Release (ec);
8297 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8299 if (!source.Emit (ec, this)) {
8300 if (leave_copy)
8301 throw new NotImplementedException ();
8303 return;
8306 throw new NotImplementedException ();
8309 public void AddressOf (EmitContext ec, AddressOp mode)
8311 int rank = ea.Expr.Type.GetArrayRank ();
8312 ILGenerator ig = ec.ig;
8314 LoadArrayAndArguments (ec);
8316 if (rank == 1){
8317 ig.Emit (OpCodes.Ldelema, type);
8318 } else {
8319 MethodInfo address = FetchAddressMethod ();
8320 ig.Emit (OpCodes.Call, address);
8324 #if NET_4_0
8325 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8327 return SLE.Expression.ArrayAccess (
8328 ea.Expr.MakeExpression (ctx),
8329 Arguments.MakeExpression (ea.Arguments, ctx));
8331 #endif
8333 public override SLE.Expression MakeExpression (BuilderContext ctx)
8335 return SLE.Expression.ArrayIndex (
8336 ea.Expr.MakeExpression (ctx),
8337 Arguments.MakeExpression (ea.Arguments, ctx));
8340 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8342 type = storey.MutateType (type);
8343 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8347 /// <summary>
8348 /// Expressions that represent an indexer call.
8349 /// </summary>
8350 public class IndexerAccess : Expression, IDynamicAssign
8352 class IndexerMethodGroupExpr : MethodGroupExpr
8354 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8355 : base (null, loc)
8357 Methods = indexers.Methods.ToArray ();
8360 public override string Name {
8361 get {
8362 return "this";
8366 protected override int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
8369 // Here is the trick, decrease number of arguments by 1 when only
8370 // available property method is setter. This makes overload resolution
8371 // work correctly for indexers.
8374 if (method.Name [0] == 'g')
8375 return parameters.Count;
8377 return parameters.Count - 1;
8381 class Indexers
8383 // Contains either property getter or setter
8384 public List<MethodSpec> Methods;
8385 public List<PropertyInfo> Properties;
8387 Indexers ()
8391 void Append (Type caller_type, MemberInfo [] mi)
8393 if (mi == null)
8394 return;
8396 foreach (PropertyInfo property in mi) {
8397 MethodInfo accessor = property.GetGetMethod (true);
8398 if (accessor == null)
8399 accessor = property.GetSetMethod (true);
8401 if (Methods == null) {
8402 Methods = new List<MethodSpec> ();
8403 Properties = new List<PropertyInfo> ();
8406 Methods.Add (Import.CreateMethod (accessor));
8407 Properties.Add (property);
8411 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8413 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8415 return TypeManager.MemberLookup (
8416 caller_type, caller_type, lookup_type, MemberTypes.Property,
8417 BindingFlags.Public | BindingFlags.Instance |
8418 BindingFlags.DeclaredOnly, p_name, null);
8421 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8423 Indexers ix = new Indexers ();
8425 if (TypeManager.IsGenericParameter (lookup_type)) {
8426 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8427 if (gc == null)
8428 return ix;
8430 if (gc.HasClassConstraint) {
8431 Type class_contraint = gc.ClassConstraint;
8432 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8433 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8434 class_contraint = class_contraint.BaseType;
8438 Type[] ifaces = gc.InterfaceConstraints;
8439 foreach (Type itype in ifaces)
8440 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8442 return ix;
8445 Type copy = lookup_type;
8446 while (copy != TypeManager.object_type && copy != null){
8447 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8448 copy = copy.BaseType;
8451 if (lookup_type.IsInterface) {
8452 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8453 if (ifaces != null) {
8454 foreach (Type itype in ifaces)
8455 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8459 return ix;
8464 // Points to our "data" repository
8466 MethodSpec get, set;
8467 bool is_base_indexer;
8468 bool prepared;
8469 LocalTemporary temp;
8470 LocalTemporary prepared_value;
8471 Expression set_expr;
8473 protected Type indexer_type;
8474 protected Type current_type;
8475 protected Expression instance_expr;
8476 protected Arguments arguments;
8478 public IndexerAccess (ElementAccess ea, Location loc)
8479 : this (ea.Expr, false, loc)
8481 this.arguments = ea.Arguments;
8484 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8485 Location loc)
8487 this.instance_expr = instance_expr;
8488 this.is_base_indexer = is_base_indexer;
8489 this.loc = loc;
8492 static string GetAccessorName (bool isSet)
8494 return isSet ? "set" : "get";
8497 public override Expression CreateExpressionTree (ResolveContext ec)
8499 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8500 instance_expr.CreateExpressionTree (ec),
8501 new TypeOfMethod (get, loc));
8503 return CreateExpressionFactoryCall (ec, "Call", args);
8506 protected virtual void CommonResolve (ResolveContext ec)
8508 indexer_type = instance_expr.Type;
8509 current_type = ec.CurrentType;
8512 protected override Expression DoResolve (ResolveContext ec)
8514 return ResolveAccessor (ec, null);
8517 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8519 if (right_side == EmptyExpression.OutAccess.Instance) {
8520 right_side.DoResolveLValue (ec, this);
8521 return null;
8524 // if the indexer returns a value type, and we try to set a field in it
8525 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8526 Error_CannotModifyIntermediateExpressionValue (ec);
8529 return ResolveAccessor (ec, right_side);
8532 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8534 CommonResolve (ec);
8536 MethodGroupExpr mg;
8537 Indexers ilist;
8538 bool dynamic;
8540 arguments.Resolve (ec, out dynamic);
8542 if (TypeManager.IsDynamicType (indexer_type)) {
8543 dynamic = true;
8544 mg = null;
8545 ilist = null;
8546 } else {
8547 ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8548 if (ilist.Methods == null) {
8549 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8550 TypeManager.CSharpName (indexer_type));
8551 return null;
8554 mg = new IndexerMethodGroupExpr (ilist, loc);
8555 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8556 if (mg == null)
8557 return null;
8560 if (dynamic) {
8561 Arguments args = new Arguments (arguments.Count + 1);
8562 if (is_base_indexer) {
8563 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8564 } else {
8565 args.Add (new Argument (instance_expr));
8567 args.AddRange (arguments);
8569 var expr = new DynamicIndexBinder (args, loc);
8570 if (right_side != null)
8571 return expr.ResolveLValue (ec, right_side);
8573 return expr.Resolve (ec);
8576 var mi = (MethodSpec) mg;
8577 PropertyInfo pi = null;
8578 for (int i = 0; i < ilist.Methods.Count; ++i) {
8579 if (ilist.Methods [i].MetaInfo == mi.MetaInfo) {
8580 pi = (PropertyInfo) ilist.Properties [i];
8581 break;
8585 type = TypeManager.TypeToCoreType (pi.PropertyType);
8586 if (type.IsPointer && !ec.IsUnsafe)
8587 UnsafeError (ec, loc);
8589 MethodSpec accessor = null;
8590 if (right_side == null) {
8591 var m = pi.GetGetMethod (true);
8592 if (m != null)
8593 accessor = get = Import.CreateMethod (m);
8594 } else {
8595 var m = pi.GetSetMethod (true);
8596 if (m != null)
8597 accessor = set = Import.CreateMethod (m);
8598 if (accessor == null && pi.GetGetMethod (true) != null) {
8599 ec.Report.SymbolRelatedToPreviousError (pi);
8600 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8601 TypeManager.GetFullNameSignature (pi));
8602 return null;
8605 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8608 if (accessor == null) {
8609 ec.Report.SymbolRelatedToPreviousError (pi);
8610 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8611 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8612 return null;
8616 // Only base will allow this invocation to happen.
8618 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8619 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (pi));
8622 bool must_do_cs1540_check;
8623 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8624 if (set == null) {
8625 var m = pi.GetSetMethod (true);
8626 if (m != null)
8627 set = Import.CreateMethod (m);
8628 } else {
8629 var m = pi.GetGetMethod (true);
8630 if (m != null)
8631 get = Import.CreateMethod (m);
8634 if (set != null && get != null &&
8635 (set.MetaInfo.Attributes & MethodAttributes.MemberAccessMask) != (get.MetaInfo.Attributes & MethodAttributes.MemberAccessMask)) {
8636 ec.Report.SymbolRelatedToPreviousError (accessor.MetaInfo);
8637 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8638 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8639 } else {
8640 ec.Report.SymbolRelatedToPreviousError (pi);
8641 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi), ec.Report);
8645 instance_expr.CheckMarshalByRefAccess (ec);
8647 if (must_do_cs1540_check && (instance_expr != EmptyExpression.Null) &&
8648 !TypeManager.IsInstantiationOfSameGenericType (instance_expr.Type, ec.CurrentType) &&
8649 !TypeManager.IsNestedChildOf (ec.CurrentType, instance_expr.Type) &&
8650 !TypeManager.IsSubclassOf (instance_expr.Type, ec.CurrentType)) {
8651 ec.Report.SymbolRelatedToPreviousError (accessor.MetaInfo);
8652 Error_CannotAccessProtected (ec, loc, accessor.MetaInfo, instance_expr.Type, ec.CurrentType);
8653 return null;
8656 eclass = ExprClass.IndexerAccess;
8657 return this;
8660 public override void Emit (EmitContext ec)
8662 Emit (ec, false);
8665 public void Emit (EmitContext ec, bool leave_copy)
8667 if (prepared) {
8668 prepared_value.Emit (ec);
8669 } else {
8670 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8671 arguments, loc, false, false);
8674 if (leave_copy) {
8675 ec.ig.Emit (OpCodes.Dup);
8676 temp = new LocalTemporary (Type);
8677 temp.Store (ec);
8682 // source is ignored, because we already have a copy of it from the
8683 // LValue resolution and we have already constructed a pre-cached
8684 // version of the arguments (ea.set_arguments);
8686 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8688 prepared = prepare_for_load;
8689 Expression value = set_expr;
8691 if (prepared) {
8692 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8693 arguments, loc, true, false);
8695 prepared_value = new LocalTemporary (type);
8696 prepared_value.Store (ec);
8697 source.Emit (ec);
8698 prepared_value.Release (ec);
8700 if (leave_copy) {
8701 ec.ig.Emit (OpCodes.Dup);
8702 temp = new LocalTemporary (Type);
8703 temp.Store (ec);
8705 } else if (leave_copy) {
8706 temp = new LocalTemporary (Type);
8707 source.Emit (ec);
8708 temp.Store (ec);
8709 value = temp;
8712 if (!prepared)
8713 arguments.Add (new Argument (value));
8715 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8717 if (temp != null) {
8718 temp.Emit (ec);
8719 temp.Release (ec);
8723 public override string GetSignatureForError ()
8725 return TypeManager.CSharpSignature (get != null ? get.MetaInfo : set.MetaInfo, false);
8728 #if NET_4_0
8729 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8731 var value = new[] { set_expr.MakeExpression (ctx) };
8732 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8734 return SLE.Expression.Block (
8735 SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) set.MetaInfo, args),
8736 value [0]);
8738 #endif
8740 public override SLE.Expression MakeExpression (BuilderContext ctx)
8742 var args = Arguments.MakeExpression (arguments, ctx);
8743 return SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) get.MetaInfo, args);
8746 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8748 if (get != null)
8749 storey.MutateGenericMethod (get);
8750 if (set != null)
8751 storey.MutateGenericMethod (set);
8753 instance_expr.MutateHoistedGenericType (storey);
8754 if (arguments != null)
8755 arguments.MutateHoistedGenericType (storey);
8757 type = storey.MutateType (type);
8760 protected override void CloneTo (CloneContext clonectx, Expression t)
8762 IndexerAccess target = (IndexerAccess) t;
8764 if (arguments != null)
8765 target.arguments = arguments.Clone (clonectx);
8767 if (instance_expr != null)
8768 target.instance_expr = instance_expr.Clone (clonectx);
8772 /// <summary>
8773 /// The base operator for method names
8774 /// </summary>
8775 public class BaseAccess : Expression {
8776 public readonly string Identifier;
8777 TypeArguments args;
8779 public BaseAccess (string member, Location l)
8781 this.Identifier = member;
8782 loc = l;
8785 public BaseAccess (string member, TypeArguments args, Location l)
8786 : this (member, l)
8788 this.args = args;
8791 public override Expression CreateExpressionTree (ResolveContext ec)
8793 throw new NotSupportedException ("ET");
8796 protected override Expression DoResolve (ResolveContext ec)
8798 Expression c = CommonResolve (ec);
8800 if (c == null)
8801 return null;
8804 // MethodGroups use this opportunity to flag an error on lacking ()
8806 if (!(c is MethodGroupExpr))
8807 return c.Resolve (ec);
8808 return c;
8811 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8813 Expression c = CommonResolve (ec);
8815 if (c == null)
8816 return null;
8819 // MethodGroups use this opportunity to flag an error on lacking ()
8821 if (! (c is MethodGroupExpr))
8822 return c.DoResolveLValue (ec, right_side);
8824 return c;
8827 Expression CommonResolve (ResolveContext ec)
8829 Expression member_lookup;
8830 Type current_type = ec.CurrentType;
8831 Type base_type = current_type.BaseType;
8833 if (!This.IsThisAvailable (ec)) {
8834 if (ec.IsStatic) {
8835 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8836 } else {
8837 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8839 return null;
8842 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier,
8843 AllMemberTypes, AllBindingFlags, loc);
8844 if (member_lookup == null) {
8845 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier,
8846 null, AllMemberTypes, AllBindingFlags);
8847 return null;
8850 Expression left;
8852 if (ec.IsStatic)
8853 left = new TypeExpression (base_type, loc);
8854 else
8855 left = ec.GetThis (loc);
8857 MemberExpr me = member_lookup as MemberExpr;
8858 if (me == null){
8859 if (member_lookup is TypeExpression){
8860 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8861 Identifier, member_lookup.GetSignatureForError ());
8862 } else {
8863 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8864 Identifier, member_lookup.ExprClassName);
8867 return null;
8870 me = me.ResolveMemberAccess (ec, left, loc, null);
8871 if (me == null)
8872 return null;
8874 me.IsBase = true;
8875 if (args != null) {
8876 args.Resolve (ec);
8877 me.SetTypeArguments (ec, args);
8880 return me;
8883 public override void Emit (EmitContext ec)
8885 throw new Exception ("Should never be called");
8888 protected override void CloneTo (CloneContext clonectx, Expression t)
8890 BaseAccess target = (BaseAccess) t;
8892 if (args != null)
8893 target.args = args.Clone ();
8897 /// <summary>
8898 /// The base indexer operator
8899 /// </summary>
8900 public class BaseIndexerAccess : IndexerAccess {
8901 public BaseIndexerAccess (Arguments args, Location loc)
8902 : base (null, true, loc)
8904 this.arguments = args;
8907 protected override void CommonResolve (ResolveContext ec)
8909 instance_expr = ec.GetThis (loc);
8911 current_type = ec.CurrentType.BaseType;
8912 indexer_type = current_type;
8915 public override Expression CreateExpressionTree (ResolveContext ec)
8917 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8918 return base.CreateExpressionTree (ec);
8922 /// <summary>
8923 /// This class exists solely to pass the Type around and to be a dummy
8924 /// that can be passed to the conversion functions (this is used by
8925 /// foreach implementation to typecast the object return value from
8926 /// get_Current into the proper type. All code has been generated and
8927 /// we only care about the side effect conversions to be performed
8929 /// This is also now used as a placeholder where a no-action expression
8930 /// is needed (the `New' class).
8931 /// </summary>
8932 public class EmptyExpression : Expression {
8933 public static readonly Expression Null = new EmptyExpression ();
8935 public class OutAccess : EmptyExpression
8937 public static readonly OutAccess Instance = new OutAccess ();
8939 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8941 rc.Report.Error (206, right_side.Location,
8942 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8944 return null;
8948 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8949 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8950 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8952 static EmptyExpression temp = new EmptyExpression ();
8953 public static EmptyExpression Grab ()
8955 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8956 temp = null;
8957 return retval;
8960 public static void Release (EmptyExpression e)
8962 temp = e;
8965 EmptyExpression ()
8967 // FIXME: Don't set to object
8968 type = TypeManager.object_type;
8969 eclass = ExprClass.Value;
8970 loc = Location.Null;
8973 public EmptyExpression (Type t)
8975 type = t;
8976 eclass = ExprClass.Value;
8977 loc = Location.Null;
8980 public override Expression CreateExpressionTree (ResolveContext ec)
8982 throw new NotSupportedException ("ET");
8985 protected override Expression DoResolve (ResolveContext ec)
8987 return this;
8990 public override void Emit (EmitContext ec)
8992 // nothing, as we only exist to not do anything.
8995 public override void EmitSideEffect (EmitContext ec)
9000 // This is just because we might want to reuse this bad boy
9001 // instead of creating gazillions of EmptyExpressions.
9002 // (CanImplicitConversion uses it)
9004 public void SetType (Type t)
9006 type = t;
9011 // Empty statement expression
9013 public sealed class EmptyExpressionStatement : ExpressionStatement
9015 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
9017 private EmptyExpressionStatement ()
9019 loc = Location.Null;
9022 public override Expression CreateExpressionTree (ResolveContext ec)
9024 return null;
9027 public override void EmitStatement (EmitContext ec)
9029 // Do nothing
9032 protected override Expression DoResolve (ResolveContext ec)
9034 eclass = ExprClass.Value;
9035 type = TypeManager.object_type;
9036 return this;
9039 public override void Emit (EmitContext ec)
9041 // Do nothing
9045 public class UserCast : Expression {
9046 MethodSpec method;
9047 Expression source;
9049 public UserCast (MethodSpec method, Expression source, Location l)
9051 this.method = method;
9052 this.source = source;
9053 type = TypeManager.TypeToCoreType (method.ReturnType);
9054 loc = l;
9057 public Expression Source {
9058 get {
9059 return source;
9063 public override Expression CreateExpressionTree (ResolveContext ec)
9065 Arguments args = new Arguments (3);
9066 args.Add (new Argument (source.CreateExpressionTree (ec)));
9067 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9068 args.Add (new Argument (new TypeOfMethod (method, loc)));
9069 return CreateExpressionFactoryCall (ec, "Convert", args);
9072 protected override Expression DoResolve (ResolveContext ec)
9074 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method.MetaInfo);
9075 if (oa != null)
9076 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9078 eclass = ExprClass.Value;
9079 return this;
9082 public override void Emit (EmitContext ec)
9084 source.Emit (ec);
9085 ec.ig.Emit (OpCodes.Call, (MethodInfo) method.MetaInfo);
9088 public override string GetSignatureForError ()
9090 return TypeManager.CSharpSignature (method.MetaInfo);
9093 public override SLE.Expression MakeExpression (BuilderContext ctx)
9095 return SLE.Expression.Convert (source.MakeExpression (ctx), type, (MethodInfo) method.MetaInfo);
9098 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9100 source.MutateHoistedGenericType (storey);
9101 storey.MutateGenericMethod (method);
9105 // <summary>
9106 // This class is used to "construct" the type during a typecast
9107 // operation. Since the Type.GetType class in .NET can parse
9108 // the type specification, we just use this to construct the type
9109 // one bit at a time.
9110 // </summary>
9111 public class ComposedCast : TypeExpr {
9112 FullNamedExpression left;
9113 string dim;
9115 public ComposedCast (FullNamedExpression left, string dim)
9116 : this (left, dim, left.Location)
9120 public ComposedCast (FullNamedExpression left, string dim, Location l)
9122 this.left = left;
9123 this.dim = dim;
9124 loc = l;
9127 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
9129 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
9130 if (lexpr == null)
9131 return null;
9133 Type ltype = lexpr.Type;
9134 if ((dim.Length > 0) && (dim [0] == '?')) {
9135 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
9136 if (dim.Length > 1)
9137 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
9138 return nullable.ResolveAsTypeTerminal (ec, false);
9141 if (dim == "*" && !TypeManager.VerifyUnmanaged (ec.Compiler, ltype, loc))
9142 return null;
9144 if (dim.Length != 0 && dim [0] == '[') {
9145 if (TypeManager.IsSpecialType (ltype)) {
9146 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9147 return null;
9150 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9151 ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
9152 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9153 TypeManager.CSharpName (ltype));
9157 if (dim != "")
9158 type = TypeManager.GetConstructedType (ltype, dim);
9159 else
9160 type = ltype;
9162 if (type == null)
9163 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9165 if (type.IsPointer && !ec.IsUnsafe){
9166 UnsafeError (ec.Compiler.Report, loc);
9169 eclass = ExprClass.Type;
9170 return this;
9173 public override string GetSignatureForError ()
9175 return left.GetSignatureForError () + dim;
9178 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
9180 return ResolveAsBaseTerminal (ec, silent);
9184 public class FixedBufferPtr : Expression {
9185 Expression array;
9187 public FixedBufferPtr (Expression array, Type array_type, Location l)
9189 this.array = array;
9190 this.loc = l;
9192 type = TypeManager.GetPointerType (array_type);
9193 eclass = ExprClass.Value;
9196 public override Expression CreateExpressionTree (ResolveContext ec)
9198 Error_PointerInsideExpressionTree (ec);
9199 return null;
9202 public override void Emit(EmitContext ec)
9204 array.Emit (ec);
9207 protected override Expression DoResolve (ResolveContext ec)
9210 // We are born fully resolved
9212 return this;
9218 // This class is used to represent the address of an array, used
9219 // only by the Fixed statement, this generates "&a [0]" construct
9220 // for fixed (char *pa = a)
9222 public class ArrayPtr : FixedBufferPtr {
9223 Type array_type;
9225 public ArrayPtr (Expression array, Type array_type, Location l):
9226 base (array, array_type, l)
9228 this.array_type = array_type;
9231 public override void Emit (EmitContext ec)
9233 base.Emit (ec);
9235 ILGenerator ig = ec.ig;
9236 IntLiteral.EmitInt (ig, 0);
9237 ig.Emit (OpCodes.Ldelema, array_type);
9242 // Encapsulates a conversion rules required for array indexes
9244 public class ArrayIndexCast : TypeCast
9246 public ArrayIndexCast (Expression expr)
9247 : base (expr, TypeManager.int32_type)
9249 if (expr.Type == TypeManager.int32_type)
9250 throw new ArgumentException ("unnecessary array index conversion");
9253 public override Expression CreateExpressionTree (ResolveContext ec)
9255 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9256 return base.CreateExpressionTree (ec);
9260 public override void Emit (EmitContext ec)
9262 child.Emit (ec);
9264 var expr_type = child.Type;
9266 if (expr_type == TypeManager.uint32_type)
9267 ec.ig.Emit (OpCodes.Conv_U);
9268 else if (expr_type == TypeManager.int64_type)
9269 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9270 else if (expr_type == TypeManager.uint64_type)
9271 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9272 else
9273 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9276 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
9278 return child.GetAttributableValue (ec, value_type, out value);
9283 // Implements the `stackalloc' keyword
9285 public class StackAlloc : Expression {
9286 Type otype;
9287 Expression t;
9288 Expression count;
9290 public StackAlloc (Expression type, Expression count, Location l)
9292 t = type;
9293 this.count = count;
9294 loc = l;
9297 public override Expression CreateExpressionTree (ResolveContext ec)
9299 throw new NotSupportedException ("ET");
9302 protected override Expression DoResolve (ResolveContext ec)
9304 count = count.Resolve (ec);
9305 if (count == null)
9306 return null;
9308 if (count.Type != TypeManager.uint32_type){
9309 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9310 if (count == null)
9311 return null;
9314 Constant c = count as Constant;
9315 if (c != null && c.IsNegative) {
9316 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9319 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9320 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9323 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9324 if (texpr == null)
9325 return null;
9327 otype = texpr.Type;
9329 if (!TypeManager.VerifyUnmanaged (ec.Compiler, otype, loc))
9330 return null;
9332 type = TypeManager.GetPointerType (otype);
9333 eclass = ExprClass.Value;
9335 return this;
9338 public override void Emit (EmitContext ec)
9340 int size = GetTypeSize (otype);
9341 ILGenerator ig = ec.ig;
9343 count.Emit (ec);
9345 if (size == 0)
9346 ig.Emit (OpCodes.Sizeof, otype);
9347 else
9348 IntConstant.EmitInt (ig, size);
9350 ig.Emit (OpCodes.Mul_Ovf_Un);
9351 ig.Emit (OpCodes.Localloc);
9354 protected override void CloneTo (CloneContext clonectx, Expression t)
9356 StackAlloc target = (StackAlloc) t;
9357 target.count = count.Clone (clonectx);
9358 target.t = t.Clone (clonectx);
9363 // An object initializer expression
9365 public class ElementInitializer : Assign
9367 public readonly string Name;
9369 public ElementInitializer (string name, Expression initializer, Location loc)
9370 : base (null, initializer, loc)
9372 this.Name = name;
9375 protected override void CloneTo (CloneContext clonectx, Expression t)
9377 ElementInitializer target = (ElementInitializer) t;
9378 target.source = source.Clone (clonectx);
9381 public override Expression CreateExpressionTree (ResolveContext ec)
9383 Arguments args = new Arguments (2);
9384 FieldExpr fe = target as FieldExpr;
9385 if (fe != null)
9386 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9387 else
9388 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9390 args.Add (new Argument (source.CreateExpressionTree (ec)));
9391 return CreateExpressionFactoryCall (ec,
9392 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9393 args);
9396 protected override Expression DoResolve (ResolveContext ec)
9398 if (source == null)
9399 return EmptyExpressionStatement.Instance;
9401 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9402 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9404 if (me == null)
9405 return null;
9407 target = me;
9408 me.InstanceExpression = ec.CurrentInitializerVariable;
9410 if (source is CollectionOrObjectInitializers) {
9411 Expression previous = ec.CurrentInitializerVariable;
9412 ec.CurrentInitializerVariable = target;
9413 source = source.Resolve (ec);
9414 ec.CurrentInitializerVariable = previous;
9415 if (source == null)
9416 return null;
9418 eclass = source.eclass;
9419 type = source.Type;
9420 return this;
9423 Expression expr = base.DoResolve (ec);
9424 if (expr == null)
9425 return null;
9428 // Ignore field initializers with default value
9430 Constant c = source as Constant;
9431 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9432 return EmptyExpressionStatement.Instance.Resolve (ec);
9434 return expr;
9437 protected override Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
9439 MemberInfo member = members [0];
9440 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9441 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9442 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9443 else
9444 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9445 TypeManager.GetFullNameSignature (member));
9447 return null;
9450 public override void EmitStatement (EmitContext ec)
9452 if (source is CollectionOrObjectInitializers)
9453 source.Emit (ec);
9454 else
9455 base.EmitStatement (ec);
9460 // A collection initializer expression
9462 class CollectionElementInitializer : Invocation
9464 public class ElementInitializerArgument : Argument
9466 public ElementInitializerArgument (Expression e)
9467 : base (e)
9472 sealed class AddMemberAccess : MemberAccess
9474 public AddMemberAccess (Expression expr, Location loc)
9475 : base (expr, "Add", loc)
9479 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
9481 if (TypeManager.HasElementType (type))
9482 return;
9484 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9488 public CollectionElementInitializer (Expression argument)
9489 : base (null, new Arguments (1))
9491 base.arguments.Add (new ElementInitializerArgument (argument));
9492 this.loc = argument.Location;
9495 public CollectionElementInitializer (List<Expression> arguments, Location loc)
9496 : base (null, new Arguments (arguments.Count))
9498 foreach (Expression e in arguments)
9499 base.arguments.Add (new ElementInitializerArgument (e));
9501 this.loc = loc;
9504 public override Expression CreateExpressionTree (ResolveContext ec)
9506 Arguments args = new Arguments (2);
9507 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9509 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
9510 foreach (Argument a in arguments)
9511 expr_initializers.Add (a.CreateExpressionTree (ec));
9513 args.Add (new Argument (new ArrayCreation (
9514 CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
9515 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9518 protected override void CloneTo (CloneContext clonectx, Expression t)
9520 CollectionElementInitializer target = (CollectionElementInitializer) t;
9521 if (arguments != null)
9522 target.arguments = arguments.Clone (clonectx);
9525 protected override Expression DoResolve (ResolveContext ec)
9527 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9529 return base.DoResolve (ec);
9534 // A block of object or collection initializers
9536 public class CollectionOrObjectInitializers : ExpressionStatement
9538 IList<Expression> initializers;
9539 bool is_collection_initialization;
9541 public static readonly CollectionOrObjectInitializers Empty =
9542 new CollectionOrObjectInitializers (Array.AsReadOnly (new Expression [0]), Location.Null);
9544 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
9546 this.initializers = initializers;
9547 this.loc = loc;
9550 public bool IsEmpty {
9551 get {
9552 return initializers.Count == 0;
9556 public bool IsCollectionInitializer {
9557 get {
9558 return is_collection_initialization;
9562 protected override void CloneTo (CloneContext clonectx, Expression target)
9564 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9566 t.initializers = new List<Expression> (initializers.Count);
9567 foreach (var e in initializers)
9568 t.initializers.Add (e.Clone (clonectx));
9571 public override Expression CreateExpressionTree (ResolveContext ec)
9573 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
9574 foreach (Expression e in initializers) {
9575 Expression expr = e.CreateExpressionTree (ec);
9576 if (expr != null)
9577 expr_initializers.Add (expr);
9580 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9583 protected override Expression DoResolve (ResolveContext ec)
9585 List<string> element_names = null;
9586 for (int i = 0; i < initializers.Count; ++i) {
9587 Expression initializer = (Expression) initializers [i];
9588 ElementInitializer element_initializer = initializer as ElementInitializer;
9590 if (i == 0) {
9591 if (element_initializer != null) {
9592 element_names = new List<string> (initializers.Count);
9593 element_names.Add (element_initializer.Name);
9594 } else if (initializer is CompletingExpression){
9595 initializer.Resolve (ec);
9596 throw new InternalErrorException ("This line should never be reached");
9597 } else {
9598 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9599 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9600 "object initializer because type `{1}' does not implement `{2}' interface",
9601 ec.CurrentInitializerVariable.GetSignatureForError (),
9602 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9603 TypeManager.CSharpName (TypeManager.ienumerable_type));
9604 return null;
9606 is_collection_initialization = true;
9608 } else {
9609 if (is_collection_initialization != (element_initializer == null)) {
9610 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9611 is_collection_initialization ? "collection initializer" : "object initializer");
9612 continue;
9615 if (!is_collection_initialization) {
9616 if (element_names.Contains (element_initializer.Name)) {
9617 ec.Report.Error (1912, element_initializer.Location,
9618 "An object initializer includes more than one member `{0}' initialization",
9619 element_initializer.Name);
9620 } else {
9621 element_names.Add (element_initializer.Name);
9626 Expression e = initializer.Resolve (ec);
9627 if (e == EmptyExpressionStatement.Instance)
9628 initializers.RemoveAt (i--);
9629 else
9630 initializers [i] = e;
9633 type = ec.CurrentInitializerVariable.Type;
9634 if (is_collection_initialization) {
9635 if (TypeManager.HasElementType (type)) {
9636 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9637 TypeManager.CSharpName (type));
9641 eclass = ExprClass.Variable;
9642 return this;
9645 public override void Emit (EmitContext ec)
9647 EmitStatement (ec);
9650 public override void EmitStatement (EmitContext ec)
9652 foreach (ExpressionStatement e in initializers)
9653 e.EmitStatement (ec);
9656 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9658 foreach (Expression e in initializers)
9659 e.MutateHoistedGenericType (storey);
9664 // New expression with element/object initializers
9666 public class NewInitialize : New
9669 // This class serves as a proxy for variable initializer target instances.
9670 // A real variable is assigned later when we resolve left side of an
9671 // assignment
9673 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9675 NewInitialize new_instance;
9677 public InitializerTargetExpression (NewInitialize newInstance)
9679 this.type = newInstance.type;
9680 this.loc = newInstance.loc;
9681 this.eclass = newInstance.eclass;
9682 this.new_instance = newInstance;
9685 public override Expression CreateExpressionTree (ResolveContext ec)
9687 // Should not be reached
9688 throw new NotSupportedException ("ET");
9691 protected override Expression DoResolve (ResolveContext ec)
9693 return this;
9696 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9698 return this;
9701 public override void Emit (EmitContext ec)
9703 Expression e = (Expression) new_instance.instance;
9704 e.Emit (ec);
9707 #region IMemoryLocation Members
9709 public void AddressOf (EmitContext ec, AddressOp mode)
9711 new_instance.instance.AddressOf (ec, mode);
9714 #endregion
9717 CollectionOrObjectInitializers initializers;
9718 IMemoryLocation instance;
9720 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9721 : base (requested_type, arguments, l)
9723 this.initializers = initializers;
9726 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9728 instance = base.EmitAddressOf (ec, Mode);
9730 if (!initializers.IsEmpty)
9731 initializers.Emit (ec);
9733 return instance;
9736 protected override void CloneTo (CloneContext clonectx, Expression t)
9738 base.CloneTo (clonectx, t);
9740 NewInitialize target = (NewInitialize) t;
9741 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9744 public override Expression CreateExpressionTree (ResolveContext ec)
9746 Arguments args = new Arguments (2);
9747 args.Add (new Argument (base.CreateExpressionTree (ec)));
9748 if (!initializers.IsEmpty)
9749 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9751 return CreateExpressionFactoryCall (ec,
9752 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9753 args);
9756 protected override Expression DoResolve (ResolveContext ec)
9758 Expression e = base.DoResolve (ec);
9759 if (type == null)
9760 return null;
9762 Expression previous = ec.CurrentInitializerVariable;
9763 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9764 initializers.Resolve (ec);
9765 ec.CurrentInitializerVariable = previous;
9766 return e;
9769 public override bool Emit (EmitContext ec, IMemoryLocation target)
9771 bool left_on_stack = base.Emit (ec, target);
9773 if (initializers.IsEmpty)
9774 return left_on_stack;
9776 LocalTemporary temp = target as LocalTemporary;
9777 if (temp == null) {
9778 if (!left_on_stack) {
9779 VariableReference vr = target as VariableReference;
9781 // FIXME: This still does not work correctly for pre-set variables
9782 if (vr != null && vr.IsRef)
9783 target.AddressOf (ec, AddressOp.Load);
9785 ((Expression) target).Emit (ec);
9786 left_on_stack = true;
9789 temp = new LocalTemporary (type);
9792 instance = temp;
9793 if (left_on_stack)
9794 temp.Store (ec);
9796 initializers.Emit (ec);
9798 if (left_on_stack) {
9799 temp.Emit (ec);
9800 temp.Release (ec);
9803 return left_on_stack;
9806 public override bool HasInitializer {
9807 get {
9808 return !initializers.IsEmpty;
9812 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9814 base.MutateHoistedGenericType (storey);
9815 initializers.MutateHoistedGenericType (storey);
9819 public class NewAnonymousType : New
9821 static readonly IList<AnonymousTypeParameter> EmptyParameters = Array.AsReadOnly (new AnonymousTypeParameter[0]);
9823 List<AnonymousTypeParameter> parameters;
9824 readonly TypeContainer parent;
9825 AnonymousTypeClass anonymous_type;
9827 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
9828 : base (null, null, loc)
9830 this.parameters = parameters;
9831 this.parent = parent;
9834 protected override void CloneTo (CloneContext clonectx, Expression target)
9836 if (parameters == null)
9837 return;
9839 NewAnonymousType t = (NewAnonymousType) target;
9840 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
9841 foreach (AnonymousTypeParameter atp in parameters)
9842 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
9845 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
9847 AnonymousTypeClass type = parent.Module.Compiled.GetAnonymousType (parameters);
9848 if (type != null)
9849 return type;
9851 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9852 if (type == null)
9853 return null;
9855 type.DefineType ();
9856 type.Define ();
9857 type.EmitType ();
9858 if (ec.Report.Errors == 0)
9859 type.CloseType ();
9861 parent.Module.Compiled.AddAnonymousType (type);
9862 return type;
9865 public override Expression CreateExpressionTree (ResolveContext ec)
9867 if (parameters == null)
9868 return base.CreateExpressionTree (ec);
9870 var init = new ArrayInitializer (parameters.Count, loc);
9871 foreach (Property p in anonymous_type.Properties)
9872 init.Add (new TypeOfMethod (Import.CreateMethod (TypeBuilder.GetMethod (type, p.GetBuilder)), loc));
9874 var ctor_args = new ArrayInitializer (Arguments.Count, loc);
9875 foreach (Argument a in Arguments)
9876 ctor_args.Add (a.CreateExpressionTree (ec));
9878 Arguments args = new Arguments (3);
9879 args.Add (new Argument (method.CreateExpressionTree (ec)));
9880 args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, "[]", ctor_args, loc)));
9881 args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", init, loc)));
9883 return CreateExpressionFactoryCall (ec, "New", args);
9886 protected override Expression DoResolve (ResolveContext ec)
9888 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9889 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9890 return null;
9893 if (parameters == null) {
9894 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9895 RequestedType = new TypeExpression (anonymous_type.TypeBuilder, loc);
9896 return base.DoResolve (ec);
9899 bool error = false;
9900 Arguments = new Arguments (parameters.Count);
9901 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9902 for (int i = 0; i < parameters.Count; ++i) {
9903 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9904 if (e == null) {
9905 error = true;
9906 continue;
9909 Arguments.Add (new Argument (e));
9910 t_args [i] = new TypeExpression (e.Type, e.Location);
9913 if (error)
9914 return null;
9916 anonymous_type = CreateAnonymousType (ec, parameters);
9917 if (anonymous_type == null)
9918 return null;
9920 RequestedType = new GenericTypeExpr (anonymous_type.TypeBuilder, new TypeArguments (t_args), loc);
9921 return base.DoResolve (ec);
9925 public class AnonymousTypeParameter : ShimExpression
9927 public readonly string Name;
9929 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9930 : base (initializer)
9932 this.Name = name;
9933 this.loc = loc;
9936 public AnonymousTypeParameter (Parameter parameter)
9937 : base (new SimpleName (parameter.Name, parameter.Location))
9939 this.Name = parameter.Name;
9940 this.loc = parameter.Location;
9943 public override bool Equals (object o)
9945 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9946 return other != null && Name == other.Name;
9949 public override int GetHashCode ()
9951 return Name.GetHashCode ();
9954 protected override Expression DoResolve (ResolveContext ec)
9956 Expression e = expr.Resolve (ec);
9957 if (e == null)
9958 return null;
9960 if (e.eclass == ExprClass.MethodGroup) {
9961 Error_InvalidInitializer (ec, e.ExprClassName);
9962 return null;
9965 type = e.Type;
9966 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9967 type == InternalType.AnonymousMethod || type.IsPointer) {
9968 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9969 return null;
9972 return e;
9975 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9977 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9978 Name, initializer);