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 ());
4791 if (type.IsPointer){
4799 // Only base will allow this invocation to happen.
4801 if (mg.IsBase && method.IsAbstract){
4802 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4806 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4808 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4810 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4814 IsSpecialMethodInvocation (method, loc);
4816 if (mg.InstanceExpression != null)
4817 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4819 eclass = ExprClass.Value;
4823 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4825 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4828 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4830 if (!TypeManager.IsSpecialMethod (method))
4833 Report.SymbolRelatedToPreviousError (method);
4834 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4835 TypeManager.CSharpSignature (method, true));
4841 /// Emits a list of resolved Arguments that are in the arguments
4844 /// The MethodBase argument might be null if the
4845 /// emission of the arguments is known not to contain
4846 /// a `params' field (for example in constructors or other routines
4847 /// that keep their arguments in this structure)
4849 /// if `dup_args' is true, a copy of the arguments will be left
4850 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4851 /// which will be duplicated before any other args. Only EmitCall
4852 /// should be using this interface.
4854 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4856 if (arguments == null)
4859 int top = arguments.Count;
4860 LocalTemporary [] temps = null;
4862 if (dup_args && top != 0)
4863 temps = new LocalTemporary [top];
4865 int argument_index = 0;
4867 for (int i = 0; i < top; i++) {
4868 a = (Argument) arguments [argument_index++];
4871 ec.ig.Emit (OpCodes.Dup);
4872 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4877 if (this_arg != null)
4880 for (int i = 0; i < top; i ++) {
4881 temps [i].Emit (ec);
4882 temps [i].Release (ec);
4887 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4889 AParametersCollection pd = TypeManager.GetParameterData (mb);
4891 Argument a = (Argument) arguments [pd.Count - 1];
4892 Arglist list = (Arglist) a.Expr;
4894 return list.ArgumentTypes;
4898 /// This checks the ConditionalAttribute on the method
4900 public static bool IsMethodExcluded (MethodBase method, Location loc)
4902 if (method.IsConstructor)
4905 method = TypeManager.DropGenericMethodArguments (method);
4906 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4907 IMethodData md = TypeManager.GetMethod (method);
4909 return md.IsExcluded ();
4911 // For some methods (generated by delegate class) GetMethod returns null
4912 // because they are not included in builder_to_method table
4916 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4920 /// is_base tells whether we want to force the use of the `call'
4921 /// opcode instead of using callvirt. Call is required to call
4922 /// a specific method, while callvirt will always use the most
4923 /// recent method in the vtable.
4925 /// is_static tells whether this is an invocation on a static method
4927 /// instance_expr is an expression that represents the instance
4928 /// it must be non-null if is_static is false.
4930 /// method is the method to invoke.
4932 /// Arguments is the list of arguments to pass to the method or constructor.
4934 public static void EmitCall (EmitContext ec, bool is_base,
4935 Expression instance_expr,
4936 MethodBase method, ArrayList Arguments, Location loc)
4938 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4941 // `dup_args' leaves an extra copy of the arguments on the stack
4942 // `omit_args' does not leave any arguments at all.
4943 // So, basically, you could make one call with `dup_args' set to true,
4944 // and then another with `omit_args' set to true, and the two calls
4945 // would have the same set of arguments. However, each argument would
4946 // only have been evaluated once.
4947 public static void EmitCall (EmitContext ec, bool is_base,
4948 Expression instance_expr,
4949 MethodBase method, ArrayList Arguments, Location loc,
4950 bool dup_args, bool omit_args)
4952 ILGenerator ig = ec.ig;
4953 bool struct_call = false;
4954 bool this_call = false;
4955 LocalTemporary this_arg = null;
4957 Type decl_type = method.DeclaringType;
4959 if (!ec.IsInObsoleteScope) {
4961 // This checks ObsoleteAttribute on the method and on the declaring type
4963 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4965 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4967 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4969 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4973 if (IsMethodExcluded (method, loc))
4976 bool is_static = method.IsStatic;
4978 if (instance_expr == EmptyExpression.Null) {
4979 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4983 this_call = instance_expr is This;
4984 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4988 // If this is ourselves, push "this"
4992 Type iexpr_type = instance_expr.Type;
4995 // Push the instance expression
4997 if (TypeManager.IsValueType (iexpr_type)) {
4999 // Special case: calls to a function declared in a
5000 // reference-type with a value-type argument need
5001 // to have their value boxed.
5002 if (decl_type.IsValueType ||
5003 TypeManager.IsGenericParameter (iexpr_type)) {
5005 // If the expression implements IMemoryLocation, then
5006 // we can optimize and use AddressOf on the
5009 // If not we have to use some temporary storage for
5011 if (instance_expr is IMemoryLocation) {
5012 ((IMemoryLocation)instance_expr).
5013 AddressOf (ec, AddressOp.LoadStore);
5015 LocalTemporary temp = new LocalTemporary (iexpr_type);
5016 instance_expr.Emit (ec);
5018 temp.AddressOf (ec, AddressOp.Load);
5021 // avoid the overhead of doing this all the time.
5023 t = TypeManager.GetReferenceType (iexpr_type);
5025 instance_expr.Emit (ec);
5026 ig.Emit (OpCodes.Box, instance_expr.Type);
5027 t = TypeManager.object_type;
5030 instance_expr.Emit (ec);
5031 t = instance_expr.Type;
5035 ig.Emit (OpCodes.Dup);
5036 if (Arguments != null && Arguments.Count != 0) {
5037 this_arg = new LocalTemporary (t);
5038 this_arg.Store (ec);
5045 EmitArguments (ec, Arguments, dup_args, this_arg);
5048 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5049 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5053 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5054 call_op = OpCodes.Call;
5056 call_op = OpCodes.Callvirt;
5058 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5059 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5060 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5067 // and DoFoo is not virtual, you can omit the callvirt,
5068 // because you don't need the null checking behavior.
5070 if (method is MethodInfo)
5071 ig.Emit (call_op, (MethodInfo) method);
5073 ig.Emit (call_op, (ConstructorInfo) method);
5076 public override void Emit (EmitContext ec)
5078 mg.EmitCall (ec, Arguments);
5081 public override void EmitStatement (EmitContext ec)
5086 // Pop the return value if there is one
5088 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5089 ec.ig.Emit (OpCodes.Pop);
5092 protected override void CloneTo (CloneContext clonectx, Expression t)
5094 Invocation target = (Invocation) t;
5096 if (Arguments != null) {
5097 target.Arguments = new ArrayList (Arguments.Count);
5098 foreach (Argument a in Arguments)
5099 target.Arguments.Add (a.Clone (clonectx));
5102 target.expr = expr.Clone (clonectx);
5105 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5107 mg.MutateHoistedGenericType (storey);
5108 if (Arguments != null) {
5109 foreach (Argument a in Arguments)
5110 a.Expr.MutateHoistedGenericType (storey);
5116 // It's either a cast or delegate invocation
5118 public class InvocationOrCast : ExpressionStatement
5121 Expression argument;
5123 public InvocationOrCast (Expression expr, Expression argument)
5126 this.argument = argument;
5127 this.loc = expr.Location;
5130 public override Expression CreateExpressionTree (EmitContext ec)
5132 throw new NotSupportedException ("ET");
5135 public override Expression DoResolve (EmitContext ec)
5137 Expression e = ResolveCore (ec);
5141 return e.Resolve (ec);
5144 Expression ResolveCore (EmitContext ec)
5147 // First try to resolve it as a cast.
5149 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5151 return new Cast (te, argument, loc);
5155 // This can either be a type or a delegate invocation.
5156 // Let's just resolve it and see what we'll get.
5158 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5163 // Ok, so it's a Cast.
5165 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5166 return new Cast (expr, argument, loc);
5169 if (expr.eclass == ExprClass.Namespace) {
5170 expr.Error_UnexpectedKind (null, "type", loc);
5175 // It's a delegate invocation.
5177 if (!TypeManager.IsDelegateType (expr.Type)) {
5178 Error (149, "Method name expected");
5182 ArrayList args = new ArrayList (1);
5183 args.Add (new Argument (argument, Argument.AType.Expression));
5184 return new DelegateInvocation (expr, args, loc);
5187 public override ExpressionStatement ResolveStatement (EmitContext ec)
5189 Expression e = ResolveCore (ec);
5193 ExpressionStatement s = e as ExpressionStatement;
5195 Error_InvalidExpressionStatement ();
5199 return s.ResolveStatement (ec);
5202 public override void Emit (EmitContext ec)
5204 throw new Exception ("Cannot happen");
5207 public override void EmitStatement (EmitContext ec)
5209 throw new Exception ("Cannot happen");
5212 protected override void CloneTo (CloneContext clonectx, Expression t)
5214 InvocationOrCast target = (InvocationOrCast) t;
5216 target.expr = expr.Clone (clonectx);
5217 target.argument = argument.Clone (clonectx);
5222 // This class is used to "disable" the code generation for the
5223 // temporary variable when initializing value types.
5225 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5226 public void AddressOf (EmitContext ec, AddressOp Mode)
5233 /// Implements the new expression
5235 public class New : ExpressionStatement, IMemoryLocation {
5236 ArrayList Arguments;
5239 // During bootstrap, it contains the RequestedType,
5240 // but if `type' is not null, it *might* contain a NewDelegate
5241 // (because of field multi-initialization)
5243 public Expression RequestedType;
5245 MethodGroupExpr method;
5248 // If set, the new expression is for a value_target, and
5249 // we will not leave anything on the stack.
5251 protected Expression value_target;
5252 protected bool value_target_set;
5253 bool is_type_parameter = false;
5255 public New (Expression requested_type, ArrayList arguments, Location l)
5257 RequestedType = requested_type;
5258 Arguments = arguments;
5262 public bool SetTargetVariable (Expression value)
5264 value_target = value;
5265 value_target_set = true;
5266 if (!(value_target is IMemoryLocation)){
5267 Error_UnexpectedKind (null, "variable", loc);
5274 // This function is used to disable the following code sequence for
5275 // value type initialization:
5277 // AddressOf (temporary)
5281 // Instead the provide will have provided us with the address on the
5282 // stack to store the results.
5284 static Expression MyEmptyExpression;
5286 public void DisableTemporaryValueType ()
5288 if (MyEmptyExpression == null)
5289 MyEmptyExpression = new EmptyAddressOf ();
5292 // To enable this, look into:
5293 // test-34 and test-89 and self bootstrapping.
5295 // For instance, we can avoid a copy by using `newobj'
5296 // instead of Call + Push-temp on value types.
5297 // value_target = MyEmptyExpression;
5302 /// Converts complex core type syntax like 'new int ()' to simple constant
5304 public static Constant Constantify (Type t)
5306 if (t == TypeManager.int32_type)
5307 return new IntConstant (0, Location.Null);
5308 if (t == TypeManager.uint32_type)
5309 return new UIntConstant (0, Location.Null);
5310 if (t == TypeManager.int64_type)
5311 return new LongConstant (0, Location.Null);
5312 if (t == TypeManager.uint64_type)
5313 return new ULongConstant (0, Location.Null);
5314 if (t == TypeManager.float_type)
5315 return new FloatConstant (0, Location.Null);
5316 if (t == TypeManager.double_type)
5317 return new DoubleConstant (0, Location.Null);
5318 if (t == TypeManager.short_type)
5319 return new ShortConstant (0, Location.Null);
5320 if (t == TypeManager.ushort_type)
5321 return new UShortConstant (0, Location.Null);
5322 if (t == TypeManager.sbyte_type)
5323 return new SByteConstant (0, Location.Null);
5324 if (t == TypeManager.byte_type)
5325 return new ByteConstant (0, Location.Null);
5326 if (t == TypeManager.char_type)
5327 return new CharConstant ('\0', Location.Null);
5328 if (t == TypeManager.bool_type)
5329 return new BoolConstant (false, Location.Null);
5330 if (t == TypeManager.decimal_type)
5331 return new DecimalConstant (0, Location.Null);
5332 if (TypeManager.IsEnumType (t))
5333 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5339 // Checks whether the type is an interface that has the
5340 // [ComImport, CoClass] attributes and must be treated
5343 public Expression CheckComImport (EmitContext ec)
5345 if (!type.IsInterface)
5349 // Turn the call into:
5350 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5352 Type real_class = AttributeTester.GetCoClassAttribute (type);
5353 if (real_class == null)
5356 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5357 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5358 return cast.Resolve (ec);
5361 public override Expression CreateExpressionTree (EmitContext ec)
5363 ArrayList args = Arguments == null ?
5364 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5366 if (method == null) {
5367 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5369 args.Add (new Argument (method.CreateExpressionTree (ec)));
5370 if (Arguments != null) {
5372 foreach (Argument a in Arguments) {
5373 expr = a.Expr.CreateExpressionTree (ec);
5375 args.Add (new Argument (expr));
5380 return CreateExpressionFactoryCall ("New", args);
5383 public override Expression DoResolve (EmitContext ec)
5386 // The New DoResolve might be called twice when initializing field
5387 // expressions (see EmitFieldInitializers, the call to
5388 // GetInitializerExpression will perform a resolve on the expression,
5389 // and later the assign will trigger another resolution
5391 // This leads to bugs (#37014)
5394 if (RequestedType is NewDelegate)
5395 return RequestedType;
5399 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5405 if (type.IsPointer) {
5406 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5407 TypeManager.CSharpName (type));
5411 if (Arguments == null) {
5412 Expression c = Constantify (type);
5417 if (TypeManager.IsDelegateType (type)) {
5418 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5422 if (type.IsGenericParameter) {
5423 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5425 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5426 Error (304, String.Format (
5427 "Cannot create an instance of the " +
5428 "variable type '{0}' because it " +
5429 "doesn't have the new() constraint",
5434 if ((Arguments != null) && (Arguments.Count != 0)) {
5435 Error (417, String.Format (
5436 "`{0}': cannot provide arguments " +
5437 "when creating an instance of a " +
5438 "variable type.", type));
5442 if (TypeManager.activator_create_instance == null) {
5443 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5444 if (activator_type != null) {
5445 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5446 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5450 is_type_parameter = true;
5451 eclass = ExprClass.Value;
5456 if (type.IsAbstract && type.IsSealed) {
5457 Report.SymbolRelatedToPreviousError (type);
5458 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5462 if (type.IsInterface || type.IsAbstract){
5463 if (!TypeManager.IsGenericType (type)) {
5464 RequestedType = CheckComImport (ec);
5465 if (RequestedType != null)
5466 return RequestedType;
5469 Report.SymbolRelatedToPreviousError (type);
5470 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5474 bool is_struct = type.IsValueType;
5475 eclass = ExprClass.Value;
5478 // SRE returns a match for .ctor () on structs (the object constructor),
5479 // so we have to manually ignore it.
5481 if (is_struct && Arguments == null)
5484 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5485 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5486 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5488 if (Arguments != null){
5489 foreach (Argument a in Arguments){
5490 if (!a.Resolve (ec, loc))
5498 method = ml as MethodGroupExpr;
5499 if (method == null) {
5500 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5504 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5511 bool DoEmitTypeParameter (EmitContext ec)
5514 ILGenerator ig = ec.ig;
5515 // IMemoryLocation ml;
5517 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5518 new Type [] { type });
5520 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5521 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5522 ig.Emit (OpCodes.Call, ci);
5526 // Allow DoEmit() to be called multiple times.
5527 // We need to create a new LocalTemporary each time since
5528 // you can't share LocalBuilders among ILGeneators.
5529 LocalTemporary temp = new LocalTemporary (type);
5531 Label label_activator = ig.DefineLabel ();
5532 Label label_end = ig.DefineLabel ();
5534 temp.AddressOf (ec, AddressOp.Store);
5535 ig.Emit (OpCodes.Initobj, type);
5538 ig.Emit (OpCodes.Box, type);
5539 ig.Emit (OpCodes.Brfalse, label_activator);
5541 temp.AddressOf (ec, AddressOp.Store);
5542 ig.Emit (OpCodes.Initobj, type);
5544 ig.Emit (OpCodes.Br, label_end);
5546 ig.MarkLabel (label_activator);
5548 ig.Emit (OpCodes.Call, ci);
5549 ig.MarkLabel (label_end);
5552 throw new InternalErrorException ();
5557 // This DoEmit can be invoked in two contexts:
5558 // * As a mechanism that will leave a value on the stack (new object)
5559 // * As one that wont (init struct)
5561 // You can control whether a value is required on the stack by passing
5562 // need_value_on_stack. The code *might* leave a value on the stack
5563 // so it must be popped manually
5565 // If we are dealing with a ValueType, we have a few
5566 // situations to deal with:
5568 // * The target is a ValueType, and we have been provided
5569 // the instance (this is easy, we are being assigned).
5571 // * The target of New is being passed as an argument,
5572 // to a boxing operation or a function that takes a
5575 // In this case, we need to create a temporary variable
5576 // that is the argument of New.
5578 // Returns whether a value is left on the stack
5580 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5582 bool is_value_type = TypeManager.IsValueType (type);
5583 ILGenerator ig = ec.ig;
5588 // Allow DoEmit() to be called multiple times.
5589 // We need to create a new LocalTemporary each time since
5590 // you can't share LocalBuilders among ILGeneators.
5591 if (!value_target_set)
5592 value_target = new LocalTemporary (type);
5594 ml = (IMemoryLocation) value_target;
5595 ml.AddressOf (ec, AddressOp.Store);
5599 method.EmitArguments (ec, Arguments);
5603 ig.Emit (OpCodes.Initobj, type);
5605 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5606 if (need_value_on_stack){
5607 value_target.Emit (ec);
5612 ConstructorInfo ci = (ConstructorInfo) method;
5614 if (TypeManager.IsGenericType (type))
5615 ci = TypeBuilder.GetConstructor (type, ci);
5617 ig.Emit (OpCodes.Newobj, ci);
5622 public override void Emit (EmitContext ec)
5624 if (is_type_parameter)
5625 DoEmitTypeParameter (ec);
5630 public override void EmitStatement (EmitContext ec)
5632 bool value_on_stack;
5634 if (is_type_parameter)
5635 value_on_stack = DoEmitTypeParameter (ec);
5637 value_on_stack = DoEmit (ec, false);
5640 ec.ig.Emit (OpCodes.Pop);
5644 public virtual bool HasInitializer {
5650 public void AddressOf (EmitContext ec, AddressOp Mode)
5652 if (is_type_parameter) {
5653 LocalTemporary temp = new LocalTemporary (type);
5654 DoEmitTypeParameter (ec);
5656 temp.AddressOf (ec, Mode);
5660 if (!type.IsValueType){
5662 // We throw an exception. So far, I believe we only need to support
5664 // foreach (int j in new StructType ())
5667 throw new Exception ("AddressOf should not be used for classes");
5670 if (!value_target_set)
5671 value_target = new LocalTemporary (type);
5672 IMemoryLocation ml = (IMemoryLocation) value_target;
5674 ml.AddressOf (ec, AddressOp.Store);
5675 if (method == null) {
5676 ec.ig.Emit (OpCodes.Initobj, type);
5678 method.EmitArguments (ec, Arguments);
5679 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5682 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5685 protected override void CloneTo (CloneContext clonectx, Expression t)
5687 New target = (New) t;
5689 target.RequestedType = RequestedType.Clone (clonectx);
5690 if (Arguments != null){
5691 target.Arguments = new ArrayList ();
5692 foreach (Argument a in Arguments){
5693 target.Arguments.Add (a.Clone (clonectx));
5698 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5700 if (method != null) {
5701 method.MutateHoistedGenericType (storey);
5702 if (Arguments != null) {
5703 foreach (Argument a in Arguments)
5704 a.Expr.MutateHoistedGenericType (storey);
5708 type = storey.MutateType (type);
5713 /// 14.5.10.2: Represents an array creation expression.
5717 /// There are two possible scenarios here: one is an array creation
5718 /// expression that specifies the dimensions and optionally the
5719 /// initialization data and the other which does not need dimensions
5720 /// specified but where initialization data is mandatory.
5722 public class ArrayCreation : Expression {
5723 FullNamedExpression requested_base_type;
5724 ArrayList initializers;
5727 // The list of Argument types.
5728 // This is used to construct the `newarray' or constructor signature
5730 protected ArrayList arguments;
5732 protected Type array_element_type;
5733 bool expect_initializers = false;
5734 int num_arguments = 0;
5735 protected int dimensions;
5736 protected readonly string rank;
5738 protected ArrayList array_data;
5742 // The number of constants in array initializers
5743 int const_initializers_count;
5744 bool only_constant_initializers;
5746 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5748 this.requested_base_type = requested_base_type;
5749 this.initializers = initializers;
5753 arguments = new ArrayList (exprs.Count);
5755 foreach (Expression e in exprs) {
5756 arguments.Add (new Argument (e, Argument.AType.Expression));
5761 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5763 this.requested_base_type = requested_base_type;
5764 this.initializers = initializers;
5768 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5770 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5772 //dimensions = tmp.Length - 1;
5773 expect_initializers = true;
5776 void Error_IncorrectArrayInitializer ()
5778 Error (178, "Invalid rank specifier: expected `,' or `]'");
5781 protected override void Error_NegativeArrayIndex (Location loc)
5783 Report.Error (248, loc, "Cannot create an array with a negative size");
5786 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5788 if (specified_dims) {
5789 Argument a = (Argument) arguments [idx];
5791 if (!a.Resolve (ec, loc))
5794 Constant c = a.Expr as Constant;
5796 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5800 Report.Error (150, a.Expr.Location, "A constant value is expected");
5804 int value = (int) c.GetValue ();
5806 if (value != probe.Count) {
5807 Error_IncorrectArrayInitializer ();
5811 bounds [idx] = value;
5814 int child_bounds = -1;
5815 only_constant_initializers = true;
5816 for (int i = 0; i < probe.Count; ++i) {
5817 object o = probe [i];
5818 if (o is ArrayList) {
5819 ArrayList sub_probe = o as ArrayList;
5820 int current_bounds = sub_probe.Count;
5822 if (child_bounds == -1)
5823 child_bounds = current_bounds;
5825 else if (child_bounds != current_bounds){
5826 Error_IncorrectArrayInitializer ();
5829 if (idx + 1 >= dimensions){
5830 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5834 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5838 if (child_bounds != -1){
5839 Error_IncorrectArrayInitializer ();
5843 Expression element = ResolveArrayElement (ec, (Expression) o);
5844 if (element == null)
5847 // Initializers with the default values can be ignored
5848 Constant c = element as Constant;
5850 if (c.IsDefaultInitializer (array_element_type)) {
5854 ++const_initializers_count;
5857 only_constant_initializers = false;
5860 array_data.Add (element);
5867 public override Expression CreateExpressionTree (EmitContext ec)
5871 if (array_data == null) {
5872 args = new ArrayList (arguments.Count + 1);
5873 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5874 foreach (Argument a in arguments) {
5875 if (arguments.Count == 1) {
5876 Constant c = a.Expr as Constant;
5877 if (c.IsDefaultValue)
5878 return CreateExpressionFactoryCall ("NewArrayInit", args);
5880 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5883 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5886 if (dimensions > 1) {
5887 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5891 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5892 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5893 if (array_data != null) {
5894 for (int i = 0; i < array_data.Count; ++i) {
5895 Expression e = (Expression) array_data [i];
5897 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5899 args.Add (new Argument (e.CreateExpressionTree (ec)));
5903 return CreateExpressionFactoryCall ("NewArrayInit", args);
5906 public void UpdateIndices ()
5909 for (ArrayList probe = initializers; probe != null;) {
5910 if (probe.Count > 0 && probe [0] is ArrayList) {
5911 Expression e = new IntConstant (probe.Count, Location.Null);
5912 arguments.Add (new Argument (e, Argument.AType.Expression));
5914 bounds [i++] = probe.Count;
5916 probe = (ArrayList) probe [0];
5919 Expression e = new IntConstant (probe.Count, Location.Null);
5920 arguments.Add (new Argument (e, Argument.AType.Expression));
5922 bounds [i++] = probe.Count;
5929 Expression first_emit;
5930 LocalTemporary first_emit_temp;
5932 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5934 element = element.Resolve (ec);
5935 if (element == null)
5938 if (element is CompoundAssign.Helper) {
5939 if (first_emit != null)
5940 throw new InternalErrorException ("Can only handle one mutator at a time");
5941 first_emit = element;
5942 element = first_emit_temp = new LocalTemporary (element.Type);
5945 return Convert.ImplicitConversionRequired (
5946 ec, element, array_element_type, loc);
5949 protected bool ResolveInitializers (EmitContext ec)
5951 if (initializers == null) {
5952 return !expect_initializers;
5956 // We use this to store all the date values in the order in which we
5957 // will need to store them in the byte blob later
5959 array_data = new ArrayList ();
5960 bounds = new System.Collections.Specialized.HybridDictionary ();
5962 if (arguments != null)
5963 return CheckIndices (ec, initializers, 0, true);
5965 arguments = new ArrayList ();
5967 if (!CheckIndices (ec, initializers, 0, false))
5976 // Resolved the type of the array
5978 bool ResolveArrayType (EmitContext ec)
5980 if (requested_base_type == null) {
5981 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5985 if (requested_base_type is VarExpr) {
5986 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5990 StringBuilder array_qualifier = new StringBuilder (rank);
5993 // `In the first form allocates an array instace of the type that results
5994 // from deleting each of the individual expression from the expression list'
5996 if (num_arguments > 0) {
5997 array_qualifier.Append ("[");
5998 for (int i = num_arguments-1; i > 0; i--)
5999 array_qualifier.Append (",");
6000 array_qualifier.Append ("]");
6006 TypeExpr array_type_expr;
6007 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6008 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6009 if (array_type_expr == null)
6012 type = array_type_expr.Type;
6013 array_element_type = TypeManager.GetElementType (type);
6014 dimensions = type.GetArrayRank ();
6019 public override Expression DoResolve (EmitContext ec)
6024 if (!ResolveArrayType (ec))
6028 // First step is to validate the initializers and fill
6029 // in any missing bits
6031 if (!ResolveInitializers (ec))
6034 if (arguments.Count != dimensions) {
6035 Error_IncorrectArrayInitializer ();
6038 foreach (Argument a in arguments){
6039 if (!a.Resolve (ec, loc))
6042 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6045 eclass = ExprClass.Value;
6049 MethodInfo GetArrayMethod (int arguments)
6051 ModuleBuilder mb = CodeGen.Module.Builder;
6053 Type[] arg_types = new Type[arguments];
6054 for (int i = 0; i < arguments; i++)
6055 arg_types[i] = TypeManager.int32_type;
6057 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6061 Report.Error (-6, "New invocation: Can not find a constructor for " +
6062 "this argument list");
6069 byte [] MakeByteBlob ()
6074 int count = array_data.Count;
6076 if (TypeManager.IsEnumType (array_element_type))
6077 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6079 factor = GetTypeSize (array_element_type);
6081 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6083 data = new byte [(count * factor + 3) & ~3];
6086 for (int i = 0; i < count; ++i) {
6087 object v = array_data [i];
6089 if (v is EnumConstant)
6090 v = ((EnumConstant) v).Child;
6092 if (v is Constant && !(v is StringConstant))
6093 v = ((Constant) v).GetValue ();
6099 if (array_element_type == TypeManager.int64_type){
6100 if (!(v is Expression)){
6101 long val = (long) v;
6103 for (int j = 0; j < factor; ++j) {
6104 data [idx + j] = (byte) (val & 0xFF);
6108 } else if (array_element_type == TypeManager.uint64_type){
6109 if (!(v is Expression)){
6110 ulong val = (ulong) v;
6112 for (int j = 0; j < factor; ++j) {
6113 data [idx + j] = (byte) (val & 0xFF);
6117 } else if (array_element_type == TypeManager.float_type) {
6118 if (!(v is Expression)){
6119 element = BitConverter.GetBytes ((float) v);
6121 for (int j = 0; j < factor; ++j)
6122 data [idx + j] = element [j];
6123 if (!BitConverter.IsLittleEndian)
6124 System.Array.Reverse (data, idx, 4);
6126 } else if (array_element_type == TypeManager.double_type) {
6127 if (!(v is Expression)){
6128 element = BitConverter.GetBytes ((double) v);
6130 for (int j = 0; j < factor; ++j)
6131 data [idx + j] = element [j];
6133 // FIXME: Handle the ARM float format.
6134 if (!BitConverter.IsLittleEndian)
6135 System.Array.Reverse (data, idx, 8);
6137 } else if (array_element_type == TypeManager.char_type){
6138 if (!(v is Expression)){
6139 int val = (int) ((char) v);
6141 data [idx] = (byte) (val & 0xff);
6142 data [idx+1] = (byte) (val >> 8);
6144 } else if (array_element_type == TypeManager.short_type){
6145 if (!(v is Expression)){
6146 int val = (int) ((short) v);
6148 data [idx] = (byte) (val & 0xff);
6149 data [idx+1] = (byte) (val >> 8);
6151 } else if (array_element_type == TypeManager.ushort_type){
6152 if (!(v is Expression)){
6153 int val = (int) ((ushort) v);
6155 data [idx] = (byte) (val & 0xff);
6156 data [idx+1] = (byte) (val >> 8);
6158 } else if (array_element_type == TypeManager.int32_type) {
6159 if (!(v is Expression)){
6162 data [idx] = (byte) (val & 0xff);
6163 data [idx+1] = (byte) ((val >> 8) & 0xff);
6164 data [idx+2] = (byte) ((val >> 16) & 0xff);
6165 data [idx+3] = (byte) (val >> 24);
6167 } else if (array_element_type == TypeManager.uint32_type) {
6168 if (!(v is Expression)){
6169 uint val = (uint) v;
6171 data [idx] = (byte) (val & 0xff);
6172 data [idx+1] = (byte) ((val >> 8) & 0xff);
6173 data [idx+2] = (byte) ((val >> 16) & 0xff);
6174 data [idx+3] = (byte) (val >> 24);
6176 } else if (array_element_type == TypeManager.sbyte_type) {
6177 if (!(v is Expression)){
6178 sbyte val = (sbyte) v;
6179 data [idx] = (byte) val;
6181 } else if (array_element_type == TypeManager.byte_type) {
6182 if (!(v is Expression)){
6183 byte val = (byte) v;
6184 data [idx] = (byte) val;
6186 } else if (array_element_type == TypeManager.bool_type) {
6187 if (!(v is Expression)){
6188 bool val = (bool) v;
6189 data [idx] = (byte) (val ? 1 : 0);
6191 } else if (array_element_type == TypeManager.decimal_type){
6192 if (!(v is Expression)){
6193 int [] bits = Decimal.GetBits ((decimal) v);
6196 // FIXME: For some reason, this doesn't work on the MS runtime.
6197 int [] nbits = new int [4];
6198 nbits [0] = bits [3];
6199 nbits [1] = bits [2];
6200 nbits [2] = bits [0];
6201 nbits [3] = bits [1];
6203 for (int j = 0; j < 4; j++){
6204 data [p++] = (byte) (nbits [j] & 0xff);
6205 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6206 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6207 data [p++] = (byte) (nbits [j] >> 24);
6211 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6219 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6221 array_element_type = storey.MutateType (array_element_type);
6222 type = storey.MutateType (type);
6223 if (arguments != null) {
6224 foreach (Argument a in arguments)
6225 a.Expr.MutateHoistedGenericType (storey);
6228 if (array_data != null) {
6229 foreach (Expression e in array_data)
6230 e.MutateHoistedGenericType (storey);
6235 // Emits the initializers for the array
6237 void EmitStaticInitializers (EmitContext ec)
6239 // FIXME: This should go to Resolve !
6240 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6241 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6242 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6243 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6244 if (TypeManager.void_initializearray_array_fieldhandle == null)
6249 // First, the static data
6252 ILGenerator ig = ec.ig;
6254 byte [] data = MakeByteBlob ();
6256 fb = RootContext.MakeStaticData (data);
6258 ig.Emit (OpCodes.Dup);
6259 ig.Emit (OpCodes.Ldtoken, fb);
6260 ig.Emit (OpCodes.Call,
6261 TypeManager.void_initializearray_array_fieldhandle);
6265 // Emits pieces of the array that can not be computed at compile
6266 // time (variables and string locations).
6268 // This always expect the top value on the stack to be the array
6270 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6272 ILGenerator ig = ec.ig;
6273 int dims = bounds.Count;
6274 int [] current_pos = new int [dims];
6276 MethodInfo set = null;
6279 Type [] args = new Type [dims + 1];
6281 for (int j = 0; j < dims; j++)
6282 args [j] = TypeManager.int32_type;
6283 args [dims] = array_element_type;
6285 set = CodeGen.Module.Builder.GetArrayMethod (
6287 CallingConventions.HasThis | CallingConventions.Standard,
6288 TypeManager.void_type, args);
6291 for (int i = 0; i < array_data.Count; i++){
6293 Expression e = (Expression)array_data [i];
6295 // Constant can be initialized via StaticInitializer
6296 if (e != null && !(!emitConstants && e is Constant)) {
6297 Type etype = e.Type;
6299 ig.Emit (OpCodes.Dup);
6301 for (int idx = 0; idx < dims; idx++)
6302 IntConstant.EmitInt (ig, current_pos [idx]);
6305 // If we are dealing with a struct, get the
6306 // address of it, so we can store it.
6308 if ((dims == 1) && etype.IsValueType &&
6309 (!TypeManager.IsBuiltinOrEnum (etype) ||
6310 etype == TypeManager.decimal_type)) {
6315 // Let new know that we are providing
6316 // the address where to store the results
6318 n.DisableTemporaryValueType ();
6321 ig.Emit (OpCodes.Ldelema, etype);
6327 bool is_stobj, has_type_arg;
6328 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6330 ig.Emit (OpCodes.Stobj, etype);
6331 else if (has_type_arg)
6332 ig.Emit (op, etype);
6336 ig.Emit (OpCodes.Call, set);
6343 for (int j = dims - 1; j >= 0; j--){
6345 if (current_pos [j] < (int) bounds [j])
6347 current_pos [j] = 0;
6352 public override void Emit (EmitContext ec)
6354 ILGenerator ig = ec.ig;
6356 if (first_emit != null) {
6357 first_emit.Emit (ec);
6358 first_emit_temp.Store (ec);
6361 foreach (Argument a in arguments)
6364 if (arguments.Count == 1)
6365 ig.Emit (OpCodes.Newarr, array_element_type);
6367 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6370 if (initializers == null)
6373 // Emit static initializer for arrays which have contain more than 4 items and
6374 // the static initializer will initialize at least 25% of array values.
6375 // NOTE: const_initializers_count does not contain default constant values.
6376 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6377 TypeManager.IsPrimitiveType (array_element_type)) {
6378 EmitStaticInitializers (ec);
6380 if (!only_constant_initializers)
6381 EmitDynamicInitializers (ec, false);
6383 EmitDynamicInitializers (ec, true);
6386 if (first_emit_temp != null)
6387 first_emit_temp.Release (ec);
6390 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6392 if (arguments.Count != 1) {
6393 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6394 return base.GetAttributableValue (ec, null, out value);
6397 if (array_data == null) {
6398 Constant c = (Constant)((Argument)arguments [0]).Expr;
6399 if (c.IsDefaultValue) {
6400 value = Array.CreateInstance (array_element_type, 0);
6403 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6404 return base.GetAttributableValue (ec, null, out value);
6407 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6408 object element_value;
6409 for (int i = 0; i < ret.Length; ++i)
6411 Expression e = (Expression)array_data [i];
6413 // Is null when an initializer is optimized (value == predefined value)
6417 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6421 ret.SetValue (element_value, i);
6427 protected override void CloneTo (CloneContext clonectx, Expression t)
6429 ArrayCreation target = (ArrayCreation) t;
6431 if (requested_base_type != null)
6432 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6434 if (arguments != null){
6435 target.arguments = new ArrayList (arguments.Count);
6436 foreach (Argument a in arguments)
6437 target.arguments.Add (a.Clone (clonectx));
6440 if (initializers != null){
6441 target.initializers = new ArrayList (initializers.Count);
6442 foreach (object initializer in initializers)
6443 if (initializer is ArrayList) {
6444 ArrayList this_al = (ArrayList)initializer;
6445 ArrayList al = new ArrayList (this_al.Count);
6446 target.initializers.Add (al);
6447 foreach (Expression e in this_al)
6448 al.Add (e.Clone (clonectx));
6450 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6457 // Represents an implicitly typed array epxression
6459 public class ImplicitlyTypedArrayCreation : ArrayCreation
6461 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6462 : base (null, rank, initializers, loc)
6464 if (RootContext.Version <= LanguageVersion.ISO_2)
6465 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6467 if (rank.Length > 2) {
6468 while (rank [++dimensions] == ',');
6474 public override Expression DoResolve (EmitContext ec)
6479 if (!ResolveInitializers (ec))
6482 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6483 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6484 arguments.Count != dimensions) {
6485 Error_NoBestType ();
6490 // At this point we found common base type for all initializer elements
6491 // but we have to be sure that all static initializer elements are of
6494 UnifyInitializerElement (ec);
6496 type = TypeManager.GetConstructedType (array_element_type, rank);
6497 eclass = ExprClass.Value;
6501 void Error_NoBestType ()
6503 Report.Error (826, loc,
6504 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6508 // Converts static initializer only
6510 void UnifyInitializerElement (EmitContext ec)
6512 for (int i = 0; i < array_data.Count; ++i) {
6513 Expression e = (Expression)array_data[i];
6515 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6519 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6521 element = element.Resolve (ec);
6522 if (element == null)
6525 if (array_element_type == null) {
6526 array_element_type = element.Type;
6530 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6534 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6535 array_element_type = element.Type;
6539 Error_NoBestType ();
6544 public sealed class CompilerGeneratedThis : This
6546 public static This Instance = new CompilerGeneratedThis ();
6548 private CompilerGeneratedThis ()
6549 : base (Location.Null)
6553 public CompilerGeneratedThis (Type type, Location loc)
6559 public override Expression DoResolve (EmitContext ec)
6561 eclass = ExprClass.Variable;
6563 type = ec.ContainerType;
6567 public override HoistedVariable HoistedVariable {
6568 get { return null; }
6573 /// Represents the `this' construct
6576 public class This : VariableReference
6578 sealed class ThisVariable : ILocalVariable
6580 public static readonly ILocalVariable Instance = new ThisVariable ();
6582 public void Emit (EmitContext ec)
6584 ec.ig.Emit (OpCodes.Ldarg_0);
6587 public void EmitAssign (EmitContext ec)
6589 throw new InvalidOperationException ();
6592 public void EmitAddressOf (EmitContext ec)
6594 ec.ig.Emit (OpCodes.Ldarg_0);
6599 VariableInfo variable_info;
6602 public This (Block block, Location loc)
6608 public This (Location loc)
6613 public override VariableInfo VariableInfo {
6614 get { return variable_info; }
6617 public override bool IsFixedVariable {
6618 get { return !TypeManager.IsValueType (type); }
6621 protected override bool IsHoistedEmitRequired (EmitContext ec)
6624 // Handle 'this' differently, it cannot be assigned hence
6625 // when we are not inside anonymous method we can emit direct access
6627 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6630 public override HoistedVariable HoistedVariable {
6631 get { return TopToplevelBlock.HoistedThisVariable; }
6634 public override bool IsRef {
6635 get { return is_struct; }
6638 protected override ILocalVariable Variable {
6639 get { return ThisVariable.Instance; }
6642 // TODO: Move to ToplevelBlock
6643 ToplevelBlock TopToplevelBlock {
6645 ToplevelBlock tl = block.Toplevel;
6646 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6651 public static bool IsThisAvailable (EmitContext ec)
6653 if (ec.IsStatic || ec.IsInFieldInitializer)
6656 if (ec.CurrentAnonymousMethod == null)
6659 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6665 public bool ResolveBase (EmitContext ec)
6667 if (eclass != ExprClass.Invalid)
6670 eclass = ExprClass.Variable;
6672 if (ec.TypeContainer.CurrentType != null)
6673 type = ec.TypeContainer.CurrentType;
6675 type = ec.ContainerType;
6677 if (!IsThisAvailable (ec)) {
6679 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6681 Report.Error (1673, loc,
6682 "Anonymous methods inside structs cannot access instance members of `this'. " +
6683 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6687 is_struct = ec.TypeContainer is Struct;
6689 if (block != null) {
6690 if (block.Toplevel.ThisVariable != null)
6691 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6693 AnonymousExpression am = ec.CurrentAnonymousMethod;
6696 // this is hoisted to very top level block
6698 if (ec.IsVariableCapturingRequired) {
6699 // TODO: it could be optimized
6700 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6701 if (HoistedVariable == null) {
6702 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6712 // Called from Invocation to check if the invocation is correct
6714 public override void CheckMarshalByRefAccess (EmitContext ec)
6716 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6717 !variable_info.IsAssigned (ec)) {
6718 Error (188, "The `this' object cannot be used before all of its " +
6719 "fields are assigned to");
6720 variable_info.SetAssigned (ec);
6724 public override Expression CreateExpressionTree (EmitContext ec)
6726 ArrayList args = new ArrayList (2);
6727 args.Add (new Argument (this));
6728 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6729 return CreateExpressionFactoryCall ("Constant", args);
6732 public override Expression DoResolve (EmitContext ec)
6734 if (!ResolveBase (ec))
6738 if (ec.IsInFieldInitializer) {
6739 Error (27, "Keyword `this' is not available in the current context");
6746 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6748 if (!ResolveBase (ec))
6751 if (variable_info != null)
6752 variable_info.SetAssigned (ec);
6754 if (ec.TypeContainer is Class){
6755 if (right_side == EmptyExpression.UnaryAddress)
6756 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6757 else if (right_side == EmptyExpression.OutAccess)
6758 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6760 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6766 public override int GetHashCode()
6768 return block.GetHashCode ();
6771 public override string Name {
6772 get { return "this"; }
6775 public override bool Equals (object obj)
6777 This t = obj as This;
6781 return block == t.block;
6784 protected override void CloneTo (CloneContext clonectx, Expression t)
6786 This target = (This) t;
6788 target.block = clonectx.LookupBlock (block);
6791 public void RemoveHoisting ()
6793 TopToplevelBlock.HoistedThisVariable = null;
6796 public override void SetHasAddressTaken ()
6803 /// Represents the `__arglist' construct
6805 public class ArglistAccess : Expression
6807 public ArglistAccess (Location loc)
6812 public override Expression CreateExpressionTree (EmitContext ec)
6814 throw new NotSupportedException ("ET");
6817 public override Expression DoResolve (EmitContext ec)
6819 eclass = ExprClass.Variable;
6820 type = TypeManager.runtime_argument_handle_type;
6822 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6824 Error (190, "The __arglist construct is valid only within " +
6825 "a variable argument method");
6832 public override void Emit (EmitContext ec)
6834 ec.ig.Emit (OpCodes.Arglist);
6837 protected override void CloneTo (CloneContext clonectx, Expression target)
6844 /// Represents the `__arglist (....)' construct
6846 public class Arglist : Expression
6848 Argument[] Arguments;
6850 public Arglist (Location loc)
6851 : this (Argument.Empty, loc)
6855 public Arglist (Argument[] args, Location l)
6861 public Type[] ArgumentTypes {
6863 Type[] retval = new Type [Arguments.Length];
6864 for (int i = 0; i < Arguments.Length; i++)
6865 retval [i] = Arguments [i].Type;
6870 public override Expression CreateExpressionTree (EmitContext ec)
6872 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6876 public override Expression DoResolve (EmitContext ec)
6878 eclass = ExprClass.Variable;
6879 type = TypeManager.runtime_argument_handle_type;
6881 foreach (Argument arg in Arguments) {
6882 if (!arg.Resolve (ec, loc))
6889 public override void Emit (EmitContext ec)
6891 foreach (Argument arg in Arguments)
6895 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6897 foreach (Argument arg in Arguments)
6898 arg.Expr.MutateHoistedGenericType (storey);
6901 protected override void CloneTo (CloneContext clonectx, Expression t)
6903 Arglist target = (Arglist) t;
6905 target.Arguments = new Argument [Arguments.Length];
6906 for (int i = 0; i < Arguments.Length; i++)
6907 target.Arguments [i] = Arguments [i].Clone (clonectx);
6912 /// Implements the typeof operator
6914 public class TypeOf : Expression {
6915 Expression QueriedType;
6916 protected Type typearg;
6918 public TypeOf (Expression queried_type, Location l)
6920 QueriedType = queried_type;
6924 public override Expression CreateExpressionTree (EmitContext ec)
6926 ArrayList args = new ArrayList (2);
6927 args.Add (new Argument (this));
6928 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6929 return CreateExpressionFactoryCall ("Constant", args);
6932 public override Expression DoResolve (EmitContext ec)
6934 if (eclass != ExprClass.Invalid)
6937 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6941 typearg = texpr.Type;
6943 if (typearg == TypeManager.void_type) {
6944 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6948 if (typearg.IsPointer && !ec.InUnsafe){
6953 type = TypeManager.type_type;
6955 return DoResolveBase ();
6958 protected Expression DoResolveBase ()
6960 if (TypeManager.system_type_get_type_from_handle == null) {
6961 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6962 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6965 // Even though what is returned is a type object, it's treated as a value by the compiler.
6966 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6967 eclass = ExprClass.Value;
6971 public override void Emit (EmitContext ec)
6973 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6974 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6977 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6979 if (TypeManager.ContainsGenericParameters (typearg) &&
6980 !TypeManager.IsGenericTypeDefinition (typearg)) {
6981 Report.SymbolRelatedToPreviousError (typearg);
6982 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6983 TypeManager.CSharpName (typearg));
6988 if (value_type == TypeManager.object_type) {
6989 value = (object)typearg;
6996 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6998 typearg = storey.MutateType (typearg);
7001 public Type TypeArgument {
7007 protected override void CloneTo (CloneContext clonectx, Expression t)
7009 TypeOf target = (TypeOf) t;
7010 if (QueriedType != null)
7011 target.QueriedType = QueriedType.Clone (clonectx);
7016 /// Implements the `typeof (void)' operator
7018 public class TypeOfVoid : TypeOf {
7019 public TypeOfVoid (Location l) : base (null, l)
7024 public override Expression DoResolve (EmitContext ec)
7026 type = TypeManager.type_type;
7027 typearg = TypeManager.void_type;
7029 return DoResolveBase ();
7033 class TypeOfMethodInfo : TypeOfMethod
7035 public TypeOfMethodInfo (MethodBase method, Location loc)
7036 : base (method, loc)
7040 public override Expression DoResolve (EmitContext ec)
7042 type = typeof (MethodInfo);
7043 return base.DoResolve (ec);
7046 public override void Emit (EmitContext ec)
7048 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7050 ec.ig.Emit (OpCodes.Castclass, type);
7054 class TypeOfConstructorInfo : TypeOfMethod
7056 public TypeOfConstructorInfo (MethodBase method, Location loc)
7057 : base (method, loc)
7061 public override Expression DoResolve (EmitContext ec)
7063 type = typeof (ConstructorInfo);
7064 return base.DoResolve (ec);
7067 public override void Emit (EmitContext ec)
7069 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7071 ec.ig.Emit (OpCodes.Castclass, type);
7075 abstract class TypeOfMethod : Expression
7077 protected readonly MethodBase method;
7079 protected TypeOfMethod (MethodBase method, Location loc)
7081 this.method = method;
7085 public override Expression CreateExpressionTree (EmitContext ec)
7087 ArrayList args = new ArrayList (2);
7088 args.Add (new Argument (this));
7089 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7090 return CreateExpressionFactoryCall ("Constant", args);
7093 public override Expression DoResolve (EmitContext ec)
7095 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7096 MethodInfo mi = is_generic ?
7097 TypeManager.methodbase_get_type_from_handle_generic :
7098 TypeManager.methodbase_get_type_from_handle;
7101 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7102 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7104 if (t == null || handle_type == null)
7107 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7109 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7110 new Type[] { handle_type } );
7113 TypeManager.methodbase_get_type_from_handle_generic = mi;
7115 TypeManager.methodbase_get_type_from_handle = mi;
7118 eclass = ExprClass.Value;
7122 public override void Emit (EmitContext ec)
7124 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7127 mi = TypeManager.methodbase_get_type_from_handle_generic;
7128 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7130 mi = TypeManager.methodbase_get_type_from_handle;
7133 ec.ig.Emit (OpCodes.Call, mi);
7137 internal class TypeOfField : Expression
7139 readonly FieldInfo field;
7141 public TypeOfField (FieldInfo field, Location loc)
7147 public override Expression CreateExpressionTree (EmitContext ec)
7149 throw new NotSupportedException ("ET");
7152 public override Expression DoResolve (EmitContext ec)
7154 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7155 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7156 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7158 if (t != null && handle_type != null)
7159 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7160 "GetFieldFromHandle", loc, handle_type);
7163 type = typeof (FieldInfo);
7164 eclass = ExprClass.Value;
7168 public override void Emit (EmitContext ec)
7170 ec.ig.Emit (OpCodes.Ldtoken, field);
7171 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7176 /// Implements the sizeof expression
7178 public class SizeOf : Expression {
7179 readonly Expression QueriedType;
7182 public SizeOf (Expression queried_type, Location l)
7184 this.QueriedType = queried_type;
7188 public override Expression CreateExpressionTree (EmitContext ec)
7190 Error_PointerInsideExpressionTree ();
7194 public override Expression DoResolve (EmitContext ec)
7196 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7200 type_queried = texpr.Type;
7201 if (TypeManager.IsEnumType (type_queried))
7202 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7204 int size_of = GetTypeSize (type_queried);
7206 return new IntConstant (size_of, loc);
7209 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7214 Report.Error (233, loc,
7215 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7216 TypeManager.CSharpName (type_queried));
7219 type = TypeManager.int32_type;
7220 eclass = ExprClass.Value;
7224 public override void Emit (EmitContext ec)
7226 int size = GetTypeSize (type_queried);
7229 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7231 IntConstant.EmitInt (ec.ig, size);
7234 protected override void CloneTo (CloneContext clonectx, Expression t)
7240 /// Implements the qualified-alias-member (::) expression.
7242 public class QualifiedAliasMember : MemberAccess
7244 readonly string alias;
7245 public static readonly string GlobalAlias = "global";
7247 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7248 : base (null, identifier, targs, l)
7253 public QualifiedAliasMember (string alias, string identifier, Location l)
7254 : base (null, identifier, l)
7259 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7261 if (alias == GlobalAlias) {
7262 expr = RootNamespace.Global;
7263 return base.ResolveAsTypeStep (ec, silent);
7266 int errors = Report.Errors;
7267 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7269 if (errors == Report.Errors)
7270 Report.Error (432, loc, "Alias `{0}' not found", alias);
7274 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7278 if (expr.eclass == ExprClass.Type) {
7280 Report.Error (431, loc,
7281 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7289 public override Expression DoResolve (EmitContext ec)
7291 return ResolveAsTypeStep (ec, false);
7294 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7296 Report.Error (687, loc,
7297 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7298 GetSignatureForError ());
7301 public override string GetSignatureForError ()
7304 if (targs != null) {
7305 name = TypeManager.RemoveGenericArity (Name) + "<" +
7306 targs.GetSignatureForError () + ">";
7309 return alias + "::" + name;
7312 protected override void CloneTo (CloneContext clonectx, Expression t)
7319 /// Implements the member access expression
7321 public class MemberAccess : ATypeNameExpression {
7322 protected Expression expr;
7324 public MemberAccess (Expression expr, string id)
7325 : base (id, expr.Location)
7330 public MemberAccess (Expression expr, string identifier, Location loc)
7331 : base (identifier, loc)
7336 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7337 : base (identifier, args, loc)
7342 // TODO: this method has very poor performace for Enum fields and
7343 // probably for other constants as well
7344 Expression DoResolve (EmitContext ec, Expression right_side)
7347 throw new Exception ();
7350 // Resolve the expression with flow analysis turned off, we'll do the definite
7351 // assignment checks later. This is because we don't know yet what the expression
7352 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7353 // definite assignment check on the actual field and not on the whole struct.
7356 SimpleName original = expr as SimpleName;
7357 Expression expr_resolved = expr.Resolve (ec,
7358 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7359 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7361 if (expr_resolved == null)
7364 string LookupIdentifier = MemberName.MakeName (Name, targs);
7366 if (expr_resolved is Namespace) {
7367 Namespace ns = (Namespace) expr_resolved;
7368 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7370 if ((retval != null) && (targs != null))
7371 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7375 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7379 Type expr_type = expr_resolved.Type;
7380 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7381 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7382 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7386 Constant c = expr_resolved as Constant;
7387 if (c != null && c.GetValue () == null) {
7388 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7389 "System.NullReferenceException");
7392 if (targs != null) {
7393 if (!targs.Resolve (ec))
7397 Expression member_lookup;
7398 member_lookup = MemberLookup (
7399 ec.ContainerType, expr_type, expr_type, Name, loc);
7401 if ((member_lookup == null) && (targs != null)) {
7402 member_lookup = MemberLookup (
7403 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7406 if (member_lookup == null) {
7407 ExprClass expr_eclass = expr_resolved.eclass;
7410 // Extension methods are not allowed on all expression types
7412 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7413 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7414 expr_eclass == ExprClass.EventAccess) {
7415 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7416 if (ex_method_lookup != null) {
7417 ex_method_lookup.ExtensionExpression = expr_resolved;
7419 if (targs != null) {
7420 ex_method_lookup.SetTypeArguments (targs);
7423 return ex_method_lookup.DoResolve (ec);
7427 expr = expr_resolved;
7428 Error_MemberLookupFailed (
7429 ec.ContainerType, expr_type, expr_type, Name, null,
7430 AllMemberTypes, AllBindingFlags);
7434 TypeExpr texpr = member_lookup as TypeExpr;
7435 if (texpr != null) {
7436 if (!(expr_resolved is TypeExpr) &&
7437 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7438 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7439 Name, member_lookup.GetSignatureForError ());
7443 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7444 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7445 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7450 ConstructedType ct = expr_resolved as ConstructedType;
7453 // When looking up a nested type in a generic instance
7454 // via reflection, we always get a generic type definition
7455 // and not a generic instance - so we have to do this here.
7457 // See gtest-172-lib.cs and gtest-172.cs for an example.
7459 ct = new ConstructedType (
7460 member_lookup.Type, ct.TypeArguments, loc);
7462 return ct.ResolveAsTypeStep (ec, false);
7465 return member_lookup;
7468 MemberExpr me = (MemberExpr) member_lookup;
7469 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7473 if (targs != null) {
7474 me.SetTypeArguments (targs);
7477 if (original != null && !TypeManager.IsValueType (expr_type)) {
7478 if (me.IsInstance) {
7479 LocalVariableReference var = expr_resolved as LocalVariableReference;
7480 if (var != null && !var.VerifyAssigned (ec))
7485 // The following DoResolve/DoResolveLValue will do the definite assignment
7488 if (right_side != null)
7489 return me.DoResolveLValue (ec, right_side);
7491 return me.DoResolve (ec);
7494 public override Expression DoResolve (EmitContext ec)
7496 return DoResolve (ec, null);
7499 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7501 return DoResolve (ec, right_side);
7504 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7506 return ResolveNamespaceOrType (ec, silent);
7509 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7511 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7513 if (new_expr == null)
7516 string LookupIdentifier = MemberName.MakeName (Name, targs);
7518 if (new_expr is Namespace) {
7519 Namespace ns = (Namespace) new_expr;
7520 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7522 if ((retval != null) && (targs != null))
7523 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7525 if (!silent && retval == null)
7526 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7530 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7531 if (tnew_expr == null)
7534 Type expr_type = tnew_expr.Type;
7536 if (expr_type.IsPointer){
7537 Error (23, "The `.' operator can not be applied to pointer operands (" +
7538 TypeManager.CSharpName (expr_type) + ")");
7542 Expression member_lookup = MemberLookup (
7543 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7544 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7545 if (member_lookup == null) {
7549 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7553 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7558 TypeArguments the_args = targs;
7559 Type declaring_type = texpr.Type.DeclaringType;
7560 if (TypeManager.HasGenericArguments (declaring_type)) {
7561 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7562 expr_type = expr_type.BaseType;
7565 TypeArguments new_args = new TypeArguments (loc);
7566 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7567 new_args.Add (new TypeExpression (decl, loc));
7570 new_args.Add (targs);
7572 the_args = new_args;
7575 if (the_args != null) {
7576 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7577 return ctype.ResolveAsTypeStep (rc, false);
7584 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7586 Expression member_lookup = MemberLookup (
7587 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7588 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7590 if (member_lookup != null) {
7591 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7592 if (expr_type == null)
7595 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7599 member_lookup = MemberLookup (
7600 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7601 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7603 if (member_lookup == null) {
7604 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7605 Name, expr_type.GetSignatureForError ());
7607 // TODO: Report.SymbolRelatedToPreviousError
7608 member_lookup.Error_UnexpectedKind (null, "type", loc);
7612 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7614 if (RootContext.Version > LanguageVersion.ISO_2 &&
7615 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7616 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7617 "extension method `{1}' of type `{0}' could be found " +
7618 "(are you missing a using directive or an assembly reference?)",
7619 TypeManager.CSharpName (type), name);
7623 base.Error_TypeDoesNotContainDefinition (type, name);
7626 public override string GetSignatureForError ()
7628 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7631 protected override void CloneTo (CloneContext clonectx, Expression t)
7633 MemberAccess target = (MemberAccess) t;
7635 target.expr = expr.Clone (clonectx);
7640 /// Implements checked expressions
7642 public class CheckedExpr : Expression {
7644 public Expression Expr;
7646 public CheckedExpr (Expression e, Location l)
7652 public override Expression CreateExpressionTree (EmitContext ec)
7654 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7655 return Expr.CreateExpressionTree (ec);
7658 public override Expression DoResolve (EmitContext ec)
7660 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7661 Expr = Expr.Resolve (ec);
7666 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7669 eclass = Expr.eclass;
7674 public override void Emit (EmitContext ec)
7676 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7680 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7682 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7683 Expr.EmitBranchable (ec, target, on_true);
7686 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7688 Expr.MutateHoistedGenericType (storey);
7691 protected override void CloneTo (CloneContext clonectx, Expression t)
7693 CheckedExpr target = (CheckedExpr) t;
7695 target.Expr = Expr.Clone (clonectx);
7700 /// Implements the unchecked expression
7702 public class UnCheckedExpr : Expression {
7704 public Expression Expr;
7706 public UnCheckedExpr (Expression e, Location l)
7712 public override Expression CreateExpressionTree (EmitContext ec)
7714 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7715 return Expr.CreateExpressionTree (ec);
7718 public override Expression DoResolve (EmitContext ec)
7720 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7721 Expr = Expr.Resolve (ec);
7726 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7729 eclass = Expr.eclass;
7734 public override void Emit (EmitContext ec)
7736 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7740 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7742 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7743 Expr.EmitBranchable (ec, target, on_true);
7746 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7748 Expr.MutateHoistedGenericType (storey);
7751 protected override void CloneTo (CloneContext clonectx, Expression t)
7753 UnCheckedExpr target = (UnCheckedExpr) t;
7755 target.Expr = Expr.Clone (clonectx);
7760 /// An Element Access expression.
7762 /// During semantic analysis these are transformed into
7763 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7765 public class ElementAccess : Expression {
7766 public ArrayList Arguments;
7767 public Expression Expr;
7769 public ElementAccess (Expression e, ArrayList e_list)
7777 Arguments = new ArrayList (e_list.Count);
7778 foreach (Expression tmp in e_list)
7779 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7782 bool CommonResolve (EmitContext ec)
7784 Expr = Expr.Resolve (ec);
7786 if (Arguments == null)
7789 foreach (Argument a in Arguments){
7790 if (!a.Resolve (ec, loc))
7794 return Expr != null;
7797 public override Expression CreateExpressionTree (EmitContext ec)
7799 ArrayList args = new ArrayList (Arguments.Count + 1);
7800 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7801 foreach (Argument a in Arguments)
7802 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7804 return CreateExpressionFactoryCall ("ArrayIndex", args);
7807 Expression MakePointerAccess (EmitContext ec, Type t)
7809 if (Arguments.Count != 1){
7810 Error (196, "A pointer must be indexed by only one value");
7814 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7817 return new Indirection (p, loc).Resolve (ec);
7820 public override Expression DoResolve (EmitContext ec)
7822 if (!CommonResolve (ec))
7826 // We perform some simple tests, and then to "split" the emit and store
7827 // code we create an instance of a different class, and return that.
7829 // I am experimenting with this pattern.
7833 if (t == TypeManager.array_type){
7834 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7839 return (new ArrayAccess (this, loc)).Resolve (ec);
7841 return MakePointerAccess (ec, t);
7843 FieldExpr fe = Expr as FieldExpr;
7845 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7847 return MakePointerAccess (ec, ff.ElementType);
7850 return (new IndexerAccess (this, loc)).Resolve (ec);
7853 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7855 if (!CommonResolve (ec))
7860 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7863 return MakePointerAccess (ec, type);
7865 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7866 Error_CannotModifyIntermediateExpressionValue (ec);
7868 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7871 public override void Emit (EmitContext ec)
7873 throw new Exception ("Should never be reached");
7876 public override string GetSignatureForError ()
7878 return Expr.GetSignatureForError ();
7881 protected override void CloneTo (CloneContext clonectx, Expression t)
7883 ElementAccess target = (ElementAccess) t;
7885 target.Expr = Expr.Clone (clonectx);
7886 target.Arguments = new ArrayList (Arguments.Count);
7887 foreach (Argument a in Arguments)
7888 target.Arguments.Add (a.Clone (clonectx));
7893 /// Implements array access
7895 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7897 // Points to our "data" repository
7901 LocalTemporary temp;
7905 public ArrayAccess (ElementAccess ea_data, Location l)
7911 public override Expression CreateExpressionTree (EmitContext ec)
7913 return ea.CreateExpressionTree (ec);
7916 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7918 return DoResolve (ec);
7921 public override Expression DoResolve (EmitContext ec)
7924 ExprClass eclass = ea.Expr.eclass;
7926 // As long as the type is valid
7927 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7928 eclass == ExprClass.Value)) {
7929 ea.Expr.Error_UnexpectedKind ("variable or value");
7934 if (eclass != ExprClass.Invalid)
7937 Type t = ea.Expr.Type;
7938 int rank = ea.Arguments.Count;
7939 if (t.GetArrayRank () != rank) {
7940 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7941 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7945 type = TypeManager.GetElementType (t);
7946 if (type.IsPointer && !ec.InUnsafe) {
7947 UnsafeError (ea.Location);
7951 foreach (Argument a in ea.Arguments) {
7952 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7955 eclass = ExprClass.Variable;
7961 /// Emits the right opcode to load an object of Type `t'
7962 /// from an array of T
7964 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7967 MethodInfo get = FetchGetMethod ();
7968 ig.Emit (OpCodes.Call, get);
7972 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7973 ig.Emit (OpCodes.Ldelem_U1);
7974 else if (type == TypeManager.sbyte_type)
7975 ig.Emit (OpCodes.Ldelem_I1);
7976 else if (type == TypeManager.short_type)
7977 ig.Emit (OpCodes.Ldelem_I2);
7978 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7979 ig.Emit (OpCodes.Ldelem_U2);
7980 else if (type == TypeManager.int32_type)
7981 ig.Emit (OpCodes.Ldelem_I4);
7982 else if (type == TypeManager.uint32_type)
7983 ig.Emit (OpCodes.Ldelem_U4);
7984 else if (type == TypeManager.uint64_type)
7985 ig.Emit (OpCodes.Ldelem_I8);
7986 else if (type == TypeManager.int64_type)
7987 ig.Emit (OpCodes.Ldelem_I8);
7988 else if (type == TypeManager.float_type)
7989 ig.Emit (OpCodes.Ldelem_R4);
7990 else if (type == TypeManager.double_type)
7991 ig.Emit (OpCodes.Ldelem_R8);
7992 else if (type == TypeManager.intptr_type)
7993 ig.Emit (OpCodes.Ldelem_I);
7994 else if (TypeManager.IsEnumType (type)){
7995 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7996 } else if (type.IsValueType){
7997 ig.Emit (OpCodes.Ldelema, type);
7998 ig.Emit (OpCodes.Ldobj, type);
8000 } else if (type.IsGenericParameter) {
8001 ig.Emit (OpCodes.Ldelem, type);
8003 } else if (type.IsPointer)
8004 ig.Emit (OpCodes.Ldelem_I);
8006 ig.Emit (OpCodes.Ldelem_Ref);
8009 protected override void Error_NegativeArrayIndex (Location loc)
8011 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8015 /// Returns the right opcode to store an object of Type `t'
8016 /// from an array of T.
8018 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8020 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8021 has_type_arg = false; is_stobj = false;
8022 t = TypeManager.TypeToCoreType (t);
8023 if (TypeManager.IsEnumType (t))
8024 t = TypeManager.GetEnumUnderlyingType (t);
8025 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8026 t == TypeManager.bool_type)
8027 return OpCodes.Stelem_I1;
8028 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8029 t == TypeManager.char_type)
8030 return OpCodes.Stelem_I2;
8031 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8032 return OpCodes.Stelem_I4;
8033 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8034 return OpCodes.Stelem_I8;
8035 else if (t == TypeManager.float_type)
8036 return OpCodes.Stelem_R4;
8037 else if (t == TypeManager.double_type)
8038 return OpCodes.Stelem_R8;
8039 else if (t == TypeManager.intptr_type) {
8040 has_type_arg = true;
8042 return OpCodes.Stobj;
8043 } else if (t.IsValueType) {
8044 has_type_arg = true;
8046 return OpCodes.Stobj;
8048 } else if (t.IsGenericParameter) {
8049 has_type_arg = true;
8050 return OpCodes.Stelem;
8053 } else if (t.IsPointer)
8054 return OpCodes.Stelem_I;
8056 return OpCodes.Stelem_Ref;
8059 MethodInfo FetchGetMethod ()
8061 ModuleBuilder mb = CodeGen.Module.Builder;
8062 int arg_count = ea.Arguments.Count;
8063 Type [] args = new Type [arg_count];
8066 for (int i = 0; i < arg_count; i++){
8067 //args [i++] = a.Type;
8068 args [i] = TypeManager.int32_type;
8071 get = mb.GetArrayMethod (
8072 ea.Expr.Type, "Get",
8073 CallingConventions.HasThis |
8074 CallingConventions.Standard,
8080 MethodInfo FetchAddressMethod ()
8082 ModuleBuilder mb = CodeGen.Module.Builder;
8083 int arg_count = ea.Arguments.Count;
8084 Type [] args = new Type [arg_count];
8088 ret_type = TypeManager.GetReferenceType (type);
8090 for (int i = 0; i < arg_count; i++){
8091 //args [i++] = a.Type;
8092 args [i] = TypeManager.int32_type;
8095 address = mb.GetArrayMethod (
8096 ea.Expr.Type, "Address",
8097 CallingConventions.HasThis |
8098 CallingConventions.Standard,
8105 // Load the array arguments into the stack.
8107 void LoadArrayAndArguments (EmitContext ec)
8111 for (int i = 0; i < ea.Arguments.Count; ++i) {
8112 ((Argument)ea.Arguments [i]).Emit (ec);
8116 public void Emit (EmitContext ec, bool leave_copy)
8118 int rank = ea.Expr.Type.GetArrayRank ();
8119 ILGenerator ig = ec.ig;
8122 LoadFromPtr (ig, this.type);
8124 LoadArrayAndArguments (ec);
8125 EmitLoadOpcode (ig, type, rank);
8129 ig.Emit (OpCodes.Dup);
8130 temp = new LocalTemporary (this.type);
8135 public override void Emit (EmitContext ec)
8140 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8142 int rank = ea.Expr.Type.GetArrayRank ();
8143 ILGenerator ig = ec.ig;
8144 Type t = source.Type;
8145 prepared = prepare_for_load;
8148 AddressOf (ec, AddressOp.LoadStore);
8149 ec.ig.Emit (OpCodes.Dup);
8151 LoadArrayAndArguments (ec);
8155 bool is_stobj, has_type_arg;
8156 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8160 // The stobj opcode used by value types will need
8161 // an address on the stack, not really an array/array
8165 ig.Emit (OpCodes.Ldelema, t);
8170 ec.ig.Emit (OpCodes.Dup);
8171 temp = new LocalTemporary (this.type);
8176 StoreFromPtr (ig, t);
8178 ig.Emit (OpCodes.Stobj, t);
8179 else if (has_type_arg)
8186 ec.ig.Emit (OpCodes.Dup);
8187 temp = new LocalTemporary (this.type);
8192 StoreFromPtr (ig, t);
8194 int arg_count = ea.Arguments.Count;
8195 Type [] args = new Type [arg_count + 1];
8196 for (int i = 0; i < arg_count; i++) {
8197 //args [i++] = a.Type;
8198 args [i] = TypeManager.int32_type;
8200 args [arg_count] = type;
8202 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8203 ea.Expr.Type, "Set",
8204 CallingConventions.HasThis |
8205 CallingConventions.Standard,
8206 TypeManager.void_type, args);
8208 ig.Emit (OpCodes.Call, set);
8218 public void AddressOf (EmitContext ec, AddressOp mode)
8220 int rank = ea.Expr.Type.GetArrayRank ();
8221 ILGenerator ig = ec.ig;
8223 LoadArrayAndArguments (ec);
8226 ig.Emit (OpCodes.Ldelema, type);
8228 MethodInfo address = FetchAddressMethod ();
8229 ig.Emit (OpCodes.Call, address);
8233 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8235 type = storey.MutateType (type);
8240 /// Expressions that represent an indexer call.
8242 public class IndexerAccess : Expression, IAssignMethod
8244 class IndexerMethodGroupExpr : MethodGroupExpr
8246 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8249 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8252 public override string Name {
8258 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8261 // Here is the trick, decrease number of arguments by 1 when only
8262 // available property method is setter. This makes overload resolution
8263 // work correctly for indexers.
8266 if (method.Name [0] == 'g')
8267 return parameters.Count;
8269 return parameters.Count - 1;
8275 // Contains either property getter or setter
8276 public ArrayList Methods;
8277 public ArrayList Properties;
8283 void Append (Type caller_type, MemberInfo [] mi)
8288 foreach (PropertyInfo property in mi) {
8289 MethodInfo accessor = property.GetGetMethod (true);
8290 if (accessor == null)
8291 accessor = property.GetSetMethod (true);
8293 if (Methods == null) {
8294 Methods = new ArrayList ();
8295 Properties = new ArrayList ();
8298 Methods.Add (accessor);
8299 Properties.Add (property);
8303 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8305 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8307 return TypeManager.MemberLookup (
8308 caller_type, caller_type, lookup_type, MemberTypes.Property,
8309 BindingFlags.Public | BindingFlags.Instance |
8310 BindingFlags.DeclaredOnly, p_name, null);
8313 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8315 Indexers ix = new Indexers ();
8318 if (lookup_type.IsGenericParameter) {
8319 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8323 if (gc.HasClassConstraint)
8324 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8326 Type[] ifaces = gc.InterfaceConstraints;
8327 foreach (Type itype in ifaces)
8328 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8334 Type copy = lookup_type;
8335 while (copy != TypeManager.object_type && copy != null){
8336 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8337 copy = copy.BaseType;
8340 if (lookup_type.IsInterface) {
8341 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8342 if (ifaces != null) {
8343 foreach (Type itype in ifaces)
8344 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8359 // Points to our "data" repository
8361 MethodInfo get, set;
8362 bool is_base_indexer;
8364 LocalTemporary temp;
8365 LocalTemporary prepared_value;
8366 Expression set_expr;
8368 protected Type indexer_type;
8369 protected Type current_type;
8370 protected Expression instance_expr;
8371 protected ArrayList arguments;
8373 public IndexerAccess (ElementAccess ea, Location loc)
8374 : this (ea.Expr, false, loc)
8376 this.arguments = ea.Arguments;
8379 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8382 this.instance_expr = instance_expr;
8383 this.is_base_indexer = is_base_indexer;
8384 this.eclass = ExprClass.Value;
8388 static string GetAccessorName (AccessorType at)
8390 if (at == AccessorType.Set)
8393 if (at == AccessorType.Get)
8396 throw new NotImplementedException (at.ToString ());
8399 public override Expression CreateExpressionTree (EmitContext ec)
8401 ArrayList args = new ArrayList (arguments.Count + 2);
8402 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8403 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8404 foreach (Argument a in arguments)
8405 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8407 return CreateExpressionFactoryCall ("Call", args);
8410 protected virtual bool CommonResolve (EmitContext ec)
8412 indexer_type = instance_expr.Type;
8413 current_type = ec.ContainerType;
8418 public override Expression DoResolve (EmitContext ec)
8420 return ResolveAccessor (ec, AccessorType.Get);
8423 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8425 if (right_side == EmptyExpression.OutAccess) {
8426 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8427 GetSignatureForError ());
8431 // if the indexer returns a value type, and we try to set a field in it
8432 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8433 Error_CannotModifyIntermediateExpressionValue (ec);
8436 Expression e = ResolveAccessor (ec, AccessorType.Set);
8440 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8444 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8446 if (!CommonResolve (ec))
8449 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8450 if (ilist.Methods == null) {
8451 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8452 TypeManager.CSharpName (indexer_type));
8456 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8457 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8461 MethodInfo mi = (MethodInfo) mg;
8462 PropertyInfo pi = null;
8463 for (int i = 0; i < ilist.Methods.Count; ++i) {
8464 if (ilist.Methods [i] == mi) {
8465 pi = (PropertyInfo) ilist.Properties [i];
8470 type = TypeManager.TypeToCoreType (pi.PropertyType);
8471 if (type.IsPointer && !ec.InUnsafe)
8474 MethodInfo accessor;
8475 if (accessorType == AccessorType.Get) {
8476 accessor = get = pi.GetGetMethod (true);
8478 accessor = set = pi.GetSetMethod (true);
8479 if (accessor == null && pi.GetGetMethod (true) != null) {
8480 Report.SymbolRelatedToPreviousError (pi);
8481 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8482 TypeManager.GetFullNameSignature (pi));
8487 if (accessor == null) {
8488 Report.SymbolRelatedToPreviousError (pi);
8489 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8490 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8495 // Only base will allow this invocation to happen.
8497 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8498 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8501 bool must_do_cs1540_check;
8502 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8504 set = pi.GetSetMethod (true);
8506 get = pi.GetGetMethod (true);
8508 if (set != null && get != null &&
8509 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8510 Report.SymbolRelatedToPreviousError (accessor);
8511 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8512 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8514 Report.SymbolRelatedToPreviousError (pi);
8515 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8519 instance_expr.CheckMarshalByRefAccess (ec);
8520 eclass = ExprClass.IndexerAccess;
8524 public void Emit (EmitContext ec, bool leave_copy)
8527 prepared_value.Emit (ec);
8529 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8530 arguments, loc, false, false);
8534 ec.ig.Emit (OpCodes.Dup);
8535 temp = new LocalTemporary (Type);
8541 // source is ignored, because we already have a copy of it from the
8542 // LValue resolution and we have already constructed a pre-cached
8543 // version of the arguments (ea.set_arguments);
8545 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8547 prepared = prepare_for_load;
8548 Expression value = set_expr;
8551 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8552 arguments, loc, true, false);
8554 prepared_value = new LocalTemporary (type);
8555 prepared_value.Store (ec);
8557 prepared_value.Release (ec);
8560 ec.ig.Emit (OpCodes.Dup);
8561 temp = new LocalTemporary (Type);
8564 } else if (leave_copy) {
8565 temp = new LocalTemporary (Type);
8571 arguments.Add (new Argument (value, Argument.AType.Expression));
8572 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8580 public override void Emit (EmitContext ec)
8585 public override string GetSignatureForError ()
8587 return TypeManager.CSharpSignature (get != null ? get : set, false);
8590 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8593 get = storey.MutateGenericMethod (get);
8595 set = storey.MutateGenericMethod (set);
8597 instance_expr.MutateHoistedGenericType (storey);
8598 foreach (Argument a in arguments)
8599 a.Expr.MutateHoistedGenericType (storey);
8601 type = storey.MutateType (type);
8604 protected override void CloneTo (CloneContext clonectx, Expression t)
8606 IndexerAccess target = (IndexerAccess) t;
8608 if (arguments != null){
8609 target.arguments = new ArrayList ();
8610 foreach (Argument a in arguments)
8611 target.arguments.Add (a.Clone (clonectx));
8613 if (instance_expr != null)
8614 target.instance_expr = instance_expr.Clone (clonectx);
8619 /// The base operator for method names
8621 public class BaseAccess : Expression {
8622 public readonly string Identifier;
8625 public BaseAccess (string member, Location l)
8627 this.Identifier = member;
8631 public BaseAccess (string member, TypeArguments args, Location l)
8637 public override Expression CreateExpressionTree (EmitContext ec)
8639 throw new NotSupportedException ("ET");
8642 public override Expression DoResolve (EmitContext ec)
8644 Expression c = CommonResolve (ec);
8650 // MethodGroups use this opportunity to flag an error on lacking ()
8652 if (!(c is MethodGroupExpr))
8653 return c.Resolve (ec);
8657 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8659 Expression c = CommonResolve (ec);
8665 // MethodGroups use this opportunity to flag an error on lacking ()
8667 if (! (c is MethodGroupExpr))
8668 return c.DoResolveLValue (ec, right_side);
8673 Expression CommonResolve (EmitContext ec)
8675 Expression member_lookup;
8676 Type current_type = ec.ContainerType;
8677 Type base_type = current_type.BaseType;
8679 if (!This.IsThisAvailable (ec)) {
8681 Error (1511, "Keyword `base' is not available in a static method");
8683 Error (1512, "Keyword `base' is not available in the current context");
8688 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8689 AllMemberTypes, AllBindingFlags, loc);
8690 if (member_lookup == null) {
8691 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8692 null, AllMemberTypes, AllBindingFlags);
8699 left = new TypeExpression (base_type, loc);
8701 left = ec.GetThis (loc);
8703 MemberExpr me = (MemberExpr) member_lookup;
8704 me = me.ResolveMemberAccess (ec, left, loc, null);
8711 me.SetTypeArguments (args);
8717 public override void Emit (EmitContext ec)
8719 throw new Exception ("Should never be called");
8722 protected override void CloneTo (CloneContext clonectx, Expression t)
8724 BaseAccess target = (BaseAccess) t;
8727 target.args = args.Clone ();
8732 /// The base indexer operator
8734 public class BaseIndexerAccess : IndexerAccess {
8735 public BaseIndexerAccess (ArrayList args, Location loc)
8736 : base (null, true, loc)
8738 arguments = new ArrayList ();
8739 foreach (Expression tmp in args)
8740 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8743 protected override bool CommonResolve (EmitContext ec)
8745 instance_expr = ec.GetThis (loc);
8747 current_type = ec.ContainerType.BaseType;
8748 indexer_type = current_type;
8750 foreach (Argument a in arguments){
8751 if (!a.Resolve (ec, loc))
8758 public override Expression CreateExpressionTree (EmitContext ec)
8760 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8761 return base.CreateExpressionTree (ec);
8766 /// This class exists solely to pass the Type around and to be a dummy
8767 /// that can be passed to the conversion functions (this is used by
8768 /// foreach implementation to typecast the object return value from
8769 /// get_Current into the proper type. All code has been generated and
8770 /// we only care about the side effect conversions to be performed
8772 /// This is also now used as a placeholder where a no-action expression
8773 /// is needed (the `New' class).
8775 public class EmptyExpression : Expression {
8776 public static readonly Expression Null = new EmptyExpression ();
8778 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8779 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8780 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8781 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8783 static EmptyExpression temp = new EmptyExpression ();
8784 public static EmptyExpression Grab ()
8786 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8791 public static void Release (EmptyExpression e)
8796 // TODO: should be protected
8797 public EmptyExpression ()
8799 type = TypeManager.object_type;
8800 eclass = ExprClass.Value;
8801 loc = Location.Null;
8804 public EmptyExpression (Type t)
8807 eclass = ExprClass.Value;
8808 loc = Location.Null;
8811 public override Expression CreateExpressionTree (EmitContext ec)
8813 throw new NotSupportedException ("ET");
8816 public override Expression DoResolve (EmitContext ec)
8821 public override void Emit (EmitContext ec)
8823 // nothing, as we only exist to not do anything.
8826 public override void EmitSideEffect (EmitContext ec)
8831 // This is just because we might want to reuse this bad boy
8832 // instead of creating gazillions of EmptyExpressions.
8833 // (CanImplicitConversion uses it)
8835 public void SetType (Type t)
8842 // Empty statement expression
8844 public sealed class EmptyExpressionStatement : ExpressionStatement
8846 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8848 private EmptyExpressionStatement ()
8850 type = TypeManager.object_type;
8851 eclass = ExprClass.Value;
8852 loc = Location.Null;
8855 public override Expression CreateExpressionTree (EmitContext ec)
8860 public override void EmitStatement (EmitContext ec)
8865 public override Expression DoResolve (EmitContext ec)
8870 public override void Emit (EmitContext ec)
8876 public class UserCast : Expression {
8880 public UserCast (MethodInfo method, Expression source, Location l)
8882 this.method = method;
8883 this.source = source;
8884 type = TypeManager.TypeToCoreType (method.ReturnType);
8885 eclass = ExprClass.Value;
8889 public Expression Source {
8895 public override Expression CreateExpressionTree (EmitContext ec)
8897 ArrayList args = new ArrayList (3);
8898 args.Add (new Argument (source.CreateExpressionTree (ec)));
8899 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8900 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8901 return CreateExpressionFactoryCall ("Convert", args);
8904 public override Expression DoResolve (EmitContext ec)
8907 // We are born fully resolved
8912 public override void Emit (EmitContext ec)
8915 ec.ig.Emit (OpCodes.Call, method);
8918 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8920 source.MutateHoistedGenericType (storey);
8921 method = storey.MutateGenericMethod (method);
8926 // This class is used to "construct" the type during a typecast
8927 // operation. Since the Type.GetType class in .NET can parse
8928 // the type specification, we just use this to construct the type
8929 // one bit at a time.
8931 public class ComposedCast : TypeExpr {
8932 FullNamedExpression left;
8935 public ComposedCast (FullNamedExpression left, string dim)
8936 : this (left, dim, left.Location)
8940 public ComposedCast (FullNamedExpression left, string dim, Location l)
8947 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8949 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8953 Type ltype = lexpr.Type;
8955 if ((dim.Length > 0) && (dim [0] == '?')) {
8956 TypeExpr nullable = new Nullable.NullableType (left, loc);
8958 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8959 return nullable.ResolveAsTypeTerminal (ec, false);
8963 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8966 if (dim.Length != 0 && dim [0] == '[') {
8967 if (TypeManager.IsSpecialType (ltype)) {
8968 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8972 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8973 Report.SymbolRelatedToPreviousError (ltype);
8974 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8975 TypeManager.CSharpName (ltype));
8980 type = TypeManager.GetConstructedType (ltype, dim);
8985 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8987 if (type.IsPointer && !ec.IsInUnsafeScope){
8991 eclass = ExprClass.Type;
8995 public override string GetSignatureForError ()
8997 return left.GetSignatureForError () + dim;
9000 protected override void CloneTo (CloneContext clonectx, Expression t)
9002 ComposedCast target = (ComposedCast) t;
9004 target.left = (FullNamedExpression)left.Clone (clonectx);
9008 public class FixedBufferPtr : Expression {
9011 public FixedBufferPtr (Expression array, Type array_type, Location l)
9016 type = TypeManager.GetPointerType (array_type);
9017 eclass = ExprClass.Value;
9020 public override Expression CreateExpressionTree (EmitContext ec)
9022 Error_PointerInsideExpressionTree ();
9026 public override void Emit(EmitContext ec)
9031 public override Expression DoResolve (EmitContext ec)
9034 // We are born fully resolved
9042 // This class is used to represent the address of an array, used
9043 // only by the Fixed statement, this generates "&a [0]" construct
9044 // for fixed (char *pa = a)
9046 public class ArrayPtr : FixedBufferPtr {
9049 public ArrayPtr (Expression array, Type array_type, Location l):
9050 base (array, array_type, l)
9052 this.array_type = array_type;
9055 public override void Emit (EmitContext ec)
9059 ILGenerator ig = ec.ig;
9060 IntLiteral.EmitInt (ig, 0);
9061 ig.Emit (OpCodes.Ldelema, array_type);
9066 // Encapsulates a conversion rules required for array indexes
9068 public class ArrayIndexCast : TypeCast
9070 public ArrayIndexCast (Expression expr)
9071 : base (expr, expr.Type)
9075 public override Expression CreateExpressionTree (EmitContext ec)
9077 ArrayList args = new ArrayList (2);
9078 args.Add (new Argument (child.CreateExpressionTree (ec)));
9079 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9080 return CreateExpressionFactoryCall ("ConvertChecked", args);
9083 public override void Emit (EmitContext ec)
9087 if (type == TypeManager.int32_type)
9090 if (type == TypeManager.uint32_type)
9091 ec.ig.Emit (OpCodes.Conv_U);
9092 else if (type == TypeManager.int64_type)
9093 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9094 else if (type == TypeManager.uint64_type)
9095 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9097 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9102 // Implements the `stackalloc' keyword
9104 public class StackAlloc : Expression {
9109 public StackAlloc (Expression type, Expression count, Location l)
9116 public override Expression CreateExpressionTree (EmitContext ec)
9118 throw new NotSupportedException ("ET");
9121 public override Expression DoResolve (EmitContext ec)
9123 count = count.Resolve (ec);
9127 if (count.Type != TypeManager.uint32_type){
9128 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9133 Constant c = count as Constant;
9134 if (c != null && c.IsNegative) {
9135 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9139 if (ec.InCatch || ec.InFinally) {
9140 Error (255, "Cannot use stackalloc in finally or catch");
9144 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9150 if (!TypeManager.VerifyUnManaged (otype, loc))
9153 type = TypeManager.GetPointerType (otype);
9154 eclass = ExprClass.Value;
9159 public override void Emit (EmitContext ec)
9161 int size = GetTypeSize (otype);
9162 ILGenerator ig = ec.ig;
9167 ig.Emit (OpCodes.Sizeof, otype);
9169 IntConstant.EmitInt (ig, size);
9171 ig.Emit (OpCodes.Mul_Ovf_Un);
9172 ig.Emit (OpCodes.Localloc);
9175 protected override void CloneTo (CloneContext clonectx, Expression t)
9177 StackAlloc target = (StackAlloc) t;
9178 target.count = count.Clone (clonectx);
9179 target.t = t.Clone (clonectx);
9184 // An object initializer expression
9186 public class ElementInitializer : Assign
9188 public readonly string Name;
9190 public ElementInitializer (string name, Expression initializer, Location loc)
9191 : base (null, initializer, loc)
9196 protected override void CloneTo (CloneContext clonectx, Expression t)
9198 ElementInitializer target = (ElementInitializer) t;
9199 target.source = source.Clone (clonectx);
9202 public override Expression CreateExpressionTree (EmitContext ec)
9204 ArrayList args = new ArrayList (2);
9205 FieldExpr fe = target as FieldExpr;
9207 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9209 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9211 args.Add (new Argument (source.CreateExpressionTree (ec)));
9212 return CreateExpressionFactoryCall (
9213 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9217 public override Expression DoResolve (EmitContext ec)
9220 return EmptyExpressionStatement.Instance;
9222 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9223 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9229 me.InstanceExpression = ec.CurrentInitializerVariable;
9231 if (source is CollectionOrObjectInitializers) {
9232 Expression previous = ec.CurrentInitializerVariable;
9233 ec.CurrentInitializerVariable = target;
9234 source = source.Resolve (ec);
9235 ec.CurrentInitializerVariable = previous;
9239 eclass = source.eclass;
9244 Expression expr = base.DoResolve (ec);
9249 // Ignore field initializers with default value
9251 Constant c = source as Constant;
9252 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9253 return EmptyExpressionStatement.Instance;
9258 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9260 MemberInfo member = members [0];
9261 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9262 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9263 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9265 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9266 TypeManager.GetFullNameSignature (member));
9271 public override void EmitStatement (EmitContext ec)
9273 if (source is CollectionOrObjectInitializers)
9276 base.EmitStatement (ec);
9281 // A collection initializer expression
9283 public class CollectionElementInitializer : Invocation
9285 public class ElementInitializerArgument : Argument
9287 public ElementInitializerArgument (Expression e)
9293 public CollectionElementInitializer (Expression argument)
9294 : base (null, new ArrayList (1), true)
9296 Arguments.Add (argument);
9297 this.loc = argument.Location;
9300 public CollectionElementInitializer (ArrayList arguments, Location loc)
9301 : base (null, arguments, true)
9306 public override Expression CreateExpressionTree (EmitContext ec)
9308 ArrayList args = new ArrayList (2);
9309 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9311 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9312 foreach (Argument a in Arguments)
9313 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9315 args.Add (new Argument (new ArrayCreation (
9316 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9317 return CreateExpressionFactoryCall ("ElementInit", args);
9320 protected override void CloneTo (CloneContext clonectx, Expression t)
9322 CollectionElementInitializer target = (CollectionElementInitializer) t;
9324 target.Arguments = new ArrayList (Arguments.Count);
9325 foreach (Expression e in Arguments)
9326 target.Arguments.Add (e.Clone (clonectx));
9329 public override Expression DoResolve (EmitContext ec)
9331 if (eclass != ExprClass.Invalid)
9334 // TODO: We could call a constructor which takes element count argument,
9335 // for known types like List<T>, Dictionary<T, U>
9337 for (int i = 0; i < Arguments.Count; ++i) {
9338 Expression expr = Arguments [i] as Expression;
9342 expr = expr.Resolve (ec);
9346 Arguments [i] = new ElementInitializerArgument (expr);
9349 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9351 return base.DoResolve (ec);
9356 // A block of object or collection initializers
9358 public class CollectionOrObjectInitializers : ExpressionStatement
9360 ArrayList initializers;
9362 public static readonly CollectionOrObjectInitializers Empty =
9363 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9365 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9367 this.initializers = initializers;
9371 public bool IsEmpty {
9373 return initializers.Count == 0;
9377 public bool IsCollectionInitializer {
9379 return type == typeof (CollectionOrObjectInitializers);
9383 protected override void CloneTo (CloneContext clonectx, Expression target)
9385 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9387 t.initializers = new ArrayList (initializers.Count);
9388 foreach (Expression e in initializers)
9389 t.initializers.Add (e.Clone (clonectx));
9392 public override Expression CreateExpressionTree (EmitContext ec)
9394 ArrayList expr_initializers = new ArrayList (initializers.Count);
9395 foreach (Expression e in initializers) {
9396 Expression expr = e.CreateExpressionTree (ec);
9398 expr_initializers.Add (expr);
9401 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9404 public override Expression DoResolve (EmitContext ec)
9406 if (eclass != ExprClass.Invalid)
9409 bool is_elements_initialization = false;
9410 ArrayList element_names = null;
9411 for (int i = 0; i < initializers.Count; ++i) {
9412 Expression initializer = (Expression) initializers [i];
9413 ElementInitializer element_initializer = initializer as ElementInitializer;
9416 if (element_initializer != null) {
9417 is_elements_initialization = true;
9418 element_names = new ArrayList (initializers.Count);
9419 element_names.Add (element_initializer.Name);
9421 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9422 TypeManager.ienumerable_type)) {
9423 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9424 "object initializer because type `{1}' does not implement `{2}' interface",
9425 ec.CurrentInitializerVariable.GetSignatureForError (),
9426 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9427 TypeManager.CSharpName (TypeManager.ienumerable_type));
9432 if (is_elements_initialization == (element_initializer == null)) {
9433 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9434 is_elements_initialization ? "object initializer" : "collection initializer");
9438 if (is_elements_initialization) {
9439 if (element_names.Contains (element_initializer.Name)) {
9440 Report.Error (1912, element_initializer.Location,
9441 "An object initializer includes more than one member `{0}' initialization",
9442 element_initializer.Name);
9444 element_names.Add (element_initializer.Name);
9449 Expression e = initializer.Resolve (ec);
9450 if (e == EmptyExpressionStatement.Instance)
9451 initializers.RemoveAt (i--);
9453 initializers [i] = e;
9456 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9457 eclass = ExprClass.Variable;
9461 public override void Emit (EmitContext ec)
9466 public override void EmitStatement (EmitContext ec)
9468 foreach (ExpressionStatement e in initializers)
9469 e.EmitStatement (ec);
9472 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9474 foreach (Expression e in initializers)
9475 e.MutateHoistedGenericType (storey);
9480 // New expression with element/object initializers
9482 public class NewInitialize : New
9485 // This class serves as a proxy for variable initializer target instances.
9486 // A real variable is assigned later when we resolve left side of an
9489 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9491 NewInitialize new_instance;
9493 public InitializerTargetExpression (NewInitialize newInstance)
9495 this.type = newInstance.type;
9496 this.loc = newInstance.loc;
9497 this.eclass = newInstance.eclass;
9498 this.new_instance = newInstance;
9501 public override Expression CreateExpressionTree (EmitContext ec)
9503 // Should not be reached
9504 throw new NotSupportedException ("ET");
9507 public override Expression DoResolve (EmitContext ec)
9512 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9517 public override void Emit (EmitContext ec)
9519 new_instance.value_target.Emit (ec);
9522 #region IMemoryLocation Members
9524 public void AddressOf (EmitContext ec, AddressOp mode)
9526 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9532 CollectionOrObjectInitializers initializers;
9534 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9535 : base (requested_type, arguments, l)
9537 this.initializers = initializers;
9540 protected override void CloneTo (CloneContext clonectx, Expression t)
9542 base.CloneTo (clonectx, t);
9544 NewInitialize target = (NewInitialize) t;
9545 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9548 public override Expression CreateExpressionTree (EmitContext ec)
9550 ArrayList args = new ArrayList (2);
9551 args.Add (new Argument (base.CreateExpressionTree (ec)));
9552 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9554 return CreateExpressionFactoryCall (
9555 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9559 public override Expression DoResolve (EmitContext ec)
9561 if (eclass != ExprClass.Invalid)
9564 Expression e = base.DoResolve (ec);
9568 // Empty initializer can be optimized to simple new
9569 if (initializers.IsEmpty)
9572 Expression previous = ec.CurrentInitializerVariable;
9573 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9574 initializers.Resolve (ec);
9575 ec.CurrentInitializerVariable = previous;
9579 public override void Emit (EmitContext ec)
9584 // If target is non-hoisted variable, let's use it
9586 VariableReference variable = value_target as VariableReference;
9587 if (variable != null && variable.HoistedVariable == null) {
9589 StoreFromPtr (ec.ig, type);
9591 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9594 if (value_target == null || value_target_set)
9595 value_target = new LocalTemporary (type);
9597 ((LocalTemporary) value_target).Store (ec);
9600 initializers.Emit (ec);
9602 if (variable == null) {
9603 value_target.Emit (ec);
9604 value_target = null;
9608 public override void EmitStatement (EmitContext ec)
9610 if (initializers.IsEmpty) {
9611 base.EmitStatement (ec);
9617 if (value_target == null) {
9618 LocalTemporary variable = new LocalTemporary (type);
9619 variable.Store (ec);
9620 value_target = variable;
9623 initializers.EmitStatement (ec);
9626 public override bool HasInitializer {
9628 return !initializers.IsEmpty;
9632 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9634 base.MutateHoistedGenericType (storey);
9635 initializers.MutateHoistedGenericType (storey);
9639 public class AnonymousTypeDeclaration : Expression
9641 ArrayList parameters;
9642 readonly TypeContainer parent;
9643 static readonly ArrayList EmptyParameters = new ArrayList (0);
9645 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9647 this.parameters = parameters;
9648 this.parent = parent;
9652 protected override void CloneTo (CloneContext clonectx, Expression target)
9654 if (parameters == null)
9657 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9658 t.parameters = new ArrayList (parameters.Count);
9659 foreach (AnonymousTypeParameter atp in parameters)
9660 t.parameters.Add (atp.Clone (clonectx));
9663 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9665 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9669 type = AnonymousTypeClass.Create (parent, parameters, loc);
9674 type.DefineMembers ();
9679 RootContext.ToplevelTypes.AddAnonymousType (type);
9683 public override Expression CreateExpressionTree (EmitContext ec)
9685 throw new NotSupportedException ("ET");
9688 public override Expression DoResolve (EmitContext ec)
9690 AnonymousTypeClass anonymous_type;
9692 if (parameters == null) {
9693 anonymous_type = CreateAnonymousType (EmptyParameters);
9694 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9695 null, loc).Resolve (ec);
9699 ArrayList arguments = new ArrayList (parameters.Count);
9700 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9701 for (int i = 0; i < parameters.Count; ++i) {
9702 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9708 arguments.Add (new Argument (e));
9709 t_args [i] = new TypeExpression (e.Type, e.Location);
9715 anonymous_type = CreateAnonymousType (parameters);
9716 if (anonymous_type == null)
9719 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9720 new TypeArguments (loc, t_args), loc);
9722 return new New (te, arguments, loc).Resolve (ec);
9725 public override void Emit (EmitContext ec)
9727 throw new InternalErrorException ("Should not be reached");
9731 public class AnonymousTypeParameter : Expression
9733 public readonly string Name;
9734 Expression initializer;
9736 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9740 this.initializer = initializer;
9743 public AnonymousTypeParameter (Parameter parameter)
9745 this.Name = parameter.Name;
9746 this.loc = parameter.Location;
9747 this.initializer = new SimpleName (Name, loc);
9750 protected override void CloneTo (CloneContext clonectx, Expression target)
9752 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9753 t.initializer = initializer.Clone (clonectx);
9756 public override Expression CreateExpressionTree (EmitContext ec)
9758 throw new NotSupportedException ("ET");
9761 public override bool Equals (object o)
9763 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9764 return other != null && Name == other.Name;
9767 public override int GetHashCode ()
9769 return Name.GetHashCode ();
9772 public override Expression DoResolve (EmitContext ec)
9774 Expression e = initializer.Resolve (ec);
9778 if (e.eclass == ExprClass.MethodGroup) {
9779 Error_InvalidInitializer (e.ExprClassName);
9784 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9785 type == TypeManager.anonymous_method_type || type.IsPointer) {
9786 Error_InvalidInitializer (e.GetSignatureForError ());
9793 protected virtual void Error_InvalidInitializer (string initializer)
9795 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9799 public override void Emit (EmitContext ec)
9801 throw new InternalErrorException ("Should not be reached");