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 == TypeManager.void_type) {
1147 // TODO: Void is missing location (ProbeType.Location)
1148 Error_VoidInvalidInTheContext (Location);
1152 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1153 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1157 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1158 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1163 if (expr.Type == TypeManager.anonymous_method_type) {
1164 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1172 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1174 expr.MutateHoistedGenericType (storey);
1175 probe_type_expr.MutateHoistedGenericType (storey);
1178 protected abstract string OperatorName { get; }
1180 protected override void CloneTo (CloneContext clonectx, Expression t)
1182 Probe target = (Probe) t;
1184 target.expr = expr.Clone (clonectx);
1185 target.ProbeType = ProbeType.Clone (clonectx);
1191 /// Implementation of the `is' operator.
1193 public class Is : Probe {
1194 Nullable.Unwrap expr_unwrap;
1196 public Is (Expression expr, Expression probe_type, Location l)
1197 : base (expr, probe_type, l)
1201 public override Expression CreateExpressionTree (EmitContext ec)
1203 ArrayList args = new ArrayList (2);
1204 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1205 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1206 return CreateExpressionFactoryCall ("TypeIs", args);
1209 public override void Emit (EmitContext ec)
1211 ILGenerator ig = ec.ig;
1212 if (expr_unwrap != null) {
1213 expr_unwrap.EmitCheck (ec);
1218 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1219 ig.Emit (OpCodes.Ldnull);
1220 ig.Emit (OpCodes.Cgt_Un);
1223 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1225 ILGenerator ig = ec.ig;
1226 if (expr_unwrap != null) {
1227 expr_unwrap.EmitCheck (ec);
1230 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1232 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1235 Expression CreateConstantResult (bool result)
1238 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1242 TypeManager.CSharpName (probe_type_expr.Type));
1244 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1247 public override Expression DoResolve (EmitContext ec)
1249 if (base.DoResolve (ec) == null)
1253 bool d_is_nullable = false;
1256 // If E is a method group or the null literal, or if the type of E is a reference
1257 // type or a nullable type and the value of E is null, the result is false
1259 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1260 return CreateConstantResult (false);
1262 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1263 d = TypeManager.GetTypeArguments (d) [0];
1264 d_is_nullable = true;
1267 type = TypeManager.bool_type;
1268 eclass = ExprClass.Value;
1269 Type t = probe_type_expr.Type;
1270 bool t_is_nullable = false;
1271 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1272 t = TypeManager.GetTypeArguments (t) [0];
1273 t_is_nullable = true;
1276 if (t.IsValueType) {
1279 // D and T are the same value types but D can be null
1281 if (d_is_nullable && !t_is_nullable) {
1282 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1287 // The result is true if D and T are the same value types
1289 return CreateConstantResult (true);
1292 if (TypeManager.IsGenericParameter (d))
1293 return ResolveGenericParameter (t, d);
1296 // An unboxing conversion exists
1298 if (Convert.ExplicitReferenceConversionExists (d, t))
1301 if (TypeManager.IsGenericParameter (t))
1302 return ResolveGenericParameter (d, t);
1304 if (d.IsValueType) {
1306 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1307 return CreateConstantResult (true);
1309 if (TypeManager.IsGenericParameter (d))
1310 return ResolveGenericParameter (t, d);
1312 if (TypeManager.ContainsGenericParameters (d))
1315 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1316 Convert.ExplicitReferenceConversionExists (d, t)) {
1322 return CreateConstantResult (false);
1325 Expression ResolveGenericParameter (Type d, Type t)
1328 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1329 if (constraints != null) {
1330 if (constraints.IsReferenceType && d.IsValueType)
1331 return CreateConstantResult (false);
1333 if (constraints.IsValueType && !d.IsValueType)
1334 return CreateConstantResult (TypeManager.IsEqual (d, t));
1337 if (!TypeManager.IsReferenceType (expr.Type))
1338 expr = new BoxedCast (expr, d);
1346 protected override string OperatorName {
1347 get { return "is"; }
1352 /// Implementation of the `as' operator.
1354 public class As : Probe {
1356 Expression resolved_type;
1358 public As (Expression expr, Expression probe_type, Location l)
1359 : base (expr, probe_type, l)
1363 public override Expression CreateExpressionTree (EmitContext ec)
1365 ArrayList args = new ArrayList (2);
1366 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1367 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1368 return CreateExpressionFactoryCall ("TypeAs", args);
1371 public override void Emit (EmitContext ec)
1373 ILGenerator ig = ec.ig;
1378 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1381 if (TypeManager.IsNullableType (type))
1382 ig.Emit (OpCodes.Unbox_Any, type);
1386 public override Expression DoResolve (EmitContext ec)
1388 if (resolved_type == null) {
1389 resolved_type = base.DoResolve (ec);
1391 if (resolved_type == null)
1395 type = probe_type_expr.Type;
1396 eclass = ExprClass.Value;
1397 Type etype = expr.Type;
1399 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1400 if (probe_type_expr is TypeParameterExpr) {
1401 Report.Error (413, loc,
1402 "The `as' operator cannot be used with a non-reference type parameter `{0}'",
1403 probe_type_expr.GetSignatureForError ());
1405 Report.Error (77, loc,
1406 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1407 TypeManager.CSharpName (type));
1412 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1413 return Nullable.LiftedNull.CreateFromExpression (this);
1416 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1423 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1424 if (TypeManager.IsGenericParameter (etype))
1425 expr = new BoxedCast (expr, etype);
1431 if (TypeManager.ContainsGenericParameters (etype) ||
1432 TypeManager.ContainsGenericParameters (type)) {
1433 expr = new BoxedCast (expr, etype);
1438 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1439 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1444 protected override string OperatorName {
1445 get { return "as"; }
1448 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1450 return expr.GetAttributableValue (ec, value_type, out value);
1455 /// This represents a typecast in the source language.
1457 /// FIXME: Cast expressions have an unusual set of parsing
1458 /// rules, we need to figure those out.
1460 public class Cast : Expression {
1461 Expression target_type;
1464 public Cast (Expression cast_type, Expression expr)
1465 : this (cast_type, expr, cast_type.Location)
1469 public Cast (Expression cast_type, Expression expr, Location loc)
1471 this.target_type = cast_type;
1475 if (target_type == TypeManager.system_void_expr)
1476 Error_VoidInvalidInTheContext (loc);
1479 public Expression TargetType {
1480 get { return target_type; }
1483 public Expression Expr {
1484 get { return expr; }
1487 public override Expression CreateExpressionTree (EmitContext ec)
1489 throw new NotSupportedException ("ET");
1492 public override Expression DoResolve (EmitContext ec)
1494 expr = expr.Resolve (ec);
1498 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1504 if (type.IsAbstract && type.IsSealed) {
1505 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1509 eclass = ExprClass.Value;
1511 Constant c = expr as Constant;
1513 c = c.TryReduce (ec, type, loc);
1518 if (type.IsPointer && !ec.InUnsafe) {
1522 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1526 public override void Emit (EmitContext ec)
1528 throw new Exception ("Should not happen");
1531 protected override void CloneTo (CloneContext clonectx, Expression t)
1533 Cast target = (Cast) t;
1535 target.target_type = target_type.Clone (clonectx);
1536 target.expr = expr.Clone (clonectx);
1541 // C# 2.0 Default value expression
1543 public class DefaultValueExpression : Expression
1547 public DefaultValueExpression (Expression expr, Location loc)
1553 public override Expression CreateExpressionTree (EmitContext ec)
1555 ArrayList args = new ArrayList (2);
1556 args.Add (new Argument (this));
1557 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1558 return CreateExpressionFactoryCall ("Constant", args);
1561 public override Expression DoResolve (EmitContext ec)
1563 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1569 if (type == TypeManager.void_type) {
1570 Error_VoidInvalidInTheContext (loc);
1574 if (TypeManager.IsReferenceType (type)) {
1575 return new EmptyConstantCast (new NullLiteral (Location), type);
1578 // return ReducedExpression.Create (new NullLiteral (Location), this);
1581 Constant c = New.Constantify (type);
1585 eclass = ExprClass.Variable;
1589 public override void Emit (EmitContext ec)
1591 LocalTemporary temp_storage = new LocalTemporary(type);
1593 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1594 ec.ig.Emit(OpCodes.Initobj, type);
1595 temp_storage.Emit(ec);
1598 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1600 type = storey.MutateType (type);
1603 protected override void CloneTo (CloneContext clonectx, Expression t)
1605 DefaultValueExpression target = (DefaultValueExpression) t;
1607 target.expr = expr.Clone (clonectx);
1612 /// Binary operators
1614 public class Binary : Expression {
1616 protected class PredefinedOperator {
1617 protected readonly Type left;
1618 protected readonly Type right;
1619 public readonly Operator OperatorsMask;
1620 public Type ReturnType;
1622 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1623 : this (ltype, rtype, op_mask, ltype)
1627 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1628 : this (type, type, op_mask, return_type)
1632 public PredefinedOperator (Type type, Operator op_mask)
1633 : this (type, type, op_mask, type)
1637 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1639 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1640 throw new InternalErrorException ("Only masked values can be used");
1644 this.OperatorsMask = op_mask;
1645 this.ReturnType = return_type;
1648 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1650 b.type = ReturnType;
1652 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1653 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1656 // A user operators does not support multiple user conversions, but decimal type
1657 // is considered to be predefined type therefore we apply predefined operators rules
1658 // and then look for decimal user-operator implementation
1660 if (left == TypeManager.decimal_type)
1661 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1666 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1669 // We are dealing with primitive types only
1671 return left == ltype && ltype == rtype;
1674 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1676 if (TypeManager.IsEqual (left, lexpr.Type) &&
1677 TypeManager.IsEqual (right, rexpr.Type))
1680 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1681 Convert.ImplicitConversionExists (ec, rexpr, right);
1684 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1687 if (left != null && best_operator.left != null) {
1688 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1692 // When second arguments are same as the first one, the result is same
1694 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1695 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1698 if (result == 0 || result > 2)
1701 return result == 1 ? best_operator : this;
1705 class PredefinedStringOperator : PredefinedOperator {
1706 public PredefinedStringOperator (Type type, Operator op_mask)
1707 : base (type, op_mask, type)
1709 ReturnType = TypeManager.string_type;
1712 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1713 : base (ltype, rtype, op_mask)
1715 ReturnType = TypeManager.string_type;
1718 public override Expression ConvertResult (EmitContext ec, Binary b)
1721 // Use original expression for nullable arguments
1723 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1725 b.left = unwrap.Original;
1727 unwrap = b.right as Nullable.Unwrap;
1729 b.right = unwrap.Original;
1731 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1732 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1735 // Start a new concat expression using converted expression
1737 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1741 class PredefinedShiftOperator : PredefinedOperator {
1742 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1743 base (ltype, TypeManager.int32_type, op_mask)
1747 public override Expression ConvertResult (EmitContext ec, Binary b)
1749 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1751 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1753 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1756 // b = b.left >> b.right & (0x1f|0x3f)
1758 b.right = new Binary (Operator.BitwiseAnd,
1759 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1762 // Expression tree representation does not use & mask
1764 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1765 b.type = ReturnType;
1770 class PredefinedPointerOperator : PredefinedOperator {
1771 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1772 : base (ltype, rtype, op_mask)
1776 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1777 : base (ltype, rtype, op_mask, retType)
1781 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1782 : base (type, op_mask, return_type)
1786 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1789 if (!lexpr.Type.IsPointer)
1792 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1796 if (right == null) {
1797 if (!rexpr.Type.IsPointer)
1800 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1807 public override Expression ConvertResult (EmitContext ec, Binary b)
1810 b.left = EmptyCast.Create (b.left, left);
1811 } else if (right != null) {
1812 b.right = EmptyCast.Create (b.right, right);
1815 Type r_type = ReturnType;
1816 if (r_type == null) {
1818 r_type = b.left.Type;
1820 r_type = b.right.Type;
1823 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1828 public enum Operator {
1829 Multiply = 0 | ArithmeticMask,
1830 Division = 1 | ArithmeticMask,
1831 Modulus = 2 | ArithmeticMask,
1832 Addition = 3 | ArithmeticMask | AdditionMask,
1833 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1835 LeftShift = 5 | ShiftMask,
1836 RightShift = 6 | ShiftMask,
1838 LessThan = 7 | ComparisonMask | RelationalMask,
1839 GreaterThan = 8 | ComparisonMask | RelationalMask,
1840 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1841 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1842 Equality = 11 | ComparisonMask | EqualityMask,
1843 Inequality = 12 | ComparisonMask | EqualityMask,
1845 BitwiseAnd = 13 | BitwiseMask,
1846 ExclusiveOr = 14 | BitwiseMask,
1847 BitwiseOr = 15 | BitwiseMask,
1849 LogicalAnd = 16 | LogicalMask,
1850 LogicalOr = 17 | LogicalMask,
1855 ValuesOnlyMask = ArithmeticMask - 1,
1856 ArithmeticMask = 1 << 5,
1858 ComparisonMask = 1 << 7,
1859 EqualityMask = 1 << 8,
1860 BitwiseMask = 1 << 9,
1861 LogicalMask = 1 << 10,
1862 AdditionMask = 1 << 11,
1863 SubtractionMask = 1 << 12,
1864 RelationalMask = 1 << 13
1867 readonly Operator oper;
1868 protected Expression left, right;
1869 readonly bool is_compound;
1870 Expression enum_conversion;
1872 static PredefinedOperator [] standard_operators;
1873 static PredefinedOperator [] pointer_operators;
1875 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1876 : this (oper, left, right)
1878 this.is_compound = isCompound;
1881 public Binary (Operator oper, Expression left, Expression right)
1886 this.loc = left.Location;
1889 public Operator Oper {
1896 /// Returns a stringified representation of the Operator
1898 string OperName (Operator oper)
1902 case Operator.Multiply:
1905 case Operator.Division:
1908 case Operator.Modulus:
1911 case Operator.Addition:
1914 case Operator.Subtraction:
1917 case Operator.LeftShift:
1920 case Operator.RightShift:
1923 case Operator.LessThan:
1926 case Operator.GreaterThan:
1929 case Operator.LessThanOrEqual:
1932 case Operator.GreaterThanOrEqual:
1935 case Operator.Equality:
1938 case Operator.Inequality:
1941 case Operator.BitwiseAnd:
1944 case Operator.BitwiseOr:
1947 case Operator.ExclusiveOr:
1950 case Operator.LogicalOr:
1953 case Operator.LogicalAnd:
1957 s = oper.ToString ();
1967 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1969 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1972 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1975 // TODO: This should be handled as Type of method group in CSharpName
1976 if (left.eclass == ExprClass.MethodGroup)
1977 l = left.ExprClassName;
1979 l = TypeManager.CSharpName (left.Type);
1981 if (right.eclass == ExprClass.MethodGroup)
1982 r = right.ExprClassName;
1984 r = TypeManager.CSharpName (right.Type);
1986 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1990 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1992 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
1995 static string GetOperatorMetadataName (Operator op)
1997 CSharp.Operator.OpType op_type;
1999 case Operator.Addition:
2000 op_type = CSharp.Operator.OpType.Addition; break;
2001 case Operator.BitwiseAnd:
2002 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2003 case Operator.BitwiseOr:
2004 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2005 case Operator.Division:
2006 op_type = CSharp.Operator.OpType.Division; break;
2007 case Operator.Equality:
2008 op_type = CSharp.Operator.OpType.Equality; break;
2009 case Operator.ExclusiveOr:
2010 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2011 case Operator.GreaterThan:
2012 op_type = CSharp.Operator.OpType.GreaterThan; break;
2013 case Operator.GreaterThanOrEqual:
2014 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2015 case Operator.Inequality:
2016 op_type = CSharp.Operator.OpType.Inequality; break;
2017 case Operator.LeftShift:
2018 op_type = CSharp.Operator.OpType.LeftShift; break;
2019 case Operator.LessThan:
2020 op_type = CSharp.Operator.OpType.LessThan; break;
2021 case Operator.LessThanOrEqual:
2022 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2023 case Operator.Modulus:
2024 op_type = CSharp.Operator.OpType.Modulus; break;
2025 case Operator.Multiply:
2026 op_type = CSharp.Operator.OpType.Multiply; break;
2027 case Operator.RightShift:
2028 op_type = CSharp.Operator.OpType.RightShift; break;
2029 case Operator.Subtraction:
2030 op_type = CSharp.Operator.OpType.Subtraction; break;
2032 throw new InternalErrorException (op.ToString ());
2035 return CSharp.Operator.GetMetadataName (op_type);
2038 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2041 ILGenerator ig = ec.ig;
2044 case Operator.Multiply:
2046 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2047 opcode = OpCodes.Mul_Ovf;
2048 else if (!IsFloat (l))
2049 opcode = OpCodes.Mul_Ovf_Un;
2051 opcode = OpCodes.Mul;
2053 opcode = OpCodes.Mul;
2057 case Operator.Division:
2059 opcode = OpCodes.Div_Un;
2061 opcode = OpCodes.Div;
2064 case Operator.Modulus:
2066 opcode = OpCodes.Rem_Un;
2068 opcode = OpCodes.Rem;
2071 case Operator.Addition:
2073 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2074 opcode = OpCodes.Add_Ovf;
2075 else if (!IsFloat (l))
2076 opcode = OpCodes.Add_Ovf_Un;
2078 opcode = OpCodes.Add;
2080 opcode = OpCodes.Add;
2083 case Operator.Subtraction:
2085 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2086 opcode = OpCodes.Sub_Ovf;
2087 else if (!IsFloat (l))
2088 opcode = OpCodes.Sub_Ovf_Un;
2090 opcode = OpCodes.Sub;
2092 opcode = OpCodes.Sub;
2095 case Operator.RightShift:
2097 opcode = OpCodes.Shr_Un;
2099 opcode = OpCodes.Shr;
2102 case Operator.LeftShift:
2103 opcode = OpCodes.Shl;
2106 case Operator.Equality:
2107 opcode = OpCodes.Ceq;
2110 case Operator.Inequality:
2111 ig.Emit (OpCodes.Ceq);
2112 ig.Emit (OpCodes.Ldc_I4_0);
2114 opcode = OpCodes.Ceq;
2117 case Operator.LessThan:
2119 opcode = OpCodes.Clt_Un;
2121 opcode = OpCodes.Clt;
2124 case Operator.GreaterThan:
2126 opcode = OpCodes.Cgt_Un;
2128 opcode = OpCodes.Cgt;
2131 case Operator.LessThanOrEqual:
2132 if (IsUnsigned (l) || IsFloat (l))
2133 ig.Emit (OpCodes.Cgt_Un);
2135 ig.Emit (OpCodes.Cgt);
2136 ig.Emit (OpCodes.Ldc_I4_0);
2138 opcode = OpCodes.Ceq;
2141 case Operator.GreaterThanOrEqual:
2142 if (IsUnsigned (l) || IsFloat (l))
2143 ig.Emit (OpCodes.Clt_Un);
2145 ig.Emit (OpCodes.Clt);
2147 ig.Emit (OpCodes.Ldc_I4_0);
2149 opcode = OpCodes.Ceq;
2152 case Operator.BitwiseOr:
2153 opcode = OpCodes.Or;
2156 case Operator.BitwiseAnd:
2157 opcode = OpCodes.And;
2160 case Operator.ExclusiveOr:
2161 opcode = OpCodes.Xor;
2165 throw new InternalErrorException (oper.ToString ());
2171 static bool IsUnsigned (Type t)
2176 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2177 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2180 static bool IsFloat (Type t)
2182 return t == TypeManager.float_type || t == TypeManager.double_type;
2185 Expression ResolveOperator (EmitContext ec)
2188 Type r = right.Type;
2190 bool primitives_only = false;
2192 if (standard_operators == null)
2193 CreateStandardOperatorsTable ();
2196 // Handles predefined primitive types
2198 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2199 if ((oper & Operator.ShiftMask) == 0) {
2200 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2203 primitives_only = true;
2207 if (l.IsPointer || r.IsPointer)
2208 return ResolveOperatorPointer (ec, l, r);
2211 bool lenum = TypeManager.IsEnumType (l);
2212 bool renum = TypeManager.IsEnumType (r);
2213 if (lenum || renum) {
2214 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2216 // TODO: Can this be ambiguous
2222 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2223 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2225 expr = ResolveOperatorDelegate (ec, l, r);
2227 // TODO: Can this be ambiguous
2233 expr = ResolveUserOperator (ec, l, r);
2237 // Predefined reference types equality
2238 if ((oper & Operator.EqualityMask) != 0) {
2239 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2245 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2248 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2249 // if 'left' is not an enumeration constant, create one from the type of 'right'
2250 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2253 case Operator.BitwiseOr:
2254 case Operator.BitwiseAnd:
2255 case Operator.ExclusiveOr:
2256 case Operator.Equality:
2257 case Operator.Inequality:
2258 case Operator.LessThan:
2259 case Operator.LessThanOrEqual:
2260 case Operator.GreaterThan:
2261 case Operator.GreaterThanOrEqual:
2262 if (TypeManager.IsEnumType (left.Type))
2265 if (left.IsZeroInteger)
2266 return left.TryReduce (ec, right.Type, loc);
2270 case Operator.Addition:
2271 case Operator.Subtraction:
2274 case Operator.Multiply:
2275 case Operator.Division:
2276 case Operator.Modulus:
2277 case Operator.LeftShift:
2278 case Operator.RightShift:
2279 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2283 Error_OperatorCannotBeApplied (this.left, this.right);
2288 // The `|' operator used on types which were extended is dangerous
2290 void CheckBitwiseOrOnSignExtended ()
2292 OpcodeCast lcast = left as OpcodeCast;
2293 if (lcast != null) {
2294 if (IsUnsigned (lcast.UnderlyingType))
2298 OpcodeCast rcast = right as OpcodeCast;
2299 if (rcast != null) {
2300 if (IsUnsigned (rcast.UnderlyingType))
2304 if (lcast == null && rcast == null)
2307 // FIXME: consider constants
2309 Report.Warning (675, 3, loc,
2310 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2311 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2314 static void CreatePointerOperatorsTable ()
2316 ArrayList temp = new ArrayList ();
2319 // Pointer arithmetic:
2321 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2322 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2323 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2324 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2326 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2327 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2328 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2329 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2332 // T* operator + (int y, T* x);
2333 // T* operator + (uint y, T *x);
2334 // T* operator + (long y, T *x);
2335 // T* operator + (ulong y, T *x);
2337 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2338 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2339 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2340 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2343 // long operator - (T* x, T *y)
2345 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2347 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2350 static void CreateStandardOperatorsTable ()
2352 ArrayList temp = new ArrayList ();
2353 Type bool_type = TypeManager.bool_type;
2355 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2356 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2357 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2358 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2359 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2360 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2361 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2363 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2364 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2365 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2366 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2367 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2368 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2369 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2371 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2373 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2374 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2375 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2377 temp.Add (new PredefinedOperator (bool_type,
2378 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2380 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2381 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2382 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2383 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2385 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2389 // Rules used during binary numeric promotion
2391 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2396 Constant c = prim_expr as Constant;
2398 temp = c.ConvertImplicitly (type);
2405 if (type == TypeManager.uint32_type) {
2406 etype = prim_expr.Type;
2407 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2408 type = TypeManager.int64_type;
2410 if (type != second_expr.Type) {
2411 c = second_expr as Constant;
2413 temp = c.ConvertImplicitly (type);
2415 temp = Convert.ImplicitNumericConversion (second_expr, type);
2421 } else if (type == TypeManager.uint64_type) {
2423 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2425 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2426 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2430 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2439 // 7.2.6.2 Binary numeric promotions
2441 public bool DoBinaryOperatorPromotion (EmitContext ec)
2443 Type ltype = left.Type;
2444 Type rtype = right.Type;
2447 foreach (Type t in ConstantFold.binary_promotions) {
2449 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2452 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2455 Type int32 = TypeManager.int32_type;
2456 if (ltype != int32) {
2457 Constant c = left as Constant;
2459 temp = c.ConvertImplicitly (int32);
2461 temp = Convert.ImplicitNumericConversion (left, int32);
2468 if (rtype != int32) {
2469 Constant c = right as Constant;
2471 temp = c.ConvertImplicitly (int32);
2473 temp = Convert.ImplicitNumericConversion (right, int32);
2483 public override Expression DoResolve (EmitContext ec)
2488 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2489 left = ((ParenthesizedExpression) left).Expr;
2490 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2494 if (left.eclass == ExprClass.Type) {
2495 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2499 left = left.Resolve (ec);
2504 Constant lc = left as Constant;
2506 if (lc != null && lc.Type == TypeManager.bool_type &&
2507 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2508 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2510 // FIXME: resolve right expression as unreachable
2511 // right.Resolve (ec);
2513 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2517 right = right.Resolve (ec);
2521 eclass = ExprClass.Value;
2522 Constant rc = right as Constant;
2524 // The conversion rules are ignored in enum context but why
2525 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2526 left = lc = EnumLiftUp (ec, lc, rc, loc);
2530 right = rc = EnumLiftUp (ec, rc, lc, loc);
2535 if (rc != null && lc != null) {
2536 int prev_e = Report.Errors;
2537 Expression e = ConstantFold.BinaryFold (
2538 ec, oper, lc, rc, loc);
2539 if (e != null || Report.Errors != prev_e)
2542 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2543 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2545 if ((ResolveOperator (ec)) == null) {
2546 Error_OperatorCannotBeApplied (left, right);
2551 // The result is a constant with side-effect
2553 Constant side_effect = rc == null ?
2554 new SideEffectConstant (lc, right, loc) :
2555 new SideEffectConstant (rc, left, loc);
2557 return ReducedExpression.Create (side_effect, this);
2561 // Comparison warnings
2562 if ((oper & Operator.ComparisonMask) != 0) {
2563 if (left.Equals (right)) {
2564 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2566 CheckUselessComparison (lc, right.Type);
2567 CheckUselessComparison (rc, left.Type);
2570 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2571 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2572 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2573 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2575 return DoResolveCore (ec, left, right);
2578 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2580 Expression expr = ResolveOperator (ec);
2582 Error_OperatorCannotBeApplied (left_orig, right_orig);
2584 if (left == null || right == null)
2585 throw new InternalErrorException ("Invalid conversion");
2587 if (oper == Operator.BitwiseOr)
2588 CheckBitwiseOrOnSignExtended ();
2593 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2595 left.MutateHoistedGenericType (storey);
2596 right.MutateHoistedGenericType (storey);
2600 // D operator + (D x, D y)
2601 // D operator - (D x, D y)
2602 // bool operator == (D x, D y)
2603 // bool operator != (D x, D y)
2605 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2607 bool is_equality = (oper & Operator.EqualityMask) != 0;
2608 if (!TypeManager.IsEqual (l, r)) {
2610 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2611 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2616 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2617 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2628 // Resolve delegate equality as a user operator
2631 return ResolveUserOperator (ec, l, r);
2634 ArrayList args = new ArrayList (2);
2635 args.Add (new Argument (left, Argument.AType.Expression));
2636 args.Add (new Argument (right, Argument.AType.Expression));
2638 if (oper == Operator.Addition) {
2639 if (TypeManager.delegate_combine_delegate_delegate == null) {
2640 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2641 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2644 method = TypeManager.delegate_combine_delegate_delegate;
2646 if (TypeManager.delegate_remove_delegate_delegate == null) {
2647 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2648 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2651 method = TypeManager.delegate_remove_delegate_delegate;
2654 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2655 mg = mg.OverloadResolve (ec, ref args, false, loc);
2657 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2661 // Enumeration operators
2663 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2666 // bool operator == (E x, E y);
2667 // bool operator != (E x, E y);
2668 // bool operator < (E x, E y);
2669 // bool operator > (E x, E y);
2670 // bool operator <= (E x, E y);
2671 // bool operator >= (E x, E y);
2673 // E operator & (E x, E y);
2674 // E operator | (E x, E y);
2675 // E operator ^ (E x, E y);
2677 // U operator - (E e, E f)
2678 // E operator - (E e, U x)
2680 // E operator + (U x, E e)
2681 // E operator + (E e, U x)
2683 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2684 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2687 Expression ltemp = left;
2688 Expression rtemp = right;
2689 Type underlying_type;
2692 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2694 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2700 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2708 if (TypeManager.IsEqual (ltype, rtype)) {
2709 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2711 if (left is Constant)
2712 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2714 left = EmptyCast.Create (left, underlying_type);
2716 if (right is Constant)
2717 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2719 right = EmptyCast.Create (right, underlying_type);
2721 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2723 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2724 Constant c = right as Constant;
2725 if (c == null || !c.IsDefaultValue)
2728 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2731 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2734 if (left is Constant)
2735 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2737 left = EmptyCast.Create (left, underlying_type);
2740 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2742 if (oper != Operator.Addition) {
2743 Constant c = left as Constant;
2744 if (c == null || !c.IsDefaultValue)
2747 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2750 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2753 if (right is Constant)
2754 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2756 right = EmptyCast.Create (right, underlying_type);
2763 // C# specification uses explicit cast syntax which means binary promotion
2764 // should happen, however it seems that csc does not do that
2766 if (!DoBinaryOperatorPromotion (ec)) {
2772 Type res_type = null;
2773 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2774 Type promoted_type = lenum ? left.Type : right.Type;
2775 enum_conversion = Convert.ExplicitNumericConversion (
2776 new EmptyExpression (promoted_type), underlying_type);
2778 if (oper == Operator.Subtraction && renum && lenum)
2779 res_type = underlying_type;
2780 else if (oper == Operator.Addition && renum)
2786 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2787 if (!is_compound || expr == null)
2791 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2794 if (Convert.ImplicitConversionExists (ec, left, rtype))
2797 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2800 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2805 // 7.9.6 Reference type equality operators
2807 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2810 // operator != (object a, object b)
2811 // operator == (object a, object b)
2814 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2816 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2819 type = TypeManager.bool_type;
2820 GenericConstraints constraints;
2822 bool lgen = TypeManager.IsGenericParameter (l);
2824 if (TypeManager.IsEqual (l, r)) {
2827 // Only allow to compare same reference type parameter
2829 constraints = TypeManager.GetTypeParameterConstraints (l);
2830 if (constraints != null && constraints.IsReferenceType)
2836 if (l == TypeManager.anonymous_method_type)
2839 if (TypeManager.IsValueType (l))
2845 bool rgen = TypeManager.IsGenericParameter (r);
2848 // a, Both operands are reference-type values or the value null
2849 // b, One operand is a value of type T where T is a type-parameter and
2850 // the other operand is the value null. Furthermore T does not have the
2851 // value type constrain
2853 if (left is NullLiteral || right is NullLiteral) {
2855 constraints = TypeManager.GetTypeParameterConstraints (l);
2856 if (constraints != null && constraints.HasValueTypeConstraint)
2859 left = new BoxedCast (left, TypeManager.object_type);
2864 constraints = TypeManager.GetTypeParameterConstraints (r);
2865 if (constraints != null && constraints.HasValueTypeConstraint)
2868 right = new BoxedCast (right, TypeManager.object_type);
2874 // An interface is converted to the object before the
2875 // standard conversion is applied. It's not clear from the
2876 // standard but it looks like it works like that.
2879 constraints = TypeManager.GetTypeParameterConstraints (l);
2880 if (constraints == null || constraints.IsReferenceType)
2882 } else if (l.IsInterface) {
2883 l = TypeManager.object_type;
2884 } else if (l.IsValueType) {
2889 constraints = TypeManager.GetTypeParameterConstraints (r);
2890 if (constraints == null || constraints.IsReferenceType)
2892 } else if (r.IsInterface) {
2893 r = TypeManager.object_type;
2894 } else if (r.IsValueType) {
2899 const string ref_comparison = "Possible unintended reference comparison. " +
2900 "Consider casting the {0} side of the expression to `string' to compare the values";
2903 // A standard implicit conversion exists from the type of either
2904 // operand to the type of the other operand
2906 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2907 if (l == TypeManager.string_type)
2908 Report.Warning (253, 2, loc, ref_comparison, "right");
2913 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2914 if (r == TypeManager.string_type)
2915 Report.Warning (252, 2, loc, ref_comparison, "left");
2924 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2927 // bool operator == (void* x, void* y);
2928 // bool operator != (void* x, void* y);
2929 // bool operator < (void* x, void* y);
2930 // bool operator > (void* x, void* y);
2931 // bool operator <= (void* x, void* y);
2932 // bool operator >= (void* x, void* y);
2934 if ((oper & Operator.ComparisonMask) != 0) {
2937 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2944 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2950 type = TypeManager.bool_type;
2954 if (pointer_operators == null)
2955 CreatePointerOperatorsTable ();
2957 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2961 // Build-in operators method overloading
2963 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2965 PredefinedOperator best_operator = null;
2967 Type r = right.Type;
2968 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2970 foreach (PredefinedOperator po in operators) {
2971 if ((po.OperatorsMask & oper_mask) == 0)
2974 if (primitives_only) {
2975 if (!po.IsPrimitiveApplicable (l, r))
2978 if (!po.IsApplicable (ec, left, right))
2982 if (best_operator == null) {
2984 if (primitives_only)
2990 best_operator = po.ResolveBetterOperator (ec, best_operator);
2992 if (best_operator == null) {
2993 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2994 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3001 if (best_operator == null)
3004 Expression expr = best_operator.ConvertResult (ec, this);
3005 if (enum_type == null)
3009 // HACK: required by enum_conversion
3011 expr.Type = enum_type;
3012 return EmptyCast.Create (expr, enum_type);
3016 // Performs user-operator overloading
3018 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3021 if (oper == Operator.LogicalAnd)
3022 user_oper = Operator.BitwiseAnd;
3023 else if (oper == Operator.LogicalOr)
3024 user_oper = Operator.BitwiseOr;
3028 string op = GetOperatorMetadataName (user_oper);
3030 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3031 MethodGroupExpr right_operators = null;
3033 if (!TypeManager.IsEqual (r, l)) {
3034 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3035 if (right_operators == null && left_operators == null)
3037 } else if (left_operators == null) {
3041 ArrayList args = new ArrayList (2);
3042 Argument larg = new Argument (left);
3044 Argument rarg = new Argument (right);
3047 MethodGroupExpr union;
3050 // User-defined operator implementations always take precedence
3051 // over predefined operator implementations
3053 if (left_operators != null && right_operators != null) {
3054 if (IsPredefinedUserOperator (l, user_oper)) {
3055 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3057 union = left_operators;
3058 } else if (IsPredefinedUserOperator (r, user_oper)) {
3059 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3061 union = right_operators;
3063 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3065 } else if (left_operators != null) {
3066 union = left_operators;
3068 union = right_operators;
3071 union = union.OverloadResolve (ec, ref args, true, loc);
3075 Expression oper_expr;
3077 // TODO: CreateExpressionTree is allocated every time
3078 if (user_oper != oper) {
3079 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3080 oper == Operator.LogicalAnd, loc).Resolve (ec);
3082 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3085 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3086 // and not invoke user operator
3088 if ((oper & Operator.EqualityMask) != 0) {
3089 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3090 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3091 type = TypeManager.bool_type;
3092 if (left is NullLiteral || right is NullLiteral)
3093 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3094 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3096 // Two System.Delegate(s) are never equal
3108 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3113 private void CheckUselessComparison (Constant c, Type type)
3115 if (c == null || !IsTypeIntegral (type)
3116 || c is StringConstant
3117 || c is BoolConstant
3118 || c is FloatConstant
3119 || c is DoubleConstant
3120 || c is DecimalConstant
3126 if (c is ULongConstant) {
3127 ulong uvalue = ((ULongConstant) c).Value;
3128 if (uvalue > long.MaxValue) {
3129 if (type == TypeManager.byte_type ||
3130 type == TypeManager.sbyte_type ||
3131 type == TypeManager.short_type ||
3132 type == TypeManager.ushort_type ||
3133 type == TypeManager.int32_type ||
3134 type == TypeManager.uint32_type ||
3135 type == TypeManager.int64_type ||
3136 type == TypeManager.char_type)
3137 WarnUselessComparison (type);
3140 value = (long) uvalue;
3142 else if (c is ByteConstant)
3143 value = ((ByteConstant) c).Value;
3144 else if (c is SByteConstant)
3145 value = ((SByteConstant) c).Value;
3146 else if (c is ShortConstant)
3147 value = ((ShortConstant) c).Value;
3148 else if (c is UShortConstant)
3149 value = ((UShortConstant) c).Value;
3150 else if (c is IntConstant)
3151 value = ((IntConstant) c).Value;
3152 else if (c is UIntConstant)
3153 value = ((UIntConstant) c).Value;
3154 else if (c is LongConstant)
3155 value = ((LongConstant) c).Value;
3156 else if (c is CharConstant)
3157 value = ((CharConstant)c).Value;
3162 if (IsValueOutOfRange (value, type))
3163 WarnUselessComparison (type);
3166 static bool IsValueOutOfRange (long value, Type type)
3168 if (IsTypeUnsigned (type) && value < 0)
3170 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3171 type == TypeManager.byte_type && value >= 0x100 ||
3172 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3173 type == TypeManager.ushort_type && value >= 0x10000 ||
3174 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3175 type == TypeManager.uint32_type && value >= 0x100000000;
3178 static bool IsBuildInEqualityOperator (Type t)
3180 return t == TypeManager.object_type || t == TypeManager.string_type ||
3181 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3184 static bool IsPredefinedUserOperator (Type t, Operator op)
3187 // Some predefined types have user operators
3189 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3192 private static bool IsTypeIntegral (Type type)
3194 return type == TypeManager.uint64_type ||
3195 type == TypeManager.int64_type ||
3196 type == TypeManager.uint32_type ||
3197 type == TypeManager.int32_type ||
3198 type == TypeManager.ushort_type ||
3199 type == TypeManager.short_type ||
3200 type == TypeManager.sbyte_type ||
3201 type == TypeManager.byte_type ||
3202 type == TypeManager.char_type;
3205 private static bool IsTypeUnsigned (Type type)
3207 return type == TypeManager.uint64_type ||
3208 type == TypeManager.uint32_type ||
3209 type == TypeManager.ushort_type ||
3210 type == TypeManager.byte_type ||
3211 type == TypeManager.char_type;
3214 private void WarnUselessComparison (Type type)
3216 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}'",
3217 TypeManager.CSharpName (type));
3221 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3222 /// context of a conditional bool expression. This function will return
3223 /// false if it is was possible to use EmitBranchable, or true if it was.
3225 /// The expression's code is generated, and we will generate a branch to `target'
3226 /// if the resulting expression value is equal to isTrue
3228 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3230 ILGenerator ig = ec.ig;
3233 // This is more complicated than it looks, but its just to avoid
3234 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3235 // but on top of that we want for == and != to use a special path
3236 // if we are comparing against null
3238 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3239 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3242 // put the constant on the rhs, for simplicity
3244 if (left is Constant) {
3245 Expression swap = right;
3250 if (((Constant) right).IsZeroInteger) {
3251 left.EmitBranchable (ec, target, my_on_true);
3254 if (right.Type == TypeManager.bool_type) {
3255 // right is a boolean, and it's not 'false' => it is 'true'
3256 left.EmitBranchable (ec, target, !my_on_true);
3260 } else if (oper == Operator.LogicalAnd) {
3263 Label tests_end = ig.DefineLabel ();
3265 left.EmitBranchable (ec, tests_end, false);
3266 right.EmitBranchable (ec, target, true);
3267 ig.MarkLabel (tests_end);
3270 // This optimizes code like this
3271 // if (true && i > 4)
3273 if (!(left is Constant))
3274 left.EmitBranchable (ec, target, false);
3276 if (!(right is Constant))
3277 right.EmitBranchable (ec, target, false);
3282 } else if (oper == Operator.LogicalOr){
3284 left.EmitBranchable (ec, target, true);
3285 right.EmitBranchable (ec, target, true);
3288 Label tests_end = ig.DefineLabel ();
3289 left.EmitBranchable (ec, tests_end, true);
3290 right.EmitBranchable (ec, target, false);
3291 ig.MarkLabel (tests_end);
3296 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3297 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3298 oper == Operator.Equality || oper == Operator.Inequality)) {
3299 base.EmitBranchable (ec, target, on_true);
3307 bool is_unsigned = IsUnsigned (t) || IsFloat (t);
3310 case Operator.Equality:
3312 ig.Emit (OpCodes.Beq, target);
3314 ig.Emit (OpCodes.Bne_Un, target);
3317 case Operator.Inequality:
3319 ig.Emit (OpCodes.Bne_Un, target);
3321 ig.Emit (OpCodes.Beq, target);
3324 case Operator.LessThan:
3327 ig.Emit (OpCodes.Blt_Un, target);
3329 ig.Emit (OpCodes.Blt, target);
3332 ig.Emit (OpCodes.Bge_Un, target);
3334 ig.Emit (OpCodes.Bge, target);
3337 case Operator.GreaterThan:
3340 ig.Emit (OpCodes.Bgt_Un, target);
3342 ig.Emit (OpCodes.Bgt, target);
3345 ig.Emit (OpCodes.Ble_Un, target);
3347 ig.Emit (OpCodes.Ble, target);
3350 case Operator.LessThanOrEqual:
3353 ig.Emit (OpCodes.Ble_Un, target);
3355 ig.Emit (OpCodes.Ble, target);
3358 ig.Emit (OpCodes.Bgt_Un, target);
3360 ig.Emit (OpCodes.Bgt, target);
3364 case Operator.GreaterThanOrEqual:
3367 ig.Emit (OpCodes.Bge_Un, target);
3369 ig.Emit (OpCodes.Bge, target);
3372 ig.Emit (OpCodes.Blt_Un, target);
3374 ig.Emit (OpCodes.Blt, target);
3377 throw new InternalErrorException (oper.ToString ());
3381 public override void Emit (EmitContext ec)
3383 EmitOperator (ec, left.Type);
3386 protected virtual void EmitOperator (EmitContext ec, Type l)
3388 ILGenerator ig = ec.ig;
3391 // Handle short-circuit operators differently
3394 if ((oper & Operator.LogicalMask) != 0) {
3395 Label load_result = ig.DefineLabel ();
3396 Label end = ig.DefineLabel ();
3398 bool is_or = oper == Operator.LogicalOr;
3399 left.EmitBranchable (ec, load_result, is_or);
3401 ig.Emit (OpCodes.Br_S, end);
3403 ig.MarkLabel (load_result);
3404 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3412 // Optimize zero-based operations
3414 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3416 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3417 Constant rc = right as Constant;
3418 if (rc != null && rc.IsDefaultValue) {
3424 EmitOperatorOpcode (ec, oper, l);
3427 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3428 // expression because that would wrap lifted binary operation
3430 if (enum_conversion != null)
3431 enum_conversion.Emit (ec);
3434 public override void EmitSideEffect (EmitContext ec)
3436 if ((oper & Operator.LogicalMask) != 0 ||
3437 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3438 base.EmitSideEffect (ec);
3440 left.EmitSideEffect (ec);
3441 right.EmitSideEffect (ec);
3445 protected override void CloneTo (CloneContext clonectx, Expression t)
3447 Binary target = (Binary) t;
3449 target.left = left.Clone (clonectx);
3450 target.right = right.Clone (clonectx);
3453 public override Expression CreateExpressionTree (EmitContext ec)
3455 return CreateExpressionTree (ec, null);
3458 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3461 bool lift_arg = false;
3464 case Operator.Addition:
3465 if (method == null && ec.CheckState && !IsFloat (type))
3466 method_name = "AddChecked";
3468 method_name = "Add";
3470 case Operator.BitwiseAnd:
3471 method_name = "And";
3473 case Operator.BitwiseOr:
3476 case Operator.Division:
3477 method_name = "Divide";
3479 case Operator.Equality:
3480 method_name = "Equal";
3483 case Operator.ExclusiveOr:
3484 method_name = "ExclusiveOr";
3486 case Operator.GreaterThan:
3487 method_name = "GreaterThan";
3490 case Operator.GreaterThanOrEqual:
3491 method_name = "GreaterThanOrEqual";
3494 case Operator.Inequality:
3495 method_name = "NotEqual";
3498 case Operator.LeftShift:
3499 method_name = "LeftShift";
3501 case Operator.LessThan:
3502 method_name = "LessThan";
3505 case Operator.LessThanOrEqual:
3506 method_name = "LessThanOrEqual";
3509 case Operator.LogicalAnd:
3510 method_name = "AndAlso";
3512 case Operator.LogicalOr:
3513 method_name = "OrElse";
3515 case Operator.Modulus:
3516 method_name = "Modulo";
3518 case Operator.Multiply:
3519 if (method == null && ec.CheckState && !IsFloat (type))
3520 method_name = "MultiplyChecked";
3522 method_name = "Multiply";
3524 case Operator.RightShift:
3525 method_name = "RightShift";
3527 case Operator.Subtraction:
3528 if (method == null && ec.CheckState && !IsFloat (type))
3529 method_name = "SubtractChecked";
3531 method_name = "Subtract";
3535 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3538 ArrayList args = new ArrayList (2);
3539 args.Add (new Argument (left.CreateExpressionTree (ec)));
3540 args.Add (new Argument (right.CreateExpressionTree (ec)));
3541 if (method != null) {
3543 args.Add (new Argument (new BoolConstant (false, loc)));
3545 args.Add (new Argument (method.CreateExpressionTree (ec)));
3548 return CreateExpressionFactoryCall (method_name, args);
3553 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3554 // b, c, d... may be strings or objects.
3556 public class StringConcat : Expression {
3557 ArrayList arguments;
3559 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3562 type = TypeManager.string_type;
3563 eclass = ExprClass.Value;
3565 arguments = new ArrayList (2);
3570 public override Expression CreateExpressionTree (EmitContext ec)
3572 Argument arg = (Argument) arguments [0];
3573 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3577 // Creates nested calls tree from an array of arguments used for IL emit
3579 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3581 ArrayList concat_args = new ArrayList (2);
3582 ArrayList add_args = new ArrayList (3);
3584 concat_args.Add (left);
3585 add_args.Add (new Argument (left_etree));
3587 concat_args.Add (arguments [pos]);
3588 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3590 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3594 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3598 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3600 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3601 if (++pos == arguments.Count)
3604 left = new Argument (new EmptyExpression (method.Type));
3605 return CreateExpressionAddCall (ec, left, expr, pos);
3608 public override Expression DoResolve (EmitContext ec)
3613 public void Append (EmitContext ec, Expression operand)
3618 StringConstant sc = operand as StringConstant;
3620 if (arguments.Count != 0) {
3621 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3622 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3623 if (last_expr_constant != null) {
3624 last_argument.Expr = new StringConstant (
3625 last_expr_constant.Value + sc.Value, sc.Location);
3631 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3633 StringConcat concat_oper = operand as StringConcat;
3634 if (concat_oper != null) {
3635 arguments.AddRange (concat_oper.arguments);
3640 arguments.Add (new Argument (operand));
3643 Expression CreateConcatMemberExpression ()
3645 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3648 public override void Emit (EmitContext ec)
3650 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3651 concat = concat.Resolve (ec);
3656 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3658 foreach (Argument a in arguments)
3659 a.Expr.MutateHoistedGenericType (storey);
3664 // User-defined conditional logical operator
3666 public class ConditionalLogicalOperator : UserOperatorCall {
3667 readonly bool is_and;
3670 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3671 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3672 : base (oper_method, arguments, expr_tree, loc)
3674 this.is_and = is_and;
3677 public override Expression DoResolve (EmitContext ec)
3679 MethodInfo method = (MethodInfo)mg;
3680 type = TypeManager.TypeToCoreType (method.ReturnType);
3681 AParametersCollection pd = TypeManager.GetParameterData (method);
3682 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3683 Report.Error (217, loc,
3684 "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",
3685 TypeManager.CSharpSignature (method));
3689 Expression left_dup = new EmptyExpression (type);
3690 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3691 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3692 if (op_true == null || op_false == null) {
3693 Report.Error (218, loc,
3694 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3695 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3699 oper = is_and ? op_false : op_true;
3700 eclass = ExprClass.Value;
3704 public override void Emit (EmitContext ec)
3706 ILGenerator ig = ec.ig;
3707 Label end_target = ig.DefineLabel ();
3710 // Emit and duplicate left argument
3712 ((Argument)arguments [0]).Expr.Emit (ec);
3713 ig.Emit (OpCodes.Dup);
3714 arguments.RemoveAt (0);
3716 oper.EmitBranchable (ec, end_target, true);
3718 ig.MarkLabel (end_target);
3722 public class PointerArithmetic : Expression {
3723 Expression left, right;
3727 // We assume that `l' is always a pointer
3729 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3738 public override Expression CreateExpressionTree (EmitContext ec)
3740 Error_PointerInsideExpressionTree ();
3744 public override Expression DoResolve (EmitContext ec)
3746 eclass = ExprClass.Variable;
3748 if (left.Type == TypeManager.void_ptr_type) {
3749 Error (242, "The operation in question is undefined on void pointers");
3756 public override void Emit (EmitContext ec)
3758 Type op_type = left.Type;
3759 ILGenerator ig = ec.ig;
3761 // It must be either array or fixed buffer
3763 if (TypeManager.HasElementType (op_type)) {
3764 element = TypeManager.GetElementType (op_type);
3766 FieldExpr fe = left as FieldExpr;
3768 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3773 int size = GetTypeSize (element);
3774 Type rtype = right.Type;
3776 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3778 // handle (pointer - pointer)
3782 ig.Emit (OpCodes.Sub);
3786 ig.Emit (OpCodes.Sizeof, element);
3788 IntLiteral.EmitInt (ig, size);
3789 ig.Emit (OpCodes.Div);
3791 ig.Emit (OpCodes.Conv_I8);
3794 // handle + and - on (pointer op int)
3798 Constant right_const = right as Constant;
3799 if (right_const != null) {
3801 // Optimize 0-based arithmetic
3803 if (right_const.IsDefaultValue)
3807 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3811 ig.Emit (OpCodes.Sizeof, element);
3812 right = EmptyExpression.Null;
3817 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3818 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3819 ig.Emit (OpCodes.Conv_I);
3820 } else if (rtype == TypeManager.uint32_type) {
3821 ig.Emit (OpCodes.Conv_U);
3824 if (right_const == null && size != 1){
3826 ig.Emit (OpCodes.Sizeof, element);
3828 IntLiteral.EmitInt (ig, size);
3829 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3830 ig.Emit (OpCodes.Conv_I8);
3832 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3835 if (rtype == TypeManager.int64_type)
3836 ig.Emit (OpCodes.Conv_I);
3837 else if (rtype == TypeManager.uint64_type)
3838 ig.Emit (OpCodes.Conv_U);
3840 Binary.EmitOperatorOpcode (ec, op, op_type);
3846 /// Implements the ternary conditional operator (?:)
3848 public class Conditional : Expression {
3849 Expression expr, true_expr, false_expr;
3851 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3854 this.true_expr = true_expr;
3855 this.false_expr = false_expr;
3856 this.loc = expr.Location;
3859 public Expression Expr {
3865 public Expression TrueExpr {
3871 public Expression FalseExpr {
3877 public override Expression CreateExpressionTree (EmitContext ec)
3879 ArrayList args = new ArrayList (3);
3880 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3881 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3882 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3883 return CreateExpressionFactoryCall ("Condition", args);
3886 public override Expression DoResolve (EmitContext ec)
3888 expr = expr.Resolve (ec);
3893 if (expr.Type != TypeManager.bool_type){
3894 expr = Expression.ResolveBoolean (
3901 Assign ass = expr as Assign;
3902 if (ass != null && ass.Source is Constant) {
3903 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3906 true_expr = true_expr.Resolve (ec);
3907 false_expr = false_expr.Resolve (ec);
3909 if (true_expr == null || false_expr == null)
3912 eclass = ExprClass.Value;
3913 Type true_type = true_expr.Type;
3914 Type false_type = false_expr.Type;
3918 // First, if an implicit conversion exists from true_expr
3919 // to false_expr, then the result type is of type false_expr.Type
3921 if (!TypeManager.IsEqual (true_type, false_type)) {
3922 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3925 // Check if both can convert implicitl to each other's type
3927 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3929 "Can not compute type of conditional expression " +
3930 "as `" + TypeManager.CSharpName (true_expr.Type) +
3931 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3932 "' convert implicitly to each other");
3937 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3940 Report.Error (173, loc,
3941 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3942 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3947 // Dead code optimalization
3948 Constant c = expr as Constant;
3950 bool is_false = c.IsDefaultValue;
3951 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3952 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3958 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3960 expr.MutateHoistedGenericType (storey);
3961 true_expr.MutateHoistedGenericType (storey);
3962 false_expr.MutateHoistedGenericType (storey);
3963 type = storey.MutateType (type);
3966 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3971 public override void Emit (EmitContext ec)
3973 ILGenerator ig = ec.ig;
3974 Label false_target = ig.DefineLabel ();
3975 Label end_target = ig.DefineLabel ();
3977 expr.EmitBranchable (ec, false_target, false);
3978 true_expr.Emit (ec);
3980 if (type.IsInterface) {
3981 LocalBuilder temp = ec.GetTemporaryLocal (type);
3982 ig.Emit (OpCodes.Stloc, temp);
3983 ig.Emit (OpCodes.Ldloc, temp);
3984 ec.FreeTemporaryLocal (temp, type);
3987 ig.Emit (OpCodes.Br, end_target);
3988 ig.MarkLabel (false_target);
3989 false_expr.Emit (ec);
3990 ig.MarkLabel (end_target);
3993 protected override void CloneTo (CloneContext clonectx, Expression t)
3995 Conditional target = (Conditional) t;
3997 target.expr = expr.Clone (clonectx);
3998 target.true_expr = true_expr.Clone (clonectx);
3999 target.false_expr = false_expr.Clone (clonectx);
4003 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4004 LocalTemporary temp;
4007 public abstract HoistedVariable HoistedVariable { get; }
4008 public abstract bool IsFixedVariable { get; }
4009 public abstract bool IsRef { get; }
4010 public abstract string Name { get; }
4011 public abstract void SetHasAddressTaken ();
4014 // Variable IL data, it has to be protected to encapsulate hoisted variables
4016 protected abstract ILocalVariable Variable { get; }
4019 // Variable flow-analysis data
4021 public abstract VariableInfo VariableInfo { get; }
4024 public void AddressOf (EmitContext ec, AddressOp mode)
4026 if (IsHoistedEmitRequired (ec)) {
4027 HoistedVariable.AddressOf (ec, mode);
4031 Variable.EmitAddressOf (ec);
4034 public override void Emit (EmitContext ec)
4039 public override void EmitSideEffect (EmitContext ec)
4045 // This method is used by parameters that are references, that are
4046 // being passed as references: we only want to pass the pointer (that
4047 // is already stored in the parameter, not the address of the pointer,
4048 // and not the value of the variable).
4050 public void EmitLoad (EmitContext ec)
4055 public void Emit (EmitContext ec, bool leave_copy)
4057 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4059 if (IsHoistedEmitRequired (ec)) {
4060 HoistedVariable.Emit (ec, leave_copy);
4068 // If we are a reference, we loaded on the stack a pointer
4069 // Now lets load the real value
4071 LoadFromPtr (ec.ig, type);
4075 ec.ig.Emit (OpCodes.Dup);
4078 temp = new LocalTemporary (Type);
4084 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4085 bool prepare_for_load)
4087 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4090 if (IsHoistedEmitRequired (ec)) {
4091 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4100 // HACK: variable is already emitted when source is an initializer
4101 if (source is NewInitialize) {
4109 ec.ig.Emit (OpCodes.Dup);
4111 temp = new LocalTemporary (Type);
4117 StoreFromPtr (ec.ig, type);
4119 Variable.EmitAssign (ec);
4127 public bool IsHoisted {
4128 get { return HoistedVariable != null; }
4131 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4134 // Default implementation return true when there is a hosted variable
4136 return HoistedVariable != null;
4139 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4141 type = storey.MutateType (type);
4148 public class LocalVariableReference : VariableReference {
4149 readonly string name;
4151 public LocalInfo local_info;
4154 public LocalVariableReference (Block block, string name, Location l)
4159 eclass = ExprClass.Variable;
4163 // Setting `is_readonly' to false will allow you to create a writable
4164 // reference to a read-only variable. This is used by foreach and using.
4166 public LocalVariableReference (Block block, string name, Location l,
4167 LocalInfo local_info, bool is_readonly)
4168 : this (block, name, l)
4170 this.local_info = local_info;
4171 this.is_readonly = is_readonly;
4174 public override VariableInfo VariableInfo {
4175 get { return local_info.VariableInfo; }
4178 public override HoistedVariable HoistedVariable {
4179 get { return local_info.HoistedVariableReference; }
4183 // A local variable is always fixed
4185 public override bool IsFixedVariable {
4186 get { return true; }
4189 public override bool IsRef {
4190 get { return false; }
4193 public bool IsReadOnly {
4194 get { return is_readonly; }
4197 public override string Name {
4198 get { return name; }
4201 public bool VerifyAssigned (EmitContext ec)
4203 VariableInfo variable_info = local_info.VariableInfo;
4204 return variable_info == null || variable_info.IsAssigned (ec, loc);
4207 void ResolveLocalInfo ()
4209 if (local_info == null) {
4210 local_info = Block.GetLocalInfo (Name);
4211 type = local_info.VariableType;
4212 is_readonly = local_info.ReadOnly;
4216 public override void SetHasAddressTaken ()
4218 local_info.AddressTaken = true;
4221 public override Expression CreateExpressionTree (EmitContext ec)
4223 ArrayList arg = new ArrayList (1);
4224 arg.Add (new Argument (this));
4225 return CreateExpressionFactoryCall ("Constant", arg);
4228 Expression DoResolveBase (EmitContext ec)
4230 type = local_info.VariableType;
4232 Expression e = Block.GetConstantExpression (Name);
4234 return e.Resolve (ec);
4236 VerifyAssigned (ec);
4239 // If we are referencing a variable from the external block
4240 // flag it for capturing
4242 if (ec.MustCaptureVariable (local_info)) {
4243 if (local_info.AddressTaken)
4244 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4246 if (ec.IsVariableCapturingRequired) {
4247 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4248 storey.CaptureLocalVariable (ec, local_info);
4255 public override Expression DoResolve (EmitContext ec)
4257 ResolveLocalInfo ();
4258 local_info.Used = true;
4260 if (type == null && local_info.Type is VarExpr) {
4261 local_info.VariableType = TypeManager.object_type;
4262 Error_VariableIsUsedBeforeItIsDeclared (Name);
4266 return DoResolveBase (ec);
4269 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4271 ResolveLocalInfo ();
4274 if (right_side == EmptyExpression.OutAccess)
4275 local_info.Used = true;
4277 // Infer implicitly typed local variable
4279 VarExpr ve = local_info.Type as VarExpr;
4281 if (!ve.InferType (ec, right_side))
4283 type = local_info.VariableType = ve.Type;
4290 if (right_side == EmptyExpression.OutAccess) {
4291 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4292 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4293 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4294 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4295 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4296 } else if (right_side == EmptyExpression.UnaryAddress) {
4297 code = 459; msg = "Cannot take the address of {1} `{0}'";
4299 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4301 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4302 } else if (VariableInfo != null) {
4303 VariableInfo.SetAssigned (ec);
4306 return DoResolveBase (ec);
4309 public override int GetHashCode ()
4311 return Name.GetHashCode ();
4314 public override bool Equals (object obj)
4316 LocalVariableReference lvr = obj as LocalVariableReference;
4320 return Name == lvr.Name && Block == lvr.Block;
4323 protected override ILocalVariable Variable {
4324 get { return local_info; }
4327 public override string ToString ()
4329 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4332 protected override void CloneTo (CloneContext clonectx, Expression t)
4334 LocalVariableReference target = (LocalVariableReference) t;
4336 target.Block = clonectx.LookupBlock (Block);
4337 if (local_info != null)
4338 target.local_info = clonectx.LookupVariable (local_info);
4343 /// This represents a reference to a parameter in the intermediate
4346 public class ParameterReference : VariableReference {
4347 readonly ToplevelParameterInfo pi;
4348 readonly ToplevelBlock referenced;
4350 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4353 this.referenced = referenced;
4357 public override bool IsRef {
4358 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4361 bool HasOutModifier {
4362 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4365 public override HoistedVariable HoistedVariable {
4366 get { return pi.Parameter.HoistedVariableReference; }
4370 // A ref or out parameter is classified as a moveable variable, even
4371 // if the argument given for the parameter is a fixed variable
4373 public override bool IsFixedVariable {
4374 get { return !IsRef; }
4377 public override string Name {
4378 get { return Parameter.Name; }
4381 public Parameter Parameter {
4382 get { return pi.Parameter; }
4385 public override VariableInfo VariableInfo {
4386 get { return pi.VariableInfo; }
4389 protected override ILocalVariable Variable {
4390 get { return Parameter; }
4393 public bool IsAssigned (EmitContext ec, Location loc)
4395 // HACK: Variables are not captured in probing mode
4396 if (ec.IsInProbingMode)
4399 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4402 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4406 public override void SetHasAddressTaken ()
4408 Parameter.HasAddressTaken = true;
4411 void SetAssigned (EmitContext ec)
4413 if (HasOutModifier && ec.DoFlowAnalysis)
4414 ec.CurrentBranching.SetAssigned (VariableInfo);
4417 bool DoResolveBase (EmitContext ec)
4419 type = pi.ParameterType;
4420 eclass = ExprClass.Variable;
4422 AnonymousExpression am = ec.CurrentAnonymousMethod;
4426 ToplevelBlock declared = pi.Block;
4427 if (declared != referenced) {
4429 Report.Error (1628, loc,
4430 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4431 Name, am.ContainerType);
4439 if (ec.IsVariableCapturingRequired) {
4440 if (pi.Parameter.HasAddressTaken)
4441 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4443 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4444 storey.CaptureParameter (ec, this);
4450 public override int GetHashCode ()
4452 return Name.GetHashCode ();
4455 public override bool Equals (object obj)
4457 ParameterReference pr = obj as ParameterReference;
4461 return Name == pr.Name && referenced == pr.referenced;
4464 protected override void CloneTo (CloneContext clonectx, Expression target)
4469 public override Expression CreateExpressionTree (EmitContext ec)
4471 if (IsHoistedEmitRequired (ec))
4472 return HoistedVariable.CreateExpressionTree (ec);
4474 return Parameter.ExpressionTreeVariableReference ();
4478 // Notice that for ref/out parameters, the type exposed is not the
4479 // same type exposed externally.
4482 // externally we expose "int&"
4483 // here we expose "int".
4485 // We record this in "is_ref". This means that the type system can treat
4486 // the type as it is expected, but when we generate the code, we generate
4487 // the alternate kind of code.
4489 public override Expression DoResolve (EmitContext ec)
4491 if (!DoResolveBase (ec))
4494 if (HasOutModifier && ec.DoFlowAnalysis &&
4495 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4501 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4503 if (!DoResolveBase (ec))
4506 // HACK: parameters are not captured when probing is on
4507 if (!ec.IsInProbingMode)
4513 static public void EmitLdArg (ILGenerator ig, int x)
4517 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4518 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4519 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4520 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4521 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4524 ig.Emit (OpCodes.Ldarg, x);
4529 /// Used for arguments to New(), Invocation()
4531 public class Argument {
4532 public enum AType : byte {
4539 public static readonly Argument[] Empty = new Argument [0];
4541 public readonly AType ArgType;
4542 public Expression Expr;
4544 public Argument (Expression expr, AType type)
4547 this.ArgType = type;
4550 public Argument (Expression expr)
4553 this.ArgType = AType.Expression;
4557 get { return Expr.Type; }
4560 public Parameter.Modifier Modifier
4565 return Parameter.Modifier.OUT;
4568 return Parameter.Modifier.REF;
4571 return Parameter.Modifier.NONE;
4576 public string GetSignatureForError ()
4578 if (Expr.eclass == ExprClass.MethodGroup)
4579 return Expr.ExprClassName;
4581 return TypeManager.CSharpName (Expr.Type);
4584 public bool ResolveMethodGroup (EmitContext ec)
4586 SimpleName sn = Expr as SimpleName;
4588 Expr = sn.GetMethodGroup ();
4590 // FIXME: csc doesn't report any error if you try to use `ref' or
4591 // `out' in a delegate creation expression.
4592 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4599 public bool Resolve (EmitContext ec, Location loc)
4604 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4605 // Verify that the argument is readable
4606 if (ArgType != AType.Out)
4607 Expr = Expr.Resolve (ec);
4609 // Verify that the argument is writeable
4610 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4611 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4613 return Expr != null;
4617 public void Emit (EmitContext ec)
4619 if (ArgType != AType.Ref && ArgType != AType.Out) {
4624 AddressOp mode = AddressOp.Store;
4625 if (ArgType == AType.Ref)
4626 mode |= AddressOp.Load;
4628 IMemoryLocation ml = (IMemoryLocation) Expr;
4629 ParameterReference pr = ml as ParameterReference;
4632 // ParameterReferences might already be references, so we want
4633 // to pass just the value
4635 if (pr != null && pr.IsRef)
4638 ml.AddressOf (ec, mode);
4641 public Argument Clone (CloneContext clonectx)
4643 return new Argument (Expr.Clone (clonectx), ArgType);
4648 /// Invocation of methods or delegates.
4650 public class Invocation : ExpressionStatement {
4651 protected ArrayList Arguments;
4652 protected Expression expr;
4653 protected MethodGroupExpr mg;
4654 bool arguments_resolved;
4657 // arguments is an ArrayList, but we do not want to typecast,
4658 // as it might be null.
4660 public Invocation (Expression expr, ArrayList arguments)
4662 SimpleName sn = expr as SimpleName;
4664 this.expr = sn.GetMethodGroup ();
4668 Arguments = arguments;
4670 loc = expr.Location;
4673 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4674 : this (expr, arguments)
4676 this.arguments_resolved = arguments_resolved;
4679 public override Expression CreateExpressionTree (EmitContext ec)
4684 // Special conversion for nested expression trees
4686 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4687 args = new ArrayList (1);
4688 args.Add (new Argument (this));
4689 return CreateExpressionFactoryCall ("Quote", args);
4692 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4694 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4697 args = new ArrayList (arg_count);
4700 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4702 args.Add (new Argument (new NullLiteral (loc)));
4704 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4707 // Use extension argument when exists
4710 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4712 args.Add (new Argument (e));
4715 if (Arguments != null) {
4716 foreach (Argument a in Arguments) {
4717 Expression e = a.Expr.CreateExpressionTree (ec);
4719 args.Add (new Argument (e));
4724 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4726 return CreateExpressionFactoryCall ("Call", args);
4729 public override Expression DoResolve (EmitContext ec)
4731 // Don't resolve already resolved expression
4732 if (eclass != ExprClass.Invalid)
4735 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4736 if (expr_resolved == null)
4739 mg = expr_resolved as MethodGroupExpr;
4741 Type expr_type = expr_resolved.Type;
4743 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4744 return (new DelegateInvocation (
4745 expr_resolved, Arguments, loc)).Resolve (ec);
4748 MemberExpr me = expr_resolved as MemberExpr;
4750 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4754 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4756 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4757 expr_resolved.GetSignatureForError ());
4761 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4765 // Next, evaluate all the expressions in the argument list
4767 if (Arguments != null && !arguments_resolved) {
4768 for (int i = 0; i < Arguments.Count; ++i)
4770 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4775 mg = DoResolveOverload (ec);
4779 MethodInfo method = (MethodInfo)mg;
4780 if (method != null) {
4781 type = TypeManager.TypeToCoreType (method.ReturnType);
4783 // TODO: this is a copy of mg.ResolveMemberAccess method
4784 Expression iexpr = mg.InstanceExpression;
4785 if (method.IsStatic) {
4786 if (iexpr == null ||
4787 iexpr is This || iexpr is EmptyExpression ||
4788 mg.IdenticalTypeName) {
4789 mg.InstanceExpression = null;
4791 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4797 if (type.IsPointer){
4805 // Only base will allow this invocation to happen.
4807 if (mg.IsBase && method.IsAbstract){
4808 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4812 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4814 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4816 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4820 IsSpecialMethodInvocation (method, loc);
4822 if (mg.InstanceExpression != null)
4823 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4825 eclass = ExprClass.Value;
4829 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4831 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4834 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4836 if (!TypeManager.IsSpecialMethod (method))
4839 Report.SymbolRelatedToPreviousError (method);
4840 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4841 TypeManager.CSharpSignature (method, true));
4847 /// Emits a list of resolved Arguments that are in the arguments
4850 /// The MethodBase argument might be null if the
4851 /// emission of the arguments is known not to contain
4852 /// a `params' field (for example in constructors or other routines
4853 /// that keep their arguments in this structure)
4855 /// if `dup_args' is true, a copy of the arguments will be left
4856 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4857 /// which will be duplicated before any other args. Only EmitCall
4858 /// should be using this interface.
4860 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4862 if (arguments == null)
4865 int top = arguments.Count;
4866 LocalTemporary [] temps = null;
4868 if (dup_args && top != 0)
4869 temps = new LocalTemporary [top];
4871 int argument_index = 0;
4873 for (int i = 0; i < top; i++) {
4874 a = (Argument) arguments [argument_index++];
4877 ec.ig.Emit (OpCodes.Dup);
4878 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4883 if (this_arg != null)
4886 for (int i = 0; i < top; i ++) {
4887 temps [i].Emit (ec);
4888 temps [i].Release (ec);
4893 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4895 AParametersCollection pd = TypeManager.GetParameterData (mb);
4897 Argument a = (Argument) arguments [pd.Count - 1];
4898 Arglist list = (Arglist) a.Expr;
4900 return list.ArgumentTypes;
4904 /// This checks the ConditionalAttribute on the method
4906 public static bool IsMethodExcluded (MethodBase method, Location loc)
4908 if (method.IsConstructor)
4911 method = TypeManager.DropGenericMethodArguments (method);
4912 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4913 IMethodData md = TypeManager.GetMethod (method);
4915 return md.IsExcluded ();
4917 // For some methods (generated by delegate class) GetMethod returns null
4918 // because they are not included in builder_to_method table
4922 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4926 /// is_base tells whether we want to force the use of the `call'
4927 /// opcode instead of using callvirt. Call is required to call
4928 /// a specific method, while callvirt will always use the most
4929 /// recent method in the vtable.
4931 /// is_static tells whether this is an invocation on a static method
4933 /// instance_expr is an expression that represents the instance
4934 /// it must be non-null if is_static is false.
4936 /// method is the method to invoke.
4938 /// Arguments is the list of arguments to pass to the method or constructor.
4940 public static void EmitCall (EmitContext ec, bool is_base,
4941 Expression instance_expr,
4942 MethodBase method, ArrayList Arguments, Location loc)
4944 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4947 // `dup_args' leaves an extra copy of the arguments on the stack
4948 // `omit_args' does not leave any arguments at all.
4949 // So, basically, you could make one call with `dup_args' set to true,
4950 // and then another with `omit_args' set to true, and the two calls
4951 // would have the same set of arguments. However, each argument would
4952 // only have been evaluated once.
4953 public static void EmitCall (EmitContext ec, bool is_base,
4954 Expression instance_expr,
4955 MethodBase method, ArrayList Arguments, Location loc,
4956 bool dup_args, bool omit_args)
4958 ILGenerator ig = ec.ig;
4959 bool struct_call = false;
4960 bool this_call = false;
4961 LocalTemporary this_arg = null;
4963 Type decl_type = method.DeclaringType;
4965 if (!ec.IsInObsoleteScope) {
4967 // This checks ObsoleteAttribute on the method and on the declaring type
4969 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4971 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4973 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4975 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4979 if (IsMethodExcluded (method, loc))
4982 bool is_static = method.IsStatic;
4984 if (instance_expr == EmptyExpression.Null) {
4985 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4989 this_call = instance_expr is This;
4990 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4994 // If this is ourselves, push "this"
4998 Type iexpr_type = instance_expr.Type;
5001 // Push the instance expression
5003 if (TypeManager.IsValueType (iexpr_type)) {
5005 // Special case: calls to a function declared in a
5006 // reference-type with a value-type argument need
5007 // to have their value boxed.
5008 if (decl_type.IsValueType ||
5009 TypeManager.IsGenericParameter (iexpr_type)) {
5011 // If the expression implements IMemoryLocation, then
5012 // we can optimize and use AddressOf on the
5015 // If not we have to use some temporary storage for
5017 if (instance_expr is IMemoryLocation) {
5018 ((IMemoryLocation)instance_expr).
5019 AddressOf (ec, AddressOp.LoadStore);
5021 LocalTemporary temp = new LocalTemporary (iexpr_type);
5022 instance_expr.Emit (ec);
5024 temp.AddressOf (ec, AddressOp.Load);
5027 // avoid the overhead of doing this all the time.
5029 t = TypeManager.GetReferenceType (iexpr_type);
5031 instance_expr.Emit (ec);
5032 ig.Emit (OpCodes.Box, instance_expr.Type);
5033 t = TypeManager.object_type;
5036 instance_expr.Emit (ec);
5037 t = instance_expr.Type;
5041 ig.Emit (OpCodes.Dup);
5042 if (Arguments != null && Arguments.Count != 0) {
5043 this_arg = new LocalTemporary (t);
5044 this_arg.Store (ec);
5051 EmitArguments (ec, Arguments, dup_args, this_arg);
5054 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5055 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5059 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5060 call_op = OpCodes.Call;
5062 call_op = OpCodes.Callvirt;
5064 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5065 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5066 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5073 // and DoFoo is not virtual, you can omit the callvirt,
5074 // because you don't need the null checking behavior.
5076 if (method is MethodInfo)
5077 ig.Emit (call_op, (MethodInfo) method);
5079 ig.Emit (call_op, (ConstructorInfo) method);
5082 public override void Emit (EmitContext ec)
5084 mg.EmitCall (ec, Arguments);
5087 public override void EmitStatement (EmitContext ec)
5092 // Pop the return value if there is one
5094 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5095 ec.ig.Emit (OpCodes.Pop);
5098 protected override void CloneTo (CloneContext clonectx, Expression t)
5100 Invocation target = (Invocation) t;
5102 if (Arguments != null) {
5103 target.Arguments = new ArrayList (Arguments.Count);
5104 foreach (Argument a in Arguments)
5105 target.Arguments.Add (a.Clone (clonectx));
5108 target.expr = expr.Clone (clonectx);
5111 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5113 mg.MutateHoistedGenericType (storey);
5114 if (Arguments != null) {
5115 foreach (Argument a in Arguments)
5116 a.Expr.MutateHoistedGenericType (storey);
5122 // It's either a cast or delegate invocation
5124 public class InvocationOrCast : ExpressionStatement
5127 Expression argument;
5129 public InvocationOrCast (Expression expr, Expression argument)
5132 this.argument = argument;
5133 this.loc = expr.Location;
5136 public override Expression CreateExpressionTree (EmitContext ec)
5138 throw new NotSupportedException ("ET");
5141 public override Expression DoResolve (EmitContext ec)
5143 Expression e = ResolveCore (ec);
5147 return e.Resolve (ec);
5150 Expression ResolveCore (EmitContext ec)
5153 // First try to resolve it as a cast.
5155 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5157 return new Cast (te, argument, loc);
5161 // This can either be a type or a delegate invocation.
5162 // Let's just resolve it and see what we'll get.
5164 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5169 // Ok, so it's a Cast.
5171 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5172 return new Cast (expr, argument, loc);
5175 if (expr.eclass == ExprClass.Namespace) {
5176 expr.Error_UnexpectedKind (null, "type", loc);
5181 // It's a delegate invocation.
5183 if (!TypeManager.IsDelegateType (expr.Type)) {
5184 Error (149, "Method name expected");
5188 ArrayList args = new ArrayList (1);
5189 args.Add (new Argument (argument, Argument.AType.Expression));
5190 return new DelegateInvocation (expr, args, loc);
5193 public override ExpressionStatement ResolveStatement (EmitContext ec)
5195 Expression e = ResolveCore (ec);
5199 ExpressionStatement s = e as ExpressionStatement;
5201 Error_InvalidExpressionStatement ();
5205 return s.ResolveStatement (ec);
5208 public override void Emit (EmitContext ec)
5210 throw new Exception ("Cannot happen");
5213 public override void EmitStatement (EmitContext ec)
5215 throw new Exception ("Cannot happen");
5218 protected override void CloneTo (CloneContext clonectx, Expression t)
5220 InvocationOrCast target = (InvocationOrCast) t;
5222 target.expr = expr.Clone (clonectx);
5223 target.argument = argument.Clone (clonectx);
5228 // This class is used to "disable" the code generation for the
5229 // temporary variable when initializing value types.
5231 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5232 public void AddressOf (EmitContext ec, AddressOp Mode)
5239 /// Implements the new expression
5241 public class New : ExpressionStatement, IMemoryLocation {
5242 ArrayList Arguments;
5245 // During bootstrap, it contains the RequestedType,
5246 // but if `type' is not null, it *might* contain a NewDelegate
5247 // (because of field multi-initialization)
5249 public Expression RequestedType;
5251 MethodGroupExpr method;
5254 // If set, the new expression is for a value_target, and
5255 // we will not leave anything on the stack.
5257 protected Expression value_target;
5258 protected bool value_target_set;
5259 bool is_type_parameter = false;
5261 public New (Expression requested_type, ArrayList arguments, Location l)
5263 RequestedType = requested_type;
5264 Arguments = arguments;
5268 public bool SetTargetVariable (Expression value)
5270 value_target = value;
5271 value_target_set = true;
5272 if (!(value_target is IMemoryLocation)){
5273 Error_UnexpectedKind (null, "variable", loc);
5280 // This function is used to disable the following code sequence for
5281 // value type initialization:
5283 // AddressOf (temporary)
5287 // Instead the provide will have provided us with the address on the
5288 // stack to store the results.
5290 static Expression MyEmptyExpression;
5292 public void DisableTemporaryValueType ()
5294 if (MyEmptyExpression == null)
5295 MyEmptyExpression = new EmptyAddressOf ();
5298 // To enable this, look into:
5299 // test-34 and test-89 and self bootstrapping.
5301 // For instance, we can avoid a copy by using `newobj'
5302 // instead of Call + Push-temp on value types.
5303 // value_target = MyEmptyExpression;
5308 /// Converts complex core type syntax like 'new int ()' to simple constant
5310 public static Constant Constantify (Type t)
5312 if (t == TypeManager.int32_type)
5313 return new IntConstant (0, Location.Null);
5314 if (t == TypeManager.uint32_type)
5315 return new UIntConstant (0, Location.Null);
5316 if (t == TypeManager.int64_type)
5317 return new LongConstant (0, Location.Null);
5318 if (t == TypeManager.uint64_type)
5319 return new ULongConstant (0, Location.Null);
5320 if (t == TypeManager.float_type)
5321 return new FloatConstant (0, Location.Null);
5322 if (t == TypeManager.double_type)
5323 return new DoubleConstant (0, Location.Null);
5324 if (t == TypeManager.short_type)
5325 return new ShortConstant (0, Location.Null);
5326 if (t == TypeManager.ushort_type)
5327 return new UShortConstant (0, Location.Null);
5328 if (t == TypeManager.sbyte_type)
5329 return new SByteConstant (0, Location.Null);
5330 if (t == TypeManager.byte_type)
5331 return new ByteConstant (0, Location.Null);
5332 if (t == TypeManager.char_type)
5333 return new CharConstant ('\0', Location.Null);
5334 if (t == TypeManager.bool_type)
5335 return new BoolConstant (false, Location.Null);
5336 if (t == TypeManager.decimal_type)
5337 return new DecimalConstant (0, Location.Null);
5338 if (TypeManager.IsEnumType (t))
5339 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5345 // Checks whether the type is an interface that has the
5346 // [ComImport, CoClass] attributes and must be treated
5349 public Expression CheckComImport (EmitContext ec)
5351 if (!type.IsInterface)
5355 // Turn the call into:
5356 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5358 Type real_class = AttributeTester.GetCoClassAttribute (type);
5359 if (real_class == null)
5362 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5363 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5364 return cast.Resolve (ec);
5367 public override Expression CreateExpressionTree (EmitContext ec)
5369 ArrayList args = Arguments == null ?
5370 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5372 if (method == null) {
5373 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5375 args.Add (new Argument (method.CreateExpressionTree (ec)));
5376 if (Arguments != null) {
5378 foreach (Argument a in Arguments) {
5379 expr = a.Expr.CreateExpressionTree (ec);
5381 args.Add (new Argument (expr));
5386 return CreateExpressionFactoryCall ("New", args);
5389 public override Expression DoResolve (EmitContext ec)
5392 // The New DoResolve might be called twice when initializing field
5393 // expressions (see EmitFieldInitializers, the call to
5394 // GetInitializerExpression will perform a resolve on the expression,
5395 // and later the assign will trigger another resolution
5397 // This leads to bugs (#37014)
5400 if (RequestedType is NewDelegate)
5401 return RequestedType;
5405 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5411 if (type == TypeManager.void_type) {
5412 Error_VoidInvalidInTheContext (loc);
5416 if (type.IsPointer) {
5417 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5418 TypeManager.CSharpName (type));
5422 if (Arguments == null) {
5423 Expression c = Constantify (type);
5428 if (TypeManager.IsDelegateType (type)) {
5429 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5433 if (type.IsGenericParameter) {
5434 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5436 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5437 Error (304, String.Format (
5438 "Cannot create an instance of the " +
5439 "variable type '{0}' because it " +
5440 "doesn't have the new() constraint",
5445 if ((Arguments != null) && (Arguments.Count != 0)) {
5446 Error (417, String.Format (
5447 "`{0}': cannot provide arguments " +
5448 "when creating an instance of a " +
5449 "variable type.", type));
5453 if (TypeManager.activator_create_instance == null) {
5454 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5455 if (activator_type != null) {
5456 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5457 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5461 is_type_parameter = true;
5462 eclass = ExprClass.Value;
5467 if (type.IsAbstract && type.IsSealed) {
5468 Report.SymbolRelatedToPreviousError (type);
5469 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5473 if (type.IsInterface || type.IsAbstract){
5474 if (!TypeManager.IsGenericType (type)) {
5475 RequestedType = CheckComImport (ec);
5476 if (RequestedType != null)
5477 return RequestedType;
5480 Report.SymbolRelatedToPreviousError (type);
5481 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5485 bool is_struct = type.IsValueType;
5486 eclass = ExprClass.Value;
5489 // SRE returns a match for .ctor () on structs (the object constructor),
5490 // so we have to manually ignore it.
5492 if (is_struct && Arguments == null)
5495 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5496 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5497 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5499 if (Arguments != null){
5500 foreach (Argument a in Arguments){
5501 if (!a.Resolve (ec, loc))
5509 method = ml as MethodGroupExpr;
5510 if (method == null) {
5511 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5515 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5522 bool DoEmitTypeParameter (EmitContext ec)
5525 ILGenerator ig = ec.ig;
5526 // IMemoryLocation ml;
5528 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5529 new Type [] { type });
5531 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5532 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5533 ig.Emit (OpCodes.Call, ci);
5537 // Allow DoEmit() to be called multiple times.
5538 // We need to create a new LocalTemporary each time since
5539 // you can't share LocalBuilders among ILGeneators.
5540 LocalTemporary temp = new LocalTemporary (type);
5542 Label label_activator = ig.DefineLabel ();
5543 Label label_end = ig.DefineLabel ();
5545 temp.AddressOf (ec, AddressOp.Store);
5546 ig.Emit (OpCodes.Initobj, type);
5549 ig.Emit (OpCodes.Box, type);
5550 ig.Emit (OpCodes.Brfalse, label_activator);
5552 temp.AddressOf (ec, AddressOp.Store);
5553 ig.Emit (OpCodes.Initobj, type);
5555 ig.Emit (OpCodes.Br, label_end);
5557 ig.MarkLabel (label_activator);
5559 ig.Emit (OpCodes.Call, ci);
5560 ig.MarkLabel (label_end);
5563 throw new InternalErrorException ();
5568 // This DoEmit can be invoked in two contexts:
5569 // * As a mechanism that will leave a value on the stack (new object)
5570 // * As one that wont (init struct)
5572 // You can control whether a value is required on the stack by passing
5573 // need_value_on_stack. The code *might* leave a value on the stack
5574 // so it must be popped manually
5576 // If we are dealing with a ValueType, we have a few
5577 // situations to deal with:
5579 // * The target is a ValueType, and we have been provided
5580 // the instance (this is easy, we are being assigned).
5582 // * The target of New is being passed as an argument,
5583 // to a boxing operation or a function that takes a
5586 // In this case, we need to create a temporary variable
5587 // that is the argument of New.
5589 // Returns whether a value is left on the stack
5591 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5593 bool is_value_type = TypeManager.IsValueType (type);
5594 ILGenerator ig = ec.ig;
5599 // Allow DoEmit() to be called multiple times.
5600 // We need to create a new LocalTemporary each time since
5601 // you can't share LocalBuilders among ILGeneators.
5602 if (!value_target_set)
5603 value_target = new LocalTemporary (type);
5605 ml = (IMemoryLocation) value_target;
5606 ml.AddressOf (ec, AddressOp.Store);
5610 method.EmitArguments (ec, Arguments);
5614 ig.Emit (OpCodes.Initobj, type);
5616 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5617 if (need_value_on_stack){
5618 value_target.Emit (ec);
5623 ConstructorInfo ci = (ConstructorInfo) method;
5625 if (TypeManager.IsGenericType (type))
5626 ci = TypeBuilder.GetConstructor (type, ci);
5628 ig.Emit (OpCodes.Newobj, ci);
5633 public override void Emit (EmitContext ec)
5635 if (is_type_parameter)
5636 DoEmitTypeParameter (ec);
5641 public override void EmitStatement (EmitContext ec)
5643 bool value_on_stack;
5645 if (is_type_parameter)
5646 value_on_stack = DoEmitTypeParameter (ec);
5648 value_on_stack = DoEmit (ec, false);
5651 ec.ig.Emit (OpCodes.Pop);
5655 public virtual bool HasInitializer {
5661 public void AddressOf (EmitContext ec, AddressOp Mode)
5663 if (is_type_parameter) {
5664 LocalTemporary temp = new LocalTemporary (type);
5665 DoEmitTypeParameter (ec);
5667 temp.AddressOf (ec, Mode);
5671 if (!type.IsValueType){
5673 // We throw an exception. So far, I believe we only need to support
5675 // foreach (int j in new StructType ())
5678 throw new Exception ("AddressOf should not be used for classes");
5681 if (!value_target_set)
5682 value_target = new LocalTemporary (type);
5683 IMemoryLocation ml = (IMemoryLocation) value_target;
5685 ml.AddressOf (ec, AddressOp.Store);
5686 if (method == null) {
5687 ec.ig.Emit (OpCodes.Initobj, type);
5689 method.EmitArguments (ec, Arguments);
5690 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5693 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5696 protected override void CloneTo (CloneContext clonectx, Expression t)
5698 New target = (New) t;
5700 target.RequestedType = RequestedType.Clone (clonectx);
5701 if (Arguments != null){
5702 target.Arguments = new ArrayList ();
5703 foreach (Argument a in Arguments){
5704 target.Arguments.Add (a.Clone (clonectx));
5709 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5711 if (method != null) {
5712 method.MutateHoistedGenericType (storey);
5713 if (Arguments != null) {
5714 foreach (Argument a in Arguments)
5715 a.Expr.MutateHoistedGenericType (storey);
5719 type = storey.MutateType (type);
5724 /// 14.5.10.2: Represents an array creation expression.
5728 /// There are two possible scenarios here: one is an array creation
5729 /// expression that specifies the dimensions and optionally the
5730 /// initialization data and the other which does not need dimensions
5731 /// specified but where initialization data is mandatory.
5733 public class ArrayCreation : Expression {
5734 FullNamedExpression requested_base_type;
5735 ArrayList initializers;
5738 // The list of Argument types.
5739 // This is used to construct the `newarray' or constructor signature
5741 protected ArrayList arguments;
5743 protected Type array_element_type;
5744 bool expect_initializers = false;
5745 int num_arguments = 0;
5746 protected int dimensions;
5747 protected readonly string rank;
5749 protected ArrayList array_data;
5753 // The number of constants in array initializers
5754 int const_initializers_count;
5755 bool only_constant_initializers;
5757 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5759 this.requested_base_type = requested_base_type;
5760 this.initializers = initializers;
5764 arguments = new ArrayList (exprs.Count);
5766 foreach (Expression e in exprs) {
5767 arguments.Add (new Argument (e, Argument.AType.Expression));
5772 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5774 this.requested_base_type = requested_base_type;
5775 this.initializers = initializers;
5779 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5781 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5783 //dimensions = tmp.Length - 1;
5784 expect_initializers = true;
5787 void Error_IncorrectArrayInitializer ()
5789 Error (178, "Invalid rank specifier: expected `,' or `]'");
5792 protected override void Error_NegativeArrayIndex (Location loc)
5794 Report.Error (248, loc, "Cannot create an array with a negative size");
5797 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5799 if (specified_dims) {
5800 Argument a = (Argument) arguments [idx];
5802 if (!a.Resolve (ec, loc))
5805 Constant c = a.Expr as Constant;
5807 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5811 Report.Error (150, a.Expr.Location, "A constant value is expected");
5815 int value = (int) c.GetValue ();
5817 if (value != probe.Count) {
5818 Error_IncorrectArrayInitializer ();
5822 bounds [idx] = value;
5825 int child_bounds = -1;
5826 only_constant_initializers = true;
5827 for (int i = 0; i < probe.Count; ++i) {
5828 object o = probe [i];
5829 if (o is ArrayList) {
5830 ArrayList sub_probe = o as ArrayList;
5831 int current_bounds = sub_probe.Count;
5833 if (child_bounds == -1)
5834 child_bounds = current_bounds;
5836 else if (child_bounds != current_bounds){
5837 Error_IncorrectArrayInitializer ();
5840 if (idx + 1 >= dimensions){
5841 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5845 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5849 if (child_bounds != -1){
5850 Error_IncorrectArrayInitializer ();
5854 Expression element = ResolveArrayElement (ec, (Expression) o);
5855 if (element == null)
5858 // Initializers with the default values can be ignored
5859 Constant c = element as Constant;
5861 if (c.IsDefaultInitializer (array_element_type)) {
5865 ++const_initializers_count;
5868 only_constant_initializers = false;
5871 array_data.Add (element);
5878 public override Expression CreateExpressionTree (EmitContext ec)
5882 if (array_data == null) {
5883 args = new ArrayList (arguments.Count + 1);
5884 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5885 foreach (Argument a in arguments) {
5886 if (arguments.Count == 1) {
5887 Constant c = a.Expr as Constant;
5888 if (c.IsDefaultValue)
5889 return CreateExpressionFactoryCall ("NewArrayInit", args);
5891 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5894 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5897 if (dimensions > 1) {
5898 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5902 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5903 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5904 if (array_data != null) {
5905 for (int i = 0; i < array_data.Count; ++i) {
5906 Expression e = (Expression) array_data [i];
5908 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5910 args.Add (new Argument (e.CreateExpressionTree (ec)));
5914 return CreateExpressionFactoryCall ("NewArrayInit", args);
5917 public void UpdateIndices ()
5920 for (ArrayList probe = initializers; probe != null;) {
5921 if (probe.Count > 0 && probe [0] is ArrayList) {
5922 Expression e = new IntConstant (probe.Count, Location.Null);
5923 arguments.Add (new Argument (e, Argument.AType.Expression));
5925 bounds [i++] = probe.Count;
5927 probe = (ArrayList) probe [0];
5930 Expression e = new IntConstant (probe.Count, Location.Null);
5931 arguments.Add (new Argument (e, Argument.AType.Expression));
5933 bounds [i++] = probe.Count;
5940 Expression first_emit;
5941 LocalTemporary first_emit_temp;
5943 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5945 element = element.Resolve (ec);
5946 if (element == null)
5949 if (element is CompoundAssign.Helper) {
5950 if (first_emit != null)
5951 throw new InternalErrorException ("Can only handle one mutator at a time");
5952 first_emit = element;
5953 element = first_emit_temp = new LocalTemporary (element.Type);
5956 return Convert.ImplicitConversionRequired (
5957 ec, element, array_element_type, loc);
5960 protected bool ResolveInitializers (EmitContext ec)
5962 if (initializers == null) {
5963 return !expect_initializers;
5967 // We use this to store all the date values in the order in which we
5968 // will need to store them in the byte blob later
5970 array_data = new ArrayList ();
5971 bounds = new System.Collections.Specialized.HybridDictionary ();
5973 if (arguments != null)
5974 return CheckIndices (ec, initializers, 0, true);
5976 arguments = new ArrayList ();
5978 if (!CheckIndices (ec, initializers, 0, false))
5987 // Resolved the type of the array
5989 bool ResolveArrayType (EmitContext ec)
5991 if (requested_base_type == null) {
5992 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5996 StringBuilder array_qualifier = new StringBuilder (rank);
5999 // `In the first form allocates an array instace of the type that results
6000 // from deleting each of the individual expression from the expression list'
6002 if (num_arguments > 0) {
6003 array_qualifier.Append ("[");
6004 for (int i = num_arguments-1; i > 0; i--)
6005 array_qualifier.Append (",");
6006 array_qualifier.Append ("]");
6012 TypeExpr array_type_expr;
6013 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6014 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6015 if (array_type_expr == null)
6018 type = array_type_expr.Type;
6019 array_element_type = TypeManager.GetElementType (type);
6020 dimensions = type.GetArrayRank ();
6025 public override Expression DoResolve (EmitContext ec)
6030 if (!ResolveArrayType (ec))
6034 // First step is to validate the initializers and fill
6035 // in any missing bits
6037 if (!ResolveInitializers (ec))
6040 if (arguments.Count != dimensions) {
6041 Error_IncorrectArrayInitializer ();
6044 foreach (Argument a in arguments){
6045 if (!a.Resolve (ec, loc))
6048 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6051 eclass = ExprClass.Value;
6055 MethodInfo GetArrayMethod (int arguments)
6057 ModuleBuilder mb = CodeGen.Module.Builder;
6059 Type[] arg_types = new Type[arguments];
6060 for (int i = 0; i < arguments; i++)
6061 arg_types[i] = TypeManager.int32_type;
6063 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6067 Report.Error (-6, "New invocation: Can not find a constructor for " +
6068 "this argument list");
6075 byte [] MakeByteBlob ()
6080 int count = array_data.Count;
6082 if (TypeManager.IsEnumType (array_element_type))
6083 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6085 factor = GetTypeSize (array_element_type);
6087 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6089 data = new byte [(count * factor + 3) & ~3];
6092 for (int i = 0; i < count; ++i) {
6093 object v = array_data [i];
6095 if (v is EnumConstant)
6096 v = ((EnumConstant) v).Child;
6098 if (v is Constant && !(v is StringConstant))
6099 v = ((Constant) v).GetValue ();
6105 if (array_element_type == TypeManager.int64_type){
6106 if (!(v is Expression)){
6107 long val = (long) v;
6109 for (int j = 0; j < factor; ++j) {
6110 data [idx + j] = (byte) (val & 0xFF);
6114 } else if (array_element_type == TypeManager.uint64_type){
6115 if (!(v is Expression)){
6116 ulong val = (ulong) v;
6118 for (int j = 0; j < factor; ++j) {
6119 data [idx + j] = (byte) (val & 0xFF);
6123 } else if (array_element_type == TypeManager.float_type) {
6124 if (!(v is Expression)){
6125 element = BitConverter.GetBytes ((float) v);
6127 for (int j = 0; j < factor; ++j)
6128 data [idx + j] = element [j];
6129 if (!BitConverter.IsLittleEndian)
6130 System.Array.Reverse (data, idx, 4);
6132 } else if (array_element_type == TypeManager.double_type) {
6133 if (!(v is Expression)){
6134 element = BitConverter.GetBytes ((double) v);
6136 for (int j = 0; j < factor; ++j)
6137 data [idx + j] = element [j];
6139 // FIXME: Handle the ARM float format.
6140 if (!BitConverter.IsLittleEndian)
6141 System.Array.Reverse (data, idx, 8);
6143 } else if (array_element_type == TypeManager.char_type){
6144 if (!(v is Expression)){
6145 int val = (int) ((char) v);
6147 data [idx] = (byte) (val & 0xff);
6148 data [idx+1] = (byte) (val >> 8);
6150 } else if (array_element_type == TypeManager.short_type){
6151 if (!(v is Expression)){
6152 int val = (int) ((short) v);
6154 data [idx] = (byte) (val & 0xff);
6155 data [idx+1] = (byte) (val >> 8);
6157 } else if (array_element_type == TypeManager.ushort_type){
6158 if (!(v is Expression)){
6159 int val = (int) ((ushort) v);
6161 data [idx] = (byte) (val & 0xff);
6162 data [idx+1] = (byte) (val >> 8);
6164 } else if (array_element_type == TypeManager.int32_type) {
6165 if (!(v is Expression)){
6168 data [idx] = (byte) (val & 0xff);
6169 data [idx+1] = (byte) ((val >> 8) & 0xff);
6170 data [idx+2] = (byte) ((val >> 16) & 0xff);
6171 data [idx+3] = (byte) (val >> 24);
6173 } else if (array_element_type == TypeManager.uint32_type) {
6174 if (!(v is Expression)){
6175 uint val = (uint) v;
6177 data [idx] = (byte) (val & 0xff);
6178 data [idx+1] = (byte) ((val >> 8) & 0xff);
6179 data [idx+2] = (byte) ((val >> 16) & 0xff);
6180 data [idx+3] = (byte) (val >> 24);
6182 } else if (array_element_type == TypeManager.sbyte_type) {
6183 if (!(v is Expression)){
6184 sbyte val = (sbyte) v;
6185 data [idx] = (byte) val;
6187 } else if (array_element_type == TypeManager.byte_type) {
6188 if (!(v is Expression)){
6189 byte val = (byte) v;
6190 data [idx] = (byte) val;
6192 } else if (array_element_type == TypeManager.bool_type) {
6193 if (!(v is Expression)){
6194 bool val = (bool) v;
6195 data [idx] = (byte) (val ? 1 : 0);
6197 } else if (array_element_type == TypeManager.decimal_type){
6198 if (!(v is Expression)){
6199 int [] bits = Decimal.GetBits ((decimal) v);
6202 // FIXME: For some reason, this doesn't work on the MS runtime.
6203 int [] nbits = new int [4];
6204 nbits [0] = bits [3];
6205 nbits [1] = bits [2];
6206 nbits [2] = bits [0];
6207 nbits [3] = bits [1];
6209 for (int j = 0; j < 4; j++){
6210 data [p++] = (byte) (nbits [j] & 0xff);
6211 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6212 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6213 data [p++] = (byte) (nbits [j] >> 24);
6217 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6225 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6227 array_element_type = storey.MutateType (array_element_type);
6228 type = storey.MutateType (type);
6229 if (arguments != null) {
6230 foreach (Argument a in arguments)
6231 a.Expr.MutateHoistedGenericType (storey);
6234 if (array_data != null) {
6235 foreach (Expression e in array_data)
6236 e.MutateHoistedGenericType (storey);
6241 // Emits the initializers for the array
6243 void EmitStaticInitializers (EmitContext ec)
6245 // FIXME: This should go to Resolve !
6246 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6247 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6248 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6249 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6250 if (TypeManager.void_initializearray_array_fieldhandle == null)
6255 // First, the static data
6258 ILGenerator ig = ec.ig;
6260 byte [] data = MakeByteBlob ();
6262 fb = RootContext.MakeStaticData (data);
6264 ig.Emit (OpCodes.Dup);
6265 ig.Emit (OpCodes.Ldtoken, fb);
6266 ig.Emit (OpCodes.Call,
6267 TypeManager.void_initializearray_array_fieldhandle);
6271 // Emits pieces of the array that can not be computed at compile
6272 // time (variables and string locations).
6274 // This always expect the top value on the stack to be the array
6276 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6278 ILGenerator ig = ec.ig;
6279 int dims = bounds.Count;
6280 int [] current_pos = new int [dims];
6282 MethodInfo set = null;
6285 Type [] args = new Type [dims + 1];
6287 for (int j = 0; j < dims; j++)
6288 args [j] = TypeManager.int32_type;
6289 args [dims] = array_element_type;
6291 set = CodeGen.Module.Builder.GetArrayMethod (
6293 CallingConventions.HasThis | CallingConventions.Standard,
6294 TypeManager.void_type, args);
6297 for (int i = 0; i < array_data.Count; i++){
6299 Expression e = (Expression)array_data [i];
6301 // Constant can be initialized via StaticInitializer
6302 if (e != null && !(!emitConstants && e is Constant)) {
6303 Type etype = e.Type;
6305 ig.Emit (OpCodes.Dup);
6307 for (int idx = 0; idx < dims; idx++)
6308 IntConstant.EmitInt (ig, current_pos [idx]);
6311 // If we are dealing with a struct, get the
6312 // address of it, so we can store it.
6314 if ((dims == 1) && etype.IsValueType &&
6315 (!TypeManager.IsBuiltinOrEnum (etype) ||
6316 etype == TypeManager.decimal_type)) {
6321 // Let new know that we are providing
6322 // the address where to store the results
6324 n.DisableTemporaryValueType ();
6327 ig.Emit (OpCodes.Ldelema, etype);
6333 bool is_stobj, has_type_arg;
6334 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6336 ig.Emit (OpCodes.Stobj, etype);
6337 else if (has_type_arg)
6338 ig.Emit (op, etype);
6342 ig.Emit (OpCodes.Call, set);
6349 for (int j = dims - 1; j >= 0; j--){
6351 if (current_pos [j] < (int) bounds [j])
6353 current_pos [j] = 0;
6358 public override void Emit (EmitContext ec)
6360 ILGenerator ig = ec.ig;
6362 if (first_emit != null) {
6363 first_emit.Emit (ec);
6364 first_emit_temp.Store (ec);
6367 foreach (Argument a in arguments)
6370 if (arguments.Count == 1)
6371 ig.Emit (OpCodes.Newarr, array_element_type);
6373 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6376 if (initializers == null)
6379 // Emit static initializer for arrays which have contain more than 4 items and
6380 // the static initializer will initialize at least 25% of array values.
6381 // NOTE: const_initializers_count does not contain default constant values.
6382 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6383 TypeManager.IsPrimitiveType (array_element_type)) {
6384 EmitStaticInitializers (ec);
6386 if (!only_constant_initializers)
6387 EmitDynamicInitializers (ec, false);
6389 EmitDynamicInitializers (ec, true);
6392 if (first_emit_temp != null)
6393 first_emit_temp.Release (ec);
6396 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6398 if (arguments.Count != 1) {
6399 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6400 return base.GetAttributableValue (ec, null, out value);
6403 if (array_data == null) {
6404 Constant c = (Constant)((Argument)arguments [0]).Expr;
6405 if (c.IsDefaultValue) {
6406 value = Array.CreateInstance (array_element_type, 0);
6409 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6410 return base.GetAttributableValue (ec, null, out value);
6413 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6414 object element_value;
6415 for (int i = 0; i < ret.Length; ++i)
6417 Expression e = (Expression)array_data [i];
6419 // Is null when an initializer is optimized (value == predefined value)
6423 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6427 ret.SetValue (element_value, i);
6433 protected override void CloneTo (CloneContext clonectx, Expression t)
6435 ArrayCreation target = (ArrayCreation) t;
6437 if (requested_base_type != null)
6438 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6440 if (arguments != null){
6441 target.arguments = new ArrayList (arguments.Count);
6442 foreach (Argument a in arguments)
6443 target.arguments.Add (a.Clone (clonectx));
6446 if (initializers != null){
6447 target.initializers = new ArrayList (initializers.Count);
6448 foreach (object initializer in initializers)
6449 if (initializer is ArrayList) {
6450 ArrayList this_al = (ArrayList)initializer;
6451 ArrayList al = new ArrayList (this_al.Count);
6452 target.initializers.Add (al);
6453 foreach (Expression e in this_al)
6454 al.Add (e.Clone (clonectx));
6456 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6463 // Represents an implicitly typed array epxression
6465 public class ImplicitlyTypedArrayCreation : ArrayCreation
6467 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6468 : base (null, rank, initializers, loc)
6470 if (RootContext.Version <= LanguageVersion.ISO_2)
6471 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6473 if (rank.Length > 2) {
6474 while (rank [++dimensions] == ',');
6480 public override Expression DoResolve (EmitContext ec)
6485 if (!ResolveInitializers (ec))
6488 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6489 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6490 arguments.Count != dimensions) {
6491 Error_NoBestType ();
6496 // At this point we found common base type for all initializer elements
6497 // but we have to be sure that all static initializer elements are of
6500 UnifyInitializerElement (ec);
6502 type = TypeManager.GetConstructedType (array_element_type, rank);
6503 eclass = ExprClass.Value;
6507 void Error_NoBestType ()
6509 Report.Error (826, loc,
6510 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6514 // Converts static initializer only
6516 void UnifyInitializerElement (EmitContext ec)
6518 for (int i = 0; i < array_data.Count; ++i) {
6519 Expression e = (Expression)array_data[i];
6521 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6525 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6527 element = element.Resolve (ec);
6528 if (element == null)
6531 if (array_element_type == null) {
6532 array_element_type = element.Type;
6536 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6540 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6541 array_element_type = element.Type;
6545 Error_NoBestType ();
6550 public sealed class CompilerGeneratedThis : This
6552 public static This Instance = new CompilerGeneratedThis ();
6554 private CompilerGeneratedThis ()
6555 : base (Location.Null)
6559 public CompilerGeneratedThis (Type type, Location loc)
6565 public override Expression DoResolve (EmitContext ec)
6567 eclass = ExprClass.Variable;
6569 type = ec.ContainerType;
6573 public override HoistedVariable HoistedVariable {
6574 get { return null; }
6579 /// Represents the `this' construct
6582 public class This : VariableReference
6584 sealed class ThisVariable : ILocalVariable
6586 public static readonly ILocalVariable Instance = new ThisVariable ();
6588 public void Emit (EmitContext ec)
6590 ec.ig.Emit (OpCodes.Ldarg_0);
6593 public void EmitAssign (EmitContext ec)
6595 throw new InvalidOperationException ();
6598 public void EmitAddressOf (EmitContext ec)
6600 ec.ig.Emit (OpCodes.Ldarg_0);
6605 VariableInfo variable_info;
6608 public This (Block block, Location loc)
6614 public This (Location loc)
6619 public override VariableInfo VariableInfo {
6620 get { return variable_info; }
6623 public override bool IsFixedVariable {
6624 get { return !TypeManager.IsValueType (type); }
6627 protected override bool IsHoistedEmitRequired (EmitContext ec)
6630 // Handle 'this' differently, it cannot be assigned hence
6631 // when we are not inside anonymous method we can emit direct access
6633 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6636 public override HoistedVariable HoistedVariable {
6637 get { return TopToplevelBlock.HoistedThisVariable; }
6640 public override bool IsRef {
6641 get { return is_struct; }
6644 protected override ILocalVariable Variable {
6645 get { return ThisVariable.Instance; }
6648 // TODO: Move to ToplevelBlock
6649 ToplevelBlock TopToplevelBlock {
6651 ToplevelBlock tl = block.Toplevel;
6652 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6657 public static bool IsThisAvailable (EmitContext ec)
6659 if (ec.IsStatic || ec.IsInFieldInitializer)
6662 if (ec.CurrentAnonymousMethod == null)
6665 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6671 public bool ResolveBase (EmitContext ec)
6673 if (eclass != ExprClass.Invalid)
6676 eclass = ExprClass.Variable;
6678 if (ec.TypeContainer.CurrentType != null)
6679 type = ec.TypeContainer.CurrentType;
6681 type = ec.ContainerType;
6683 if (!IsThisAvailable (ec)) {
6685 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6687 Report.Error (1673, loc,
6688 "Anonymous methods inside structs cannot access instance members of `this'. " +
6689 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6693 is_struct = ec.TypeContainer is Struct;
6695 if (block != null) {
6696 if (block.Toplevel.ThisVariable != null)
6697 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6699 AnonymousExpression am = ec.CurrentAnonymousMethod;
6702 // this is hoisted to very top level block
6704 if (ec.IsVariableCapturingRequired) {
6705 // TODO: it could be optimized
6706 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6707 if (HoistedVariable == null) {
6708 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6718 // Called from Invocation to check if the invocation is correct
6720 public override void CheckMarshalByRefAccess (EmitContext ec)
6722 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6723 !variable_info.IsAssigned (ec)) {
6724 Error (188, "The `this' object cannot be used before all of its " +
6725 "fields are assigned to");
6726 variable_info.SetAssigned (ec);
6730 public override Expression CreateExpressionTree (EmitContext ec)
6732 ArrayList args = new ArrayList (2);
6733 args.Add (new Argument (this));
6734 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6735 return CreateExpressionFactoryCall ("Constant", args);
6738 public override Expression DoResolve (EmitContext ec)
6740 if (!ResolveBase (ec))
6744 if (ec.IsInFieldInitializer) {
6745 Error (27, "Keyword `this' is not available in the current context");
6752 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6754 if (!ResolveBase (ec))
6757 if (variable_info != null)
6758 variable_info.SetAssigned (ec);
6760 if (ec.TypeContainer is Class){
6761 if (right_side == EmptyExpression.UnaryAddress)
6762 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6763 else if (right_side == EmptyExpression.OutAccess)
6764 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6766 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6772 public override int GetHashCode()
6774 return block.GetHashCode ();
6777 public override string Name {
6778 get { return "this"; }
6781 public override bool Equals (object obj)
6783 This t = obj as This;
6787 return block == t.block;
6790 protected override void CloneTo (CloneContext clonectx, Expression t)
6792 This target = (This) t;
6794 target.block = clonectx.LookupBlock (block);
6797 public void RemoveHoisting ()
6799 TopToplevelBlock.HoistedThisVariable = null;
6802 public override void SetHasAddressTaken ()
6809 /// Represents the `__arglist' construct
6811 public class ArglistAccess : Expression
6813 public ArglistAccess (Location loc)
6818 public override Expression CreateExpressionTree (EmitContext ec)
6820 throw new NotSupportedException ("ET");
6823 public override Expression DoResolve (EmitContext ec)
6825 eclass = ExprClass.Variable;
6826 type = TypeManager.runtime_argument_handle_type;
6828 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6830 Error (190, "The __arglist construct is valid only within " +
6831 "a variable argument method");
6838 public override void Emit (EmitContext ec)
6840 ec.ig.Emit (OpCodes.Arglist);
6843 protected override void CloneTo (CloneContext clonectx, Expression target)
6850 /// Represents the `__arglist (....)' construct
6852 public class Arglist : Expression
6854 Argument[] Arguments;
6856 public Arglist (Location loc)
6857 : this (Argument.Empty, loc)
6861 public Arglist (Argument[] args, Location l)
6867 public Type[] ArgumentTypes {
6869 Type[] retval = new Type [Arguments.Length];
6870 for (int i = 0; i < Arguments.Length; i++)
6871 retval [i] = Arguments [i].Type;
6876 public override Expression CreateExpressionTree (EmitContext ec)
6878 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6882 public override Expression DoResolve (EmitContext ec)
6884 eclass = ExprClass.Variable;
6885 type = TypeManager.runtime_argument_handle_type;
6887 foreach (Argument arg in Arguments) {
6888 if (!arg.Resolve (ec, loc))
6895 public override void Emit (EmitContext ec)
6897 foreach (Argument arg in Arguments)
6901 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6903 foreach (Argument arg in Arguments)
6904 arg.Expr.MutateHoistedGenericType (storey);
6907 protected override void CloneTo (CloneContext clonectx, Expression t)
6909 Arglist target = (Arglist) t;
6911 target.Arguments = new Argument [Arguments.Length];
6912 for (int i = 0; i < Arguments.Length; i++)
6913 target.Arguments [i] = Arguments [i].Clone (clonectx);
6918 /// Implements the typeof operator
6920 public class TypeOf : Expression {
6921 Expression QueriedType;
6922 protected Type typearg;
6924 public TypeOf (Expression queried_type, Location l)
6926 QueriedType = queried_type;
6930 public override Expression CreateExpressionTree (EmitContext ec)
6932 ArrayList args = new ArrayList (2);
6933 args.Add (new Argument (this));
6934 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6935 return CreateExpressionFactoryCall ("Constant", args);
6938 public override Expression DoResolve (EmitContext ec)
6940 if (eclass != ExprClass.Invalid)
6943 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6947 typearg = texpr.Type;
6949 if (typearg == TypeManager.void_type) {
6950 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6954 if (typearg.IsPointer && !ec.InUnsafe){
6959 type = TypeManager.type_type;
6961 return DoResolveBase ();
6964 protected Expression DoResolveBase ()
6966 if (TypeManager.system_type_get_type_from_handle == null) {
6967 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6968 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6971 // Even though what is returned is a type object, it's treated as a value by the compiler.
6972 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6973 eclass = ExprClass.Value;
6977 public override void Emit (EmitContext ec)
6979 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6980 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6983 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6985 if (TypeManager.ContainsGenericParameters (typearg) &&
6986 !TypeManager.IsGenericTypeDefinition (typearg)) {
6987 Report.SymbolRelatedToPreviousError (typearg);
6988 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6989 TypeManager.CSharpName (typearg));
6994 if (value_type == TypeManager.object_type) {
6995 value = (object)typearg;
7002 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7004 typearg = storey.MutateType (typearg);
7007 public Type TypeArgument {
7013 protected override void CloneTo (CloneContext clonectx, Expression t)
7015 TypeOf target = (TypeOf) t;
7016 if (QueriedType != null)
7017 target.QueriedType = QueriedType.Clone (clonectx);
7022 /// Implements the `typeof (void)' operator
7024 public class TypeOfVoid : TypeOf {
7025 public TypeOfVoid (Location l) : base (null, l)
7030 public override Expression DoResolve (EmitContext ec)
7032 type = TypeManager.type_type;
7033 typearg = TypeManager.void_type;
7035 return DoResolveBase ();
7039 class TypeOfMethodInfo : TypeOfMethod
7041 public TypeOfMethodInfo (MethodBase method, Location loc)
7042 : base (method, loc)
7046 public override Expression DoResolve (EmitContext ec)
7048 type = typeof (MethodInfo);
7049 return base.DoResolve (ec);
7052 public override void Emit (EmitContext ec)
7054 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7056 ec.ig.Emit (OpCodes.Castclass, type);
7060 class TypeOfConstructorInfo : TypeOfMethod
7062 public TypeOfConstructorInfo (MethodBase method, Location loc)
7063 : base (method, loc)
7067 public override Expression DoResolve (EmitContext ec)
7069 type = typeof (ConstructorInfo);
7070 return base.DoResolve (ec);
7073 public override void Emit (EmitContext ec)
7075 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7077 ec.ig.Emit (OpCodes.Castclass, type);
7081 abstract class TypeOfMethod : Expression
7083 protected readonly MethodBase method;
7085 protected TypeOfMethod (MethodBase method, Location loc)
7087 this.method = method;
7091 public override Expression CreateExpressionTree (EmitContext ec)
7093 ArrayList args = new ArrayList (2);
7094 args.Add (new Argument (this));
7095 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7096 return CreateExpressionFactoryCall ("Constant", args);
7099 public override Expression DoResolve (EmitContext ec)
7101 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7102 MethodInfo mi = is_generic ?
7103 TypeManager.methodbase_get_type_from_handle_generic :
7104 TypeManager.methodbase_get_type_from_handle;
7107 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7108 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7110 if (t == null || handle_type == null)
7113 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7115 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7116 new Type[] { handle_type } );
7119 TypeManager.methodbase_get_type_from_handle_generic = mi;
7121 TypeManager.methodbase_get_type_from_handle = mi;
7124 eclass = ExprClass.Value;
7128 public override void Emit (EmitContext ec)
7130 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7133 mi = TypeManager.methodbase_get_type_from_handle_generic;
7134 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7136 mi = TypeManager.methodbase_get_type_from_handle;
7139 ec.ig.Emit (OpCodes.Call, mi);
7143 internal class TypeOfField : Expression
7145 readonly FieldInfo field;
7147 public TypeOfField (FieldInfo field, Location loc)
7153 public override Expression CreateExpressionTree (EmitContext ec)
7155 throw new NotSupportedException ("ET");
7158 public override Expression DoResolve (EmitContext ec)
7160 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7161 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7162 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7164 if (t != null && handle_type != null)
7165 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7166 "GetFieldFromHandle", loc, handle_type);
7169 type = typeof (FieldInfo);
7170 eclass = ExprClass.Value;
7174 public override void Emit (EmitContext ec)
7176 ec.ig.Emit (OpCodes.Ldtoken, field);
7177 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7182 /// Implements the sizeof expression
7184 public class SizeOf : Expression {
7185 readonly Expression QueriedType;
7188 public SizeOf (Expression queried_type, Location l)
7190 this.QueriedType = queried_type;
7194 public override Expression CreateExpressionTree (EmitContext ec)
7196 Error_PointerInsideExpressionTree ();
7200 public override Expression DoResolve (EmitContext ec)
7202 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7206 type_queried = texpr.Type;
7207 if (TypeManager.IsEnumType (type_queried))
7208 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7210 if (type_queried == TypeManager.void_type) {
7211 Expression.Error_VoidInvalidInTheContext (loc);
7215 int size_of = GetTypeSize (type_queried);
7217 return new IntConstant (size_of, loc);
7220 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7225 Report.Error (233, loc,
7226 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7227 TypeManager.CSharpName (type_queried));
7230 type = TypeManager.int32_type;
7231 eclass = ExprClass.Value;
7235 public override void Emit (EmitContext ec)
7237 int size = GetTypeSize (type_queried);
7240 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7242 IntConstant.EmitInt (ec.ig, size);
7245 protected override void CloneTo (CloneContext clonectx, Expression t)
7251 /// Implements the qualified-alias-member (::) expression.
7253 public class QualifiedAliasMember : MemberAccess
7255 readonly string alias;
7256 public static readonly string GlobalAlias = "global";
7258 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7259 : base (null, identifier, targs, l)
7264 public QualifiedAliasMember (string alias, string identifier, Location l)
7265 : base (null, identifier, l)
7270 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7272 if (alias == GlobalAlias) {
7273 expr = RootNamespace.Global;
7274 return base.ResolveAsTypeStep (ec, silent);
7277 int errors = Report.Errors;
7278 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7280 if (errors == Report.Errors)
7281 Report.Error (432, loc, "Alias `{0}' not found", alias);
7285 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7289 if (expr.eclass == ExprClass.Type) {
7291 Report.Error (431, loc,
7292 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7300 public override Expression DoResolve (EmitContext ec)
7302 return ResolveAsTypeStep (ec, false);
7305 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7307 Report.Error (687, loc,
7308 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7309 GetSignatureForError ());
7312 public override string GetSignatureForError ()
7315 if (targs != null) {
7316 name = TypeManager.RemoveGenericArity (Name) + "<" +
7317 targs.GetSignatureForError () + ">";
7320 return alias + "::" + name;
7323 protected override void CloneTo (CloneContext clonectx, Expression t)
7330 /// Implements the member access expression
7332 public class MemberAccess : ATypeNameExpression {
7333 protected Expression expr;
7335 public MemberAccess (Expression expr, string id)
7336 : base (id, expr.Location)
7341 public MemberAccess (Expression expr, string identifier, Location loc)
7342 : base (identifier, loc)
7347 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7348 : base (identifier, args, loc)
7353 // TODO: this method has very poor performace for Enum fields and
7354 // probably for other constants as well
7355 Expression DoResolve (EmitContext ec, Expression right_side)
7358 throw new Exception ();
7361 // Resolve the expression with flow analysis turned off, we'll do the definite
7362 // assignment checks later. This is because we don't know yet what the expression
7363 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7364 // definite assignment check on the actual field and not on the whole struct.
7367 SimpleName original = expr as SimpleName;
7368 Expression expr_resolved = expr.Resolve (ec,
7369 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7370 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7372 if (expr_resolved == null)
7375 string LookupIdentifier = MemberName.MakeName (Name, targs);
7377 if (expr_resolved is Namespace) {
7378 Namespace ns = (Namespace) expr_resolved;
7379 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7381 if ((retval != null) && (targs != null))
7382 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7386 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7390 Type expr_type = expr_resolved.Type;
7391 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7392 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7393 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7397 Constant c = expr_resolved as Constant;
7398 if (c != null && c.GetValue () == null) {
7399 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7400 "System.NullReferenceException");
7403 if (targs != null) {
7404 if (!targs.Resolve (ec))
7408 Expression member_lookup;
7409 member_lookup = MemberLookup (
7410 ec.ContainerType, expr_type, expr_type, Name, loc);
7412 if ((member_lookup == null) && (targs != null)) {
7413 member_lookup = MemberLookup (
7414 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7417 if (member_lookup == null) {
7418 ExprClass expr_eclass = expr_resolved.eclass;
7421 // Extension methods are not allowed on all expression types
7423 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7424 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7425 expr_eclass == ExprClass.EventAccess) {
7426 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7427 if (ex_method_lookup != null) {
7428 ex_method_lookup.ExtensionExpression = expr_resolved;
7430 if (targs != null) {
7431 ex_method_lookup.SetTypeArguments (targs);
7434 return ex_method_lookup.DoResolve (ec);
7438 expr = expr_resolved;
7439 Error_MemberLookupFailed (
7440 ec.ContainerType, expr_type, expr_type, Name, null,
7441 AllMemberTypes, AllBindingFlags);
7445 TypeExpr texpr = member_lookup as TypeExpr;
7446 if (texpr != null) {
7447 if (!(expr_resolved is TypeExpr) &&
7448 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7449 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7450 Name, member_lookup.GetSignatureForError ());
7454 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7455 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7456 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7461 ConstructedType ct = expr_resolved as ConstructedType;
7464 // When looking up a nested type in a generic instance
7465 // via reflection, we always get a generic type definition
7466 // and not a generic instance - so we have to do this here.
7468 // See gtest-172-lib.cs and gtest-172.cs for an example.
7470 ct = new ConstructedType (
7471 member_lookup.Type, ct.TypeArguments, loc);
7473 return ct.ResolveAsTypeStep (ec, false);
7476 return member_lookup;
7479 MemberExpr me = (MemberExpr) member_lookup;
7480 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7484 if (targs != null) {
7485 me.SetTypeArguments (targs);
7488 if (original != null && !TypeManager.IsValueType (expr_type)) {
7489 if (me.IsInstance) {
7490 LocalVariableReference var = expr_resolved as LocalVariableReference;
7491 if (var != null && !var.VerifyAssigned (ec))
7496 // The following DoResolve/DoResolveLValue will do the definite assignment
7499 if (right_side != null)
7500 return me.DoResolveLValue (ec, right_side);
7502 return me.DoResolve (ec);
7505 public override Expression DoResolve (EmitContext ec)
7507 return DoResolve (ec, null);
7510 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7512 return DoResolve (ec, right_side);
7515 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7517 return ResolveNamespaceOrType (ec, silent);
7520 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7522 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7524 if (new_expr == null)
7527 string LookupIdentifier = MemberName.MakeName (Name, targs);
7529 if (new_expr is Namespace) {
7530 Namespace ns = (Namespace) new_expr;
7531 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7533 if ((retval != null) && (targs != null))
7534 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7536 if (!silent && retval == null)
7537 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7541 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7542 if (tnew_expr == null)
7545 Type expr_type = tnew_expr.Type;
7547 if (expr_type.IsPointer){
7548 Error (23, "The `.' operator can not be applied to pointer operands (" +
7549 TypeManager.CSharpName (expr_type) + ")");
7553 Expression member_lookup = MemberLookup (
7554 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7555 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7556 if (member_lookup == null) {
7560 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7564 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7569 TypeArguments the_args = targs;
7570 Type declaring_type = texpr.Type.DeclaringType;
7571 if (TypeManager.HasGenericArguments (declaring_type)) {
7572 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7573 expr_type = expr_type.BaseType;
7576 TypeArguments new_args = new TypeArguments (loc);
7577 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7578 new_args.Add (new TypeExpression (decl, loc));
7581 new_args.Add (targs);
7583 the_args = new_args;
7586 if (the_args != null) {
7587 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7588 return ctype.ResolveAsTypeStep (rc, false);
7595 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7597 Expression member_lookup = MemberLookup (
7598 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7599 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7601 if (member_lookup != null) {
7602 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7603 if (expr_type == null)
7606 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7610 member_lookup = MemberLookup (
7611 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7612 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7614 if (member_lookup == null) {
7615 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7616 Name, expr_type.GetSignatureForError ());
7618 // TODO: Report.SymbolRelatedToPreviousError
7619 member_lookup.Error_UnexpectedKind (null, "type", loc);
7623 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7625 if (RootContext.Version > LanguageVersion.ISO_2 &&
7626 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7627 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7628 "extension method `{1}' of type `{0}' could be found " +
7629 "(are you missing a using directive or an assembly reference?)",
7630 TypeManager.CSharpName (type), name);
7634 base.Error_TypeDoesNotContainDefinition (type, name);
7637 public override string GetSignatureForError ()
7639 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7642 protected override void CloneTo (CloneContext clonectx, Expression t)
7644 MemberAccess target = (MemberAccess) t;
7646 target.expr = expr.Clone (clonectx);
7651 /// Implements checked expressions
7653 public class CheckedExpr : Expression {
7655 public Expression Expr;
7657 public CheckedExpr (Expression e, Location l)
7663 public override Expression CreateExpressionTree (EmitContext ec)
7665 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7666 return Expr.CreateExpressionTree (ec);
7669 public override Expression DoResolve (EmitContext ec)
7671 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7672 Expr = Expr.Resolve (ec);
7677 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7680 eclass = Expr.eclass;
7685 public override void Emit (EmitContext ec)
7687 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7691 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7693 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7694 Expr.EmitBranchable (ec, target, on_true);
7697 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7699 Expr.MutateHoistedGenericType (storey);
7702 protected override void CloneTo (CloneContext clonectx, Expression t)
7704 CheckedExpr target = (CheckedExpr) t;
7706 target.Expr = Expr.Clone (clonectx);
7711 /// Implements the unchecked expression
7713 public class UnCheckedExpr : Expression {
7715 public Expression Expr;
7717 public UnCheckedExpr (Expression e, Location l)
7723 public override Expression CreateExpressionTree (EmitContext ec)
7725 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7726 return Expr.CreateExpressionTree (ec);
7729 public override Expression DoResolve (EmitContext ec)
7731 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7732 Expr = Expr.Resolve (ec);
7737 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7740 eclass = Expr.eclass;
7745 public override void Emit (EmitContext ec)
7747 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7751 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7753 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7754 Expr.EmitBranchable (ec, target, on_true);
7757 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7759 Expr.MutateHoistedGenericType (storey);
7762 protected override void CloneTo (CloneContext clonectx, Expression t)
7764 UnCheckedExpr target = (UnCheckedExpr) t;
7766 target.Expr = Expr.Clone (clonectx);
7771 /// An Element Access expression.
7773 /// During semantic analysis these are transformed into
7774 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7776 public class ElementAccess : Expression {
7777 public ArrayList Arguments;
7778 public Expression Expr;
7780 public ElementAccess (Expression e, ArrayList e_list)
7788 Arguments = new ArrayList (e_list.Count);
7789 foreach (Expression tmp in e_list)
7790 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7793 bool CommonResolve (EmitContext ec)
7795 Expr = Expr.Resolve (ec);
7797 if (Arguments == null)
7800 foreach (Argument a in Arguments){
7801 if (!a.Resolve (ec, loc))
7805 return Expr != null;
7808 public override Expression CreateExpressionTree (EmitContext ec)
7810 ArrayList args = new ArrayList (Arguments.Count + 1);
7811 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7812 foreach (Argument a in Arguments)
7813 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7815 return CreateExpressionFactoryCall ("ArrayIndex", args);
7818 Expression MakePointerAccess (EmitContext ec, Type t)
7820 if (Arguments.Count != 1){
7821 Error (196, "A pointer must be indexed by only one value");
7825 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7828 return new Indirection (p, loc).Resolve (ec);
7831 public override Expression DoResolve (EmitContext ec)
7833 if (!CommonResolve (ec))
7837 // We perform some simple tests, and then to "split" the emit and store
7838 // code we create an instance of a different class, and return that.
7840 // I am experimenting with this pattern.
7844 if (t == TypeManager.array_type){
7845 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7850 return (new ArrayAccess (this, loc)).Resolve (ec);
7852 return MakePointerAccess (ec, t);
7854 FieldExpr fe = Expr as FieldExpr;
7856 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7858 return MakePointerAccess (ec, ff.ElementType);
7861 return (new IndexerAccess (this, loc)).Resolve (ec);
7864 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7866 if (!CommonResolve (ec))
7871 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7874 return MakePointerAccess (ec, type);
7876 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7877 Error_CannotModifyIntermediateExpressionValue (ec);
7879 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7882 public override void Emit (EmitContext ec)
7884 throw new Exception ("Should never be reached");
7887 public override string GetSignatureForError ()
7889 return Expr.GetSignatureForError ();
7892 protected override void CloneTo (CloneContext clonectx, Expression t)
7894 ElementAccess target = (ElementAccess) t;
7896 target.Expr = Expr.Clone (clonectx);
7897 target.Arguments = new ArrayList (Arguments.Count);
7898 foreach (Argument a in Arguments)
7899 target.Arguments.Add (a.Clone (clonectx));
7904 /// Implements array access
7906 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7908 // Points to our "data" repository
7912 LocalTemporary temp;
7916 public ArrayAccess (ElementAccess ea_data, Location l)
7922 public override Expression CreateExpressionTree (EmitContext ec)
7924 return ea.CreateExpressionTree (ec);
7927 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7929 return DoResolve (ec);
7932 public override Expression DoResolve (EmitContext ec)
7935 ExprClass eclass = ea.Expr.eclass;
7937 // As long as the type is valid
7938 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7939 eclass == ExprClass.Value)) {
7940 ea.Expr.Error_UnexpectedKind ("variable or value");
7945 if (eclass != ExprClass.Invalid)
7948 Type t = ea.Expr.Type;
7949 int rank = ea.Arguments.Count;
7950 if (t.GetArrayRank () != rank) {
7951 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7952 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7956 type = TypeManager.GetElementType (t);
7957 if (type.IsPointer && !ec.InUnsafe) {
7958 UnsafeError (ea.Location);
7962 foreach (Argument a in ea.Arguments) {
7963 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7966 eclass = ExprClass.Variable;
7972 /// Emits the right opcode to load an object of Type `t'
7973 /// from an array of T
7975 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7978 MethodInfo get = FetchGetMethod ();
7979 ig.Emit (OpCodes.Call, get);
7983 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7984 ig.Emit (OpCodes.Ldelem_U1);
7985 else if (type == TypeManager.sbyte_type)
7986 ig.Emit (OpCodes.Ldelem_I1);
7987 else if (type == TypeManager.short_type)
7988 ig.Emit (OpCodes.Ldelem_I2);
7989 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7990 ig.Emit (OpCodes.Ldelem_U2);
7991 else if (type == TypeManager.int32_type)
7992 ig.Emit (OpCodes.Ldelem_I4);
7993 else if (type == TypeManager.uint32_type)
7994 ig.Emit (OpCodes.Ldelem_U4);
7995 else if (type == TypeManager.uint64_type)
7996 ig.Emit (OpCodes.Ldelem_I8);
7997 else if (type == TypeManager.int64_type)
7998 ig.Emit (OpCodes.Ldelem_I8);
7999 else if (type == TypeManager.float_type)
8000 ig.Emit (OpCodes.Ldelem_R4);
8001 else if (type == TypeManager.double_type)
8002 ig.Emit (OpCodes.Ldelem_R8);
8003 else if (type == TypeManager.intptr_type)
8004 ig.Emit (OpCodes.Ldelem_I);
8005 else if (TypeManager.IsEnumType (type)){
8006 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8007 } else if (type.IsValueType){
8008 ig.Emit (OpCodes.Ldelema, type);
8009 ig.Emit (OpCodes.Ldobj, type);
8011 } else if (type.IsGenericParameter) {
8012 ig.Emit (OpCodes.Ldelem, type);
8014 } else if (type.IsPointer)
8015 ig.Emit (OpCodes.Ldelem_I);
8017 ig.Emit (OpCodes.Ldelem_Ref);
8020 protected override void Error_NegativeArrayIndex (Location loc)
8022 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8026 /// Returns the right opcode to store an object of Type `t'
8027 /// from an array of T.
8029 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8031 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8032 has_type_arg = false; is_stobj = false;
8033 t = TypeManager.TypeToCoreType (t);
8034 if (TypeManager.IsEnumType (t))
8035 t = TypeManager.GetEnumUnderlyingType (t);
8036 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8037 t == TypeManager.bool_type)
8038 return OpCodes.Stelem_I1;
8039 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8040 t == TypeManager.char_type)
8041 return OpCodes.Stelem_I2;
8042 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8043 return OpCodes.Stelem_I4;
8044 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8045 return OpCodes.Stelem_I8;
8046 else if (t == TypeManager.float_type)
8047 return OpCodes.Stelem_R4;
8048 else if (t == TypeManager.double_type)
8049 return OpCodes.Stelem_R8;
8050 else if (t == TypeManager.intptr_type) {
8051 has_type_arg = true;
8053 return OpCodes.Stobj;
8054 } else if (t.IsValueType) {
8055 has_type_arg = true;
8057 return OpCodes.Stobj;
8059 } else if (t.IsGenericParameter) {
8060 has_type_arg = true;
8061 return OpCodes.Stelem;
8064 } else if (t.IsPointer)
8065 return OpCodes.Stelem_I;
8067 return OpCodes.Stelem_Ref;
8070 MethodInfo FetchGetMethod ()
8072 ModuleBuilder mb = CodeGen.Module.Builder;
8073 int arg_count = ea.Arguments.Count;
8074 Type [] args = new Type [arg_count];
8077 for (int i = 0; i < arg_count; i++){
8078 //args [i++] = a.Type;
8079 args [i] = TypeManager.int32_type;
8082 get = mb.GetArrayMethod (
8083 ea.Expr.Type, "Get",
8084 CallingConventions.HasThis |
8085 CallingConventions.Standard,
8091 MethodInfo FetchAddressMethod ()
8093 ModuleBuilder mb = CodeGen.Module.Builder;
8094 int arg_count = ea.Arguments.Count;
8095 Type [] args = new Type [arg_count];
8099 ret_type = TypeManager.GetReferenceType (type);
8101 for (int i = 0; i < arg_count; i++){
8102 //args [i++] = a.Type;
8103 args [i] = TypeManager.int32_type;
8106 address = mb.GetArrayMethod (
8107 ea.Expr.Type, "Address",
8108 CallingConventions.HasThis |
8109 CallingConventions.Standard,
8116 // Load the array arguments into the stack.
8118 void LoadArrayAndArguments (EmitContext ec)
8122 for (int i = 0; i < ea.Arguments.Count; ++i) {
8123 ((Argument)ea.Arguments [i]).Emit (ec);
8127 public void Emit (EmitContext ec, bool leave_copy)
8129 int rank = ea.Expr.Type.GetArrayRank ();
8130 ILGenerator ig = ec.ig;
8133 LoadFromPtr (ig, this.type);
8135 LoadArrayAndArguments (ec);
8136 EmitLoadOpcode (ig, type, rank);
8140 ig.Emit (OpCodes.Dup);
8141 temp = new LocalTemporary (this.type);
8146 public override void Emit (EmitContext ec)
8151 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8153 int rank = ea.Expr.Type.GetArrayRank ();
8154 ILGenerator ig = ec.ig;
8155 Type t = source.Type;
8156 prepared = prepare_for_load;
8159 AddressOf (ec, AddressOp.LoadStore);
8160 ec.ig.Emit (OpCodes.Dup);
8162 LoadArrayAndArguments (ec);
8166 bool is_stobj, has_type_arg;
8167 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8171 // The stobj opcode used by value types will need
8172 // an address on the stack, not really an array/array
8176 ig.Emit (OpCodes.Ldelema, t);
8181 ec.ig.Emit (OpCodes.Dup);
8182 temp = new LocalTemporary (this.type);
8187 StoreFromPtr (ig, t);
8189 ig.Emit (OpCodes.Stobj, t);
8190 else if (has_type_arg)
8197 ec.ig.Emit (OpCodes.Dup);
8198 temp = new LocalTemporary (this.type);
8203 StoreFromPtr (ig, t);
8205 int arg_count = ea.Arguments.Count;
8206 Type [] args = new Type [arg_count + 1];
8207 for (int i = 0; i < arg_count; i++) {
8208 //args [i++] = a.Type;
8209 args [i] = TypeManager.int32_type;
8211 args [arg_count] = type;
8213 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8214 ea.Expr.Type, "Set",
8215 CallingConventions.HasThis |
8216 CallingConventions.Standard,
8217 TypeManager.void_type, args);
8219 ig.Emit (OpCodes.Call, set);
8229 public void AddressOf (EmitContext ec, AddressOp mode)
8231 int rank = ea.Expr.Type.GetArrayRank ();
8232 ILGenerator ig = ec.ig;
8234 LoadArrayAndArguments (ec);
8237 ig.Emit (OpCodes.Ldelema, type);
8239 MethodInfo address = FetchAddressMethod ();
8240 ig.Emit (OpCodes.Call, address);
8244 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8246 type = storey.MutateType (type);
8251 /// Expressions that represent an indexer call.
8253 public class IndexerAccess : Expression, IAssignMethod
8255 class IndexerMethodGroupExpr : MethodGroupExpr
8257 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8260 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8263 public override string Name {
8269 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8272 // Here is the trick, decrease number of arguments by 1 when only
8273 // available property method is setter. This makes overload resolution
8274 // work correctly for indexers.
8277 if (method.Name [0] == 'g')
8278 return parameters.Count;
8280 return parameters.Count - 1;
8286 // Contains either property getter or setter
8287 public ArrayList Methods;
8288 public ArrayList Properties;
8294 void Append (Type caller_type, MemberInfo [] mi)
8299 foreach (PropertyInfo property in mi) {
8300 MethodInfo accessor = property.GetGetMethod (true);
8301 if (accessor == null)
8302 accessor = property.GetSetMethod (true);
8304 if (Methods == null) {
8305 Methods = new ArrayList ();
8306 Properties = new ArrayList ();
8309 Methods.Add (accessor);
8310 Properties.Add (property);
8314 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8316 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8318 return TypeManager.MemberLookup (
8319 caller_type, caller_type, lookup_type, MemberTypes.Property,
8320 BindingFlags.Public | BindingFlags.Instance |
8321 BindingFlags.DeclaredOnly, p_name, null);
8324 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8326 Indexers ix = new Indexers ();
8329 if (lookup_type.IsGenericParameter) {
8330 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8334 if (gc.HasClassConstraint)
8335 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8337 Type[] ifaces = gc.InterfaceConstraints;
8338 foreach (Type itype in ifaces)
8339 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8345 Type copy = lookup_type;
8346 while (copy != TypeManager.object_type && copy != null){
8347 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8348 copy = copy.BaseType;
8351 if (lookup_type.IsInterface) {
8352 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8353 if (ifaces != null) {
8354 foreach (Type itype in ifaces)
8355 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8370 // Points to our "data" repository
8372 MethodInfo get, set;
8373 bool is_base_indexer;
8375 LocalTemporary temp;
8376 LocalTemporary prepared_value;
8377 Expression set_expr;
8379 protected Type indexer_type;
8380 protected Type current_type;
8381 protected Expression instance_expr;
8382 protected ArrayList arguments;
8384 public IndexerAccess (ElementAccess ea, Location loc)
8385 : this (ea.Expr, false, loc)
8387 this.arguments = ea.Arguments;
8390 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8393 this.instance_expr = instance_expr;
8394 this.is_base_indexer = is_base_indexer;
8395 this.eclass = ExprClass.Value;
8399 static string GetAccessorName (AccessorType at)
8401 if (at == AccessorType.Set)
8404 if (at == AccessorType.Get)
8407 throw new NotImplementedException (at.ToString ());
8410 public override Expression CreateExpressionTree (EmitContext ec)
8412 ArrayList args = new ArrayList (arguments.Count + 2);
8413 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8414 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8415 foreach (Argument a in arguments)
8416 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8418 return CreateExpressionFactoryCall ("Call", args);
8421 protected virtual bool CommonResolve (EmitContext ec)
8423 indexer_type = instance_expr.Type;
8424 current_type = ec.ContainerType;
8429 public override Expression DoResolve (EmitContext ec)
8431 return ResolveAccessor (ec, AccessorType.Get);
8434 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8436 if (right_side == EmptyExpression.OutAccess) {
8437 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8438 GetSignatureForError ());
8442 // if the indexer returns a value type, and we try to set a field in it
8443 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8444 Error_CannotModifyIntermediateExpressionValue (ec);
8447 Expression e = ResolveAccessor (ec, AccessorType.Set);
8451 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8455 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8457 if (!CommonResolve (ec))
8460 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8461 if (ilist.Methods == null) {
8462 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8463 TypeManager.CSharpName (indexer_type));
8467 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8468 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8472 MethodInfo mi = (MethodInfo) mg;
8473 PropertyInfo pi = null;
8474 for (int i = 0; i < ilist.Methods.Count; ++i) {
8475 if (ilist.Methods [i] == mi) {
8476 pi = (PropertyInfo) ilist.Properties [i];
8481 type = TypeManager.TypeToCoreType (pi.PropertyType);
8482 if (type.IsPointer && !ec.InUnsafe)
8485 MethodInfo accessor;
8486 if (accessorType == AccessorType.Get) {
8487 accessor = get = pi.GetGetMethod (true);
8489 accessor = set = pi.GetSetMethod (true);
8490 if (accessor == null && pi.GetGetMethod (true) != null) {
8491 Report.SymbolRelatedToPreviousError (pi);
8492 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8493 TypeManager.GetFullNameSignature (pi));
8498 if (accessor == null) {
8499 Report.SymbolRelatedToPreviousError (pi);
8500 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8501 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8506 // Only base will allow this invocation to happen.
8508 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8509 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8512 bool must_do_cs1540_check;
8513 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8515 set = pi.GetSetMethod (true);
8517 get = pi.GetGetMethod (true);
8519 if (set != null && get != null &&
8520 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8521 Report.SymbolRelatedToPreviousError (accessor);
8522 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8523 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8525 Report.SymbolRelatedToPreviousError (pi);
8526 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8530 instance_expr.CheckMarshalByRefAccess (ec);
8531 eclass = ExprClass.IndexerAccess;
8535 public void Emit (EmitContext ec, bool leave_copy)
8538 prepared_value.Emit (ec);
8540 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8541 arguments, loc, false, false);
8545 ec.ig.Emit (OpCodes.Dup);
8546 temp = new LocalTemporary (Type);
8552 // source is ignored, because we already have a copy of it from the
8553 // LValue resolution and we have already constructed a pre-cached
8554 // version of the arguments (ea.set_arguments);
8556 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8558 prepared = prepare_for_load;
8559 Expression value = set_expr;
8562 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8563 arguments, loc, true, false);
8565 prepared_value = new LocalTemporary (type);
8566 prepared_value.Store (ec);
8568 prepared_value.Release (ec);
8571 ec.ig.Emit (OpCodes.Dup);
8572 temp = new LocalTemporary (Type);
8575 } else if (leave_copy) {
8576 temp = new LocalTemporary (Type);
8582 arguments.Add (new Argument (value, Argument.AType.Expression));
8583 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8591 public override void Emit (EmitContext ec)
8596 public override string GetSignatureForError ()
8598 return TypeManager.CSharpSignature (get != null ? get : set, false);
8601 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8604 get = storey.MutateGenericMethod (get);
8606 set = storey.MutateGenericMethod (set);
8608 instance_expr.MutateHoistedGenericType (storey);
8609 foreach (Argument a in arguments)
8610 a.Expr.MutateHoistedGenericType (storey);
8612 type = storey.MutateType (type);
8615 protected override void CloneTo (CloneContext clonectx, Expression t)
8617 IndexerAccess target = (IndexerAccess) t;
8619 if (arguments != null){
8620 target.arguments = new ArrayList ();
8621 foreach (Argument a in arguments)
8622 target.arguments.Add (a.Clone (clonectx));
8624 if (instance_expr != null)
8625 target.instance_expr = instance_expr.Clone (clonectx);
8630 /// The base operator for method names
8632 public class BaseAccess : Expression {
8633 public readonly string Identifier;
8636 public BaseAccess (string member, Location l)
8638 this.Identifier = member;
8642 public BaseAccess (string member, TypeArguments args, Location l)
8648 public override Expression CreateExpressionTree (EmitContext ec)
8650 throw new NotSupportedException ("ET");
8653 public override Expression DoResolve (EmitContext ec)
8655 Expression c = CommonResolve (ec);
8661 // MethodGroups use this opportunity to flag an error on lacking ()
8663 if (!(c is MethodGroupExpr))
8664 return c.Resolve (ec);
8668 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8670 Expression c = CommonResolve (ec);
8676 // MethodGroups use this opportunity to flag an error on lacking ()
8678 if (! (c is MethodGroupExpr))
8679 return c.DoResolveLValue (ec, right_side);
8684 Expression CommonResolve (EmitContext ec)
8686 Expression member_lookup;
8687 Type current_type = ec.ContainerType;
8688 Type base_type = current_type.BaseType;
8690 if (!This.IsThisAvailable (ec)) {
8692 Error (1511, "Keyword `base' is not available in a static method");
8694 Error (1512, "Keyword `base' is not available in the current context");
8699 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8700 AllMemberTypes, AllBindingFlags, loc);
8701 if (member_lookup == null) {
8702 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8703 null, AllMemberTypes, AllBindingFlags);
8710 left = new TypeExpression (base_type, loc);
8712 left = ec.GetThis (loc);
8714 MemberExpr me = (MemberExpr) member_lookup;
8715 me = me.ResolveMemberAccess (ec, left, loc, null);
8722 me.SetTypeArguments (args);
8728 public override void Emit (EmitContext ec)
8730 throw new Exception ("Should never be called");
8733 protected override void CloneTo (CloneContext clonectx, Expression t)
8735 BaseAccess target = (BaseAccess) t;
8738 target.args = args.Clone ();
8743 /// The base indexer operator
8745 public class BaseIndexerAccess : IndexerAccess {
8746 public BaseIndexerAccess (ArrayList args, Location loc)
8747 : base (null, true, loc)
8749 arguments = new ArrayList ();
8750 foreach (Expression tmp in args)
8751 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8754 protected override bool CommonResolve (EmitContext ec)
8756 instance_expr = ec.GetThis (loc);
8758 current_type = ec.ContainerType.BaseType;
8759 indexer_type = current_type;
8761 foreach (Argument a in arguments){
8762 if (!a.Resolve (ec, loc))
8769 public override Expression CreateExpressionTree (EmitContext ec)
8771 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8772 return base.CreateExpressionTree (ec);
8777 /// This class exists solely to pass the Type around and to be a dummy
8778 /// that can be passed to the conversion functions (this is used by
8779 /// foreach implementation to typecast the object return value from
8780 /// get_Current into the proper type. All code has been generated and
8781 /// we only care about the side effect conversions to be performed
8783 /// This is also now used as a placeholder where a no-action expression
8784 /// is needed (the `New' class).
8786 public class EmptyExpression : Expression {
8787 public static readonly Expression Null = new EmptyExpression ();
8789 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8790 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8791 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8792 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8794 static EmptyExpression temp = new EmptyExpression ();
8795 public static EmptyExpression Grab ()
8797 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8802 public static void Release (EmptyExpression e)
8807 // TODO: should be protected
8808 public EmptyExpression ()
8810 type = TypeManager.object_type;
8811 eclass = ExprClass.Value;
8812 loc = Location.Null;
8815 public EmptyExpression (Type t)
8818 eclass = ExprClass.Value;
8819 loc = Location.Null;
8822 public override Expression CreateExpressionTree (EmitContext ec)
8824 throw new NotSupportedException ("ET");
8827 public override Expression DoResolve (EmitContext ec)
8832 public override void Emit (EmitContext ec)
8834 // nothing, as we only exist to not do anything.
8837 public override void EmitSideEffect (EmitContext ec)
8842 // This is just because we might want to reuse this bad boy
8843 // instead of creating gazillions of EmptyExpressions.
8844 // (CanImplicitConversion uses it)
8846 public void SetType (Type t)
8853 // Empty statement expression
8855 public sealed class EmptyExpressionStatement : ExpressionStatement
8857 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8859 private EmptyExpressionStatement ()
8861 type = TypeManager.object_type;
8862 eclass = ExprClass.Value;
8863 loc = Location.Null;
8866 public override Expression CreateExpressionTree (EmitContext ec)
8871 public override void EmitStatement (EmitContext ec)
8876 public override Expression DoResolve (EmitContext ec)
8881 public override void Emit (EmitContext ec)
8887 public class UserCast : Expression {
8891 public UserCast (MethodInfo method, Expression source, Location l)
8893 this.method = method;
8894 this.source = source;
8895 type = TypeManager.TypeToCoreType (method.ReturnType);
8896 eclass = ExprClass.Value;
8900 public Expression Source {
8906 public override Expression CreateExpressionTree (EmitContext ec)
8908 ArrayList args = new ArrayList (3);
8909 args.Add (new Argument (source.CreateExpressionTree (ec)));
8910 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8911 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8912 return CreateExpressionFactoryCall ("Convert", args);
8915 public override Expression DoResolve (EmitContext ec)
8918 // We are born fully resolved
8923 public override void Emit (EmitContext ec)
8926 ec.ig.Emit (OpCodes.Call, method);
8929 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8931 source.MutateHoistedGenericType (storey);
8932 method = storey.MutateGenericMethod (method);
8937 // This class is used to "construct" the type during a typecast
8938 // operation. Since the Type.GetType class in .NET can parse
8939 // the type specification, we just use this to construct the type
8940 // one bit at a time.
8942 public class ComposedCast : TypeExpr {
8943 FullNamedExpression left;
8946 public ComposedCast (FullNamedExpression left, string dim)
8947 : this (left, dim, left.Location)
8951 public ComposedCast (FullNamedExpression left, string dim, Location l)
8958 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8960 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8964 Type ltype = lexpr.Type;
8965 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8966 Error_VoidInvalidInTheContext (loc);
8971 if ((dim.Length > 0) && (dim [0] == '?')) {
8972 TypeExpr nullable = new Nullable.NullableType (left, loc);
8974 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8975 return nullable.ResolveAsTypeTerminal (ec, false);
8979 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8982 if (dim.Length != 0 && dim [0] == '[') {
8983 if (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type) {
8984 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8988 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8989 Report.SymbolRelatedToPreviousError (ltype);
8990 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8991 TypeManager.CSharpName (ltype));
8996 type = TypeManager.GetConstructedType (ltype, dim);
9001 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9003 if (type.IsPointer && !ec.IsInUnsafeScope){
9007 eclass = ExprClass.Type;
9011 public override string GetSignatureForError ()
9013 return left.GetSignatureForError () + dim;
9016 protected override void CloneTo (CloneContext clonectx, Expression t)
9018 ComposedCast target = (ComposedCast) t;
9020 target.left = (FullNamedExpression)left.Clone (clonectx);
9024 public class FixedBufferPtr : Expression {
9027 public FixedBufferPtr (Expression array, Type array_type, Location l)
9032 type = TypeManager.GetPointerType (array_type);
9033 eclass = ExprClass.Value;
9036 public override Expression CreateExpressionTree (EmitContext ec)
9038 Error_PointerInsideExpressionTree ();
9042 public override void Emit(EmitContext ec)
9047 public override Expression DoResolve (EmitContext ec)
9050 // We are born fully resolved
9058 // This class is used to represent the address of an array, used
9059 // only by the Fixed statement, this generates "&a [0]" construct
9060 // for fixed (char *pa = a)
9062 public class ArrayPtr : FixedBufferPtr {
9065 public ArrayPtr (Expression array, Type array_type, Location l):
9066 base (array, array_type, l)
9068 this.array_type = array_type;
9071 public override void Emit (EmitContext ec)
9075 ILGenerator ig = ec.ig;
9076 IntLiteral.EmitInt (ig, 0);
9077 ig.Emit (OpCodes.Ldelema, array_type);
9082 // Encapsulates a conversion rules required for array indexes
9084 public class ArrayIndexCast : TypeCast
9086 public ArrayIndexCast (Expression expr)
9087 : base (expr, expr.Type)
9091 public override Expression CreateExpressionTree (EmitContext ec)
9093 ArrayList args = new ArrayList (2);
9094 args.Add (new Argument (child.CreateExpressionTree (ec)));
9095 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9096 return CreateExpressionFactoryCall ("ConvertChecked", args);
9099 public override void Emit (EmitContext ec)
9103 if (type == TypeManager.int32_type)
9106 if (type == TypeManager.uint32_type)
9107 ec.ig.Emit (OpCodes.Conv_U);
9108 else if (type == TypeManager.int64_type)
9109 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9110 else if (type == TypeManager.uint64_type)
9111 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9113 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9118 // Implements the `stackalloc' keyword
9120 public class StackAlloc : Expression {
9125 public StackAlloc (Expression type, Expression count, Location l)
9132 public override Expression CreateExpressionTree (EmitContext ec)
9134 throw new NotSupportedException ("ET");
9137 public override Expression DoResolve (EmitContext ec)
9139 count = count.Resolve (ec);
9143 if (count.Type != TypeManager.uint32_type){
9144 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9149 Constant c = count as Constant;
9150 if (c != null && c.IsNegative) {
9151 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9155 if (ec.InCatch || ec.InFinally) {
9156 Error (255, "Cannot use stackalloc in finally or catch");
9160 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9166 if (!TypeManager.VerifyUnManaged (otype, loc))
9169 type = TypeManager.GetPointerType (otype);
9170 eclass = ExprClass.Value;
9175 public override void Emit (EmitContext ec)
9177 int size = GetTypeSize (otype);
9178 ILGenerator ig = ec.ig;
9183 ig.Emit (OpCodes.Sizeof, otype);
9185 IntConstant.EmitInt (ig, size);
9187 ig.Emit (OpCodes.Mul_Ovf_Un);
9188 ig.Emit (OpCodes.Localloc);
9191 protected override void CloneTo (CloneContext clonectx, Expression t)
9193 StackAlloc target = (StackAlloc) t;
9194 target.count = count.Clone (clonectx);
9195 target.t = t.Clone (clonectx);
9200 // An object initializer expression
9202 public class ElementInitializer : Assign
9204 public readonly string Name;
9206 public ElementInitializer (string name, Expression initializer, Location loc)
9207 : base (null, initializer, loc)
9212 protected override void CloneTo (CloneContext clonectx, Expression t)
9214 ElementInitializer target = (ElementInitializer) t;
9215 target.source = source.Clone (clonectx);
9218 public override Expression CreateExpressionTree (EmitContext ec)
9220 ArrayList args = new ArrayList (2);
9221 FieldExpr fe = target as FieldExpr;
9223 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9225 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9227 args.Add (new Argument (source.CreateExpressionTree (ec)));
9228 return CreateExpressionFactoryCall (
9229 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9233 public override Expression DoResolve (EmitContext ec)
9236 return EmptyExpressionStatement.Instance;
9238 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9239 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9245 me.InstanceExpression = ec.CurrentInitializerVariable;
9247 if (source is CollectionOrObjectInitializers) {
9248 Expression previous = ec.CurrentInitializerVariable;
9249 ec.CurrentInitializerVariable = target;
9250 source = source.Resolve (ec);
9251 ec.CurrentInitializerVariable = previous;
9255 eclass = source.eclass;
9260 Expression expr = base.DoResolve (ec);
9265 // Ignore field initializers with default value
9267 Constant c = source as Constant;
9268 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9269 return EmptyExpressionStatement.Instance;
9274 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9276 MemberInfo member = members [0];
9277 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9278 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9279 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9281 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9282 TypeManager.GetFullNameSignature (member));
9287 public override void EmitStatement (EmitContext ec)
9289 if (source is CollectionOrObjectInitializers)
9292 base.EmitStatement (ec);
9297 // A collection initializer expression
9299 public class CollectionElementInitializer : Invocation
9301 public class ElementInitializerArgument : Argument
9303 public ElementInitializerArgument (Expression e)
9309 public CollectionElementInitializer (Expression argument)
9310 : base (null, new ArrayList (1), true)
9312 Arguments.Add (argument);
9313 this.loc = argument.Location;
9316 public CollectionElementInitializer (ArrayList arguments, Location loc)
9317 : base (null, arguments, true)
9322 public override Expression CreateExpressionTree (EmitContext ec)
9324 ArrayList args = new ArrayList (2);
9325 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9327 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9328 foreach (Argument a in Arguments)
9329 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9331 args.Add (new Argument (new ArrayCreation (
9332 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9333 return CreateExpressionFactoryCall ("ElementInit", args);
9336 protected override void CloneTo (CloneContext clonectx, Expression t)
9338 CollectionElementInitializer target = (CollectionElementInitializer) t;
9340 target.Arguments = new ArrayList (Arguments.Count);
9341 foreach (Expression e in Arguments)
9342 target.Arguments.Add (e.Clone (clonectx));
9345 public override Expression DoResolve (EmitContext ec)
9347 if (eclass != ExprClass.Invalid)
9350 // TODO: We could call a constructor which takes element count argument,
9351 // for known types like List<T>, Dictionary<T, U>
9353 for (int i = 0; i < Arguments.Count; ++i) {
9354 Expression expr = Arguments [i] as Expression;
9358 expr = expr.Resolve (ec);
9362 Arguments [i] = new ElementInitializerArgument (expr);
9365 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9367 return base.DoResolve (ec);
9372 // A block of object or collection initializers
9374 public class CollectionOrObjectInitializers : ExpressionStatement
9376 ArrayList initializers;
9378 public static readonly CollectionOrObjectInitializers Empty =
9379 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9381 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9383 this.initializers = initializers;
9387 public bool IsEmpty {
9389 return initializers.Count == 0;
9393 public bool IsCollectionInitializer {
9395 return type == typeof (CollectionOrObjectInitializers);
9399 protected override void CloneTo (CloneContext clonectx, Expression target)
9401 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9403 t.initializers = new ArrayList (initializers.Count);
9404 foreach (Expression e in initializers)
9405 t.initializers.Add (e.Clone (clonectx));
9408 public override Expression CreateExpressionTree (EmitContext ec)
9410 ArrayList expr_initializers = new ArrayList (initializers.Count);
9411 foreach (Expression e in initializers) {
9412 Expression expr = e.CreateExpressionTree (ec);
9414 expr_initializers.Add (expr);
9417 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9420 public override Expression DoResolve (EmitContext ec)
9422 if (eclass != ExprClass.Invalid)
9425 bool is_elements_initialization = false;
9426 ArrayList element_names = null;
9427 for (int i = 0; i < initializers.Count; ++i) {
9428 Expression initializer = (Expression) initializers [i];
9429 ElementInitializer element_initializer = initializer as ElementInitializer;
9432 if (element_initializer != null) {
9433 is_elements_initialization = true;
9434 element_names = new ArrayList (initializers.Count);
9435 element_names.Add (element_initializer.Name);
9437 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9438 TypeManager.ienumerable_type)) {
9439 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9440 "object initializer because type `{1}' does not implement `{2}' interface",
9441 ec.CurrentInitializerVariable.GetSignatureForError (),
9442 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9443 TypeManager.CSharpName (TypeManager.ienumerable_type));
9448 if (is_elements_initialization == (element_initializer == null)) {
9449 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9450 is_elements_initialization ? "object initializer" : "collection initializer");
9454 if (is_elements_initialization) {
9455 if (element_names.Contains (element_initializer.Name)) {
9456 Report.Error (1912, element_initializer.Location,
9457 "An object initializer includes more than one member `{0}' initialization",
9458 element_initializer.Name);
9460 element_names.Add (element_initializer.Name);
9465 Expression e = initializer.Resolve (ec);
9466 if (e == EmptyExpressionStatement.Instance)
9467 initializers.RemoveAt (i--);
9469 initializers [i] = e;
9472 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9473 eclass = ExprClass.Variable;
9477 public override void Emit (EmitContext ec)
9482 public override void EmitStatement (EmitContext ec)
9484 foreach (ExpressionStatement e in initializers)
9485 e.EmitStatement (ec);
9488 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9490 foreach (Expression e in initializers)
9491 e.MutateHoistedGenericType (storey);
9496 // New expression with element/object initializers
9498 public class NewInitialize : New
9501 // This class serves as a proxy for variable initializer target instances.
9502 // A real variable is assigned later when we resolve left side of an
9505 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9507 NewInitialize new_instance;
9509 public InitializerTargetExpression (NewInitialize newInstance)
9511 this.type = newInstance.type;
9512 this.loc = newInstance.loc;
9513 this.eclass = newInstance.eclass;
9514 this.new_instance = newInstance;
9517 public override Expression CreateExpressionTree (EmitContext ec)
9519 // Should not be reached
9520 throw new NotSupportedException ("ET");
9523 public override Expression DoResolve (EmitContext ec)
9528 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9533 public override void Emit (EmitContext ec)
9535 new_instance.value_target.Emit (ec);
9538 #region IMemoryLocation Members
9540 public void AddressOf (EmitContext ec, AddressOp mode)
9542 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9548 CollectionOrObjectInitializers initializers;
9550 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9551 : base (requested_type, arguments, l)
9553 this.initializers = initializers;
9556 protected override void CloneTo (CloneContext clonectx, Expression t)
9558 base.CloneTo (clonectx, t);
9560 NewInitialize target = (NewInitialize) t;
9561 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9564 public override Expression CreateExpressionTree (EmitContext ec)
9566 ArrayList args = new ArrayList (2);
9567 args.Add (new Argument (base.CreateExpressionTree (ec)));
9568 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9570 return CreateExpressionFactoryCall (
9571 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9575 public override Expression DoResolve (EmitContext ec)
9577 if (eclass != ExprClass.Invalid)
9580 Expression e = base.DoResolve (ec);
9584 // Empty initializer can be optimized to simple new
9585 if (initializers.IsEmpty)
9588 Expression previous = ec.CurrentInitializerVariable;
9589 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9590 initializers.Resolve (ec);
9591 ec.CurrentInitializerVariable = previous;
9595 public override void Emit (EmitContext ec)
9600 // If target is non-hoisted variable, let's use it
9602 VariableReference variable = value_target as VariableReference;
9603 if (variable != null && variable.HoistedVariable == null) {
9605 StoreFromPtr (ec.ig, type);
9607 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9610 if (value_target == null || value_target_set)
9611 value_target = new LocalTemporary (type);
9613 ((LocalTemporary) value_target).Store (ec);
9616 initializers.Emit (ec);
9618 if (variable == null) {
9619 value_target.Emit (ec);
9620 value_target = null;
9624 public override void EmitStatement (EmitContext ec)
9626 if (initializers.IsEmpty) {
9627 base.EmitStatement (ec);
9633 if (value_target == null) {
9634 LocalTemporary variable = new LocalTemporary (type);
9635 variable.Store (ec);
9636 value_target = variable;
9639 initializers.EmitStatement (ec);
9642 public override bool HasInitializer {
9644 return !initializers.IsEmpty;
9648 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9650 base.MutateHoistedGenericType (storey);
9651 initializers.MutateHoistedGenericType (storey);
9655 public class AnonymousTypeDeclaration : Expression
9657 ArrayList parameters;
9658 readonly TypeContainer parent;
9659 static readonly ArrayList EmptyParameters = new ArrayList (0);
9661 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9663 this.parameters = parameters;
9664 this.parent = parent;
9668 protected override void CloneTo (CloneContext clonectx, Expression target)
9670 if (parameters == null)
9673 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9674 t.parameters = new ArrayList (parameters.Count);
9675 foreach (AnonymousTypeParameter atp in parameters)
9676 t.parameters.Add (atp.Clone (clonectx));
9679 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9681 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9685 type = AnonymousTypeClass.Create (parent, parameters, loc);
9690 type.DefineMembers ();
9695 RootContext.ToplevelTypes.AddAnonymousType (type);
9699 public override Expression CreateExpressionTree (EmitContext ec)
9701 throw new NotSupportedException ("ET");
9704 public override Expression DoResolve (EmitContext ec)
9706 AnonymousTypeClass anonymous_type;
9708 if (parameters == null) {
9709 anonymous_type = CreateAnonymousType (EmptyParameters);
9710 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9711 null, loc).Resolve (ec);
9715 ArrayList arguments = new ArrayList (parameters.Count);
9716 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9717 for (int i = 0; i < parameters.Count; ++i) {
9718 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9724 arguments.Add (new Argument (e));
9725 t_args [i] = new TypeExpression (e.Type, e.Location);
9731 anonymous_type = CreateAnonymousType (parameters);
9732 if (anonymous_type == null)
9735 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9736 new TypeArguments (loc, t_args), loc);
9738 return new New (te, arguments, loc).Resolve (ec);
9741 public override void Emit (EmitContext ec)
9743 throw new InternalErrorException ("Should not be reached");
9747 public class AnonymousTypeParameter : Expression
9749 public readonly string Name;
9750 Expression initializer;
9752 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9756 this.initializer = initializer;
9759 public AnonymousTypeParameter (Parameter parameter)
9761 this.Name = parameter.Name;
9762 this.loc = parameter.Location;
9763 this.initializer = new SimpleName (Name, loc);
9766 protected override void CloneTo (CloneContext clonectx, Expression target)
9768 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9769 t.initializer = initializer.Clone (clonectx);
9772 public override Expression CreateExpressionTree (EmitContext ec)
9774 throw new NotSupportedException ("ET");
9777 public override bool Equals (object o)
9779 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9780 return other != null && Name == other.Name;
9783 public override int GetHashCode ()
9785 return Name.GetHashCode ();
9788 public override Expression DoResolve (EmitContext ec)
9790 Expression e = initializer.Resolve (ec);
9794 if (e.eclass == ExprClass.MethodGroup) {
9795 Error_InvalidInitializer (e.ExprClassName);
9800 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9801 type == TypeManager.anonymous_method_type || type.IsPointer) {
9802 Error_InvalidInitializer (e.GetSignatureForError ());
9809 protected virtual void Error_InvalidInitializer (string initializer)
9811 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9815 public override void Emit (EmitContext ec)
9817 throw new InternalErrorException ("Should not be reached");