2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 // This is an user operator expression, automatically created during
24 public class UserOperatorCall : Expression {
25 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
27 protected readonly ArrayList arguments;
28 protected readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
34 this.arguments = args;
35 this.expr_tree = expr_tree;
37 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
38 eclass = ExprClass.Value;
42 public override Expression CreateExpressionTree (EmitContext ec)
44 if (expr_tree != null)
45 return expr_tree (ec, mg);
47 ArrayList args = new ArrayList (arguments.Count + 1);
48 args.Add (new Argument (new NullLiteral (loc)));
49 args.Add (new Argument (mg.CreateExpressionTree (ec)));
50 foreach (Argument a in arguments) {
51 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
54 return CreateExpressionFactoryCall ("Call", args);
57 protected override void CloneTo (CloneContext context, Expression target)
62 public override Expression DoResolve (EmitContext ec)
65 // We are born fully resolved
70 public override void Emit (EmitContext ec)
72 mg.EmitCall (ec, arguments);
75 public MethodGroupExpr Method {
79 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
81 foreach (Argument a in arguments)
82 a.Expr.MutateHoistedGenericType (storey);
84 mg.MutateHoistedGenericType (storey);
88 public class ParenthesizedExpression : Expression
90 public Expression Expr;
92 public ParenthesizedExpression (Expression expr)
95 this.loc = expr.Location;
98 public override Expression CreateExpressionTree (EmitContext ec)
100 throw new NotSupportedException ("ET");
103 public override Expression DoResolve (EmitContext ec)
105 Expr = Expr.Resolve (ec);
109 public override void Emit (EmitContext ec)
111 throw new Exception ("Should not happen");
114 protected override void CloneTo (CloneContext clonectx, Expression t)
116 ParenthesizedExpression target = (ParenthesizedExpression) t;
118 target.Expr = Expr.Clone (clonectx);
123 // Unary implements unary expressions.
125 public class Unary : Expression {
126 public enum Operator : byte {
127 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 static Type [] [] predefined_operators;
133 public readonly Operator Oper;
134 public Expression Expr;
135 Expression enum_conversion;
137 public Unary (Operator op, Expression expr, Location loc)
145 // This routine will attempt to simplify the unary expression when the
146 // argument is a constant.
148 Constant TryReduceConstant (EmitContext ec, Constant e)
150 if (e is EmptyConstantCast)
151 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
153 if (e is SideEffectConstant) {
154 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
155 return r == null ? null : new SideEffectConstant (r, e, r.Location);
158 Type expr_type = e.Type;
161 case Operator.UnaryPlus:
162 // Unary numeric promotions
163 if (expr_type == TypeManager.byte_type)
164 return new IntConstant (((ByteConstant)e).Value, e.Location);
165 if (expr_type == TypeManager.sbyte_type)
166 return new IntConstant (((SByteConstant)e).Value, e.Location);
167 if (expr_type == TypeManager.short_type)
168 return new IntConstant (((ShortConstant)e).Value, e.Location);
169 if (expr_type == TypeManager.ushort_type)
170 return new IntConstant (((UShortConstant)e).Value, e.Location);
171 if (expr_type == TypeManager.char_type)
172 return new IntConstant (((CharConstant)e).Value, e.Location);
174 // Predefined operators
175 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
176 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
177 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
178 expr_type == TypeManager.decimal_type)
185 case Operator.UnaryNegation:
186 // Unary numeric promotions
187 if (expr_type == TypeManager.byte_type)
188 return new IntConstant (-((ByteConstant)e).Value, e.Location);
189 if (expr_type == TypeManager.sbyte_type)
190 return new IntConstant (-((SByteConstant)e).Value, e.Location);
191 if (expr_type == TypeManager.short_type)
192 return new IntConstant (-((ShortConstant)e).Value, e.Location);
193 if (expr_type == TypeManager.ushort_type)
194 return new IntConstant (-((UShortConstant)e).Value, e.Location);
195 if (expr_type == TypeManager.char_type)
196 return new IntConstant (-((CharConstant)e).Value, e.Location);
198 // Predefined operators
199 if (expr_type == TypeManager.int32_type) {
200 int value = ((IntConstant)e).Value;
201 if (value == int.MinValue) {
202 if (ec.ConstantCheckState) {
203 ConstantFold.Error_CompileTimeOverflow (loc);
208 return new IntConstant (-value, e.Location);
210 if (expr_type == TypeManager.int64_type) {
211 long value = ((LongConstant)e).Value;
212 if (value == long.MinValue) {
213 if (ec.ConstantCheckState) {
214 ConstantFold.Error_CompileTimeOverflow (loc);
219 return new LongConstant (-value, e.Location);
222 if (expr_type == TypeManager.uint32_type) {
223 UIntLiteral uil = e as UIntLiteral;
225 if (uil.Value == 2147483648)
226 return new IntLiteral (int.MinValue, e.Location);
227 return new LongLiteral (-uil.Value, e.Location);
229 return new LongConstant (-((UIntConstant)e).Value, e.Location);
232 if (expr_type == TypeManager.uint64_type) {
233 ULongLiteral ull = e as ULongLiteral;
234 if (ull != null && ull.Value == 9223372036854775808)
235 return new LongLiteral (long.MinValue, e.Location);
239 if (expr_type == TypeManager.float_type) {
240 FloatLiteral fl = e as FloatLiteral;
241 // For better error reporting
243 fl.Value = -fl.Value;
246 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
248 if (expr_type == TypeManager.double_type) {
249 DoubleLiteral dl = e as DoubleLiteral;
250 // For better error reporting
252 dl.Value = -dl.Value;
256 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
258 if (expr_type == TypeManager.decimal_type)
259 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
263 case Operator.LogicalNot:
264 if (expr_type != TypeManager.bool_type)
267 bool b = (bool)e.GetValue ();
268 return new BoolConstant (!b, e.Location);
270 case Operator.OnesComplement:
271 // Unary numeric promotions
272 if (expr_type == TypeManager.byte_type)
273 return new IntConstant (~((ByteConstant)e).Value, e.Location);
274 if (expr_type == TypeManager.sbyte_type)
275 return new IntConstant (~((SByteConstant)e).Value, e.Location);
276 if (expr_type == TypeManager.short_type)
277 return new IntConstant (~((ShortConstant)e).Value, e.Location);
278 if (expr_type == TypeManager.ushort_type)
279 return new IntConstant (~((UShortConstant)e).Value, e.Location);
280 if (expr_type == TypeManager.char_type)
281 return new IntConstant (~((CharConstant)e).Value, e.Location);
283 // Predefined operators
284 if (expr_type == TypeManager.int32_type)
285 return new IntConstant (~((IntConstant)e).Value, e.Location);
286 if (expr_type == TypeManager.uint32_type)
287 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
288 if (expr_type == TypeManager.int64_type)
289 return new LongConstant (~((LongConstant)e).Value, e.Location);
290 if (expr_type == TypeManager.uint64_type){
291 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
293 if (e is EnumConstant) {
294 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
296 e = new EnumConstant (e, expr_type);
301 throw new Exception ("Can not constant fold: " + Oper.ToString());
304 protected Expression ResolveOperator (EmitContext ec, Expression expr)
306 eclass = ExprClass.Value;
308 if (predefined_operators == null)
309 CreatePredefinedOperatorsTable ();
311 Type expr_type = expr.Type;
312 Expression best_expr;
315 // Primitive types first
317 if (TypeManager.IsPrimitiveType (expr_type)) {
318 best_expr = ResolvePrimitivePredefinedType (expr);
319 if (best_expr == null)
322 type = best_expr.Type;
328 // E operator ~(E x);
330 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
331 return ResolveEnumOperator (ec, expr);
333 return ResolveUserType (ec, expr);
336 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
338 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
339 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
340 if (best_expr == null)
344 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
346 return EmptyCast.Create (this, type);
349 public override Expression CreateExpressionTree (EmitContext ec)
351 return CreateExpressionTree (ec, null);
354 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
358 case Operator.AddressOf:
359 Error_PointerInsideExpressionTree ();
361 case Operator.UnaryNegation:
362 if (ec.CheckState && user_op == null && !IsFloat (type))
363 method_name = "NegateChecked";
365 method_name = "Negate";
367 case Operator.OnesComplement:
368 case Operator.LogicalNot:
371 case Operator.UnaryPlus:
372 method_name = "UnaryPlus";
375 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
378 ArrayList args = new ArrayList (2);
379 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
381 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
382 return CreateExpressionFactoryCall (method_name, args);
385 static void CreatePredefinedOperatorsTable ()
387 predefined_operators = new Type [(int) Operator.TOP] [];
390 // 7.6.1 Unary plus operator
392 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
393 TypeManager.int32_type, TypeManager.uint32_type,
394 TypeManager.int64_type, TypeManager.uint64_type,
395 TypeManager.float_type, TypeManager.double_type,
396 TypeManager.decimal_type
400 // 7.6.2 Unary minus operator
402 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
403 TypeManager.int32_type,
404 TypeManager.int64_type,
405 TypeManager.float_type, TypeManager.double_type,
406 TypeManager.decimal_type
410 // 7.6.3 Logical negation operator
412 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
413 TypeManager.bool_type
417 // 7.6.4 Bitwise complement operator
419 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
420 TypeManager.int32_type, TypeManager.uint32_type,
421 TypeManager.int64_type, TypeManager.uint64_type
426 // Unary numeric promotions
428 static Expression DoNumericPromotion (Operator op, Expression expr)
430 Type expr_type = expr.Type;
431 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
432 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
433 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
434 expr_type == TypeManager.char_type)
435 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
437 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
438 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
443 public override Expression DoResolve (EmitContext ec)
445 if (Oper == Operator.AddressOf) {
446 return ResolveAddressOf (ec);
449 Expr = Expr.Resolve (ec);
453 if (TypeManager.IsNullableValueType (Expr.Type))
454 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
457 // Attempt to use a constant folding operation.
459 Constant cexpr = Expr as Constant;
461 cexpr = TryReduceConstant (ec, cexpr);
466 Expression expr = ResolveOperator (ec, Expr);
468 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
471 // Reduce unary operator on predefined types
473 if (expr == this && Oper == Operator.UnaryPlus)
479 public override Expression DoResolveLValue (EmitContext ec, Expression right)
484 public override void Emit (EmitContext ec)
486 EmitOperator (ec, type);
489 protected void EmitOperator (EmitContext ec, Type type)
491 ILGenerator ig = ec.ig;
494 case Operator.UnaryPlus:
498 case Operator.UnaryNegation:
499 if (ec.CheckState && !IsFloat (type)) {
500 ig.Emit (OpCodes.Ldc_I4_0);
501 if (type == TypeManager.int64_type)
502 ig.Emit (OpCodes.Conv_U8);
504 ig.Emit (OpCodes.Sub_Ovf);
507 ig.Emit (OpCodes.Neg);
512 case Operator.LogicalNot:
514 ig.Emit (OpCodes.Ldc_I4_0);
515 ig.Emit (OpCodes.Ceq);
518 case Operator.OnesComplement:
520 ig.Emit (OpCodes.Not);
523 case Operator.AddressOf:
524 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
528 throw new Exception ("This should not happen: Operator = "
533 // Same trick as in Binary expression
535 if (enum_conversion != null)
536 enum_conversion.Emit (ec);
539 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
541 if (Oper == Operator.LogicalNot)
542 Expr.EmitBranchable (ec, target, !on_true);
544 base.EmitBranchable (ec, target, on_true);
547 public override void EmitSideEffect (EmitContext ec)
549 Expr.EmitSideEffect (ec);
552 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
554 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
555 oper, TypeManager.CSharpName (t));
558 static bool IsFloat (Type t)
560 return t == TypeManager.float_type || t == TypeManager.double_type;
564 // Returns a stringified representation of the Operator
566 public static string OperName (Operator oper)
569 case Operator.UnaryPlus:
571 case Operator.UnaryNegation:
573 case Operator.LogicalNot:
575 case Operator.OnesComplement:
577 case Operator.AddressOf:
581 throw new NotImplementedException (oper.ToString ());
584 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
586 type = storey.MutateType (type);
587 Expr.MutateHoistedGenericType (storey);
590 Expression ResolveAddressOf (EmitContext ec)
595 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
596 if (Expr == null || Expr.eclass != ExprClass.Variable) {
597 Error (211, "Cannot take the address of the given expression");
601 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
605 IVariableReference vr = Expr as IVariableReference;
608 VariableInfo vi = vr.VariableInfo;
610 if (vi.LocalInfo != null)
611 vi.LocalInfo.Used = true;
614 // A variable is considered definitely assigned if you take its address.
619 is_fixed = vr.IsFixedVariable;
620 vr.SetHasAddressTaken ();
623 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
627 // A pointer-indirection is always fixed
629 is_fixed = Expr is Indirection;
632 if (!is_fixed && !ec.InFixedInitializer) {
633 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
636 type = TypeManager.GetPointerType (Expr.Type);
637 eclass = ExprClass.Value;
641 Expression ResolvePrimitivePredefinedType (Expression expr)
643 expr = DoNumericPromotion (Oper, expr);
644 Type expr_type = expr.Type;
645 Type[] predefined = predefined_operators [(int) Oper];
646 foreach (Type t in predefined) {
654 // Perform user-operator overload resolution
656 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
658 CSharp.Operator.OpType op_type;
660 case Operator.LogicalNot:
661 op_type = CSharp.Operator.OpType.LogicalNot; break;
662 case Operator.OnesComplement:
663 op_type = CSharp.Operator.OpType.OnesComplement; break;
664 case Operator.UnaryNegation:
665 op_type = CSharp.Operator.OpType.UnaryNegation; break;
666 case Operator.UnaryPlus:
667 op_type = CSharp.Operator.OpType.UnaryPlus; break;
669 throw new InternalErrorException (Oper.ToString ());
672 string op_name = CSharp.Operator.GetMetadataName (op_type);
673 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
677 ArrayList args = new ArrayList (1);
678 args.Add (new Argument (expr));
679 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
684 Expr = ((Argument) args [0]).Expr;
685 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
689 // Unary user type overload resolution
691 Expression ResolveUserType (EmitContext ec, Expression expr)
693 Expression best_expr = ResolveUserOperator (ec, expr);
694 if (best_expr != null)
697 Type[] predefined = predefined_operators [(int) Oper];
698 foreach (Type t in predefined) {
699 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
700 if (oper_expr == null)
704 // decimal type is predefined but has user-operators
706 if (oper_expr.Type == TypeManager.decimal_type)
707 oper_expr = ResolveUserType (ec, oper_expr);
709 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
711 if (oper_expr == null)
714 if (best_expr == null) {
715 best_expr = oper_expr;
719 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
721 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
722 OperName (Oper), TypeManager.CSharpName (expr.Type));
727 best_expr = oper_expr;
730 if (best_expr == null)
734 // HACK: Decimal user-operator is included in standard operators
736 if (best_expr.Type == TypeManager.decimal_type)
740 type = best_expr.Type;
744 protected override void CloneTo (CloneContext clonectx, Expression t)
746 Unary target = (Unary) t;
748 target.Expr = Expr.Clone (clonectx);
753 // Unary operators are turned into Indirection expressions
754 // after semantic analysis (this is so we can take the address
755 // of an indirection).
757 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
759 LocalTemporary temporary;
762 public Indirection (Expression expr, Location l)
768 public override Expression CreateExpressionTree (EmitContext ec)
770 Error_PointerInsideExpressionTree ();
774 protected override void CloneTo (CloneContext clonectx, Expression t)
776 Indirection target = (Indirection) t;
777 target.expr = expr.Clone (clonectx);
780 public override void Emit (EmitContext ec)
785 LoadFromPtr (ec.ig, Type);
788 public void Emit (EmitContext ec, bool leave_copy)
792 ec.ig.Emit (OpCodes.Dup);
793 temporary = new LocalTemporary (expr.Type);
794 temporary.Store (ec);
798 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
800 prepared = prepare_for_load;
804 if (prepare_for_load)
805 ec.ig.Emit (OpCodes.Dup);
809 ec.ig.Emit (OpCodes.Dup);
810 temporary = new LocalTemporary (expr.Type);
811 temporary.Store (ec);
814 StoreFromPtr (ec.ig, type);
816 if (temporary != null) {
818 temporary.Release (ec);
822 public void AddressOf (EmitContext ec, AddressOp Mode)
827 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
829 return DoResolve (ec);
832 public override Expression DoResolve (EmitContext ec)
834 expr = expr.Resolve (ec);
841 if (!expr.Type.IsPointer) {
842 Error (193, "The * or -> operator must be applied to a pointer");
846 if (expr.Type == TypeManager.void_ptr_type) {
847 Error (242, "The operation in question is undefined on void pointers");
851 type = TypeManager.GetElementType (expr.Type);
852 eclass = ExprClass.Variable;
856 public override string ToString ()
858 return "*(" + expr + ")";
863 /// Unary Mutator expressions (pre and post ++ and --)
867 /// UnaryMutator implements ++ and -- expressions. It derives from
868 /// ExpressionStatement becuase the pre/post increment/decrement
869 /// operators can be used in a statement context.
871 /// FIXME: Idea, we could split this up in two classes, one simpler
872 /// for the common case, and one with the extra fields for more complex
873 /// classes (indexers require temporary access; overloaded require method)
876 public class UnaryMutator : ExpressionStatement {
878 public enum Mode : byte {
885 PreDecrement = IsDecrement,
886 PostIncrement = IsPost,
887 PostDecrement = IsPost | IsDecrement
891 bool is_expr = false;
892 bool recurse = false;
897 // This is expensive for the simplest case.
899 UserOperatorCall method;
901 public UnaryMutator (Mode m, Expression e, Location l)
908 static string OperName (Mode mode)
910 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
915 /// Returns whether an object of type `t' can be incremented
916 /// or decremented with add/sub (ie, basically whether we can
917 /// use pre-post incr-decr operations on it, but it is not a
918 /// System.Decimal, which we require operator overloading to catch)
920 static bool IsIncrementableNumber (Type t)
922 return (t == TypeManager.sbyte_type) ||
923 (t == TypeManager.byte_type) ||
924 (t == TypeManager.short_type) ||
925 (t == TypeManager.ushort_type) ||
926 (t == TypeManager.int32_type) ||
927 (t == TypeManager.uint32_type) ||
928 (t == TypeManager.int64_type) ||
929 (t == TypeManager.uint64_type) ||
930 (t == TypeManager.char_type) ||
931 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
932 (t == TypeManager.float_type) ||
933 (t == TypeManager.double_type) ||
934 (t.IsPointer && t != TypeManager.void_ptr_type);
937 Expression ResolveOperator (EmitContext ec)
942 // Step 1: Perform Operator Overload location
947 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
948 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
950 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
952 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
955 ArrayList args = new ArrayList (1);
956 args.Add (new Argument (expr, Argument.AType.Expression));
957 mg = mg.OverloadResolve (ec, ref args, false, loc);
961 method = new UserOperatorCall (mg, args, null, loc);
962 Convert.ImplicitConversionRequired (ec, method, type, loc);
966 if (!IsIncrementableNumber (type)) {
967 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
968 TypeManager.CSharpName (type) + "'");
973 // The operand of the prefix/postfix increment decrement operators
974 // should be an expression that is classified as a variable,
975 // a property access or an indexer access
977 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
978 expr = expr.ResolveLValue (ec, expr, Location);
980 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
986 public override Expression CreateExpressionTree (EmitContext ec)
988 return new SimpleAssign (this, this).CreateExpressionTree (ec);
991 public override Expression DoResolve (EmitContext ec)
993 expr = expr.Resolve (ec);
998 eclass = ExprClass.Value;
1001 if (TypeManager.IsNullableValueType (expr.Type))
1002 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1005 return ResolveOperator (ec);
1009 // Loads the proper "1" into the stack based on the type, then it emits the
1010 // opcode for the operation requested
1012 void LoadOneAndEmitOp (EmitContext ec, Type t)
1015 // Measure if getting the typecode and using that is more/less efficient
1016 // that comparing types. t.GetTypeCode() is an internal call.
1018 ILGenerator ig = ec.ig;
1020 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1021 LongConstant.EmitLong (ig, 1);
1022 else if (t == TypeManager.double_type)
1023 ig.Emit (OpCodes.Ldc_R8, 1.0);
1024 else if (t == TypeManager.float_type)
1025 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1026 else if (t.IsPointer){
1027 Type et = TypeManager.GetElementType (t);
1028 int n = GetTypeSize (et);
1031 ig.Emit (OpCodes.Sizeof, et);
1033 IntConstant.EmitInt (ig, n);
1034 ig.Emit (OpCodes.Conv_I);
1037 ig.Emit (OpCodes.Ldc_I4_1);
1040 // Now emit the operation
1043 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1044 Binary.EmitOperatorOpcode (ec, op, t);
1046 if (t == TypeManager.sbyte_type){
1048 ig.Emit (OpCodes.Conv_Ovf_I1);
1050 ig.Emit (OpCodes.Conv_I1);
1051 } else if (t == TypeManager.byte_type){
1053 ig.Emit (OpCodes.Conv_Ovf_U1);
1055 ig.Emit (OpCodes.Conv_U1);
1056 } else if (t == TypeManager.short_type){
1058 ig.Emit (OpCodes.Conv_Ovf_I2);
1060 ig.Emit (OpCodes.Conv_I2);
1061 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1063 ig.Emit (OpCodes.Conv_Ovf_U2);
1065 ig.Emit (OpCodes.Conv_U2);
1070 void EmitCode (EmitContext ec, bool is_expr)
1073 this.is_expr = is_expr;
1074 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1077 public override void Emit (EmitContext ec)
1080 // We use recurse to allow ourselfs to be the source
1081 // of an assignment. This little hack prevents us from
1082 // having to allocate another expression
1085 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1087 LoadOneAndEmitOp (ec, expr.Type);
1089 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1094 EmitCode (ec, true);
1097 public override void EmitStatement (EmitContext ec)
1099 EmitCode (ec, false);
1102 protected override void CloneTo (CloneContext clonectx, Expression t)
1104 UnaryMutator target = (UnaryMutator) t;
1106 target.expr = expr.Clone (clonectx);
1111 /// Base class for the `Is' and `As' classes.
1115 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1118 public abstract class Probe : Expression {
1119 public Expression ProbeType;
1120 protected Expression expr;
1121 protected TypeExpr probe_type_expr;
1123 public Probe (Expression expr, Expression probe_type, Location l)
1125 ProbeType = probe_type;
1130 public Expression Expr {
1136 public override Expression DoResolve (EmitContext ec)
1138 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1139 if (probe_type_expr == null)
1142 expr = expr.Resolve (ec);
1146 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1147 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1151 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1152 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1157 if (expr.Type == TypeManager.anonymous_method_type) {
1158 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1166 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1168 expr.MutateHoistedGenericType (storey);
1169 probe_type_expr.MutateHoistedGenericType (storey);
1172 protected abstract string OperatorName { get; }
1174 protected override void CloneTo (CloneContext clonectx, Expression t)
1176 Probe target = (Probe) t;
1178 target.expr = expr.Clone (clonectx);
1179 target.ProbeType = ProbeType.Clone (clonectx);
1185 /// Implementation of the `is' operator.
1187 public class Is : Probe {
1188 Nullable.Unwrap expr_unwrap;
1190 public Is (Expression expr, Expression probe_type, Location l)
1191 : base (expr, probe_type, l)
1195 public override Expression CreateExpressionTree (EmitContext ec)
1197 ArrayList args = new ArrayList (2);
1198 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1199 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1200 return CreateExpressionFactoryCall ("TypeIs", args);
1203 public override void Emit (EmitContext ec)
1205 ILGenerator ig = ec.ig;
1206 if (expr_unwrap != null) {
1207 expr_unwrap.EmitCheck (ec);
1212 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1213 ig.Emit (OpCodes.Ldnull);
1214 ig.Emit (OpCodes.Cgt_Un);
1217 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1219 ILGenerator ig = ec.ig;
1220 if (expr_unwrap != null) {
1221 expr_unwrap.EmitCheck (ec);
1224 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1226 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1229 Expression CreateConstantResult (bool result)
1232 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1233 TypeManager.CSharpName (probe_type_expr.Type));
1235 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1236 TypeManager.CSharpName (probe_type_expr.Type));
1238 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1241 public override Expression DoResolve (EmitContext ec)
1243 if (base.DoResolve (ec) == null)
1247 bool d_is_nullable = false;
1250 // If E is a method group or the null literal, or if the type of E is a reference
1251 // type or a nullable type and the value of E is null, the result is false
1253 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1254 return CreateConstantResult (false);
1256 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1257 d = TypeManager.GetTypeArguments (d) [0];
1258 d_is_nullable = true;
1261 type = TypeManager.bool_type;
1262 eclass = ExprClass.Value;
1263 Type t = probe_type_expr.Type;
1264 bool t_is_nullable = false;
1265 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1266 t = TypeManager.GetTypeArguments (t) [0];
1267 t_is_nullable = true;
1270 if (t.IsValueType) {
1273 // D and T are the same value types but D can be null
1275 if (d_is_nullable && !t_is_nullable) {
1276 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1281 // The result is true if D and T are the same value types
1283 return CreateConstantResult (true);
1286 if (TypeManager.IsGenericParameter (d))
1287 return ResolveGenericParameter (t, d);
1290 // An unboxing conversion exists
1292 if (Convert.ExplicitReferenceConversionExists (d, t))
1295 if (TypeManager.IsGenericParameter (t))
1296 return ResolveGenericParameter (d, t);
1298 if (d.IsValueType) {
1300 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1301 return CreateConstantResult (true);
1303 if (TypeManager.IsGenericParameter (d))
1304 return ResolveGenericParameter (t, d);
1306 if (TypeManager.ContainsGenericParameters (d))
1309 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1310 Convert.ExplicitReferenceConversionExists (d, t)) {
1316 return CreateConstantResult (false);
1319 Expression ResolveGenericParameter (Type d, Type t)
1322 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1323 if (constraints != null) {
1324 if (constraints.IsReferenceType && d.IsValueType)
1325 return CreateConstantResult (false);
1327 if (constraints.IsValueType && !d.IsValueType)
1328 return CreateConstantResult (TypeManager.IsEqual (d, t));
1331 if (!TypeManager.IsReferenceType (expr.Type))
1332 expr = new BoxedCast (expr, d);
1340 protected override string OperatorName {
1341 get { return "is"; }
1346 /// Implementation of the `as' operator.
1348 public class As : Probe {
1350 Expression resolved_type;
1352 public As (Expression expr, Expression probe_type, Location l)
1353 : base (expr, probe_type, l)
1357 public override Expression CreateExpressionTree (EmitContext ec)
1359 ArrayList args = new ArrayList (2);
1360 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1361 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1362 return CreateExpressionFactoryCall ("TypeAs", args);
1365 public override void Emit (EmitContext ec)
1367 ILGenerator ig = ec.ig;
1372 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1375 if (TypeManager.IsNullableType (type))
1376 ig.Emit (OpCodes.Unbox_Any, type);
1380 public override Expression DoResolve (EmitContext ec)
1382 if (resolved_type == null) {
1383 resolved_type = base.DoResolve (ec);
1385 if (resolved_type == null)
1389 type = probe_type_expr.Type;
1390 eclass = ExprClass.Value;
1391 Type etype = expr.Type;
1393 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1394 if (probe_type_expr is TypeParameterExpr) {
1395 Report.Error (413, loc,
1396 "The `as' operator cannot be used with a non-reference type parameter `{0}'",
1397 probe_type_expr.GetSignatureForError ());
1399 Report.Error (77, loc,
1400 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1401 TypeManager.CSharpName (type));
1406 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1407 return Nullable.LiftedNull.CreateFromExpression (this);
1410 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1417 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1418 if (TypeManager.IsGenericParameter (etype))
1419 expr = new BoxedCast (expr, etype);
1425 if (TypeManager.ContainsGenericParameters (etype) ||
1426 TypeManager.ContainsGenericParameters (type)) {
1427 expr = new BoxedCast (expr, etype);
1432 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1433 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1438 protected override string OperatorName {
1439 get { return "as"; }
1442 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1444 return expr.GetAttributableValue (ec, value_type, out value);
1449 /// This represents a typecast in the source language.
1451 /// FIXME: Cast expressions have an unusual set of parsing
1452 /// rules, we need to figure those out.
1454 public class Cast : Expression {
1455 Expression target_type;
1458 public Cast (Expression cast_type, Expression expr)
1459 : this (cast_type, expr, cast_type.Location)
1463 public Cast (Expression cast_type, Expression expr, Location loc)
1465 this.target_type = cast_type;
1470 public Expression TargetType {
1471 get { return target_type; }
1474 public Expression Expr {
1475 get { return expr; }
1478 public override Expression CreateExpressionTree (EmitContext ec)
1480 throw new NotSupportedException ("ET");
1483 public override Expression DoResolve (EmitContext ec)
1485 expr = expr.Resolve (ec);
1489 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1495 if (type.IsAbstract && type.IsSealed) {
1496 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1500 eclass = ExprClass.Value;
1502 Constant c = expr as Constant;
1504 c = c.TryReduce (ec, type, loc);
1509 if (type.IsPointer && !ec.InUnsafe) {
1513 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1517 public override void Emit (EmitContext ec)
1519 throw new Exception ("Should not happen");
1522 protected override void CloneTo (CloneContext clonectx, Expression t)
1524 Cast target = (Cast) t;
1526 target.target_type = target_type.Clone (clonectx);
1527 target.expr = expr.Clone (clonectx);
1532 // C# 2.0 Default value expression
1534 public class DefaultValueExpression : Expression
1538 public DefaultValueExpression (Expression expr, Location loc)
1544 public override Expression CreateExpressionTree (EmitContext ec)
1546 ArrayList args = new ArrayList (2);
1547 args.Add (new Argument (this));
1548 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1549 return CreateExpressionFactoryCall ("Constant", args);
1552 public override Expression DoResolve (EmitContext ec)
1554 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1560 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1561 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1565 return new NullLiteral (Location).ConvertImplicitly (type);
1567 if (TypeManager.IsReferenceType (type)) {
1568 return new EmptyConstantCast (new NullLiteral (Location), type);
1571 // return ReducedExpression.Create (new NullLiteral (Location), this);
1574 Constant c = New.Constantify (type);
1578 eclass = ExprClass.Variable;
1582 public override void Emit (EmitContext ec)
1584 LocalTemporary temp_storage = new LocalTemporary(type);
1586 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1587 ec.ig.Emit(OpCodes.Initobj, type);
1588 temp_storage.Emit(ec);
1591 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1593 type = storey.MutateType (type);
1596 protected override void CloneTo (CloneContext clonectx, Expression t)
1598 DefaultValueExpression target = (DefaultValueExpression) t;
1600 target.expr = expr.Clone (clonectx);
1605 /// Binary operators
1607 public class Binary : Expression {
1609 protected class PredefinedOperator {
1610 protected readonly Type left;
1611 protected readonly Type right;
1612 public readonly Operator OperatorsMask;
1613 public Type ReturnType;
1615 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1616 : this (ltype, rtype, op_mask, ltype)
1620 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1621 : this (type, type, op_mask, return_type)
1625 public PredefinedOperator (Type type, Operator op_mask)
1626 : this (type, type, op_mask, type)
1630 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1632 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1633 throw new InternalErrorException ("Only masked values can be used");
1637 this.OperatorsMask = op_mask;
1638 this.ReturnType = return_type;
1641 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1643 b.type = ReturnType;
1645 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1646 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1649 // A user operators does not support multiple user conversions, but decimal type
1650 // is considered to be predefined type therefore we apply predefined operators rules
1651 // and then look for decimal user-operator implementation
1653 if (left == TypeManager.decimal_type)
1654 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1659 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1662 // We are dealing with primitive types only
1664 return left == ltype && ltype == rtype;
1667 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1669 if (TypeManager.IsEqual (left, lexpr.Type) &&
1670 TypeManager.IsEqual (right, rexpr.Type))
1673 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1674 Convert.ImplicitConversionExists (ec, rexpr, right);
1677 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1680 if (left != null && best_operator.left != null) {
1681 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1685 // When second arguments are same as the first one, the result is same
1687 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1688 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1691 if (result == 0 || result > 2)
1694 return result == 1 ? best_operator : this;
1698 class PredefinedStringOperator : PredefinedOperator {
1699 public PredefinedStringOperator (Type type, Operator op_mask)
1700 : base (type, op_mask, type)
1702 ReturnType = TypeManager.string_type;
1705 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1706 : base (ltype, rtype, op_mask)
1708 ReturnType = TypeManager.string_type;
1711 public override Expression ConvertResult (EmitContext ec, Binary b)
1714 // Use original expression for nullable arguments
1716 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1718 b.left = unwrap.Original;
1720 unwrap = b.right as Nullable.Unwrap;
1722 b.right = unwrap.Original;
1724 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1725 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1728 // Start a new concat expression using converted expression
1730 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1734 class PredefinedShiftOperator : PredefinedOperator {
1735 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1736 base (ltype, TypeManager.int32_type, op_mask)
1740 public override Expression ConvertResult (EmitContext ec, Binary b)
1742 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1744 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1746 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1749 // b = b.left >> b.right & (0x1f|0x3f)
1751 b.right = new Binary (Operator.BitwiseAnd,
1752 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1755 // Expression tree representation does not use & mask
1757 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1758 b.type = ReturnType;
1763 class PredefinedPointerOperator : PredefinedOperator {
1764 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1765 : base (ltype, rtype, op_mask)
1769 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1770 : base (ltype, rtype, op_mask, retType)
1774 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1775 : base (type, op_mask, return_type)
1779 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1782 if (!lexpr.Type.IsPointer)
1785 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1789 if (right == null) {
1790 if (!rexpr.Type.IsPointer)
1793 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1800 public override Expression ConvertResult (EmitContext ec, Binary b)
1803 b.left = EmptyCast.Create (b.left, left);
1804 } else if (right != null) {
1805 b.right = EmptyCast.Create (b.right, right);
1808 Type r_type = ReturnType;
1809 if (r_type == null) {
1811 r_type = b.left.Type;
1813 r_type = b.right.Type;
1816 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1821 public enum Operator {
1822 Multiply = 0 | ArithmeticMask,
1823 Division = 1 | ArithmeticMask,
1824 Modulus = 2 | ArithmeticMask,
1825 Addition = 3 | ArithmeticMask | AdditionMask,
1826 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1828 LeftShift = 5 | ShiftMask,
1829 RightShift = 6 | ShiftMask,
1831 LessThan = 7 | ComparisonMask | RelationalMask,
1832 GreaterThan = 8 | ComparisonMask | RelationalMask,
1833 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1834 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1835 Equality = 11 | ComparisonMask | EqualityMask,
1836 Inequality = 12 | ComparisonMask | EqualityMask,
1838 BitwiseAnd = 13 | BitwiseMask,
1839 ExclusiveOr = 14 | BitwiseMask,
1840 BitwiseOr = 15 | BitwiseMask,
1842 LogicalAnd = 16 | LogicalMask,
1843 LogicalOr = 17 | LogicalMask,
1848 ValuesOnlyMask = ArithmeticMask - 1,
1849 ArithmeticMask = 1 << 5,
1851 ComparisonMask = 1 << 7,
1852 EqualityMask = 1 << 8,
1853 BitwiseMask = 1 << 9,
1854 LogicalMask = 1 << 10,
1855 AdditionMask = 1 << 11,
1856 SubtractionMask = 1 << 12,
1857 RelationalMask = 1 << 13
1860 readonly Operator oper;
1861 protected Expression left, right;
1862 readonly bool is_compound;
1863 Expression enum_conversion;
1865 static PredefinedOperator [] standard_operators;
1866 static PredefinedOperator [] pointer_operators;
1868 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1869 : this (oper, left, right)
1871 this.is_compound = isCompound;
1874 public Binary (Operator oper, Expression left, Expression right)
1879 this.loc = left.Location;
1882 public Operator Oper {
1889 /// Returns a stringified representation of the Operator
1891 string OperName (Operator oper)
1895 case Operator.Multiply:
1898 case Operator.Division:
1901 case Operator.Modulus:
1904 case Operator.Addition:
1907 case Operator.Subtraction:
1910 case Operator.LeftShift:
1913 case Operator.RightShift:
1916 case Operator.LessThan:
1919 case Operator.GreaterThan:
1922 case Operator.LessThanOrEqual:
1925 case Operator.GreaterThanOrEqual:
1928 case Operator.Equality:
1931 case Operator.Inequality:
1934 case Operator.BitwiseAnd:
1937 case Operator.BitwiseOr:
1940 case Operator.ExclusiveOr:
1943 case Operator.LogicalOr:
1946 case Operator.LogicalAnd:
1950 s = oper.ToString ();
1960 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1962 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1965 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1968 // TODO: This should be handled as Type of method group in CSharpName
1969 if (left.eclass == ExprClass.MethodGroup)
1970 l = left.ExprClassName;
1972 l = TypeManager.CSharpName (left.Type);
1974 if (right.eclass == ExprClass.MethodGroup)
1975 r = right.ExprClassName;
1977 r = TypeManager.CSharpName (right.Type);
1979 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1983 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1985 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
1988 static string GetOperatorMetadataName (Operator op)
1990 CSharp.Operator.OpType op_type;
1992 case Operator.Addition:
1993 op_type = CSharp.Operator.OpType.Addition; break;
1994 case Operator.BitwiseAnd:
1995 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
1996 case Operator.BitwiseOr:
1997 op_type = CSharp.Operator.OpType.BitwiseOr; break;
1998 case Operator.Division:
1999 op_type = CSharp.Operator.OpType.Division; break;
2000 case Operator.Equality:
2001 op_type = CSharp.Operator.OpType.Equality; break;
2002 case Operator.ExclusiveOr:
2003 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2004 case Operator.GreaterThan:
2005 op_type = CSharp.Operator.OpType.GreaterThan; break;
2006 case Operator.GreaterThanOrEqual:
2007 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2008 case Operator.Inequality:
2009 op_type = CSharp.Operator.OpType.Inequality; break;
2010 case Operator.LeftShift:
2011 op_type = CSharp.Operator.OpType.LeftShift; break;
2012 case Operator.LessThan:
2013 op_type = CSharp.Operator.OpType.LessThan; break;
2014 case Operator.LessThanOrEqual:
2015 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2016 case Operator.Modulus:
2017 op_type = CSharp.Operator.OpType.Modulus; break;
2018 case Operator.Multiply:
2019 op_type = CSharp.Operator.OpType.Multiply; break;
2020 case Operator.RightShift:
2021 op_type = CSharp.Operator.OpType.RightShift; break;
2022 case Operator.Subtraction:
2023 op_type = CSharp.Operator.OpType.Subtraction; break;
2025 throw new InternalErrorException (op.ToString ());
2028 return CSharp.Operator.GetMetadataName (op_type);
2031 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2034 ILGenerator ig = ec.ig;
2037 case Operator.Multiply:
2039 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2040 opcode = OpCodes.Mul_Ovf;
2041 else if (!IsFloat (l))
2042 opcode = OpCodes.Mul_Ovf_Un;
2044 opcode = OpCodes.Mul;
2046 opcode = OpCodes.Mul;
2050 case Operator.Division:
2052 opcode = OpCodes.Div_Un;
2054 opcode = OpCodes.Div;
2057 case Operator.Modulus:
2059 opcode = OpCodes.Rem_Un;
2061 opcode = OpCodes.Rem;
2064 case Operator.Addition:
2066 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2067 opcode = OpCodes.Add_Ovf;
2068 else if (!IsFloat (l))
2069 opcode = OpCodes.Add_Ovf_Un;
2071 opcode = OpCodes.Add;
2073 opcode = OpCodes.Add;
2076 case Operator.Subtraction:
2078 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2079 opcode = OpCodes.Sub_Ovf;
2080 else if (!IsFloat (l))
2081 opcode = OpCodes.Sub_Ovf_Un;
2083 opcode = OpCodes.Sub;
2085 opcode = OpCodes.Sub;
2088 case Operator.RightShift:
2090 opcode = OpCodes.Shr_Un;
2092 opcode = OpCodes.Shr;
2095 case Operator.LeftShift:
2096 opcode = OpCodes.Shl;
2099 case Operator.Equality:
2100 opcode = OpCodes.Ceq;
2103 case Operator.Inequality:
2104 ig.Emit (OpCodes.Ceq);
2105 ig.Emit (OpCodes.Ldc_I4_0);
2107 opcode = OpCodes.Ceq;
2110 case Operator.LessThan:
2112 opcode = OpCodes.Clt_Un;
2114 opcode = OpCodes.Clt;
2117 case Operator.GreaterThan:
2119 opcode = OpCodes.Cgt_Un;
2121 opcode = OpCodes.Cgt;
2124 case Operator.LessThanOrEqual:
2125 if (IsUnsigned (l) || IsFloat (l))
2126 ig.Emit (OpCodes.Cgt_Un);
2128 ig.Emit (OpCodes.Cgt);
2129 ig.Emit (OpCodes.Ldc_I4_0);
2131 opcode = OpCodes.Ceq;
2134 case Operator.GreaterThanOrEqual:
2135 if (IsUnsigned (l) || IsFloat (l))
2136 ig.Emit (OpCodes.Clt_Un);
2138 ig.Emit (OpCodes.Clt);
2140 ig.Emit (OpCodes.Ldc_I4_0);
2142 opcode = OpCodes.Ceq;
2145 case Operator.BitwiseOr:
2146 opcode = OpCodes.Or;
2149 case Operator.BitwiseAnd:
2150 opcode = OpCodes.And;
2153 case Operator.ExclusiveOr:
2154 opcode = OpCodes.Xor;
2158 throw new InternalErrorException (oper.ToString ());
2164 static bool IsUnsigned (Type t)
2169 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2170 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2173 static bool IsFloat (Type t)
2175 return t == TypeManager.float_type || t == TypeManager.double_type;
2178 Expression ResolveOperator (EmitContext ec)
2181 Type r = right.Type;
2183 bool primitives_only = false;
2185 if (standard_operators == null)
2186 CreateStandardOperatorsTable ();
2189 // Handles predefined primitive types
2191 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2192 if ((oper & Operator.ShiftMask) == 0) {
2193 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2196 primitives_only = true;
2200 if (l.IsPointer || r.IsPointer)
2201 return ResolveOperatorPointer (ec, l, r);
2204 bool lenum = TypeManager.IsEnumType (l);
2205 bool renum = TypeManager.IsEnumType (r);
2206 if (lenum || renum) {
2207 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2209 // TODO: Can this be ambiguous
2215 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2216 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2218 expr = ResolveOperatorDelegate (ec, l, r);
2220 // TODO: Can this be ambiguous
2226 expr = ResolveUserOperator (ec, l, r);
2230 // Predefined reference types equality
2231 if ((oper & Operator.EqualityMask) != 0) {
2232 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2238 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2241 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2242 // if 'left' is not an enumeration constant, create one from the type of 'right'
2243 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2246 case Operator.BitwiseOr:
2247 case Operator.BitwiseAnd:
2248 case Operator.ExclusiveOr:
2249 case Operator.Equality:
2250 case Operator.Inequality:
2251 case Operator.LessThan:
2252 case Operator.LessThanOrEqual:
2253 case Operator.GreaterThan:
2254 case Operator.GreaterThanOrEqual:
2255 if (TypeManager.IsEnumType (left.Type))
2258 if (left.IsZeroInteger)
2259 return left.TryReduce (ec, right.Type, loc);
2263 case Operator.Addition:
2264 case Operator.Subtraction:
2267 case Operator.Multiply:
2268 case Operator.Division:
2269 case Operator.Modulus:
2270 case Operator.LeftShift:
2271 case Operator.RightShift:
2272 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2276 Error_OperatorCannotBeApplied (this.left, this.right);
2281 // The `|' operator used on types which were extended is dangerous
2283 void CheckBitwiseOrOnSignExtended ()
2285 OpcodeCast lcast = left as OpcodeCast;
2286 if (lcast != null) {
2287 if (IsUnsigned (lcast.UnderlyingType))
2291 OpcodeCast rcast = right as OpcodeCast;
2292 if (rcast != null) {
2293 if (IsUnsigned (rcast.UnderlyingType))
2297 if (lcast == null && rcast == null)
2300 // FIXME: consider constants
2302 Report.Warning (675, 3, loc,
2303 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2304 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2307 static void CreatePointerOperatorsTable ()
2309 ArrayList temp = new ArrayList ();
2312 // Pointer arithmetic:
2314 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2315 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2316 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2317 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2319 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2320 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2321 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2322 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2325 // T* operator + (int y, T* x);
2326 // T* operator + (uint y, T *x);
2327 // T* operator + (long y, T *x);
2328 // T* operator + (ulong y, T *x);
2330 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2331 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2332 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2333 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2336 // long operator - (T* x, T *y)
2338 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2340 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2343 static void CreateStandardOperatorsTable ()
2345 ArrayList temp = new ArrayList ();
2346 Type bool_type = TypeManager.bool_type;
2348 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2349 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2350 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2351 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2352 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2353 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2354 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2356 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2357 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2358 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2359 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2360 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2361 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2362 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2364 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2366 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2367 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2368 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2370 temp.Add (new PredefinedOperator (bool_type,
2371 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2373 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2374 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2375 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2376 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2378 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2382 // Rules used during binary numeric promotion
2384 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2389 Constant c = prim_expr as Constant;
2391 temp = c.ConvertImplicitly (type);
2398 if (type == TypeManager.uint32_type) {
2399 etype = prim_expr.Type;
2400 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2401 type = TypeManager.int64_type;
2403 if (type != second_expr.Type) {
2404 c = second_expr as Constant;
2406 temp = c.ConvertImplicitly (type);
2408 temp = Convert.ImplicitNumericConversion (second_expr, type);
2414 } else if (type == TypeManager.uint64_type) {
2416 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2418 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2419 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2423 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2432 // 7.2.6.2 Binary numeric promotions
2434 public bool DoBinaryOperatorPromotion (EmitContext ec)
2436 Type ltype = left.Type;
2437 Type rtype = right.Type;
2440 foreach (Type t in ConstantFold.binary_promotions) {
2442 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2445 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2448 Type int32 = TypeManager.int32_type;
2449 if (ltype != int32) {
2450 Constant c = left as Constant;
2452 temp = c.ConvertImplicitly (int32);
2454 temp = Convert.ImplicitNumericConversion (left, int32);
2461 if (rtype != int32) {
2462 Constant c = right as Constant;
2464 temp = c.ConvertImplicitly (int32);
2466 temp = Convert.ImplicitNumericConversion (right, int32);
2476 public override Expression DoResolve (EmitContext ec)
2481 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2482 left = ((ParenthesizedExpression) left).Expr;
2483 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2487 if (left.eclass == ExprClass.Type) {
2488 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2492 left = left.Resolve (ec);
2497 Constant lc = left as Constant;
2499 if (lc != null && lc.Type == TypeManager.bool_type &&
2500 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2501 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2503 // FIXME: resolve right expression as unreachable
2504 // right.Resolve (ec);
2506 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2510 right = right.Resolve (ec);
2514 eclass = ExprClass.Value;
2515 Constant rc = right as Constant;
2517 // The conversion rules are ignored in enum context but why
2518 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2519 left = lc = EnumLiftUp (ec, lc, rc, loc);
2523 right = rc = EnumLiftUp (ec, rc, lc, loc);
2528 if (rc != null && lc != null) {
2529 int prev_e = Report.Errors;
2530 Expression e = ConstantFold.BinaryFold (
2531 ec, oper, lc, rc, loc);
2532 if (e != null || Report.Errors != prev_e)
2535 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2536 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2538 if ((ResolveOperator (ec)) == null) {
2539 Error_OperatorCannotBeApplied (left, right);
2544 // The result is a constant with side-effect
2546 Constant side_effect = rc == null ?
2547 new SideEffectConstant (lc, right, loc) :
2548 new SideEffectConstant (rc, left, loc);
2550 return ReducedExpression.Create (side_effect, this);
2554 // Comparison warnings
2555 if ((oper & Operator.ComparisonMask) != 0) {
2556 if (left.Equals (right)) {
2557 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2559 CheckUselessComparison (lc, right.Type);
2560 CheckUselessComparison (rc, left.Type);
2563 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2564 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2565 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2566 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2568 return DoResolveCore (ec, left, right);
2571 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2573 Expression expr = ResolveOperator (ec);
2575 Error_OperatorCannotBeApplied (left_orig, right_orig);
2577 if (left == null || right == null)
2578 throw new InternalErrorException ("Invalid conversion");
2580 if (oper == Operator.BitwiseOr)
2581 CheckBitwiseOrOnSignExtended ();
2586 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2588 left.MutateHoistedGenericType (storey);
2589 right.MutateHoistedGenericType (storey);
2593 // D operator + (D x, D y)
2594 // D operator - (D x, D y)
2595 // bool operator == (D x, D y)
2596 // bool operator != (D x, D y)
2598 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2600 bool is_equality = (oper & Operator.EqualityMask) != 0;
2601 if (!TypeManager.IsEqual (l, r)) {
2603 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2604 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2609 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2610 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2621 // Resolve delegate equality as a user operator
2624 return ResolveUserOperator (ec, l, r);
2627 ArrayList args = new ArrayList (2);
2628 args.Add (new Argument (left, Argument.AType.Expression));
2629 args.Add (new Argument (right, Argument.AType.Expression));
2631 if (oper == Operator.Addition) {
2632 if (TypeManager.delegate_combine_delegate_delegate == null) {
2633 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2634 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2637 method = TypeManager.delegate_combine_delegate_delegate;
2639 if (TypeManager.delegate_remove_delegate_delegate == null) {
2640 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2641 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2644 method = TypeManager.delegate_remove_delegate_delegate;
2647 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2648 mg = mg.OverloadResolve (ec, ref args, false, loc);
2650 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2654 // Enumeration operators
2656 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2659 // bool operator == (E x, E y);
2660 // bool operator != (E x, E y);
2661 // bool operator < (E x, E y);
2662 // bool operator > (E x, E y);
2663 // bool operator <= (E x, E y);
2664 // bool operator >= (E x, E y);
2666 // E operator & (E x, E y);
2667 // E operator | (E x, E y);
2668 // E operator ^ (E x, E y);
2670 // U operator - (E e, E f)
2671 // E operator - (E e, U x)
2673 // E operator + (U x, E e)
2674 // E operator + (E e, U x)
2676 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2677 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2680 Expression ltemp = left;
2681 Expression rtemp = right;
2682 Type underlying_type;
2685 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2687 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2693 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2701 if (TypeManager.IsEqual (ltype, rtype)) {
2702 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2704 if (left is Constant)
2705 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2707 left = EmptyCast.Create (left, underlying_type);
2709 if (right is Constant)
2710 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2712 right = EmptyCast.Create (right, underlying_type);
2714 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2716 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2717 Constant c = right as Constant;
2718 if (c == null || !c.IsDefaultValue)
2721 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2724 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2727 if (left is Constant)
2728 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2730 left = EmptyCast.Create (left, underlying_type);
2733 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2735 if (oper != Operator.Addition) {
2736 Constant c = left as Constant;
2737 if (c == null || !c.IsDefaultValue)
2740 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2743 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2746 if (right is Constant)
2747 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2749 right = EmptyCast.Create (right, underlying_type);
2756 // C# specification uses explicit cast syntax which means binary promotion
2757 // should happen, however it seems that csc does not do that
2759 if (!DoBinaryOperatorPromotion (ec)) {
2765 Type res_type = null;
2766 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2767 Type promoted_type = lenum ? left.Type : right.Type;
2768 enum_conversion = Convert.ExplicitNumericConversion (
2769 new EmptyExpression (promoted_type), underlying_type);
2771 if (oper == Operator.Subtraction && renum && lenum)
2772 res_type = underlying_type;
2773 else if (oper == Operator.Addition && renum)
2779 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2780 if (!is_compound || expr == null)
2784 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2787 if (Convert.ImplicitConversionExists (ec, left, rtype))
2790 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2793 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2798 // 7.9.6 Reference type equality operators
2800 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2803 // operator != (object a, object b)
2804 // operator == (object a, object b)
2807 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2809 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2812 type = TypeManager.bool_type;
2813 GenericConstraints constraints;
2815 bool lgen = TypeManager.IsGenericParameter (l);
2817 if (TypeManager.IsEqual (l, r)) {
2820 // Only allow to compare same reference type parameter
2822 constraints = TypeManager.GetTypeParameterConstraints (l);
2823 if (constraints != null && constraints.IsReferenceType)
2829 if (l == TypeManager.anonymous_method_type)
2832 if (TypeManager.IsValueType (l))
2838 bool rgen = TypeManager.IsGenericParameter (r);
2841 // a, Both operands are reference-type values or the value null
2842 // b, One operand is a value of type T where T is a type-parameter and
2843 // the other operand is the value null. Furthermore T does not have the
2844 // value type constrain
2846 if (left is NullLiteral || right is NullLiteral) {
2848 constraints = TypeManager.GetTypeParameterConstraints (l);
2849 if (constraints != null && constraints.HasValueTypeConstraint)
2852 left = new BoxedCast (left, TypeManager.object_type);
2857 constraints = TypeManager.GetTypeParameterConstraints (r);
2858 if (constraints != null && constraints.HasValueTypeConstraint)
2861 right = new BoxedCast (right, TypeManager.object_type);
2867 // An interface is converted to the object before the
2868 // standard conversion is applied. It's not clear from the
2869 // standard but it looks like it works like that.
2872 constraints = TypeManager.GetTypeParameterConstraints (l);
2873 if (constraints == null || constraints.IsReferenceType)
2875 } else if (l.IsInterface) {
2876 l = TypeManager.object_type;
2877 } else if (l.IsValueType) {
2882 constraints = TypeManager.GetTypeParameterConstraints (r);
2883 if (constraints == null || constraints.IsReferenceType)
2885 } else if (r.IsInterface) {
2886 r = TypeManager.object_type;
2887 } else if (r.IsValueType) {
2892 const string ref_comparison = "Possible unintended reference comparison. " +
2893 "Consider casting the {0} side of the expression to `string' to compare the values";
2896 // A standard implicit conversion exists from the type of either
2897 // operand to the type of the other operand
2899 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2900 if (l == TypeManager.string_type)
2901 Report.Warning (253, 2, loc, ref_comparison, "right");
2906 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2907 if (r == TypeManager.string_type)
2908 Report.Warning (252, 2, loc, ref_comparison, "left");
2917 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2920 // bool operator == (void* x, void* y);
2921 // bool operator != (void* x, void* y);
2922 // bool operator < (void* x, void* y);
2923 // bool operator > (void* x, void* y);
2924 // bool operator <= (void* x, void* y);
2925 // bool operator >= (void* x, void* y);
2927 if ((oper & Operator.ComparisonMask) != 0) {
2930 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2937 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2943 type = TypeManager.bool_type;
2947 if (pointer_operators == null)
2948 CreatePointerOperatorsTable ();
2950 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2954 // Build-in operators method overloading
2956 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2958 PredefinedOperator best_operator = null;
2960 Type r = right.Type;
2961 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2963 foreach (PredefinedOperator po in operators) {
2964 if ((po.OperatorsMask & oper_mask) == 0)
2967 if (primitives_only) {
2968 if (!po.IsPrimitiveApplicable (l, r))
2971 if (!po.IsApplicable (ec, left, right))
2975 if (best_operator == null) {
2977 if (primitives_only)
2983 best_operator = po.ResolveBetterOperator (ec, best_operator);
2985 if (best_operator == null) {
2986 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2987 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2994 if (best_operator == null)
2997 Expression expr = best_operator.ConvertResult (ec, this);
2998 if (enum_type == null)
3002 // HACK: required by enum_conversion
3004 expr.Type = enum_type;
3005 return EmptyCast.Create (expr, enum_type);
3009 // Performs user-operator overloading
3011 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3014 if (oper == Operator.LogicalAnd)
3015 user_oper = Operator.BitwiseAnd;
3016 else if (oper == Operator.LogicalOr)
3017 user_oper = Operator.BitwiseOr;
3021 string op = GetOperatorMetadataName (user_oper);
3023 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3024 MethodGroupExpr right_operators = null;
3026 if (!TypeManager.IsEqual (r, l)) {
3027 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3028 if (right_operators == null && left_operators == null)
3030 } else if (left_operators == null) {
3034 ArrayList args = new ArrayList (2);
3035 Argument larg = new Argument (left);
3037 Argument rarg = new Argument (right);
3040 MethodGroupExpr union;
3043 // User-defined operator implementations always take precedence
3044 // over predefined operator implementations
3046 if (left_operators != null && right_operators != null) {
3047 if (IsPredefinedUserOperator (l, user_oper)) {
3048 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3050 union = left_operators;
3051 } else if (IsPredefinedUserOperator (r, user_oper)) {
3052 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3054 union = right_operators;
3056 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3058 } else if (left_operators != null) {
3059 union = left_operators;
3061 union = right_operators;
3064 union = union.OverloadResolve (ec, ref args, true, loc);
3068 Expression oper_expr;
3070 // TODO: CreateExpressionTree is allocated every time
3071 if (user_oper != oper) {
3072 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3073 oper == Operator.LogicalAnd, loc).Resolve (ec);
3075 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3078 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3079 // and not invoke user operator
3081 if ((oper & Operator.EqualityMask) != 0) {
3082 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3083 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3084 type = TypeManager.bool_type;
3085 if (left is NullLiteral || right is NullLiteral)
3086 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3087 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3089 // Two System.Delegate(s) are never equal
3101 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3106 private void CheckUselessComparison (Constant c, Type type)
3108 if (c == null || !IsTypeIntegral (type)
3109 || c is StringConstant
3110 || c is BoolConstant
3111 || c is FloatConstant
3112 || c is DoubleConstant
3113 || c is DecimalConstant
3119 if (c is ULongConstant) {
3120 ulong uvalue = ((ULongConstant) c).Value;
3121 if (uvalue > long.MaxValue) {
3122 if (type == TypeManager.byte_type ||
3123 type == TypeManager.sbyte_type ||
3124 type == TypeManager.short_type ||
3125 type == TypeManager.ushort_type ||
3126 type == TypeManager.int32_type ||
3127 type == TypeManager.uint32_type ||
3128 type == TypeManager.int64_type ||
3129 type == TypeManager.char_type)
3130 WarnUselessComparison (type);
3133 value = (long) uvalue;
3135 else if (c is ByteConstant)
3136 value = ((ByteConstant) c).Value;
3137 else if (c is SByteConstant)
3138 value = ((SByteConstant) c).Value;
3139 else if (c is ShortConstant)
3140 value = ((ShortConstant) c).Value;
3141 else if (c is UShortConstant)
3142 value = ((UShortConstant) c).Value;
3143 else if (c is IntConstant)
3144 value = ((IntConstant) c).Value;
3145 else if (c is UIntConstant)
3146 value = ((UIntConstant) c).Value;
3147 else if (c is LongConstant)
3148 value = ((LongConstant) c).Value;
3149 else if (c is CharConstant)
3150 value = ((CharConstant)c).Value;
3155 if (IsValueOutOfRange (value, type))
3156 WarnUselessComparison (type);
3159 static bool IsValueOutOfRange (long value, Type type)
3161 if (IsTypeUnsigned (type) && value < 0)
3163 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3164 type == TypeManager.byte_type && value >= 0x100 ||
3165 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3166 type == TypeManager.ushort_type && value >= 0x10000 ||
3167 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3168 type == TypeManager.uint32_type && value >= 0x100000000;
3171 static bool IsBuildInEqualityOperator (Type t)
3173 return t == TypeManager.object_type || t == TypeManager.string_type ||
3174 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3177 static bool IsPredefinedUserOperator (Type t, Operator op)
3180 // Some predefined types have user operators
3182 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3185 private static bool IsTypeIntegral (Type type)
3187 return type == TypeManager.uint64_type ||
3188 type == TypeManager.int64_type ||
3189 type == TypeManager.uint32_type ||
3190 type == TypeManager.int32_type ||
3191 type == TypeManager.ushort_type ||
3192 type == TypeManager.short_type ||
3193 type == TypeManager.sbyte_type ||
3194 type == TypeManager.byte_type ||
3195 type == TypeManager.char_type;
3198 private static bool IsTypeUnsigned (Type type)
3200 return type == TypeManager.uint64_type ||
3201 type == TypeManager.uint32_type ||
3202 type == TypeManager.ushort_type ||
3203 type == TypeManager.byte_type ||
3204 type == TypeManager.char_type;
3207 private void WarnUselessComparison (Type type)
3209 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}'",
3210 TypeManager.CSharpName (type));
3214 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3215 /// context of a conditional bool expression. This function will return
3216 /// false if it is was possible to use EmitBranchable, or true if it was.
3218 /// The expression's code is generated, and we will generate a branch to `target'
3219 /// if the resulting expression value is equal to isTrue
3221 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3223 ILGenerator ig = ec.ig;
3226 // This is more complicated than it looks, but its just to avoid
3227 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3228 // but on top of that we want for == and != to use a special path
3229 // if we are comparing against null
3231 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3232 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3235 // put the constant on the rhs, for simplicity
3237 if (left is Constant) {
3238 Expression swap = right;
3243 if (((Constant) right).IsZeroInteger) {
3244 left.EmitBranchable (ec, target, my_on_true);
3247 if (right.Type == TypeManager.bool_type) {
3248 // right is a boolean, and it's not 'false' => it is 'true'
3249 left.EmitBranchable (ec, target, !my_on_true);
3253 } else if (oper == Operator.LogicalAnd) {
3256 Label tests_end = ig.DefineLabel ();
3258 left.EmitBranchable (ec, tests_end, false);
3259 right.EmitBranchable (ec, target, true);
3260 ig.MarkLabel (tests_end);
3263 // This optimizes code like this
3264 // if (true && i > 4)
3266 if (!(left is Constant))
3267 left.EmitBranchable (ec, target, false);
3269 if (!(right is Constant))
3270 right.EmitBranchable (ec, target, false);
3275 } else if (oper == Operator.LogicalOr){
3277 left.EmitBranchable (ec, target, true);
3278 right.EmitBranchable (ec, target, true);
3281 Label tests_end = ig.DefineLabel ();
3282 left.EmitBranchable (ec, tests_end, true);
3283 right.EmitBranchable (ec, target, false);
3284 ig.MarkLabel (tests_end);
3289 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3290 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3291 oper == Operator.Equality || oper == Operator.Inequality)) {
3292 base.EmitBranchable (ec, target, on_true);
3300 bool is_float = IsFloat (t);
3301 bool is_unsigned = is_float || IsUnsigned (t);
3304 case Operator.Equality:
3306 ig.Emit (OpCodes.Beq, target);
3308 ig.Emit (OpCodes.Bne_Un, target);
3311 case Operator.Inequality:
3313 ig.Emit (OpCodes.Bne_Un, target);
3315 ig.Emit (OpCodes.Beq, target);
3318 case Operator.LessThan:
3320 if (is_unsigned && !is_float)
3321 ig.Emit (OpCodes.Blt_Un, target);
3323 ig.Emit (OpCodes.Blt, target);
3326 ig.Emit (OpCodes.Bge_Un, target);
3328 ig.Emit (OpCodes.Bge, target);
3331 case Operator.GreaterThan:
3333 if (is_unsigned && !is_float)
3334 ig.Emit (OpCodes.Bgt_Un, target);
3336 ig.Emit (OpCodes.Bgt, target);
3339 ig.Emit (OpCodes.Ble_Un, target);
3341 ig.Emit (OpCodes.Ble, target);
3344 case Operator.LessThanOrEqual:
3346 if (is_unsigned && !is_float)
3347 ig.Emit (OpCodes.Ble_Un, target);
3349 ig.Emit (OpCodes.Ble, target);
3352 ig.Emit (OpCodes.Bgt_Un, target);
3354 ig.Emit (OpCodes.Bgt, target);
3358 case Operator.GreaterThanOrEqual:
3360 if (is_unsigned && !is_float)
3361 ig.Emit (OpCodes.Bge_Un, target);
3363 ig.Emit (OpCodes.Bge, target);
3366 ig.Emit (OpCodes.Blt_Un, target);
3368 ig.Emit (OpCodes.Blt, target);
3371 throw new InternalErrorException (oper.ToString ());
3375 public override void Emit (EmitContext ec)
3377 EmitOperator (ec, left.Type);
3380 protected virtual void EmitOperator (EmitContext ec, Type l)
3382 ILGenerator ig = ec.ig;
3385 // Handle short-circuit operators differently
3388 if ((oper & Operator.LogicalMask) != 0) {
3389 Label load_result = ig.DefineLabel ();
3390 Label end = ig.DefineLabel ();
3392 bool is_or = oper == Operator.LogicalOr;
3393 left.EmitBranchable (ec, load_result, is_or);
3395 ig.Emit (OpCodes.Br_S, end);
3397 ig.MarkLabel (load_result);
3398 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3406 // Optimize zero-based operations
3408 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3410 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3411 Constant rc = right as Constant;
3412 if (rc != null && rc.IsDefaultValue) {
3418 EmitOperatorOpcode (ec, oper, l);
3421 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3422 // expression because that would wrap lifted binary operation
3424 if (enum_conversion != null)
3425 enum_conversion.Emit (ec);
3428 public override void EmitSideEffect (EmitContext ec)
3430 if ((oper & Operator.LogicalMask) != 0 ||
3431 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3432 base.EmitSideEffect (ec);
3434 left.EmitSideEffect (ec);
3435 right.EmitSideEffect (ec);
3439 protected override void CloneTo (CloneContext clonectx, Expression t)
3441 Binary target = (Binary) t;
3443 target.left = left.Clone (clonectx);
3444 target.right = right.Clone (clonectx);
3447 public override Expression CreateExpressionTree (EmitContext ec)
3449 return CreateExpressionTree (ec, null);
3452 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3455 bool lift_arg = false;
3458 case Operator.Addition:
3459 if (method == null && ec.CheckState && !IsFloat (type))
3460 method_name = "AddChecked";
3462 method_name = "Add";
3464 case Operator.BitwiseAnd:
3465 method_name = "And";
3467 case Operator.BitwiseOr:
3470 case Operator.Division:
3471 method_name = "Divide";
3473 case Operator.Equality:
3474 method_name = "Equal";
3477 case Operator.ExclusiveOr:
3478 method_name = "ExclusiveOr";
3480 case Operator.GreaterThan:
3481 method_name = "GreaterThan";
3484 case Operator.GreaterThanOrEqual:
3485 method_name = "GreaterThanOrEqual";
3488 case Operator.Inequality:
3489 method_name = "NotEqual";
3492 case Operator.LeftShift:
3493 method_name = "LeftShift";
3495 case Operator.LessThan:
3496 method_name = "LessThan";
3499 case Operator.LessThanOrEqual:
3500 method_name = "LessThanOrEqual";
3503 case Operator.LogicalAnd:
3504 method_name = "AndAlso";
3506 case Operator.LogicalOr:
3507 method_name = "OrElse";
3509 case Operator.Modulus:
3510 method_name = "Modulo";
3512 case Operator.Multiply:
3513 if (method == null && ec.CheckState && !IsFloat (type))
3514 method_name = "MultiplyChecked";
3516 method_name = "Multiply";
3518 case Operator.RightShift:
3519 method_name = "RightShift";
3521 case Operator.Subtraction:
3522 if (method == null && ec.CheckState && !IsFloat (type))
3523 method_name = "SubtractChecked";
3525 method_name = "Subtract";
3529 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3532 ArrayList args = new ArrayList (2);
3533 args.Add (new Argument (left.CreateExpressionTree (ec)));
3534 args.Add (new Argument (right.CreateExpressionTree (ec)));
3535 if (method != null) {
3537 args.Add (new Argument (new BoolConstant (false, loc)));
3539 args.Add (new Argument (method.CreateExpressionTree (ec)));
3542 return CreateExpressionFactoryCall (method_name, args);
3547 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3548 // b, c, d... may be strings or objects.
3550 public class StringConcat : Expression {
3551 ArrayList arguments;
3553 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3556 type = TypeManager.string_type;
3557 eclass = ExprClass.Value;
3559 arguments = new ArrayList (2);
3564 public override Expression CreateExpressionTree (EmitContext ec)
3566 Argument arg = (Argument) arguments [0];
3567 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3571 // Creates nested calls tree from an array of arguments used for IL emit
3573 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3575 ArrayList concat_args = new ArrayList (2);
3576 ArrayList add_args = new ArrayList (3);
3578 concat_args.Add (left);
3579 add_args.Add (new Argument (left_etree));
3581 concat_args.Add (arguments [pos]);
3582 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3584 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3588 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3592 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3594 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3595 if (++pos == arguments.Count)
3598 left = new Argument (new EmptyExpression (method.Type));
3599 return CreateExpressionAddCall (ec, left, expr, pos);
3602 public override Expression DoResolve (EmitContext ec)
3607 public void Append (EmitContext ec, Expression operand)
3612 StringConstant sc = operand as StringConstant;
3614 if (arguments.Count != 0) {
3615 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3616 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3617 if (last_expr_constant != null) {
3618 last_argument.Expr = new StringConstant (
3619 last_expr_constant.Value + sc.Value, sc.Location);
3625 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3627 StringConcat concat_oper = operand as StringConcat;
3628 if (concat_oper != null) {
3629 arguments.AddRange (concat_oper.arguments);
3634 arguments.Add (new Argument (operand));
3637 Expression CreateConcatMemberExpression ()
3639 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3642 public override void Emit (EmitContext ec)
3644 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3645 concat = concat.Resolve (ec);
3650 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3652 foreach (Argument a in arguments)
3653 a.Expr.MutateHoistedGenericType (storey);
3658 // User-defined conditional logical operator
3660 public class ConditionalLogicalOperator : UserOperatorCall {
3661 readonly bool is_and;
3664 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3665 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3666 : base (oper_method, arguments, expr_tree, loc)
3668 this.is_and = is_and;
3671 public override Expression DoResolve (EmitContext ec)
3673 MethodInfo method = (MethodInfo)mg;
3674 type = TypeManager.TypeToCoreType (method.ReturnType);
3675 AParametersCollection pd = TypeManager.GetParameterData (method);
3676 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3677 Report.Error (217, loc,
3678 "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",
3679 TypeManager.CSharpSignature (method));
3683 Expression left_dup = new EmptyExpression (type);
3684 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3685 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3686 if (op_true == null || op_false == null) {
3687 Report.Error (218, loc,
3688 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3689 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3693 oper = is_and ? op_false : op_true;
3694 eclass = ExprClass.Value;
3698 public override void Emit (EmitContext ec)
3700 ILGenerator ig = ec.ig;
3701 Label end_target = ig.DefineLabel ();
3704 // Emit and duplicate left argument
3706 ((Argument)arguments [0]).Expr.Emit (ec);
3707 ig.Emit (OpCodes.Dup);
3708 arguments.RemoveAt (0);
3710 oper.EmitBranchable (ec, end_target, true);
3712 ig.MarkLabel (end_target);
3716 public class PointerArithmetic : Expression {
3717 Expression left, right;
3721 // We assume that `l' is always a pointer
3723 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3732 public override Expression CreateExpressionTree (EmitContext ec)
3734 Error_PointerInsideExpressionTree ();
3738 public override Expression DoResolve (EmitContext ec)
3740 eclass = ExprClass.Variable;
3742 if (left.Type == TypeManager.void_ptr_type) {
3743 Error (242, "The operation in question is undefined on void pointers");
3750 public override void Emit (EmitContext ec)
3752 Type op_type = left.Type;
3753 ILGenerator ig = ec.ig;
3755 // It must be either array or fixed buffer
3757 if (TypeManager.HasElementType (op_type)) {
3758 element = TypeManager.GetElementType (op_type);
3760 FieldExpr fe = left as FieldExpr;
3762 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3767 int size = GetTypeSize (element);
3768 Type rtype = right.Type;
3770 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3772 // handle (pointer - pointer)
3776 ig.Emit (OpCodes.Sub);
3780 ig.Emit (OpCodes.Sizeof, element);
3782 IntLiteral.EmitInt (ig, size);
3783 ig.Emit (OpCodes.Div);
3785 ig.Emit (OpCodes.Conv_I8);
3788 // handle + and - on (pointer op int)
3792 Constant right_const = right as Constant;
3793 if (right_const != null) {
3795 // Optimize 0-based arithmetic
3797 if (right_const.IsDefaultValue)
3801 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3805 ig.Emit (OpCodes.Sizeof, element);
3806 right = EmptyExpression.Null;
3811 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3812 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3813 ig.Emit (OpCodes.Conv_I);
3814 } else if (rtype == TypeManager.uint32_type) {
3815 ig.Emit (OpCodes.Conv_U);
3818 if (right_const == null && size != 1){
3820 ig.Emit (OpCodes.Sizeof, element);
3822 IntLiteral.EmitInt (ig, size);
3823 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3824 ig.Emit (OpCodes.Conv_I8);
3826 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3829 if (rtype == TypeManager.int64_type)
3830 ig.Emit (OpCodes.Conv_I);
3831 else if (rtype == TypeManager.uint64_type)
3832 ig.Emit (OpCodes.Conv_U);
3834 Binary.EmitOperatorOpcode (ec, op, op_type);
3840 /// Implements the ternary conditional operator (?:)
3842 public class Conditional : Expression {
3843 Expression expr, true_expr, false_expr;
3845 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3848 this.true_expr = true_expr;
3849 this.false_expr = false_expr;
3850 this.loc = expr.Location;
3853 public Expression Expr {
3859 public Expression TrueExpr {
3865 public Expression FalseExpr {
3871 public override Expression CreateExpressionTree (EmitContext ec)
3873 ArrayList args = new ArrayList (3);
3874 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3875 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3876 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3877 return CreateExpressionFactoryCall ("Condition", args);
3880 public override Expression DoResolve (EmitContext ec)
3882 expr = expr.Resolve (ec);
3887 if (expr.Type != TypeManager.bool_type){
3888 expr = Expression.ResolveBoolean (
3895 Assign ass = expr as Assign;
3896 if (ass != null && ass.Source is Constant) {
3897 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3900 true_expr = true_expr.Resolve (ec);
3901 false_expr = false_expr.Resolve (ec);
3903 if (true_expr == null || false_expr == null)
3906 eclass = ExprClass.Value;
3907 Type true_type = true_expr.Type;
3908 Type false_type = false_expr.Type;
3912 // First, if an implicit conversion exists from true_expr
3913 // to false_expr, then the result type is of type false_expr.Type
3915 if (!TypeManager.IsEqual (true_type, false_type)) {
3916 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3919 // Check if both can convert implicitl to each other's type
3921 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3923 "Can not compute type of conditional expression " +
3924 "as `" + TypeManager.CSharpName (true_expr.Type) +
3925 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3926 "' convert implicitly to each other");
3931 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3934 Report.Error (173, loc,
3935 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3936 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3941 // Dead code optimalization
3942 Constant c = expr as Constant;
3944 bool is_false = c.IsDefaultValue;
3945 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3946 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3952 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3954 expr.MutateHoistedGenericType (storey);
3955 true_expr.MutateHoistedGenericType (storey);
3956 false_expr.MutateHoistedGenericType (storey);
3957 type = storey.MutateType (type);
3960 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3965 public override void Emit (EmitContext ec)
3967 ILGenerator ig = ec.ig;
3968 Label false_target = ig.DefineLabel ();
3969 Label end_target = ig.DefineLabel ();
3971 expr.EmitBranchable (ec, false_target, false);
3972 true_expr.Emit (ec);
3974 if (type.IsInterface) {
3975 LocalBuilder temp = ec.GetTemporaryLocal (type);
3976 ig.Emit (OpCodes.Stloc, temp);
3977 ig.Emit (OpCodes.Ldloc, temp);
3978 ec.FreeTemporaryLocal (temp, type);
3981 ig.Emit (OpCodes.Br, end_target);
3982 ig.MarkLabel (false_target);
3983 false_expr.Emit (ec);
3984 ig.MarkLabel (end_target);
3987 protected override void CloneTo (CloneContext clonectx, Expression t)
3989 Conditional target = (Conditional) t;
3991 target.expr = expr.Clone (clonectx);
3992 target.true_expr = true_expr.Clone (clonectx);
3993 target.false_expr = false_expr.Clone (clonectx);
3997 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
3998 LocalTemporary temp;
4001 public abstract HoistedVariable HoistedVariable { get; }
4002 public abstract bool IsFixedVariable { get; }
4003 public abstract bool IsRef { get; }
4004 public abstract string Name { get; }
4005 public abstract void SetHasAddressTaken ();
4008 // Variable IL data, it has to be protected to encapsulate hoisted variables
4010 protected abstract ILocalVariable Variable { get; }
4013 // Variable flow-analysis data
4015 public abstract VariableInfo VariableInfo { get; }
4018 public void AddressOf (EmitContext ec, AddressOp mode)
4020 if (IsHoistedEmitRequired (ec)) {
4021 HoistedVariable.AddressOf (ec, mode);
4025 Variable.EmitAddressOf (ec);
4028 public override void Emit (EmitContext ec)
4033 public override void EmitSideEffect (EmitContext ec)
4039 // This method is used by parameters that are references, that are
4040 // being passed as references: we only want to pass the pointer (that
4041 // is already stored in the parameter, not the address of the pointer,
4042 // and not the value of the variable).
4044 public void EmitLoad (EmitContext ec)
4049 public void Emit (EmitContext ec, bool leave_copy)
4051 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4053 if (IsHoistedEmitRequired (ec)) {
4054 HoistedVariable.Emit (ec, leave_copy);
4062 // If we are a reference, we loaded on the stack a pointer
4063 // Now lets load the real value
4065 LoadFromPtr (ec.ig, type);
4069 ec.ig.Emit (OpCodes.Dup);
4072 temp = new LocalTemporary (Type);
4078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4079 bool prepare_for_load)
4081 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4084 if (IsHoistedEmitRequired (ec)) {
4085 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4094 // HACK: variable is already emitted when source is an initializer
4095 if (source is NewInitialize) {
4103 ec.ig.Emit (OpCodes.Dup);
4105 temp = new LocalTemporary (Type);
4111 StoreFromPtr (ec.ig, type);
4113 Variable.EmitAssign (ec);
4121 public bool IsHoisted {
4122 get { return HoistedVariable != null; }
4125 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4128 // Default implementation return true when there is a hosted variable
4130 return HoistedVariable != null;
4133 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4135 type = storey.MutateType (type);
4142 public class LocalVariableReference : VariableReference {
4143 readonly string name;
4145 public LocalInfo local_info;
4148 public LocalVariableReference (Block block, string name, Location l)
4153 eclass = ExprClass.Variable;
4157 // Setting `is_readonly' to false will allow you to create a writable
4158 // reference to a read-only variable. This is used by foreach and using.
4160 public LocalVariableReference (Block block, string name, Location l,
4161 LocalInfo local_info, bool is_readonly)
4162 : this (block, name, l)
4164 this.local_info = local_info;
4165 this.is_readonly = is_readonly;
4168 public override VariableInfo VariableInfo {
4169 get { return local_info.VariableInfo; }
4172 public override HoistedVariable HoistedVariable {
4173 get { return local_info.HoistedVariableReference; }
4177 // A local variable is always fixed
4179 public override bool IsFixedVariable {
4180 get { return true; }
4183 public override bool IsRef {
4184 get { return false; }
4187 public bool IsReadOnly {
4188 get { return is_readonly; }
4191 public override string Name {
4192 get { return name; }
4195 public bool VerifyAssigned (EmitContext ec)
4197 VariableInfo variable_info = local_info.VariableInfo;
4198 return variable_info == null || variable_info.IsAssigned (ec, loc);
4201 void ResolveLocalInfo ()
4203 if (local_info == null) {
4204 local_info = Block.GetLocalInfo (Name);
4205 type = local_info.VariableType;
4206 is_readonly = local_info.ReadOnly;
4210 public override void SetHasAddressTaken ()
4212 local_info.AddressTaken = true;
4215 public override Expression CreateExpressionTree (EmitContext ec)
4217 ArrayList arg = new ArrayList (1);
4218 arg.Add (new Argument (this));
4219 return CreateExpressionFactoryCall ("Constant", arg);
4222 Expression DoResolveBase (EmitContext ec)
4224 type = local_info.VariableType;
4226 Expression e = Block.GetConstantExpression (Name);
4228 return e.Resolve (ec);
4230 VerifyAssigned (ec);
4233 // If we are referencing a variable from the external block
4234 // flag it for capturing
4236 if (ec.MustCaptureVariable (local_info)) {
4237 if (local_info.AddressTaken)
4238 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4240 if (ec.IsVariableCapturingRequired) {
4241 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4242 storey.CaptureLocalVariable (ec, local_info);
4249 public override Expression DoResolve (EmitContext ec)
4251 ResolveLocalInfo ();
4252 local_info.Used = true;
4254 if (type == null && local_info.Type is VarExpr) {
4255 local_info.VariableType = TypeManager.object_type;
4256 Error_VariableIsUsedBeforeItIsDeclared (Name);
4260 return DoResolveBase (ec);
4263 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4265 ResolveLocalInfo ();
4268 if (right_side == EmptyExpression.OutAccess)
4269 local_info.Used = true;
4271 // Infer implicitly typed local variable
4273 VarExpr ve = local_info.Type as VarExpr;
4275 if (!ve.InferType (ec, right_side))
4277 type = local_info.VariableType = ve.Type;
4284 if (right_side == EmptyExpression.OutAccess) {
4285 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4286 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4287 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4288 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4289 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4290 } else if (right_side == EmptyExpression.UnaryAddress) {
4291 code = 459; msg = "Cannot take the address of {1} `{0}'";
4293 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4295 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4296 } else if (VariableInfo != null) {
4297 VariableInfo.SetAssigned (ec);
4300 return DoResolveBase (ec);
4303 public override int GetHashCode ()
4305 return Name.GetHashCode ();
4308 public override bool Equals (object obj)
4310 LocalVariableReference lvr = obj as LocalVariableReference;
4314 return Name == lvr.Name && Block == lvr.Block;
4317 protected override ILocalVariable Variable {
4318 get { return local_info; }
4321 public override string ToString ()
4323 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4326 protected override void CloneTo (CloneContext clonectx, Expression t)
4328 LocalVariableReference target = (LocalVariableReference) t;
4330 target.Block = clonectx.LookupBlock (Block);
4331 if (local_info != null)
4332 target.local_info = clonectx.LookupVariable (local_info);
4337 /// This represents a reference to a parameter in the intermediate
4340 public class ParameterReference : VariableReference {
4341 readonly ToplevelParameterInfo pi;
4342 readonly ToplevelBlock referenced;
4344 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4347 this.referenced = referenced;
4351 public override bool IsRef {
4352 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4355 bool HasOutModifier {
4356 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4359 public override HoistedVariable HoistedVariable {
4360 get { return pi.Parameter.HoistedVariableReference; }
4364 // A ref or out parameter is classified as a moveable variable, even
4365 // if the argument given for the parameter is a fixed variable
4367 public override bool IsFixedVariable {
4368 get { return !IsRef; }
4371 public override string Name {
4372 get { return Parameter.Name; }
4375 public Parameter Parameter {
4376 get { return pi.Parameter; }
4379 public override VariableInfo VariableInfo {
4380 get { return pi.VariableInfo; }
4383 protected override ILocalVariable Variable {
4384 get { return Parameter; }
4387 public bool IsAssigned (EmitContext ec, Location loc)
4389 // HACK: Variables are not captured in probing mode
4390 if (ec.IsInProbingMode)
4393 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4396 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4400 public override void SetHasAddressTaken ()
4402 Parameter.HasAddressTaken = true;
4405 void SetAssigned (EmitContext ec)
4407 if (HasOutModifier && ec.DoFlowAnalysis)
4408 ec.CurrentBranching.SetAssigned (VariableInfo);
4411 bool DoResolveBase (EmitContext ec)
4413 type = pi.ParameterType;
4414 eclass = ExprClass.Variable;
4416 AnonymousExpression am = ec.CurrentAnonymousMethod;
4420 ToplevelBlock declared = pi.Block;
4421 if (declared != referenced) {
4423 Report.Error (1628, loc,
4424 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4425 Name, am.ContainerType);
4433 if (ec.IsVariableCapturingRequired) {
4434 if (pi.Parameter.HasAddressTaken)
4435 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4437 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4438 storey.CaptureParameter (ec, this);
4444 public override int GetHashCode ()
4446 return Name.GetHashCode ();
4449 public override bool Equals (object obj)
4451 ParameterReference pr = obj as ParameterReference;
4455 return Name == pr.Name && referenced == pr.referenced;
4458 protected override void CloneTo (CloneContext clonectx, Expression target)
4463 public override Expression CreateExpressionTree (EmitContext ec)
4465 if (IsHoistedEmitRequired (ec))
4466 return HoistedVariable.CreateExpressionTree (ec);
4468 return Parameter.ExpressionTreeVariableReference ();
4472 // Notice that for ref/out parameters, the type exposed is not the
4473 // same type exposed externally.
4476 // externally we expose "int&"
4477 // here we expose "int".
4479 // We record this in "is_ref". This means that the type system can treat
4480 // the type as it is expected, but when we generate the code, we generate
4481 // the alternate kind of code.
4483 public override Expression DoResolve (EmitContext ec)
4485 if (!DoResolveBase (ec))
4488 if (HasOutModifier && ec.DoFlowAnalysis &&
4489 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4495 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4497 if (!DoResolveBase (ec))
4500 // HACK: parameters are not captured when probing is on
4501 if (!ec.IsInProbingMode)
4507 static public void EmitLdArg (ILGenerator ig, int x)
4511 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4512 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4513 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4514 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4515 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4518 ig.Emit (OpCodes.Ldarg, x);
4523 /// Used for arguments to New(), Invocation()
4525 public class Argument {
4526 public enum AType : byte {
4533 public static readonly Argument[] Empty = new Argument [0];
4535 public readonly AType ArgType;
4536 public Expression Expr;
4538 public Argument (Expression expr, AType type)
4541 this.ArgType = type;
4544 public Argument (Expression expr)
4547 this.ArgType = AType.Expression;
4551 get { return Expr.Type; }
4554 public Parameter.Modifier Modifier
4559 return Parameter.Modifier.OUT;
4562 return Parameter.Modifier.REF;
4565 return Parameter.Modifier.NONE;
4570 public string GetSignatureForError ()
4572 if (Expr.eclass == ExprClass.MethodGroup)
4573 return Expr.ExprClassName;
4575 return TypeManager.CSharpName (Expr.Type);
4578 public bool ResolveMethodGroup (EmitContext ec)
4580 SimpleName sn = Expr as SimpleName;
4582 Expr = sn.GetMethodGroup ();
4584 // FIXME: csc doesn't report any error if you try to use `ref' or
4585 // `out' in a delegate creation expression.
4586 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4593 public bool Resolve (EmitContext ec, Location loc)
4598 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4599 // Verify that the argument is readable
4600 if (ArgType != AType.Out)
4601 Expr = Expr.Resolve (ec);
4603 // Verify that the argument is writeable
4604 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4605 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4607 return Expr != null;
4611 public void Emit (EmitContext ec)
4613 if (ArgType != AType.Ref && ArgType != AType.Out) {
4618 AddressOp mode = AddressOp.Store;
4619 if (ArgType == AType.Ref)
4620 mode |= AddressOp.Load;
4622 IMemoryLocation ml = (IMemoryLocation) Expr;
4623 ParameterReference pr = ml as ParameterReference;
4626 // ParameterReferences might already be references, so we want
4627 // to pass just the value
4629 if (pr != null && pr.IsRef)
4632 ml.AddressOf (ec, mode);
4635 public Argument Clone (CloneContext clonectx)
4637 return new Argument (Expr.Clone (clonectx), ArgType);
4642 /// Invocation of methods or delegates.
4644 public class Invocation : ExpressionStatement {
4645 protected ArrayList Arguments;
4646 protected Expression expr;
4647 protected MethodGroupExpr mg;
4648 bool arguments_resolved;
4651 // arguments is an ArrayList, but we do not want to typecast,
4652 // as it might be null.
4654 public Invocation (Expression expr, ArrayList arguments)
4656 SimpleName sn = expr as SimpleName;
4658 this.expr = sn.GetMethodGroup ();
4662 Arguments = arguments;
4664 loc = expr.Location;
4667 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4668 : this (expr, arguments)
4670 this.arguments_resolved = arguments_resolved;
4673 public override Expression CreateExpressionTree (EmitContext ec)
4678 // Special conversion for nested expression trees
4680 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4681 args = new ArrayList (1);
4682 args.Add (new Argument (this));
4683 return CreateExpressionFactoryCall ("Quote", args);
4686 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4688 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4691 args = new ArrayList (arg_count);
4694 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4696 args.Add (new Argument (new NullLiteral (loc)));
4698 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4701 // Use extension argument when exists
4704 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4706 args.Add (new Argument (e));
4709 if (Arguments != null) {
4710 foreach (Argument a in Arguments) {
4711 Expression e = a.Expr.CreateExpressionTree (ec);
4713 args.Add (new Argument (e));
4718 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4720 return CreateExpressionFactoryCall ("Call", args);
4723 public override Expression DoResolve (EmitContext ec)
4725 // Don't resolve already resolved expression
4726 if (eclass != ExprClass.Invalid)
4729 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4730 if (expr_resolved == null)
4733 mg = expr_resolved as MethodGroupExpr;
4735 Type expr_type = expr_resolved.Type;
4737 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4738 return (new DelegateInvocation (
4739 expr_resolved, Arguments, loc)).Resolve (ec);
4742 MemberExpr me = expr_resolved as MemberExpr;
4744 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4748 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4750 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4751 expr_resolved.GetSignatureForError ());
4755 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4759 // Next, evaluate all the expressions in the argument list
4761 if (Arguments != null && !arguments_resolved) {
4762 for (int i = 0; i < Arguments.Count; ++i)
4764 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4769 mg = DoResolveOverload (ec);
4773 MethodInfo method = (MethodInfo)mg;
4774 if (method != null) {
4775 type = TypeManager.TypeToCoreType (method.ReturnType);
4777 // TODO: this is a copy of mg.ResolveMemberAccess method
4778 Expression iexpr = mg.InstanceExpression;
4779 if (method.IsStatic) {
4780 if (iexpr == null ||
4781 iexpr is This || iexpr is EmptyExpression ||
4782 mg.IdenticalTypeName) {
4783 mg.InstanceExpression = null;
4785 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4789 if (iexpr == null) {
4790 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4795 if (type.IsPointer){
4803 // Only base will allow this invocation to happen.
4805 if (mg.IsBase && method.IsAbstract){
4806 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4810 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4812 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4814 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4818 IsSpecialMethodInvocation (method, loc);
4820 if (mg.InstanceExpression != null)
4821 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4823 eclass = ExprClass.Value;
4827 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4829 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4832 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4834 if (!TypeManager.IsSpecialMethod (method))
4837 Report.SymbolRelatedToPreviousError (method);
4838 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4839 TypeManager.CSharpSignature (method, true));
4845 /// Emits a list of resolved Arguments that are in the arguments
4848 /// The MethodBase argument might be null if the
4849 /// emission of the arguments is known not to contain
4850 /// a `params' field (for example in constructors or other routines
4851 /// that keep their arguments in this structure)
4853 /// if `dup_args' is true, a copy of the arguments will be left
4854 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4855 /// which will be duplicated before any other args. Only EmitCall
4856 /// should be using this interface.
4858 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4860 if (arguments == null)
4863 int top = arguments.Count;
4864 LocalTemporary [] temps = null;
4866 if (dup_args && top != 0)
4867 temps = new LocalTemporary [top];
4869 int argument_index = 0;
4871 for (int i = 0; i < top; i++) {
4872 a = (Argument) arguments [argument_index++];
4875 ec.ig.Emit (OpCodes.Dup);
4876 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4881 if (this_arg != null)
4884 for (int i = 0; i < top; i ++) {
4885 temps [i].Emit (ec);
4886 temps [i].Release (ec);
4891 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4893 AParametersCollection pd = TypeManager.GetParameterData (mb);
4895 Argument a = (Argument) arguments [pd.Count - 1];
4896 Arglist list = (Arglist) a.Expr;
4898 return list.ArgumentTypes;
4902 /// This checks the ConditionalAttribute on the method
4904 public static bool IsMethodExcluded (MethodBase method, Location loc)
4906 if (method.IsConstructor)
4909 method = TypeManager.DropGenericMethodArguments (method);
4910 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4911 IMethodData md = TypeManager.GetMethod (method);
4913 return md.IsExcluded ();
4915 // For some methods (generated by delegate class) GetMethod returns null
4916 // because they are not included in builder_to_method table
4920 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4924 /// is_base tells whether we want to force the use of the `call'
4925 /// opcode instead of using callvirt. Call is required to call
4926 /// a specific method, while callvirt will always use the most
4927 /// recent method in the vtable.
4929 /// is_static tells whether this is an invocation on a static method
4931 /// instance_expr is an expression that represents the instance
4932 /// it must be non-null if is_static is false.
4934 /// method is the method to invoke.
4936 /// Arguments is the list of arguments to pass to the method or constructor.
4938 public static void EmitCall (EmitContext ec, bool is_base,
4939 Expression instance_expr,
4940 MethodBase method, ArrayList Arguments, Location loc)
4942 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4945 // `dup_args' leaves an extra copy of the arguments on the stack
4946 // `omit_args' does not leave any arguments at all.
4947 // So, basically, you could make one call with `dup_args' set to true,
4948 // and then another with `omit_args' set to true, and the two calls
4949 // would have the same set of arguments. However, each argument would
4950 // only have been evaluated once.
4951 public static void EmitCall (EmitContext ec, bool is_base,
4952 Expression instance_expr,
4953 MethodBase method, ArrayList Arguments, Location loc,
4954 bool dup_args, bool omit_args)
4956 ILGenerator ig = ec.ig;
4957 bool struct_call = false;
4958 bool this_call = false;
4959 LocalTemporary this_arg = null;
4961 Type decl_type = method.DeclaringType;
4963 if (IsMethodExcluded (method, loc))
4966 bool is_static = method.IsStatic;
4968 this_call = instance_expr is This;
4969 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4973 // If this is ourselves, push "this"
4977 Type iexpr_type = instance_expr.Type;
4980 // Push the instance expression
4982 if (TypeManager.IsValueType (iexpr_type)) {
4984 // Special case: calls to a function declared in a
4985 // reference-type with a value-type argument need
4986 // to have their value boxed.
4987 if (decl_type.IsValueType ||
4988 TypeManager.IsGenericParameter (iexpr_type)) {
4990 // If the expression implements IMemoryLocation, then
4991 // we can optimize and use AddressOf on the
4994 // If not we have to use some temporary storage for
4996 if (instance_expr is IMemoryLocation) {
4997 ((IMemoryLocation)instance_expr).
4998 AddressOf (ec, AddressOp.LoadStore);
5000 LocalTemporary temp = new LocalTemporary (iexpr_type);
5001 instance_expr.Emit (ec);
5003 temp.AddressOf (ec, AddressOp.Load);
5006 // avoid the overhead of doing this all the time.
5008 t = TypeManager.GetReferenceType (iexpr_type);
5010 instance_expr.Emit (ec);
5011 ig.Emit (OpCodes.Box, instance_expr.Type);
5012 t = TypeManager.object_type;
5015 instance_expr.Emit (ec);
5016 t = instance_expr.Type;
5020 ig.Emit (OpCodes.Dup);
5021 if (Arguments != null && Arguments.Count != 0) {
5022 this_arg = new LocalTemporary (t);
5023 this_arg.Store (ec);
5030 EmitArguments (ec, Arguments, dup_args, this_arg);
5033 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5034 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5038 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5039 call_op = OpCodes.Call;
5041 call_op = OpCodes.Callvirt;
5043 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5044 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5045 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5052 // and DoFoo is not virtual, you can omit the callvirt,
5053 // because you don't need the null checking behavior.
5055 if (method is MethodInfo)
5056 ig.Emit (call_op, (MethodInfo) method);
5058 ig.Emit (call_op, (ConstructorInfo) method);
5061 public override void Emit (EmitContext ec)
5063 mg.EmitCall (ec, Arguments);
5066 public override void EmitStatement (EmitContext ec)
5071 // Pop the return value if there is one
5073 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5074 ec.ig.Emit (OpCodes.Pop);
5077 protected override void CloneTo (CloneContext clonectx, Expression t)
5079 Invocation target = (Invocation) t;
5081 if (Arguments != null) {
5082 target.Arguments = new ArrayList (Arguments.Count);
5083 foreach (Argument a in Arguments)
5084 target.Arguments.Add (a.Clone (clonectx));
5087 target.expr = expr.Clone (clonectx);
5090 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5092 mg.MutateHoistedGenericType (storey);
5093 if (Arguments != null) {
5094 foreach (Argument a in Arguments)
5095 a.Expr.MutateHoistedGenericType (storey);
5101 // It's either a cast or delegate invocation
5103 public class InvocationOrCast : ExpressionStatement
5106 Expression argument;
5108 public InvocationOrCast (Expression expr, Expression argument)
5111 this.argument = argument;
5112 this.loc = expr.Location;
5115 public override Expression CreateExpressionTree (EmitContext ec)
5117 throw new NotSupportedException ("ET");
5120 public override Expression DoResolve (EmitContext ec)
5122 Expression e = ResolveCore (ec);
5126 return e.Resolve (ec);
5129 Expression ResolveCore (EmitContext ec)
5132 // First try to resolve it as a cast.
5134 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5136 return new Cast (te, argument, loc);
5140 // This can either be a type or a delegate invocation.
5141 // Let's just resolve it and see what we'll get.
5143 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5148 // Ok, so it's a Cast.
5150 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5151 return new Cast (expr, argument, loc);
5154 if (expr.eclass == ExprClass.Namespace) {
5155 expr.Error_UnexpectedKind (null, "type", loc);
5160 // It's a delegate invocation.
5162 if (!TypeManager.IsDelegateType (expr.Type)) {
5163 Error (149, "Method name expected");
5167 ArrayList args = new ArrayList (1);
5168 args.Add (new Argument (argument, Argument.AType.Expression));
5169 return new DelegateInvocation (expr, args, loc);
5172 public override ExpressionStatement ResolveStatement (EmitContext ec)
5174 Expression e = ResolveCore (ec);
5178 ExpressionStatement s = e as ExpressionStatement;
5180 Error_InvalidExpressionStatement ();
5184 return s.ResolveStatement (ec);
5187 public override void Emit (EmitContext ec)
5189 throw new Exception ("Cannot happen");
5192 public override void EmitStatement (EmitContext ec)
5194 throw new Exception ("Cannot happen");
5197 protected override void CloneTo (CloneContext clonectx, Expression t)
5199 InvocationOrCast target = (InvocationOrCast) t;
5201 target.expr = expr.Clone (clonectx);
5202 target.argument = argument.Clone (clonectx);
5207 // This class is used to "disable" the code generation for the
5208 // temporary variable when initializing value types.
5210 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5211 public void AddressOf (EmitContext ec, AddressOp Mode)
5218 /// Implements the new expression
5220 public class New : ExpressionStatement, IMemoryLocation {
5221 ArrayList Arguments;
5224 // During bootstrap, it contains the RequestedType,
5225 // but if `type' is not null, it *might* contain a NewDelegate
5226 // (because of field multi-initialization)
5228 public Expression RequestedType;
5230 MethodGroupExpr method;
5233 // If set, the new expression is for a value_target, and
5234 // we will not leave anything on the stack.
5236 protected Expression value_target;
5237 protected bool value_target_set;
5238 bool is_type_parameter = false;
5240 public New (Expression requested_type, ArrayList arguments, Location l)
5242 RequestedType = requested_type;
5243 Arguments = arguments;
5247 public bool SetTargetVariable (Expression value)
5249 value_target = value;
5250 value_target_set = true;
5251 if (!(value_target is IMemoryLocation)){
5252 Error_UnexpectedKind (null, "variable", loc);
5259 // This function is used to disable the following code sequence for
5260 // value type initialization:
5262 // AddressOf (temporary)
5266 // Instead the provide will have provided us with the address on the
5267 // stack to store the results.
5269 static Expression MyEmptyExpression;
5271 public void DisableTemporaryValueType ()
5273 if (MyEmptyExpression == null)
5274 MyEmptyExpression = new EmptyAddressOf ();
5277 // To enable this, look into:
5278 // test-34 and test-89 and self bootstrapping.
5280 // For instance, we can avoid a copy by using `newobj'
5281 // instead of Call + Push-temp on value types.
5282 // value_target = MyEmptyExpression;
5287 /// Converts complex core type syntax like 'new int ()' to simple constant
5289 public static Constant Constantify (Type t)
5291 if (t == TypeManager.int32_type)
5292 return new IntConstant (0, Location.Null);
5293 if (t == TypeManager.uint32_type)
5294 return new UIntConstant (0, Location.Null);
5295 if (t == TypeManager.int64_type)
5296 return new LongConstant (0, Location.Null);
5297 if (t == TypeManager.uint64_type)
5298 return new ULongConstant (0, Location.Null);
5299 if (t == TypeManager.float_type)
5300 return new FloatConstant (0, Location.Null);
5301 if (t == TypeManager.double_type)
5302 return new DoubleConstant (0, Location.Null);
5303 if (t == TypeManager.short_type)
5304 return new ShortConstant (0, Location.Null);
5305 if (t == TypeManager.ushort_type)
5306 return new UShortConstant (0, Location.Null);
5307 if (t == TypeManager.sbyte_type)
5308 return new SByteConstant (0, Location.Null);
5309 if (t == TypeManager.byte_type)
5310 return new ByteConstant (0, Location.Null);
5311 if (t == TypeManager.char_type)
5312 return new CharConstant ('\0', Location.Null);
5313 if (t == TypeManager.bool_type)
5314 return new BoolConstant (false, Location.Null);
5315 if (t == TypeManager.decimal_type)
5316 return new DecimalConstant (0, Location.Null);
5317 if (TypeManager.IsEnumType (t))
5318 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5324 // Checks whether the type is an interface that has the
5325 // [ComImport, CoClass] attributes and must be treated
5328 public Expression CheckComImport (EmitContext ec)
5330 if (!type.IsInterface)
5334 // Turn the call into:
5335 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5337 Type real_class = AttributeTester.GetCoClassAttribute (type);
5338 if (real_class == null)
5341 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5342 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5343 return cast.Resolve (ec);
5346 public override Expression CreateExpressionTree (EmitContext ec)
5348 ArrayList args = Arguments == null ?
5349 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5351 if (method == null) {
5352 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5354 args.Add (new Argument (method.CreateExpressionTree (ec)));
5355 if (Arguments != null) {
5357 foreach (Argument a in Arguments) {
5358 expr = a.Expr.CreateExpressionTree (ec);
5360 args.Add (new Argument (expr));
5365 return CreateExpressionFactoryCall ("New", args);
5368 public override Expression DoResolve (EmitContext ec)
5371 // The New DoResolve might be called twice when initializing field
5372 // expressions (see EmitFieldInitializers, the call to
5373 // GetInitializerExpression will perform a resolve on the expression,
5374 // and later the assign will trigger another resolution
5376 // This leads to bugs (#37014)
5379 if (RequestedType is NewDelegate)
5380 return RequestedType;
5384 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5390 if (type.IsPointer) {
5391 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5392 TypeManager.CSharpName (type));
5396 if (Arguments == null) {
5397 Constant c = Constantify (type);
5399 return ReducedExpression.Create (c, this);
5402 if (TypeManager.IsDelegateType (type)) {
5403 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5407 if (type.IsGenericParameter) {
5408 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5410 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5411 Error (304, String.Format (
5412 "Cannot create an instance of the " +
5413 "variable type '{0}' because it " +
5414 "doesn't have the new() constraint",
5419 if ((Arguments != null) && (Arguments.Count != 0)) {
5420 Error (417, String.Format (
5421 "`{0}': cannot provide arguments " +
5422 "when creating an instance of a " +
5423 "variable type.", type));
5427 if (TypeManager.activator_create_instance == null) {
5428 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5429 if (activator_type != null) {
5430 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5431 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5435 is_type_parameter = true;
5436 eclass = ExprClass.Value;
5441 if (type.IsAbstract && type.IsSealed) {
5442 Report.SymbolRelatedToPreviousError (type);
5443 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5447 if (type.IsInterface || type.IsAbstract){
5448 if (!TypeManager.IsGenericType (type)) {
5449 RequestedType = CheckComImport (ec);
5450 if (RequestedType != null)
5451 return RequestedType;
5454 Report.SymbolRelatedToPreviousError (type);
5455 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5459 bool is_struct = type.IsValueType;
5460 eclass = ExprClass.Value;
5463 // SRE returns a match for .ctor () on structs (the object constructor),
5464 // so we have to manually ignore it.
5466 if (is_struct && Arguments == null)
5469 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5470 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5471 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5473 if (Arguments != null){
5474 foreach (Argument a in Arguments){
5475 if (!a.Resolve (ec, loc))
5483 method = ml as MethodGroupExpr;
5484 if (method == null) {
5485 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5489 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5496 bool DoEmitTypeParameter (EmitContext ec)
5499 ILGenerator ig = ec.ig;
5500 // IMemoryLocation ml;
5502 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5503 new Type [] { type });
5505 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5506 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5507 ig.Emit (OpCodes.Call, ci);
5511 // Allow DoEmit() to be called multiple times.
5512 // We need to create a new LocalTemporary each time since
5513 // you can't share LocalBuilders among ILGeneators.
5514 LocalTemporary temp = new LocalTemporary (type);
5516 Label label_activator = ig.DefineLabel ();
5517 Label label_end = ig.DefineLabel ();
5519 temp.AddressOf (ec, AddressOp.Store);
5520 ig.Emit (OpCodes.Initobj, type);
5523 ig.Emit (OpCodes.Box, type);
5524 ig.Emit (OpCodes.Brfalse, label_activator);
5526 temp.AddressOf (ec, AddressOp.Store);
5527 ig.Emit (OpCodes.Initobj, type);
5529 ig.Emit (OpCodes.Br, label_end);
5531 ig.MarkLabel (label_activator);
5533 ig.Emit (OpCodes.Call, ci);
5534 ig.MarkLabel (label_end);
5537 throw new InternalErrorException ();
5542 // This DoEmit can be invoked in two contexts:
5543 // * As a mechanism that will leave a value on the stack (new object)
5544 // * As one that wont (init struct)
5546 // You can control whether a value is required on the stack by passing
5547 // need_value_on_stack. The code *might* leave a value on the stack
5548 // so it must be popped manually
5550 // If we are dealing with a ValueType, we have a few
5551 // situations to deal with:
5553 // * The target is a ValueType, and we have been provided
5554 // the instance (this is easy, we are being assigned).
5556 // * The target of New is being passed as an argument,
5557 // to a boxing operation or a function that takes a
5560 // In this case, we need to create a temporary variable
5561 // that is the argument of New.
5563 // Returns whether a value is left on the stack
5565 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5567 bool is_value_type = TypeManager.IsValueType (type);
5568 ILGenerator ig = ec.ig;
5573 // Allow DoEmit() to be called multiple times.
5574 // We need to create a new LocalTemporary each time since
5575 // you can't share LocalBuilders among ILGeneators.
5576 if (!value_target_set)
5577 value_target = new LocalTemporary (type);
5579 ml = (IMemoryLocation) value_target;
5580 ml.AddressOf (ec, AddressOp.Store);
5584 method.EmitArguments (ec, Arguments);
5588 ig.Emit (OpCodes.Initobj, type);
5590 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5591 if (need_value_on_stack){
5592 value_target.Emit (ec);
5597 ConstructorInfo ci = (ConstructorInfo) method;
5599 if (TypeManager.IsGenericType (type))
5600 ci = TypeBuilder.GetConstructor (type, ci);
5602 ig.Emit (OpCodes.Newobj, ci);
5607 public override void Emit (EmitContext ec)
5609 if (is_type_parameter)
5610 DoEmitTypeParameter (ec);
5615 public override void EmitStatement (EmitContext ec)
5617 bool value_on_stack;
5619 if (is_type_parameter)
5620 value_on_stack = DoEmitTypeParameter (ec);
5622 value_on_stack = DoEmit (ec, false);
5625 ec.ig.Emit (OpCodes.Pop);
5629 public virtual bool HasInitializer {
5635 public void AddressOf (EmitContext ec, AddressOp Mode)
5637 if (is_type_parameter) {
5638 LocalTemporary temp = new LocalTemporary (type);
5639 DoEmitTypeParameter (ec);
5641 temp.AddressOf (ec, Mode);
5645 if (!type.IsValueType){
5647 // We throw an exception. So far, I believe we only need to support
5649 // foreach (int j in new StructType ())
5652 throw new Exception ("AddressOf should not be used for classes");
5655 if (!value_target_set)
5656 value_target = new LocalTemporary (type);
5657 IMemoryLocation ml = (IMemoryLocation) value_target;
5659 ml.AddressOf (ec, AddressOp.Store);
5660 if (method == null) {
5661 ec.ig.Emit (OpCodes.Initobj, type);
5663 method.EmitArguments (ec, Arguments);
5664 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5667 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5670 protected override void CloneTo (CloneContext clonectx, Expression t)
5672 New target = (New) t;
5674 target.RequestedType = RequestedType.Clone (clonectx);
5675 if (Arguments != null){
5676 target.Arguments = new ArrayList ();
5677 foreach (Argument a in Arguments){
5678 target.Arguments.Add (a.Clone (clonectx));
5683 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5685 if (method != null) {
5686 method.MutateHoistedGenericType (storey);
5687 if (Arguments != null) {
5688 foreach (Argument a in Arguments)
5689 a.Expr.MutateHoistedGenericType (storey);
5693 type = storey.MutateType (type);
5698 /// 14.5.10.2: Represents an array creation expression.
5702 /// There are two possible scenarios here: one is an array creation
5703 /// expression that specifies the dimensions and optionally the
5704 /// initialization data and the other which does not need dimensions
5705 /// specified but where initialization data is mandatory.
5707 public class ArrayCreation : Expression {
5708 FullNamedExpression requested_base_type;
5709 ArrayList initializers;
5712 // The list of Argument types.
5713 // This is used to construct the `newarray' or constructor signature
5715 protected ArrayList arguments;
5717 protected Type array_element_type;
5718 bool expect_initializers = false;
5719 int num_arguments = 0;
5720 protected int dimensions;
5721 protected readonly string rank;
5723 protected ArrayList array_data;
5727 // The number of constants in array initializers
5728 int const_initializers_count;
5729 bool only_constant_initializers;
5731 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5733 this.requested_base_type = requested_base_type;
5734 this.initializers = initializers;
5738 arguments = new ArrayList (exprs.Count);
5740 foreach (Expression e in exprs) {
5741 arguments.Add (new Argument (e, Argument.AType.Expression));
5746 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5748 this.requested_base_type = requested_base_type;
5749 this.initializers = initializers;
5753 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5755 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5757 //dimensions = tmp.Length - 1;
5758 expect_initializers = true;
5761 void Error_IncorrectArrayInitializer ()
5763 Error (178, "Invalid rank specifier: expected `,' or `]'");
5766 protected override void Error_NegativeArrayIndex (Location loc)
5768 Report.Error (248, loc, "Cannot create an array with a negative size");
5771 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5773 if (specified_dims) {
5774 Argument a = (Argument) arguments [idx];
5776 if (!a.Resolve (ec, loc))
5779 Constant c = a.Expr as Constant;
5781 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5785 Report.Error (150, a.Expr.Location, "A constant value is expected");
5789 int value = (int) c.GetValue ();
5791 if (value != probe.Count) {
5792 Error_IncorrectArrayInitializer ();
5796 bounds [idx] = value;
5799 int child_bounds = -1;
5800 only_constant_initializers = true;
5801 for (int i = 0; i < probe.Count; ++i) {
5802 object o = probe [i];
5803 if (o is ArrayList) {
5804 ArrayList sub_probe = o as ArrayList;
5805 int current_bounds = sub_probe.Count;
5807 if (child_bounds == -1)
5808 child_bounds = current_bounds;
5810 else if (child_bounds != current_bounds){
5811 Error_IncorrectArrayInitializer ();
5814 if (idx + 1 >= dimensions){
5815 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5819 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5823 if (child_bounds != -1){
5824 Error_IncorrectArrayInitializer ();
5828 Expression element = ResolveArrayElement (ec, (Expression) o);
5829 if (element == null)
5832 // Initializers with the default values can be ignored
5833 Constant c = element as Constant;
5835 if (c.IsDefaultInitializer (array_element_type)) {
5839 ++const_initializers_count;
5842 only_constant_initializers = false;
5845 array_data.Add (element);
5852 public override Expression CreateExpressionTree (EmitContext ec)
5856 if (array_data == null) {
5857 args = new ArrayList (arguments.Count + 1);
5858 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5859 foreach (Argument a in arguments) {
5860 if (arguments.Count == 1) {
5861 Constant c = a.Expr as Constant;
5862 if (c.IsDefaultValue)
5863 return CreateExpressionFactoryCall ("NewArrayInit", args);
5865 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5868 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5871 if (dimensions > 1) {
5872 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5876 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5877 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5878 if (array_data != null) {
5879 for (int i = 0; i < array_data.Count; ++i) {
5880 Expression e = (Expression) array_data [i];
5882 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5884 args.Add (new Argument (e.CreateExpressionTree (ec)));
5888 return CreateExpressionFactoryCall ("NewArrayInit", args);
5891 public void UpdateIndices ()
5894 for (ArrayList probe = initializers; probe != null;) {
5895 if (probe.Count > 0 && probe [0] is ArrayList) {
5896 Expression e = new IntConstant (probe.Count, Location.Null);
5897 arguments.Add (new Argument (e, Argument.AType.Expression));
5899 bounds [i++] = probe.Count;
5901 probe = (ArrayList) probe [0];
5904 Expression e = new IntConstant (probe.Count, Location.Null);
5905 arguments.Add (new Argument (e, Argument.AType.Expression));
5907 bounds [i++] = probe.Count;
5914 Expression first_emit;
5915 LocalTemporary first_emit_temp;
5917 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5919 element = element.Resolve (ec);
5920 if (element == null)
5923 if (element is CompoundAssign.Helper) {
5924 if (first_emit != null)
5925 throw new InternalErrorException ("Can only handle one mutator at a time");
5926 first_emit = element;
5927 element = first_emit_temp = new LocalTemporary (element.Type);
5930 return Convert.ImplicitConversionRequired (
5931 ec, element, array_element_type, loc);
5934 protected bool ResolveInitializers (EmitContext ec)
5936 if (initializers == null) {
5937 return !expect_initializers;
5941 // We use this to store all the date values in the order in which we
5942 // will need to store them in the byte blob later
5944 array_data = new ArrayList ();
5945 bounds = new System.Collections.Specialized.HybridDictionary ();
5947 if (arguments != null)
5948 return CheckIndices (ec, initializers, 0, true);
5950 arguments = new ArrayList ();
5952 if (!CheckIndices (ec, initializers, 0, false))
5961 // Resolved the type of the array
5963 bool ResolveArrayType (EmitContext ec)
5965 if (requested_base_type == null) {
5966 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5970 if (requested_base_type is VarExpr) {
5971 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5975 StringBuilder array_qualifier = new StringBuilder (rank);
5978 // `In the first form allocates an array instace of the type that results
5979 // from deleting each of the individual expression from the expression list'
5981 if (num_arguments > 0) {
5982 array_qualifier.Append ("[");
5983 for (int i = num_arguments-1; i > 0; i--)
5984 array_qualifier.Append (",");
5985 array_qualifier.Append ("]");
5991 TypeExpr array_type_expr;
5992 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5993 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5994 if (array_type_expr == null)
5997 type = array_type_expr.Type;
5998 array_element_type = TypeManager.GetElementType (type);
5999 dimensions = type.GetArrayRank ();
6004 public override Expression DoResolve (EmitContext ec)
6009 if (!ResolveArrayType (ec))
6013 // First step is to validate the initializers and fill
6014 // in any missing bits
6016 if (!ResolveInitializers (ec))
6019 if (arguments.Count != dimensions) {
6020 Error_IncorrectArrayInitializer ();
6023 foreach (Argument a in arguments){
6024 if (!a.Resolve (ec, loc))
6027 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6030 eclass = ExprClass.Value;
6034 MethodInfo GetArrayMethod (int arguments)
6036 ModuleBuilder mb = CodeGen.Module.Builder;
6038 Type[] arg_types = new Type[arguments];
6039 for (int i = 0; i < arguments; i++)
6040 arg_types[i] = TypeManager.int32_type;
6042 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6046 Report.Error (-6, "New invocation: Can not find a constructor for " +
6047 "this argument list");
6054 byte [] MakeByteBlob ()
6059 int count = array_data.Count;
6061 if (TypeManager.IsEnumType (array_element_type))
6062 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6064 factor = GetTypeSize (array_element_type);
6066 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6068 data = new byte [(count * factor + 3) & ~3];
6071 for (int i = 0; i < count; ++i) {
6072 object v = array_data [i];
6074 if (v is EnumConstant)
6075 v = ((EnumConstant) v).Child;
6077 if (v is Constant && !(v is StringConstant))
6078 v = ((Constant) v).GetValue ();
6084 if (array_element_type == TypeManager.int64_type){
6085 if (!(v is Expression)){
6086 long val = (long) v;
6088 for (int j = 0; j < factor; ++j) {
6089 data [idx + j] = (byte) (val & 0xFF);
6093 } else if (array_element_type == TypeManager.uint64_type){
6094 if (!(v is Expression)){
6095 ulong val = (ulong) v;
6097 for (int j = 0; j < factor; ++j) {
6098 data [idx + j] = (byte) (val & 0xFF);
6102 } else if (array_element_type == TypeManager.float_type) {
6103 if (!(v is Expression)){
6104 element = BitConverter.GetBytes ((float) v);
6106 for (int j = 0; j < factor; ++j)
6107 data [idx + j] = element [j];
6108 if (!BitConverter.IsLittleEndian)
6109 System.Array.Reverse (data, idx, 4);
6111 } else if (array_element_type == TypeManager.double_type) {
6112 if (!(v is Expression)){
6113 element = BitConverter.GetBytes ((double) v);
6115 for (int j = 0; j < factor; ++j)
6116 data [idx + j] = element [j];
6118 // FIXME: Handle the ARM float format.
6119 if (!BitConverter.IsLittleEndian)
6120 System.Array.Reverse (data, idx, 8);
6122 } else if (array_element_type == TypeManager.char_type){
6123 if (!(v is Expression)){
6124 int val = (int) ((char) v);
6126 data [idx] = (byte) (val & 0xff);
6127 data [idx+1] = (byte) (val >> 8);
6129 } else if (array_element_type == TypeManager.short_type){
6130 if (!(v is Expression)){
6131 int val = (int) ((short) v);
6133 data [idx] = (byte) (val & 0xff);
6134 data [idx+1] = (byte) (val >> 8);
6136 } else if (array_element_type == TypeManager.ushort_type){
6137 if (!(v is Expression)){
6138 int val = (int) ((ushort) v);
6140 data [idx] = (byte) (val & 0xff);
6141 data [idx+1] = (byte) (val >> 8);
6143 } else if (array_element_type == TypeManager.int32_type) {
6144 if (!(v is Expression)){
6147 data [idx] = (byte) (val & 0xff);
6148 data [idx+1] = (byte) ((val >> 8) & 0xff);
6149 data [idx+2] = (byte) ((val >> 16) & 0xff);
6150 data [idx+3] = (byte) (val >> 24);
6152 } else if (array_element_type == TypeManager.uint32_type) {
6153 if (!(v is Expression)){
6154 uint val = (uint) v;
6156 data [idx] = (byte) (val & 0xff);
6157 data [idx+1] = (byte) ((val >> 8) & 0xff);
6158 data [idx+2] = (byte) ((val >> 16) & 0xff);
6159 data [idx+3] = (byte) (val >> 24);
6161 } else if (array_element_type == TypeManager.sbyte_type) {
6162 if (!(v is Expression)){
6163 sbyte val = (sbyte) v;
6164 data [idx] = (byte) val;
6166 } else if (array_element_type == TypeManager.byte_type) {
6167 if (!(v is Expression)){
6168 byte val = (byte) v;
6169 data [idx] = (byte) val;
6171 } else if (array_element_type == TypeManager.bool_type) {
6172 if (!(v is Expression)){
6173 bool val = (bool) v;
6174 data [idx] = (byte) (val ? 1 : 0);
6176 } else if (array_element_type == TypeManager.decimal_type){
6177 if (!(v is Expression)){
6178 int [] bits = Decimal.GetBits ((decimal) v);
6181 // FIXME: For some reason, this doesn't work on the MS runtime.
6182 int [] nbits = new int [4];
6183 nbits [0] = bits [3];
6184 nbits [1] = bits [2];
6185 nbits [2] = bits [0];
6186 nbits [3] = bits [1];
6188 for (int j = 0; j < 4; j++){
6189 data [p++] = (byte) (nbits [j] & 0xff);
6190 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6191 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6192 data [p++] = (byte) (nbits [j] >> 24);
6196 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6204 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6206 array_element_type = storey.MutateType (array_element_type);
6207 type = storey.MutateType (type);
6208 if (arguments != null) {
6209 foreach (Argument a in arguments)
6210 a.Expr.MutateHoistedGenericType (storey);
6213 if (array_data != null) {
6214 foreach (Expression e in array_data)
6215 e.MutateHoistedGenericType (storey);
6220 // Emits the initializers for the array
6222 void EmitStaticInitializers (EmitContext ec)
6224 // FIXME: This should go to Resolve !
6225 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6226 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6227 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6228 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6229 if (TypeManager.void_initializearray_array_fieldhandle == null)
6234 // First, the static data
6237 ILGenerator ig = ec.ig;
6239 byte [] data = MakeByteBlob ();
6241 fb = RootContext.MakeStaticData (data);
6243 ig.Emit (OpCodes.Dup);
6244 ig.Emit (OpCodes.Ldtoken, fb);
6245 ig.Emit (OpCodes.Call,
6246 TypeManager.void_initializearray_array_fieldhandle);
6250 // Emits pieces of the array that can not be computed at compile
6251 // time (variables and string locations).
6253 // This always expect the top value on the stack to be the array
6255 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6257 ILGenerator ig = ec.ig;
6258 int dims = bounds.Count;
6259 int [] current_pos = new int [dims];
6261 MethodInfo set = null;
6264 Type [] args = new Type [dims + 1];
6266 for (int j = 0; j < dims; j++)
6267 args [j] = TypeManager.int32_type;
6268 args [dims] = array_element_type;
6270 set = CodeGen.Module.Builder.GetArrayMethod (
6272 CallingConventions.HasThis | CallingConventions.Standard,
6273 TypeManager.void_type, args);
6276 for (int i = 0; i < array_data.Count; i++){
6278 Expression e = (Expression)array_data [i];
6280 // Constant can be initialized via StaticInitializer
6281 if (e != null && !(!emitConstants && e is Constant)) {
6282 Type etype = e.Type;
6284 ig.Emit (OpCodes.Dup);
6286 for (int idx = 0; idx < dims; idx++)
6287 IntConstant.EmitInt (ig, current_pos [idx]);
6290 // If we are dealing with a struct, get the
6291 // address of it, so we can store it.
6293 if ((dims == 1) && etype.IsValueType &&
6294 (!TypeManager.IsBuiltinOrEnum (etype) ||
6295 etype == TypeManager.decimal_type)) {
6300 // Let new know that we are providing
6301 // the address where to store the results
6303 n.DisableTemporaryValueType ();
6306 ig.Emit (OpCodes.Ldelema, etype);
6312 bool is_stobj, has_type_arg;
6313 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6315 ig.Emit (OpCodes.Stobj, etype);
6316 else if (has_type_arg)
6317 ig.Emit (op, etype);
6321 ig.Emit (OpCodes.Call, set);
6328 for (int j = dims - 1; j >= 0; j--){
6330 if (current_pos [j] < (int) bounds [j])
6332 current_pos [j] = 0;
6337 public override void Emit (EmitContext ec)
6339 ILGenerator ig = ec.ig;
6341 if (first_emit != null) {
6342 first_emit.Emit (ec);
6343 first_emit_temp.Store (ec);
6346 foreach (Argument a in arguments)
6349 if (arguments.Count == 1)
6350 ig.Emit (OpCodes.Newarr, array_element_type);
6352 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6355 if (initializers == null)
6358 // Emit static initializer for arrays which have contain more than 4 items and
6359 // the static initializer will initialize at least 25% of array values.
6360 // NOTE: const_initializers_count does not contain default constant values.
6361 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6362 TypeManager.IsPrimitiveType (array_element_type)) {
6363 EmitStaticInitializers (ec);
6365 if (!only_constant_initializers)
6366 EmitDynamicInitializers (ec, false);
6368 EmitDynamicInitializers (ec, true);
6371 if (first_emit_temp != null)
6372 first_emit_temp.Release (ec);
6375 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6377 if (arguments.Count != 1) {
6378 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6379 return base.GetAttributableValue (ec, null, out value);
6382 if (array_data == null) {
6383 Constant c = (Constant)((Argument)arguments [0]).Expr;
6384 if (c.IsDefaultValue) {
6385 value = Array.CreateInstance (array_element_type, 0);
6388 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6389 return base.GetAttributableValue (ec, null, out value);
6392 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6393 object element_value;
6394 for (int i = 0; i < ret.Length; ++i)
6396 Expression e = (Expression)array_data [i];
6398 // Is null when an initializer is optimized (value == predefined value)
6402 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6406 ret.SetValue (element_value, i);
6412 protected override void CloneTo (CloneContext clonectx, Expression t)
6414 ArrayCreation target = (ArrayCreation) t;
6416 if (requested_base_type != null)
6417 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6419 if (arguments != null){
6420 target.arguments = new ArrayList (arguments.Count);
6421 foreach (Argument a in arguments)
6422 target.arguments.Add (a.Clone (clonectx));
6425 if (initializers != null){
6426 target.initializers = new ArrayList (initializers.Count);
6427 foreach (object initializer in initializers)
6428 if (initializer is ArrayList) {
6429 ArrayList this_al = (ArrayList)initializer;
6430 ArrayList al = new ArrayList (this_al.Count);
6431 target.initializers.Add (al);
6432 foreach (Expression e in this_al)
6433 al.Add (e.Clone (clonectx));
6435 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6442 // Represents an implicitly typed array epxression
6444 public class ImplicitlyTypedArrayCreation : ArrayCreation
6446 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6447 : base (null, rank, initializers, loc)
6449 if (RootContext.Version <= LanguageVersion.ISO_2)
6450 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6452 if (rank.Length > 2) {
6453 while (rank [++dimensions] == ',');
6459 public override Expression DoResolve (EmitContext ec)
6464 if (!ResolveInitializers (ec))
6467 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6468 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6469 arguments.Count != dimensions) {
6470 Error_NoBestType ();
6475 // At this point we found common base type for all initializer elements
6476 // but we have to be sure that all static initializer elements are of
6479 UnifyInitializerElement (ec);
6481 type = TypeManager.GetConstructedType (array_element_type, rank);
6482 eclass = ExprClass.Value;
6486 void Error_NoBestType ()
6488 Report.Error (826, loc,
6489 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6493 // Converts static initializer only
6495 void UnifyInitializerElement (EmitContext ec)
6497 for (int i = 0; i < array_data.Count; ++i) {
6498 Expression e = (Expression)array_data[i];
6500 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6504 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6506 element = element.Resolve (ec);
6507 if (element == null)
6510 if (array_element_type == null) {
6511 array_element_type = element.Type;
6515 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6519 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6520 array_element_type = element.Type;
6524 Error_NoBestType ();
6529 public sealed class CompilerGeneratedThis : This
6531 public static This Instance = new CompilerGeneratedThis ();
6533 private CompilerGeneratedThis ()
6534 : base (Location.Null)
6538 public CompilerGeneratedThis (Type type, Location loc)
6544 public override Expression DoResolve (EmitContext ec)
6546 eclass = ExprClass.Variable;
6548 type = ec.ContainerType;
6552 public override HoistedVariable HoistedVariable {
6553 get { return null; }
6558 /// Represents the `this' construct
6561 public class This : VariableReference
6563 sealed class ThisVariable : ILocalVariable
6565 public static readonly ILocalVariable Instance = new ThisVariable ();
6567 public void Emit (EmitContext ec)
6569 ec.ig.Emit (OpCodes.Ldarg_0);
6572 public void EmitAssign (EmitContext ec)
6574 throw new InvalidOperationException ();
6577 public void EmitAddressOf (EmitContext ec)
6579 ec.ig.Emit (OpCodes.Ldarg_0);
6584 VariableInfo variable_info;
6587 public This (Block block, Location loc)
6593 public This (Location loc)
6598 public override VariableInfo VariableInfo {
6599 get { return variable_info; }
6602 public override bool IsFixedVariable {
6603 get { return !TypeManager.IsValueType (type); }
6606 protected override bool IsHoistedEmitRequired (EmitContext ec)
6609 // Handle 'this' differently, it cannot be assigned hence
6610 // when we are not inside anonymous method we can emit direct access
6612 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6615 public override HoistedVariable HoistedVariable {
6616 get { return TopToplevelBlock.HoistedThisVariable; }
6619 public override bool IsRef {
6620 get { return is_struct; }
6623 protected override ILocalVariable Variable {
6624 get { return ThisVariable.Instance; }
6627 // TODO: Move to ToplevelBlock
6628 ToplevelBlock TopToplevelBlock {
6630 ToplevelBlock tl = block.Toplevel;
6631 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6636 public static bool IsThisAvailable (EmitContext ec)
6638 if (ec.IsStatic || ec.IsInFieldInitializer)
6641 if (ec.CurrentAnonymousMethod == null)
6644 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6650 public bool ResolveBase (EmitContext ec)
6652 if (eclass != ExprClass.Invalid)
6655 eclass = ExprClass.Variable;
6657 if (ec.TypeContainer.CurrentType != null)
6658 type = ec.TypeContainer.CurrentType;
6660 type = ec.ContainerType;
6662 if (!IsThisAvailable (ec)) {
6664 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6666 Report.Error (1673, loc,
6667 "Anonymous methods inside structs cannot access instance members of `this'. " +
6668 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6672 is_struct = ec.TypeContainer is Struct;
6674 if (block != null) {
6675 if (block.Toplevel.ThisVariable != null)
6676 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6678 AnonymousExpression am = ec.CurrentAnonymousMethod;
6681 // this is hoisted to very top level block
6683 if (ec.IsVariableCapturingRequired) {
6684 // TODO: it could be optimized
6685 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6686 if (HoistedVariable == null) {
6687 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6697 // Called from Invocation to check if the invocation is correct
6699 public override void CheckMarshalByRefAccess (EmitContext ec)
6701 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6702 !variable_info.IsAssigned (ec)) {
6703 Error (188, "The `this' object cannot be used before all of its " +
6704 "fields are assigned to");
6705 variable_info.SetAssigned (ec);
6709 public override Expression CreateExpressionTree (EmitContext ec)
6711 ArrayList args = new ArrayList (2);
6712 args.Add (new Argument (this));
6713 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6714 return CreateExpressionFactoryCall ("Constant", args);
6717 public override Expression DoResolve (EmitContext ec)
6719 if (!ResolveBase (ec))
6723 if (ec.IsInFieldInitializer) {
6724 Error (27, "Keyword `this' is not available in the current context");
6731 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6733 if (!ResolveBase (ec))
6736 if (variable_info != null)
6737 variable_info.SetAssigned (ec);
6739 if (ec.TypeContainer is Class){
6740 if (right_side == EmptyExpression.UnaryAddress)
6741 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6742 else if (right_side == EmptyExpression.OutAccess)
6743 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6745 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6751 public override int GetHashCode()
6753 return block.GetHashCode ();
6756 public override string Name {
6757 get { return "this"; }
6760 public override bool Equals (object obj)
6762 This t = obj as This;
6766 return block == t.block;
6769 protected override void CloneTo (CloneContext clonectx, Expression t)
6771 This target = (This) t;
6773 target.block = clonectx.LookupBlock (block);
6776 public void RemoveHoisting ()
6778 TopToplevelBlock.HoistedThisVariable = null;
6781 public override void SetHasAddressTaken ()
6788 /// Represents the `__arglist' construct
6790 public class ArglistAccess : Expression
6792 public ArglistAccess (Location loc)
6797 public override Expression CreateExpressionTree (EmitContext ec)
6799 throw new NotSupportedException ("ET");
6802 public override Expression DoResolve (EmitContext ec)
6804 eclass = ExprClass.Variable;
6805 type = TypeManager.runtime_argument_handle_type;
6807 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6809 Error (190, "The __arglist construct is valid only within " +
6810 "a variable argument method");
6817 public override void Emit (EmitContext ec)
6819 ec.ig.Emit (OpCodes.Arglist);
6822 protected override void CloneTo (CloneContext clonectx, Expression target)
6829 /// Represents the `__arglist (....)' construct
6831 public class Arglist : Expression
6833 Argument[] Arguments;
6835 public Arglist (Location loc)
6836 : this (Argument.Empty, loc)
6840 public Arglist (Argument[] args, Location l)
6846 public Type[] ArgumentTypes {
6848 Type[] retval = new Type [Arguments.Length];
6849 for (int i = 0; i < Arguments.Length; i++)
6850 retval [i] = Arguments [i].Type;
6855 public override Expression CreateExpressionTree (EmitContext ec)
6857 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6861 public override Expression DoResolve (EmitContext ec)
6863 eclass = ExprClass.Variable;
6864 type = TypeManager.runtime_argument_handle_type;
6866 foreach (Argument arg in Arguments) {
6867 if (!arg.Resolve (ec, loc))
6874 public override void Emit (EmitContext ec)
6876 foreach (Argument arg in Arguments)
6880 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6882 foreach (Argument arg in Arguments)
6883 arg.Expr.MutateHoistedGenericType (storey);
6886 protected override void CloneTo (CloneContext clonectx, Expression t)
6888 Arglist target = (Arglist) t;
6890 target.Arguments = new Argument [Arguments.Length];
6891 for (int i = 0; i < Arguments.Length; i++)
6892 target.Arguments [i] = Arguments [i].Clone (clonectx);
6897 /// Implements the typeof operator
6899 public class TypeOf : Expression {
6900 Expression QueriedType;
6901 protected Type typearg;
6903 public TypeOf (Expression queried_type, Location l)
6905 QueriedType = queried_type;
6909 public override Expression CreateExpressionTree (EmitContext ec)
6911 ArrayList args = new ArrayList (2);
6912 args.Add (new Argument (this));
6913 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6914 return CreateExpressionFactoryCall ("Constant", args);
6917 public override Expression DoResolve (EmitContext ec)
6919 if (eclass != ExprClass.Invalid)
6922 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6926 typearg = texpr.Type;
6928 if (typearg == TypeManager.void_type) {
6929 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6933 if (typearg.IsPointer && !ec.InUnsafe){
6938 type = TypeManager.type_type;
6940 return DoResolveBase ();
6943 protected Expression DoResolveBase ()
6945 if (TypeManager.system_type_get_type_from_handle == null) {
6946 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6947 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6950 // Even though what is returned is a type object, it's treated as a value by the compiler.
6951 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6952 eclass = ExprClass.Value;
6956 public override void Emit (EmitContext ec)
6958 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6959 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6962 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6964 if (TypeManager.ContainsGenericParameters (typearg) &&
6965 !TypeManager.IsGenericTypeDefinition (typearg)) {
6966 Report.SymbolRelatedToPreviousError (typearg);
6967 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6968 TypeManager.CSharpName (typearg));
6973 if (value_type == TypeManager.object_type) {
6974 value = (object)typearg;
6981 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6983 typearg = storey.MutateType (typearg);
6986 public Type TypeArgument {
6992 protected override void CloneTo (CloneContext clonectx, Expression t)
6994 TypeOf target = (TypeOf) t;
6995 if (QueriedType != null)
6996 target.QueriedType = QueriedType.Clone (clonectx);
7001 /// Implements the `typeof (void)' operator
7003 public class TypeOfVoid : TypeOf {
7004 public TypeOfVoid (Location l) : base (null, l)
7009 public override Expression DoResolve (EmitContext ec)
7011 type = TypeManager.type_type;
7012 typearg = TypeManager.void_type;
7014 return DoResolveBase ();
7018 class TypeOfMethodInfo : TypeOfMethod
7020 public TypeOfMethodInfo (MethodBase method, Location loc)
7021 : base (method, loc)
7025 public override Expression DoResolve (EmitContext ec)
7027 type = typeof (MethodInfo);
7028 return base.DoResolve (ec);
7031 public override void Emit (EmitContext ec)
7033 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7035 ec.ig.Emit (OpCodes.Castclass, type);
7039 class TypeOfConstructorInfo : TypeOfMethod
7041 public TypeOfConstructorInfo (MethodBase method, Location loc)
7042 : base (method, loc)
7046 public override Expression DoResolve (EmitContext ec)
7048 type = typeof (ConstructorInfo);
7049 return base.DoResolve (ec);
7052 public override void Emit (EmitContext ec)
7054 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7056 ec.ig.Emit (OpCodes.Castclass, type);
7060 abstract class TypeOfMethod : Expression
7062 protected readonly MethodBase method;
7064 protected TypeOfMethod (MethodBase method, Location loc)
7066 this.method = method;
7070 public override Expression CreateExpressionTree (EmitContext ec)
7072 ArrayList args = new ArrayList (2);
7073 args.Add (new Argument (this));
7074 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7075 return CreateExpressionFactoryCall ("Constant", args);
7078 public override Expression DoResolve (EmitContext ec)
7080 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7081 MethodInfo mi = is_generic ?
7082 TypeManager.methodbase_get_type_from_handle_generic :
7083 TypeManager.methodbase_get_type_from_handle;
7086 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7087 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7089 if (t == null || handle_type == null)
7092 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7094 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7095 new Type[] { handle_type } );
7098 TypeManager.methodbase_get_type_from_handle_generic = mi;
7100 TypeManager.methodbase_get_type_from_handle = mi;
7103 eclass = ExprClass.Value;
7107 public override void Emit (EmitContext ec)
7109 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7112 mi = TypeManager.methodbase_get_type_from_handle_generic;
7113 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7115 mi = TypeManager.methodbase_get_type_from_handle;
7118 ec.ig.Emit (OpCodes.Call, mi);
7122 internal class TypeOfField : Expression
7124 readonly FieldInfo field;
7126 public TypeOfField (FieldInfo field, Location loc)
7132 public override Expression CreateExpressionTree (EmitContext ec)
7134 throw new NotSupportedException ("ET");
7137 public override Expression DoResolve (EmitContext ec)
7139 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7140 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7141 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7143 if (t != null && handle_type != null)
7144 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7145 "GetFieldFromHandle", loc, handle_type);
7148 type = typeof (FieldInfo);
7149 eclass = ExprClass.Value;
7153 public override void Emit (EmitContext ec)
7155 ec.ig.Emit (OpCodes.Ldtoken, field);
7156 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7161 /// Implements the sizeof expression
7163 public class SizeOf : Expression {
7164 readonly Expression QueriedType;
7167 public SizeOf (Expression queried_type, Location l)
7169 this.QueriedType = queried_type;
7173 public override Expression CreateExpressionTree (EmitContext ec)
7175 Error_PointerInsideExpressionTree ();
7179 public override Expression DoResolve (EmitContext ec)
7181 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7185 type_queried = texpr.Type;
7186 if (TypeManager.IsEnumType (type_queried))
7187 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7189 int size_of = GetTypeSize (type_queried);
7191 return new IntConstant (size_of, loc);
7194 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7199 Report.Error (233, loc,
7200 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7201 TypeManager.CSharpName (type_queried));
7204 type = TypeManager.int32_type;
7205 eclass = ExprClass.Value;
7209 public override void Emit (EmitContext ec)
7211 int size = GetTypeSize (type_queried);
7214 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7216 IntConstant.EmitInt (ec.ig, size);
7219 protected override void CloneTo (CloneContext clonectx, Expression t)
7225 /// Implements the qualified-alias-member (::) expression.
7227 public class QualifiedAliasMember : MemberAccess
7229 readonly string alias;
7230 public static readonly string GlobalAlias = "global";
7232 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7233 : base (null, identifier, targs, l)
7238 public QualifiedAliasMember (string alias, string identifier, Location l)
7239 : base (null, identifier, l)
7244 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7246 if (alias == GlobalAlias) {
7247 expr = RootNamespace.Global;
7248 return base.ResolveAsTypeStep (ec, silent);
7251 int errors = Report.Errors;
7252 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7254 if (errors == Report.Errors)
7255 Report.Error (432, loc, "Alias `{0}' not found", alias);
7259 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7263 if (expr.eclass == ExprClass.Type) {
7265 Report.Error (431, loc,
7266 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7274 public override Expression DoResolve (EmitContext ec)
7276 return ResolveAsTypeStep (ec, false);
7279 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7281 Report.Error (687, loc,
7282 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7283 GetSignatureForError ());
7286 public override string GetSignatureForError ()
7289 if (targs != null) {
7290 name = TypeManager.RemoveGenericArity (Name) + "<" +
7291 targs.GetSignatureForError () + ">";
7294 return alias + "::" + name;
7297 protected override void CloneTo (CloneContext clonectx, Expression t)
7304 /// Implements the member access expression
7306 public class MemberAccess : ATypeNameExpression {
7307 protected Expression expr;
7309 public MemberAccess (Expression expr, string id)
7310 : base (id, expr.Location)
7315 public MemberAccess (Expression expr, string identifier, Location loc)
7316 : base (identifier, loc)
7321 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7322 : base (identifier, args, loc)
7327 // TODO: this method has very poor performace for Enum fields and
7328 // probably for other constants as well
7329 Expression DoResolve (EmitContext ec, Expression right_side)
7332 throw new Exception ();
7335 // Resolve the expression with flow analysis turned off, we'll do the definite
7336 // assignment checks later. This is because we don't know yet what the expression
7337 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7338 // definite assignment check on the actual field and not on the whole struct.
7341 SimpleName original = expr as SimpleName;
7342 Expression expr_resolved = expr.Resolve (ec,
7343 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7344 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7346 if (expr_resolved == null)
7349 string LookupIdentifier = MemberName.MakeName (Name, targs);
7351 if (expr_resolved is Namespace) {
7352 Namespace ns = (Namespace) expr_resolved;
7353 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7355 if ((retval != null) && (targs != null))
7356 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7360 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7364 Type expr_type = expr_resolved.Type;
7365 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7366 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7367 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7371 Constant c = expr_resolved as Constant;
7372 if (c != null && c.GetValue () == null) {
7373 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7374 "System.NullReferenceException");
7377 if (targs != null) {
7378 if (!targs.Resolve (ec))
7382 Expression member_lookup;
7383 member_lookup = MemberLookup (
7384 ec.ContainerType, expr_type, expr_type, Name, loc);
7386 if ((member_lookup == null) && (targs != null)) {
7387 member_lookup = MemberLookup (
7388 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7391 if (member_lookup == null) {
7392 ExprClass expr_eclass = expr_resolved.eclass;
7395 // Extension methods are not allowed on all expression types
7397 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7398 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7399 expr_eclass == ExprClass.EventAccess) {
7400 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7401 if (ex_method_lookup != null) {
7402 ex_method_lookup.ExtensionExpression = expr_resolved;
7404 if (targs != null) {
7405 ex_method_lookup.SetTypeArguments (targs);
7408 return ex_method_lookup.DoResolve (ec);
7412 expr = expr_resolved;
7413 Error_MemberLookupFailed (
7414 ec.ContainerType, expr_type, expr_type, Name, null,
7415 AllMemberTypes, AllBindingFlags);
7419 TypeExpr texpr = member_lookup as TypeExpr;
7420 if (texpr != null) {
7421 if (!(expr_resolved is TypeExpr) &&
7422 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7423 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7424 Name, member_lookup.GetSignatureForError ());
7428 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7429 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7430 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7435 ConstructedType ct = expr_resolved as ConstructedType;
7438 // When looking up a nested type in a generic instance
7439 // via reflection, we always get a generic type definition
7440 // and not a generic instance - so we have to do this here.
7442 // See gtest-172-lib.cs and gtest-172.cs for an example.
7444 ct = new ConstructedType (
7445 member_lookup.Type, ct.TypeArguments, loc);
7447 return ct.ResolveAsTypeStep (ec, false);
7450 return member_lookup;
7453 MemberExpr me = (MemberExpr) member_lookup;
7454 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7458 if (targs != null) {
7459 me.SetTypeArguments (targs);
7462 if (original != null && !TypeManager.IsValueType (expr_type)) {
7463 if (me.IsInstance) {
7464 LocalVariableReference var = expr_resolved as LocalVariableReference;
7465 if (var != null && !var.VerifyAssigned (ec))
7470 // The following DoResolve/DoResolveLValue will do the definite assignment
7473 if (right_side != null)
7474 return me.DoResolveLValue (ec, right_side);
7476 return me.DoResolve (ec);
7479 public override Expression DoResolve (EmitContext ec)
7481 return DoResolve (ec, null);
7484 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7486 return DoResolve (ec, right_side);
7489 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7491 return ResolveNamespaceOrType (ec, silent);
7494 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7496 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7498 if (new_expr == null)
7501 string LookupIdentifier = MemberName.MakeName (Name, targs);
7503 if (new_expr is Namespace) {
7504 Namespace ns = (Namespace) new_expr;
7505 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7507 if ((retval != null) && (targs != null))
7508 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7510 if (!silent && retval == null)
7511 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7515 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7516 if (tnew_expr == null)
7519 if (tnew_expr is TypeParameterExpr) {
7520 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7521 tnew_expr.GetSignatureForError ());
7525 Type expr_type = tnew_expr.Type;
7526 Expression member_lookup = MemberLookup (
7527 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7528 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7529 if (member_lookup == null) {
7533 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7537 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7542 TypeArguments the_args = targs;
7543 Type declaring_type = texpr.Type.DeclaringType;
7544 if (TypeManager.HasGenericArguments (declaring_type)) {
7545 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7546 expr_type = expr_type.BaseType;
7549 TypeArguments new_args = new TypeArguments (loc);
7550 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7551 new_args.Add (new TypeExpression (decl, loc));
7554 new_args.Add (targs);
7556 the_args = new_args;
7559 if (the_args != null) {
7560 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7561 return ctype.ResolveAsTypeStep (rc, false);
7568 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7570 Expression member_lookup = MemberLookup (
7571 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7572 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7574 if (member_lookup != null) {
7575 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7576 if (expr_type == null)
7579 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7583 member_lookup = MemberLookup (
7584 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7585 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7587 if (member_lookup == null) {
7588 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7589 Name, expr_type.GetSignatureForError ());
7591 // TODO: Report.SymbolRelatedToPreviousError
7592 member_lookup.Error_UnexpectedKind (null, "type", loc);
7596 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7598 if (RootContext.Version > LanguageVersion.ISO_2 &&
7599 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7600 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7601 "extension method `{1}' of type `{0}' could be found " +
7602 "(are you missing a using directive or an assembly reference?)",
7603 TypeManager.CSharpName (type), name);
7607 base.Error_TypeDoesNotContainDefinition (type, name);
7610 public override string GetSignatureForError ()
7612 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7615 protected override void CloneTo (CloneContext clonectx, Expression t)
7617 MemberAccess target = (MemberAccess) t;
7619 target.expr = expr.Clone (clonectx);
7624 /// Implements checked expressions
7626 public class CheckedExpr : Expression {
7628 public Expression Expr;
7630 public CheckedExpr (Expression e, Location l)
7636 public override Expression CreateExpressionTree (EmitContext ec)
7638 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7639 return Expr.CreateExpressionTree (ec);
7642 public override Expression DoResolve (EmitContext ec)
7644 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7645 Expr = Expr.Resolve (ec);
7650 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7653 eclass = Expr.eclass;
7658 public override void Emit (EmitContext ec)
7660 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7664 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7666 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7667 Expr.EmitBranchable (ec, target, on_true);
7670 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7672 Expr.MutateHoistedGenericType (storey);
7675 protected override void CloneTo (CloneContext clonectx, Expression t)
7677 CheckedExpr target = (CheckedExpr) t;
7679 target.Expr = Expr.Clone (clonectx);
7684 /// Implements the unchecked expression
7686 public class UnCheckedExpr : Expression {
7688 public Expression Expr;
7690 public UnCheckedExpr (Expression e, Location l)
7696 public override Expression CreateExpressionTree (EmitContext ec)
7698 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7699 return Expr.CreateExpressionTree (ec);
7702 public override Expression DoResolve (EmitContext ec)
7704 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7705 Expr = Expr.Resolve (ec);
7710 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7713 eclass = Expr.eclass;
7718 public override void Emit (EmitContext ec)
7720 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7724 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7726 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7727 Expr.EmitBranchable (ec, target, on_true);
7730 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7732 Expr.MutateHoistedGenericType (storey);
7735 protected override void CloneTo (CloneContext clonectx, Expression t)
7737 UnCheckedExpr target = (UnCheckedExpr) t;
7739 target.Expr = Expr.Clone (clonectx);
7744 /// An Element Access expression.
7746 /// During semantic analysis these are transformed into
7747 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7749 public class ElementAccess : Expression {
7750 public ArrayList Arguments;
7751 public Expression Expr;
7753 public ElementAccess (Expression e, ArrayList e_list)
7761 Arguments = new ArrayList (e_list.Count);
7762 foreach (Expression tmp in e_list)
7763 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7766 bool CommonResolve (EmitContext ec)
7768 Expr = Expr.Resolve (ec);
7770 if (Arguments == null)
7773 foreach (Argument a in Arguments){
7774 if (!a.Resolve (ec, loc))
7778 return Expr != null;
7781 public override Expression CreateExpressionTree (EmitContext ec)
7783 ArrayList args = new ArrayList (Arguments.Count + 1);
7784 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7785 foreach (Argument a in Arguments)
7786 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7788 return CreateExpressionFactoryCall ("ArrayIndex", args);
7791 Expression MakePointerAccess (EmitContext ec, Type t)
7793 if (Arguments.Count != 1){
7794 Error (196, "A pointer must be indexed by only one value");
7798 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7801 return new Indirection (p, loc).Resolve (ec);
7804 public override Expression DoResolve (EmitContext ec)
7806 if (!CommonResolve (ec))
7810 // We perform some simple tests, and then to "split" the emit and store
7811 // code we create an instance of a different class, and return that.
7813 // I am experimenting with this pattern.
7817 if (t == TypeManager.array_type){
7818 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7823 return (new ArrayAccess (this, loc)).Resolve (ec);
7825 return MakePointerAccess (ec, t);
7827 FieldExpr fe = Expr as FieldExpr;
7829 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7831 return MakePointerAccess (ec, ff.ElementType);
7834 return (new IndexerAccess (this, loc)).Resolve (ec);
7837 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7839 if (!CommonResolve (ec))
7844 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7847 return MakePointerAccess (ec, type);
7849 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7850 Error_CannotModifyIntermediateExpressionValue (ec);
7852 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7855 public override void Emit (EmitContext ec)
7857 throw new Exception ("Should never be reached");
7860 public override string GetSignatureForError ()
7862 return Expr.GetSignatureForError ();
7865 protected override void CloneTo (CloneContext clonectx, Expression t)
7867 ElementAccess target = (ElementAccess) t;
7869 target.Expr = Expr.Clone (clonectx);
7870 target.Arguments = new ArrayList (Arguments.Count);
7871 foreach (Argument a in Arguments)
7872 target.Arguments.Add (a.Clone (clonectx));
7877 /// Implements array access
7879 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7881 // Points to our "data" repository
7885 LocalTemporary temp;
7889 public ArrayAccess (ElementAccess ea_data, Location l)
7895 public override Expression CreateExpressionTree (EmitContext ec)
7897 return ea.CreateExpressionTree (ec);
7900 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7902 return DoResolve (ec);
7905 public override Expression DoResolve (EmitContext ec)
7908 ExprClass eclass = ea.Expr.eclass;
7910 // As long as the type is valid
7911 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7912 eclass == ExprClass.Value)) {
7913 ea.Expr.Error_UnexpectedKind ("variable or value");
7918 if (eclass != ExprClass.Invalid)
7921 Type t = ea.Expr.Type;
7922 int rank = ea.Arguments.Count;
7923 if (t.GetArrayRank () != rank) {
7924 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7925 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7929 type = TypeManager.GetElementType (t);
7930 if (type.IsPointer && !ec.InUnsafe) {
7931 UnsafeError (ea.Location);
7935 foreach (Argument a in ea.Arguments) {
7936 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7939 eclass = ExprClass.Variable;
7945 /// Emits the right opcode to load an object of Type `t'
7946 /// from an array of T
7948 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7951 MethodInfo get = FetchGetMethod ();
7952 ig.Emit (OpCodes.Call, get);
7956 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7957 ig.Emit (OpCodes.Ldelem_U1);
7958 else if (type == TypeManager.sbyte_type)
7959 ig.Emit (OpCodes.Ldelem_I1);
7960 else if (type == TypeManager.short_type)
7961 ig.Emit (OpCodes.Ldelem_I2);
7962 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7963 ig.Emit (OpCodes.Ldelem_U2);
7964 else if (type == TypeManager.int32_type)
7965 ig.Emit (OpCodes.Ldelem_I4);
7966 else if (type == TypeManager.uint32_type)
7967 ig.Emit (OpCodes.Ldelem_U4);
7968 else if (type == TypeManager.uint64_type)
7969 ig.Emit (OpCodes.Ldelem_I8);
7970 else if (type == TypeManager.int64_type)
7971 ig.Emit (OpCodes.Ldelem_I8);
7972 else if (type == TypeManager.float_type)
7973 ig.Emit (OpCodes.Ldelem_R4);
7974 else if (type == TypeManager.double_type)
7975 ig.Emit (OpCodes.Ldelem_R8);
7976 else if (type == TypeManager.intptr_type)
7977 ig.Emit (OpCodes.Ldelem_I);
7978 else if (TypeManager.IsEnumType (type)){
7979 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7980 } else if (type.IsValueType){
7981 ig.Emit (OpCodes.Ldelema, type);
7982 ig.Emit (OpCodes.Ldobj, type);
7984 } else if (type.IsGenericParameter) {
7985 ig.Emit (OpCodes.Ldelem, type);
7987 } else if (type.IsPointer)
7988 ig.Emit (OpCodes.Ldelem_I);
7990 ig.Emit (OpCodes.Ldelem_Ref);
7993 protected override void Error_NegativeArrayIndex (Location loc)
7995 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7999 /// Returns the right opcode to store an object of Type `t'
8000 /// from an array of T.
8002 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8004 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8005 has_type_arg = false; is_stobj = false;
8006 t = TypeManager.TypeToCoreType (t);
8007 if (TypeManager.IsEnumType (t))
8008 t = TypeManager.GetEnumUnderlyingType (t);
8009 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8010 t == TypeManager.bool_type)
8011 return OpCodes.Stelem_I1;
8012 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8013 t == TypeManager.char_type)
8014 return OpCodes.Stelem_I2;
8015 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8016 return OpCodes.Stelem_I4;
8017 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8018 return OpCodes.Stelem_I8;
8019 else if (t == TypeManager.float_type)
8020 return OpCodes.Stelem_R4;
8021 else if (t == TypeManager.double_type)
8022 return OpCodes.Stelem_R8;
8023 else if (t == TypeManager.intptr_type) {
8024 has_type_arg = true;
8026 return OpCodes.Stobj;
8027 } else if (t.IsValueType) {
8028 has_type_arg = true;
8030 return OpCodes.Stobj;
8032 } else if (t.IsGenericParameter) {
8033 has_type_arg = true;
8034 return OpCodes.Stelem;
8037 } else if (t.IsPointer)
8038 return OpCodes.Stelem_I;
8040 return OpCodes.Stelem_Ref;
8043 MethodInfo FetchGetMethod ()
8045 ModuleBuilder mb = CodeGen.Module.Builder;
8046 int arg_count = ea.Arguments.Count;
8047 Type [] args = new Type [arg_count];
8050 for (int i = 0; i < arg_count; i++){
8051 //args [i++] = a.Type;
8052 args [i] = TypeManager.int32_type;
8055 get = mb.GetArrayMethod (
8056 ea.Expr.Type, "Get",
8057 CallingConventions.HasThis |
8058 CallingConventions.Standard,
8064 MethodInfo FetchAddressMethod ()
8066 ModuleBuilder mb = CodeGen.Module.Builder;
8067 int arg_count = ea.Arguments.Count;
8068 Type [] args = new Type [arg_count];
8072 ret_type = TypeManager.GetReferenceType (type);
8074 for (int i = 0; i < arg_count; i++){
8075 //args [i++] = a.Type;
8076 args [i] = TypeManager.int32_type;
8079 address = mb.GetArrayMethod (
8080 ea.Expr.Type, "Address",
8081 CallingConventions.HasThis |
8082 CallingConventions.Standard,
8089 // Load the array arguments into the stack.
8091 void LoadArrayAndArguments (EmitContext ec)
8095 for (int i = 0; i < ea.Arguments.Count; ++i) {
8096 ((Argument)ea.Arguments [i]).Emit (ec);
8100 public void Emit (EmitContext ec, bool leave_copy)
8102 int rank = ea.Expr.Type.GetArrayRank ();
8103 ILGenerator ig = ec.ig;
8106 LoadFromPtr (ig, this.type);
8108 LoadArrayAndArguments (ec);
8109 EmitLoadOpcode (ig, type, rank);
8113 ig.Emit (OpCodes.Dup);
8114 temp = new LocalTemporary (this.type);
8119 public override void Emit (EmitContext ec)
8124 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8126 int rank = ea.Expr.Type.GetArrayRank ();
8127 ILGenerator ig = ec.ig;
8128 Type t = source.Type;
8129 prepared = prepare_for_load;
8132 AddressOf (ec, AddressOp.LoadStore);
8133 ec.ig.Emit (OpCodes.Dup);
8135 LoadArrayAndArguments (ec);
8139 bool is_stobj, has_type_arg;
8140 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8144 // The stobj opcode used by value types will need
8145 // an address on the stack, not really an array/array
8149 ig.Emit (OpCodes.Ldelema, t);
8154 ec.ig.Emit (OpCodes.Dup);
8155 temp = new LocalTemporary (this.type);
8160 StoreFromPtr (ig, t);
8162 ig.Emit (OpCodes.Stobj, t);
8163 else if (has_type_arg)
8170 ec.ig.Emit (OpCodes.Dup);
8171 temp = new LocalTemporary (this.type);
8176 StoreFromPtr (ig, t);
8178 int arg_count = ea.Arguments.Count;
8179 Type [] args = new Type [arg_count + 1];
8180 for (int i = 0; i < arg_count; i++) {
8181 //args [i++] = a.Type;
8182 args [i] = TypeManager.int32_type;
8184 args [arg_count] = type;
8186 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8187 ea.Expr.Type, "Set",
8188 CallingConventions.HasThis |
8189 CallingConventions.Standard,
8190 TypeManager.void_type, args);
8192 ig.Emit (OpCodes.Call, set);
8202 public void AddressOf (EmitContext ec, AddressOp mode)
8204 int rank = ea.Expr.Type.GetArrayRank ();
8205 ILGenerator ig = ec.ig;
8207 LoadArrayAndArguments (ec);
8210 ig.Emit (OpCodes.Ldelema, type);
8212 MethodInfo address = FetchAddressMethod ();
8213 ig.Emit (OpCodes.Call, address);
8217 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8219 type = storey.MutateType (type);
8224 /// Expressions that represent an indexer call.
8226 public class IndexerAccess : Expression, IAssignMethod
8228 class IndexerMethodGroupExpr : MethodGroupExpr
8230 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8233 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8236 public override string Name {
8242 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8245 // Here is the trick, decrease number of arguments by 1 when only
8246 // available property method is setter. This makes overload resolution
8247 // work correctly for indexers.
8250 if (method.Name [0] == 'g')
8251 return parameters.Count;
8253 return parameters.Count - 1;
8259 // Contains either property getter or setter
8260 public ArrayList Methods;
8261 public ArrayList Properties;
8267 void Append (Type caller_type, MemberInfo [] mi)
8272 foreach (PropertyInfo property in mi) {
8273 MethodInfo accessor = property.GetGetMethod (true);
8274 if (accessor == null)
8275 accessor = property.GetSetMethod (true);
8277 if (Methods == null) {
8278 Methods = new ArrayList ();
8279 Properties = new ArrayList ();
8282 Methods.Add (accessor);
8283 Properties.Add (property);
8287 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8289 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8291 return TypeManager.MemberLookup (
8292 caller_type, caller_type, lookup_type, MemberTypes.Property,
8293 BindingFlags.Public | BindingFlags.Instance |
8294 BindingFlags.DeclaredOnly, p_name, null);
8297 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8299 Indexers ix = new Indexers ();
8302 if (lookup_type.IsGenericParameter) {
8303 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8307 if (gc.HasClassConstraint)
8308 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8310 Type[] ifaces = gc.InterfaceConstraints;
8311 foreach (Type itype in ifaces)
8312 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8318 Type copy = lookup_type;
8319 while (copy != TypeManager.object_type && copy != null){
8320 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8321 copy = copy.BaseType;
8324 if (lookup_type.IsInterface) {
8325 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8326 if (ifaces != null) {
8327 foreach (Type itype in ifaces)
8328 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8343 // Points to our "data" repository
8345 MethodInfo get, set;
8346 bool is_base_indexer;
8348 LocalTemporary temp;
8349 LocalTemporary prepared_value;
8350 Expression set_expr;
8352 protected Type indexer_type;
8353 protected Type current_type;
8354 protected Expression instance_expr;
8355 protected ArrayList arguments;
8357 public IndexerAccess (ElementAccess ea, Location loc)
8358 : this (ea.Expr, false, loc)
8360 this.arguments = ea.Arguments;
8363 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8366 this.instance_expr = instance_expr;
8367 this.is_base_indexer = is_base_indexer;
8368 this.eclass = ExprClass.Value;
8372 static string GetAccessorName (AccessorType at)
8374 if (at == AccessorType.Set)
8377 if (at == AccessorType.Get)
8380 throw new NotImplementedException (at.ToString ());
8383 public override Expression CreateExpressionTree (EmitContext ec)
8385 ArrayList args = new ArrayList (arguments.Count + 2);
8386 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8387 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8388 foreach (Argument a in arguments)
8389 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8391 return CreateExpressionFactoryCall ("Call", args);
8394 protected virtual bool CommonResolve (EmitContext ec)
8396 indexer_type = instance_expr.Type;
8397 current_type = ec.ContainerType;
8402 public override Expression DoResolve (EmitContext ec)
8404 return ResolveAccessor (ec, AccessorType.Get);
8407 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8409 if (right_side == EmptyExpression.OutAccess) {
8410 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8411 GetSignatureForError ());
8415 // if the indexer returns a value type, and we try to set a field in it
8416 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8417 Error_CannotModifyIntermediateExpressionValue (ec);
8420 Expression e = ResolveAccessor (ec, AccessorType.Set);
8424 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8428 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8430 if (!CommonResolve (ec))
8433 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8434 if (ilist.Methods == null) {
8435 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8436 TypeManager.CSharpName (indexer_type));
8440 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8441 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8445 MethodInfo mi = (MethodInfo) mg;
8446 PropertyInfo pi = null;
8447 for (int i = 0; i < ilist.Methods.Count; ++i) {
8448 if (ilist.Methods [i] == mi) {
8449 pi = (PropertyInfo) ilist.Properties [i];
8454 type = TypeManager.TypeToCoreType (pi.PropertyType);
8455 if (type.IsPointer && !ec.InUnsafe)
8458 MethodInfo accessor;
8459 if (accessorType == AccessorType.Get) {
8460 accessor = get = pi.GetGetMethod (true);
8462 accessor = set = pi.GetSetMethod (true);
8463 if (accessor == null && pi.GetGetMethod (true) != null) {
8464 Report.SymbolRelatedToPreviousError (pi);
8465 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8466 TypeManager.GetFullNameSignature (pi));
8471 if (accessor == null) {
8472 Report.SymbolRelatedToPreviousError (pi);
8473 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8474 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8479 // Only base will allow this invocation to happen.
8481 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8482 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8485 bool must_do_cs1540_check;
8486 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8488 set = pi.GetSetMethod (true);
8490 get = pi.GetGetMethod (true);
8492 if (set != null && get != null &&
8493 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8494 Report.SymbolRelatedToPreviousError (accessor);
8495 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8496 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8498 Report.SymbolRelatedToPreviousError (pi);
8499 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8503 instance_expr.CheckMarshalByRefAccess (ec);
8504 eclass = ExprClass.IndexerAccess;
8508 public void Emit (EmitContext ec, bool leave_copy)
8511 prepared_value.Emit (ec);
8513 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8514 arguments, loc, false, false);
8518 ec.ig.Emit (OpCodes.Dup);
8519 temp = new LocalTemporary (Type);
8525 // source is ignored, because we already have a copy of it from the
8526 // LValue resolution and we have already constructed a pre-cached
8527 // version of the arguments (ea.set_arguments);
8529 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8531 prepared = prepare_for_load;
8532 Expression value = set_expr;
8535 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8536 arguments, loc, true, false);
8538 prepared_value = new LocalTemporary (type);
8539 prepared_value.Store (ec);
8541 prepared_value.Release (ec);
8544 ec.ig.Emit (OpCodes.Dup);
8545 temp = new LocalTemporary (Type);
8548 } else if (leave_copy) {
8549 temp = new LocalTemporary (Type);
8555 arguments.Add (new Argument (value, Argument.AType.Expression));
8556 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8564 public override void Emit (EmitContext ec)
8569 public override string GetSignatureForError ()
8571 return TypeManager.CSharpSignature (get != null ? get : set, false);
8574 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8577 get = storey.MutateGenericMethod (get);
8579 set = storey.MutateGenericMethod (set);
8581 instance_expr.MutateHoistedGenericType (storey);
8582 foreach (Argument a in arguments)
8583 a.Expr.MutateHoistedGenericType (storey);
8585 type = storey.MutateType (type);
8588 protected override void CloneTo (CloneContext clonectx, Expression t)
8590 IndexerAccess target = (IndexerAccess) t;
8592 if (arguments != null){
8593 target.arguments = new ArrayList ();
8594 foreach (Argument a in arguments)
8595 target.arguments.Add (a.Clone (clonectx));
8597 if (instance_expr != null)
8598 target.instance_expr = instance_expr.Clone (clonectx);
8603 /// The base operator for method names
8605 public class BaseAccess : Expression {
8606 public readonly string Identifier;
8609 public BaseAccess (string member, Location l)
8611 this.Identifier = member;
8615 public BaseAccess (string member, TypeArguments args, Location l)
8621 public override Expression CreateExpressionTree (EmitContext ec)
8623 throw new NotSupportedException ("ET");
8626 public override Expression DoResolve (EmitContext ec)
8628 Expression c = CommonResolve (ec);
8634 // MethodGroups use this opportunity to flag an error on lacking ()
8636 if (!(c is MethodGroupExpr))
8637 return c.Resolve (ec);
8641 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8643 Expression c = CommonResolve (ec);
8649 // MethodGroups use this opportunity to flag an error on lacking ()
8651 if (! (c is MethodGroupExpr))
8652 return c.DoResolveLValue (ec, right_side);
8657 Expression CommonResolve (EmitContext ec)
8659 Expression member_lookup;
8660 Type current_type = ec.ContainerType;
8661 Type base_type = current_type.BaseType;
8663 if (!This.IsThisAvailable (ec)) {
8665 Error (1511, "Keyword `base' is not available in a static method");
8667 Error (1512, "Keyword `base' is not available in the current context");
8672 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8673 AllMemberTypes, AllBindingFlags, loc);
8674 if (member_lookup == null) {
8675 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8676 null, AllMemberTypes, AllBindingFlags);
8683 left = new TypeExpression (base_type, loc);
8685 left = ec.GetThis (loc);
8687 MemberExpr me = (MemberExpr) member_lookup;
8688 me = me.ResolveMemberAccess (ec, left, loc, null);
8695 me.SetTypeArguments (args);
8701 public override void Emit (EmitContext ec)
8703 throw new Exception ("Should never be called");
8706 protected override void CloneTo (CloneContext clonectx, Expression t)
8708 BaseAccess target = (BaseAccess) t;
8711 target.args = args.Clone ();
8716 /// The base indexer operator
8718 public class BaseIndexerAccess : IndexerAccess {
8719 public BaseIndexerAccess (ArrayList args, Location loc)
8720 : base (null, true, loc)
8722 arguments = new ArrayList ();
8723 foreach (Expression tmp in args)
8724 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8727 protected override bool CommonResolve (EmitContext ec)
8729 instance_expr = ec.GetThis (loc);
8731 current_type = ec.ContainerType.BaseType;
8732 indexer_type = current_type;
8734 foreach (Argument a in arguments){
8735 if (!a.Resolve (ec, loc))
8742 public override Expression CreateExpressionTree (EmitContext ec)
8744 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8745 return base.CreateExpressionTree (ec);
8750 /// This class exists solely to pass the Type around and to be a dummy
8751 /// that can be passed to the conversion functions (this is used by
8752 /// foreach implementation to typecast the object return value from
8753 /// get_Current into the proper type. All code has been generated and
8754 /// we only care about the side effect conversions to be performed
8756 /// This is also now used as a placeholder where a no-action expression
8757 /// is needed (the `New' class).
8759 public class EmptyExpression : Expression {
8760 public static readonly Expression Null = new EmptyExpression ();
8762 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8763 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8764 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8765 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8767 static EmptyExpression temp = new EmptyExpression ();
8768 public static EmptyExpression Grab ()
8770 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8775 public static void Release (EmptyExpression e)
8780 // TODO: should be protected
8781 public EmptyExpression ()
8783 type = TypeManager.object_type;
8784 eclass = ExprClass.Value;
8785 loc = Location.Null;
8788 public EmptyExpression (Type t)
8791 eclass = ExprClass.Value;
8792 loc = Location.Null;
8795 public override Expression CreateExpressionTree (EmitContext ec)
8797 throw new NotSupportedException ("ET");
8800 public override Expression DoResolve (EmitContext ec)
8805 public override void Emit (EmitContext ec)
8807 // nothing, as we only exist to not do anything.
8810 public override void EmitSideEffect (EmitContext ec)
8815 // This is just because we might want to reuse this bad boy
8816 // instead of creating gazillions of EmptyExpressions.
8817 // (CanImplicitConversion uses it)
8819 public void SetType (Type t)
8826 // Empty statement expression
8828 public sealed class EmptyExpressionStatement : ExpressionStatement
8830 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8832 private EmptyExpressionStatement ()
8834 type = TypeManager.object_type;
8835 eclass = ExprClass.Value;
8836 loc = Location.Null;
8839 public override Expression CreateExpressionTree (EmitContext ec)
8844 public override void EmitStatement (EmitContext ec)
8849 public override Expression DoResolve (EmitContext ec)
8854 public override void Emit (EmitContext ec)
8860 public class UserCast : Expression {
8864 public UserCast (MethodInfo method, Expression source, Location l)
8866 this.method = method;
8867 this.source = source;
8868 type = TypeManager.TypeToCoreType (method.ReturnType);
8870 eclass = ExprClass.Value;
8873 public Expression Source {
8879 public override Expression CreateExpressionTree (EmitContext ec)
8881 ArrayList args = new ArrayList (3);
8882 args.Add (new Argument (source.CreateExpressionTree (ec)));
8883 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8884 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8885 return CreateExpressionFactoryCall ("Convert", args);
8888 public override Expression DoResolve (EmitContext ec)
8890 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8892 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8894 eclass = ExprClass.Value;
8898 public override void Emit (EmitContext ec)
8901 ec.ig.Emit (OpCodes.Call, method);
8904 public override string GetSignatureForError ()
8906 return TypeManager.CSharpSignature (method);
8909 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8911 source.MutateHoistedGenericType (storey);
8912 method = storey.MutateGenericMethod (method);
8917 // This class is used to "construct" the type during a typecast
8918 // operation. Since the Type.GetType class in .NET can parse
8919 // the type specification, we just use this to construct the type
8920 // one bit at a time.
8922 public class ComposedCast : TypeExpr {
8923 FullNamedExpression left;
8926 public ComposedCast (FullNamedExpression left, string dim)
8927 : this (left, dim, left.Location)
8931 public ComposedCast (FullNamedExpression left, string dim, Location l)
8938 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8940 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8944 Type ltype = lexpr.Type;
8946 if ((dim.Length > 0) && (dim [0] == '?')) {
8947 TypeExpr nullable = new Nullable.NullableType (left, loc);
8949 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8950 return nullable.ResolveAsTypeTerminal (ec, false);
8954 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8957 if (dim.Length != 0 && dim [0] == '[') {
8958 if (TypeManager.IsSpecialType (ltype)) {
8959 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8963 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8964 Report.SymbolRelatedToPreviousError (ltype);
8965 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8966 TypeManager.CSharpName (ltype));
8971 type = TypeManager.GetConstructedType (ltype, dim);
8976 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8978 if (type.IsPointer && !ec.IsInUnsafeScope){
8982 eclass = ExprClass.Type;
8986 public override string GetSignatureForError ()
8988 return left.GetSignatureForError () + dim;
8991 protected override void CloneTo (CloneContext clonectx, Expression t)
8993 ComposedCast target = (ComposedCast) t;
8995 target.left = (FullNamedExpression)left.Clone (clonectx);
8998 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
9000 return ResolveAsBaseTerminal (ec, silent);
9004 public class FixedBufferPtr : Expression {
9007 public FixedBufferPtr (Expression array, Type array_type, Location l)
9012 type = TypeManager.GetPointerType (array_type);
9013 eclass = ExprClass.Value;
9016 public override Expression CreateExpressionTree (EmitContext ec)
9018 Error_PointerInsideExpressionTree ();
9022 public override void Emit(EmitContext ec)
9027 public override Expression DoResolve (EmitContext ec)
9030 // We are born fully resolved
9038 // This class is used to represent the address of an array, used
9039 // only by the Fixed statement, this generates "&a [0]" construct
9040 // for fixed (char *pa = a)
9042 public class ArrayPtr : FixedBufferPtr {
9045 public ArrayPtr (Expression array, Type array_type, Location l):
9046 base (array, array_type, l)
9048 this.array_type = array_type;
9051 public override void Emit (EmitContext ec)
9055 ILGenerator ig = ec.ig;
9056 IntLiteral.EmitInt (ig, 0);
9057 ig.Emit (OpCodes.Ldelema, array_type);
9062 // Encapsulates a conversion rules required for array indexes
9064 public class ArrayIndexCast : TypeCast
9066 public ArrayIndexCast (Expression expr)
9067 : base (expr, expr.Type)
9071 public override Expression CreateExpressionTree (EmitContext ec)
9073 ArrayList args = new ArrayList (2);
9074 args.Add (new Argument (child.CreateExpressionTree (ec)));
9075 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9076 return CreateExpressionFactoryCall ("ConvertChecked", args);
9079 public override void Emit (EmitContext ec)
9083 if (type == TypeManager.int32_type)
9086 if (type == TypeManager.uint32_type)
9087 ec.ig.Emit (OpCodes.Conv_U);
9088 else if (type == TypeManager.int64_type)
9089 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9090 else if (type == TypeManager.uint64_type)
9091 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9093 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9098 // Implements the `stackalloc' keyword
9100 public class StackAlloc : Expression {
9105 public StackAlloc (Expression type, Expression count, Location l)
9112 public override Expression CreateExpressionTree (EmitContext ec)
9114 throw new NotSupportedException ("ET");
9117 public override Expression DoResolve (EmitContext ec)
9119 count = count.Resolve (ec);
9123 if (count.Type != TypeManager.uint32_type){
9124 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9129 Constant c = count as Constant;
9130 if (c != null && c.IsNegative) {
9131 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9135 if (ec.InCatch || ec.InFinally) {
9136 Error (255, "Cannot use stackalloc in finally or catch");
9140 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9146 if (!TypeManager.VerifyUnManaged (otype, loc))
9149 type = TypeManager.GetPointerType (otype);
9150 eclass = ExprClass.Value;
9155 public override void Emit (EmitContext ec)
9157 int size = GetTypeSize (otype);
9158 ILGenerator ig = ec.ig;
9163 ig.Emit (OpCodes.Sizeof, otype);
9165 IntConstant.EmitInt (ig, size);
9167 ig.Emit (OpCodes.Mul_Ovf_Un);
9168 ig.Emit (OpCodes.Localloc);
9171 protected override void CloneTo (CloneContext clonectx, Expression t)
9173 StackAlloc target = (StackAlloc) t;
9174 target.count = count.Clone (clonectx);
9175 target.t = t.Clone (clonectx);
9180 // An object initializer expression
9182 public class ElementInitializer : Assign
9184 public readonly string Name;
9186 public ElementInitializer (string name, Expression initializer, Location loc)
9187 : base (null, initializer, loc)
9192 protected override void CloneTo (CloneContext clonectx, Expression t)
9194 ElementInitializer target = (ElementInitializer) t;
9195 target.source = source.Clone (clonectx);
9198 public override Expression CreateExpressionTree (EmitContext ec)
9200 ArrayList args = new ArrayList (2);
9201 FieldExpr fe = target as FieldExpr;
9203 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9205 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9207 args.Add (new Argument (source.CreateExpressionTree (ec)));
9208 return CreateExpressionFactoryCall (
9209 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9213 public override Expression DoResolve (EmitContext ec)
9216 return EmptyExpressionStatement.Instance;
9218 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9219 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9225 me.InstanceExpression = ec.CurrentInitializerVariable;
9227 if (source is CollectionOrObjectInitializers) {
9228 Expression previous = ec.CurrentInitializerVariable;
9229 ec.CurrentInitializerVariable = target;
9230 source = source.Resolve (ec);
9231 ec.CurrentInitializerVariable = previous;
9235 eclass = source.eclass;
9240 Expression expr = base.DoResolve (ec);
9245 // Ignore field initializers with default value
9247 Constant c = source as Constant;
9248 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9249 return EmptyExpressionStatement.Instance;
9254 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9256 MemberInfo member = members [0];
9257 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9258 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9259 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9261 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9262 TypeManager.GetFullNameSignature (member));
9267 public override void EmitStatement (EmitContext ec)
9269 if (source is CollectionOrObjectInitializers)
9272 base.EmitStatement (ec);
9277 // A collection initializer expression
9279 public class CollectionElementInitializer : Invocation
9281 public class ElementInitializerArgument : Argument
9283 public ElementInitializerArgument (Expression e)
9289 sealed class AddMemberAccess : MemberAccess
9291 public AddMemberAccess (Expression expr, Location loc)
9292 : base (expr, "Add", loc)
9296 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9298 if (TypeManager.HasElementType (type))
9301 base.Error_TypeDoesNotContainDefinition (type, name);
9305 public CollectionElementInitializer (Expression argument)
9306 : base (null, new ArrayList (1), true)
9308 Arguments.Add (argument);
9309 this.loc = argument.Location;
9312 public CollectionElementInitializer (ArrayList arguments, Location loc)
9313 : base (null, arguments, true)
9318 public override Expression CreateExpressionTree (EmitContext ec)
9320 ArrayList args = new ArrayList (2);
9321 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9323 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9324 foreach (Argument a in Arguments)
9325 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9327 args.Add (new Argument (new ArrayCreation (
9328 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9329 return CreateExpressionFactoryCall ("ElementInit", args);
9332 protected override void CloneTo (CloneContext clonectx, Expression t)
9334 CollectionElementInitializer target = (CollectionElementInitializer) t;
9336 target.Arguments = new ArrayList (Arguments.Count);
9337 foreach (Expression e in Arguments)
9338 target.Arguments.Add (e.Clone (clonectx));
9341 public override Expression DoResolve (EmitContext ec)
9343 if (eclass != ExprClass.Invalid)
9346 // TODO: We could call a constructor which takes element count argument,
9347 // for known types like List<T>, Dictionary<T, U>
9349 for (int i = 0; i < Arguments.Count; ++i) {
9350 Expression expr = Arguments [i] as Expression;
9354 expr = expr.Resolve (ec);
9358 Arguments [i] = new ElementInitializerArgument (expr);
9361 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9363 return base.DoResolve (ec);
9368 // A block of object or collection initializers
9370 public class CollectionOrObjectInitializers : ExpressionStatement
9372 ArrayList initializers;
9374 public static readonly CollectionOrObjectInitializers Empty =
9375 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9377 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9379 this.initializers = initializers;
9383 public bool IsEmpty {
9385 return initializers.Count == 0;
9389 public bool IsCollectionInitializer {
9391 return type == typeof (CollectionOrObjectInitializers);
9395 protected override void CloneTo (CloneContext clonectx, Expression target)
9397 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9399 t.initializers = new ArrayList (initializers.Count);
9400 foreach (Expression e in initializers)
9401 t.initializers.Add (e.Clone (clonectx));
9404 public override Expression CreateExpressionTree (EmitContext ec)
9406 ArrayList expr_initializers = new ArrayList (initializers.Count);
9407 foreach (Expression e in initializers) {
9408 Expression expr = e.CreateExpressionTree (ec);
9410 expr_initializers.Add (expr);
9413 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9416 public override Expression DoResolve (EmitContext ec)
9418 if (eclass != ExprClass.Invalid)
9421 bool is_collection_initialization = false;
9422 ArrayList element_names = null;
9423 for (int i = 0; i < initializers.Count; ++i) {
9424 Expression initializer = (Expression) initializers [i];
9425 ElementInitializer element_initializer = initializer as ElementInitializer;
9428 if (element_initializer != null) {
9429 element_names = new ArrayList (initializers.Count);
9430 element_names.Add (element_initializer.Name);
9432 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9433 TypeManager.ienumerable_type)) {
9434 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9435 "object initializer because type `{1}' does not implement `{2}' interface",
9436 ec.CurrentInitializerVariable.GetSignatureForError (),
9437 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9438 TypeManager.CSharpName (TypeManager.ienumerable_type));
9441 is_collection_initialization = true;
9444 if (is_collection_initialization != (element_initializer == null)) {
9445 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9446 is_collection_initialization ? "collection initializer" : "object initializer");
9450 if (!is_collection_initialization) {
9451 if (element_names.Contains (element_initializer.Name)) {
9452 Report.Error (1912, element_initializer.Location,
9453 "An object initializer includes more than one member `{0}' initialization",
9454 element_initializer.Name);
9456 element_names.Add (element_initializer.Name);
9461 Expression e = initializer.Resolve (ec);
9462 if (e == EmptyExpressionStatement.Instance)
9463 initializers.RemoveAt (i--);
9465 initializers [i] = e;
9468 if (is_collection_initialization) {
9469 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9470 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9471 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9474 type = typeof (CollectionOrObjectInitializers);
9476 type = typeof (ElementInitializer);
9479 eclass = ExprClass.Variable;
9483 public override void Emit (EmitContext ec)
9488 public override void EmitStatement (EmitContext ec)
9490 foreach (ExpressionStatement e in initializers)
9491 e.EmitStatement (ec);
9494 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9496 foreach (Expression e in initializers)
9497 e.MutateHoistedGenericType (storey);
9502 // New expression with element/object initializers
9504 public class NewInitialize : New
9507 // This class serves as a proxy for variable initializer target instances.
9508 // A real variable is assigned later when we resolve left side of an
9511 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9513 NewInitialize new_instance;
9515 public InitializerTargetExpression (NewInitialize newInstance)
9517 this.type = newInstance.type;
9518 this.loc = newInstance.loc;
9519 this.eclass = newInstance.eclass;
9520 this.new_instance = newInstance;
9523 public override Expression CreateExpressionTree (EmitContext ec)
9525 // Should not be reached
9526 throw new NotSupportedException ("ET");
9529 public override Expression DoResolve (EmitContext ec)
9534 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9539 public override void Emit (EmitContext ec)
9541 new_instance.value_target.Emit (ec);
9544 #region IMemoryLocation Members
9546 public void AddressOf (EmitContext ec, AddressOp mode)
9548 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9554 CollectionOrObjectInitializers initializers;
9556 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9557 : base (requested_type, arguments, l)
9559 this.initializers = initializers;
9562 protected override void CloneTo (CloneContext clonectx, Expression t)
9564 base.CloneTo (clonectx, t);
9566 NewInitialize target = (NewInitialize) t;
9567 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9570 public override Expression CreateExpressionTree (EmitContext ec)
9572 ArrayList args = new ArrayList (2);
9573 args.Add (new Argument (base.CreateExpressionTree (ec)));
9574 if (!initializers.IsEmpty)
9575 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9577 return CreateExpressionFactoryCall (
9578 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9582 public override Expression DoResolve (EmitContext ec)
9584 if (eclass != ExprClass.Invalid)
9587 Expression e = base.DoResolve (ec);
9591 // Empty initializer can be optimized to simple new
9592 if (initializers.IsEmpty) {
9593 initializers.Resolve (ec);
9594 return ReducedExpression.Create (e, this).Resolve (ec);
9597 Expression previous = ec.CurrentInitializerVariable;
9598 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9599 initializers.Resolve (ec);
9600 ec.CurrentInitializerVariable = previous;
9604 public override void Emit (EmitContext ec)
9609 // If target is non-hoisted variable, let's use it
9611 VariableReference variable = value_target as VariableReference;
9612 if (variable != null && variable.HoistedVariable == null) {
9614 StoreFromPtr (ec.ig, type);
9616 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9619 if (value_target == null || value_target_set)
9620 value_target = new LocalTemporary (type);
9622 ((LocalTemporary) value_target).Store (ec);
9625 initializers.Emit (ec);
9627 if (variable == null) {
9628 value_target.Emit (ec);
9629 value_target = null;
9633 public override void EmitStatement (EmitContext ec)
9635 if (initializers.IsEmpty) {
9636 base.EmitStatement (ec);
9642 if (value_target == null) {
9643 LocalTemporary variable = new LocalTemporary (type);
9644 variable.Store (ec);
9645 value_target = variable;
9648 initializers.EmitStatement (ec);
9651 public override bool HasInitializer {
9653 return !initializers.IsEmpty;
9657 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9659 base.MutateHoistedGenericType (storey);
9660 initializers.MutateHoistedGenericType (storey);
9664 public class AnonymousTypeDeclaration : Expression
9666 ArrayList parameters;
9667 readonly TypeContainer parent;
9668 static readonly ArrayList EmptyParameters = new ArrayList (0);
9670 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9672 this.parameters = parameters;
9673 this.parent = parent;
9677 protected override void CloneTo (CloneContext clonectx, Expression target)
9679 if (parameters == null)
9682 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9683 t.parameters = new ArrayList (parameters.Count);
9684 foreach (AnonymousTypeParameter atp in parameters)
9685 t.parameters.Add (atp.Clone (clonectx));
9688 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9690 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9694 type = AnonymousTypeClass.Create (parent, parameters, loc);
9699 type.DefineMembers ();
9702 if (Report.Errors == 0)
9705 RootContext.ToplevelTypes.AddAnonymousType (type);
9709 public override Expression CreateExpressionTree (EmitContext ec)
9711 throw new NotSupportedException ("ET");
9714 public override Expression DoResolve (EmitContext ec)
9716 AnonymousTypeClass anonymous_type;
9718 if (!ec.IsAnonymousMethodAllowed) {
9719 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9723 if (parameters == null) {
9724 anonymous_type = CreateAnonymousType (EmptyParameters);
9725 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9726 null, loc).Resolve (ec);
9730 ArrayList arguments = new ArrayList (parameters.Count);
9731 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9732 for (int i = 0; i < parameters.Count; ++i) {
9733 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9739 arguments.Add (new Argument (e));
9740 t_args [i] = new TypeExpression (e.Type, e.Location);
9746 anonymous_type = CreateAnonymousType (parameters);
9747 if (anonymous_type == null)
9750 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9751 new TypeArguments (loc, t_args), loc);
9753 return new New (te, arguments, loc).Resolve (ec);
9756 public override void Emit (EmitContext ec)
9758 throw new InternalErrorException ("Should not be reached");
9762 public class AnonymousTypeParameter : Expression
9764 public readonly string Name;
9765 Expression initializer;
9767 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9771 this.initializer = initializer;
9774 public AnonymousTypeParameter (Parameter parameter)
9776 this.Name = parameter.Name;
9777 this.loc = parameter.Location;
9778 this.initializer = new SimpleName (Name, loc);
9781 protected override void CloneTo (CloneContext clonectx, Expression target)
9783 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9784 t.initializer = initializer.Clone (clonectx);
9787 public override Expression CreateExpressionTree (EmitContext ec)
9789 throw new NotSupportedException ("ET");
9792 public override bool Equals (object o)
9794 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9795 return other != null && Name == other.Name;
9798 public override int GetHashCode ()
9800 return Name.GetHashCode ();
9803 public override Expression DoResolve (EmitContext ec)
9805 Expression e = initializer.Resolve (ec);
9809 if (e.eclass == ExprClass.MethodGroup) {
9810 Error_InvalidInitializer (e.ExprClassName);
9815 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9816 type == TypeManager.anonymous_method_type || type.IsPointer) {
9817 Error_InvalidInitializer (e.GetSignatureForError ());
9824 protected virtual void Error_InvalidInitializer (string initializer)
9826 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9830 public override void Emit (EmitContext ec)
9832 throw new InternalErrorException ("Should not be reached");