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 ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1575 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1579 return new NullLiteral (Location).ConvertImplicitly (type);
1581 if (TypeManager.IsReferenceType (type)) {
1582 return new EmptyConstantCast (new NullLiteral (Location), type);
1585 // return ReducedExpression.Create (new NullLiteral (Location), this);
1588 Constant c = New.Constantify (type);
1592 eclass = ExprClass.Variable;
1596 public override void Emit (EmitContext ec)
1598 LocalTemporary temp_storage = new LocalTemporary(type);
1600 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1601 ec.ig.Emit(OpCodes.Initobj, type);
1602 temp_storage.Emit(ec);
1605 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1607 type = storey.MutateType (type);
1610 protected override void CloneTo (CloneContext clonectx, Expression t)
1612 DefaultValueExpression target = (DefaultValueExpression) t;
1614 target.expr = expr.Clone (clonectx);
1619 /// Binary operators
1621 public class Binary : Expression {
1623 protected class PredefinedOperator {
1624 protected readonly Type left;
1625 protected readonly Type right;
1626 public readonly Operator OperatorsMask;
1627 public Type ReturnType;
1629 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1630 : this (ltype, rtype, op_mask, ltype)
1634 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1635 : this (type, type, op_mask, return_type)
1639 public PredefinedOperator (Type type, Operator op_mask)
1640 : this (type, type, op_mask, type)
1644 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1646 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1647 throw new InternalErrorException ("Only masked values can be used");
1651 this.OperatorsMask = op_mask;
1652 this.ReturnType = return_type;
1655 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1657 b.type = ReturnType;
1659 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1660 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1663 // A user operators does not support multiple user conversions, but decimal type
1664 // is considered to be predefined type therefore we apply predefined operators rules
1665 // and then look for decimal user-operator implementation
1667 if (left == TypeManager.decimal_type)
1668 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1673 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1676 // We are dealing with primitive types only
1678 return left == ltype && ltype == rtype;
1681 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1683 if (TypeManager.IsEqual (left, lexpr.Type) &&
1684 TypeManager.IsEqual (right, rexpr.Type))
1687 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1688 Convert.ImplicitConversionExists (ec, rexpr, right);
1691 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1694 if (left != null && best_operator.left != null) {
1695 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1699 // When second arguments are same as the first one, the result is same
1701 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1702 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1705 if (result == 0 || result > 2)
1708 return result == 1 ? best_operator : this;
1712 class PredefinedStringOperator : PredefinedOperator {
1713 public PredefinedStringOperator (Type type, Operator op_mask)
1714 : base (type, op_mask, type)
1716 ReturnType = TypeManager.string_type;
1719 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1720 : base (ltype, rtype, op_mask)
1722 ReturnType = TypeManager.string_type;
1725 public override Expression ConvertResult (EmitContext ec, Binary b)
1728 // Use original expression for nullable arguments
1730 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1732 b.left = unwrap.Original;
1734 unwrap = b.right as Nullable.Unwrap;
1736 b.right = unwrap.Original;
1738 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1739 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1742 // Start a new concat expression using converted expression
1744 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1748 class PredefinedShiftOperator : PredefinedOperator {
1749 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1750 base (ltype, TypeManager.int32_type, op_mask)
1754 public override Expression ConvertResult (EmitContext ec, Binary b)
1756 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1758 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1760 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1763 // b = b.left >> b.right & (0x1f|0x3f)
1765 b.right = new Binary (Operator.BitwiseAnd,
1766 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1769 // Expression tree representation does not use & mask
1771 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1772 b.type = ReturnType;
1777 class PredefinedPointerOperator : PredefinedOperator {
1778 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1779 : base (ltype, rtype, op_mask)
1783 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1784 : base (ltype, rtype, op_mask, retType)
1788 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1789 : base (type, op_mask, return_type)
1793 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1796 if (!lexpr.Type.IsPointer)
1799 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1803 if (right == null) {
1804 if (!rexpr.Type.IsPointer)
1807 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1814 public override Expression ConvertResult (EmitContext ec, Binary b)
1817 b.left = EmptyCast.Create (b.left, left);
1818 } else if (right != null) {
1819 b.right = EmptyCast.Create (b.right, right);
1822 Type r_type = ReturnType;
1823 if (r_type == null) {
1825 r_type = b.left.Type;
1827 r_type = b.right.Type;
1830 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1835 public enum Operator {
1836 Multiply = 0 | ArithmeticMask,
1837 Division = 1 | ArithmeticMask,
1838 Modulus = 2 | ArithmeticMask,
1839 Addition = 3 | ArithmeticMask | AdditionMask,
1840 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1842 LeftShift = 5 | ShiftMask,
1843 RightShift = 6 | ShiftMask,
1845 LessThan = 7 | ComparisonMask | RelationalMask,
1846 GreaterThan = 8 | ComparisonMask | RelationalMask,
1847 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1848 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1849 Equality = 11 | ComparisonMask | EqualityMask,
1850 Inequality = 12 | ComparisonMask | EqualityMask,
1852 BitwiseAnd = 13 | BitwiseMask,
1853 ExclusiveOr = 14 | BitwiseMask,
1854 BitwiseOr = 15 | BitwiseMask,
1856 LogicalAnd = 16 | LogicalMask,
1857 LogicalOr = 17 | LogicalMask,
1862 ValuesOnlyMask = ArithmeticMask - 1,
1863 ArithmeticMask = 1 << 5,
1865 ComparisonMask = 1 << 7,
1866 EqualityMask = 1 << 8,
1867 BitwiseMask = 1 << 9,
1868 LogicalMask = 1 << 10,
1869 AdditionMask = 1 << 11,
1870 SubtractionMask = 1 << 12,
1871 RelationalMask = 1 << 13
1874 readonly Operator oper;
1875 protected Expression left, right;
1876 readonly bool is_compound;
1877 Expression enum_conversion;
1879 static PredefinedOperator [] standard_operators;
1880 static PredefinedOperator [] pointer_operators;
1882 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1883 : this (oper, left, right)
1885 this.is_compound = isCompound;
1888 public Binary (Operator oper, Expression left, Expression right)
1893 this.loc = left.Location;
1896 public Operator Oper {
1903 /// Returns a stringified representation of the Operator
1905 string OperName (Operator oper)
1909 case Operator.Multiply:
1912 case Operator.Division:
1915 case Operator.Modulus:
1918 case Operator.Addition:
1921 case Operator.Subtraction:
1924 case Operator.LeftShift:
1927 case Operator.RightShift:
1930 case Operator.LessThan:
1933 case Operator.GreaterThan:
1936 case Operator.LessThanOrEqual:
1939 case Operator.GreaterThanOrEqual:
1942 case Operator.Equality:
1945 case Operator.Inequality:
1948 case Operator.BitwiseAnd:
1951 case Operator.BitwiseOr:
1954 case Operator.ExclusiveOr:
1957 case Operator.LogicalOr:
1960 case Operator.LogicalAnd:
1964 s = oper.ToString ();
1974 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1976 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1979 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1982 // TODO: This should be handled as Type of method group in CSharpName
1983 if (left.eclass == ExprClass.MethodGroup)
1984 l = left.ExprClassName;
1986 l = TypeManager.CSharpName (left.Type);
1988 if (right.eclass == ExprClass.MethodGroup)
1989 r = right.ExprClassName;
1991 r = TypeManager.CSharpName (right.Type);
1993 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1997 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1999 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2002 static string GetOperatorMetadataName (Operator op)
2004 CSharp.Operator.OpType op_type;
2006 case Operator.Addition:
2007 op_type = CSharp.Operator.OpType.Addition; break;
2008 case Operator.BitwiseAnd:
2009 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2010 case Operator.BitwiseOr:
2011 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2012 case Operator.Division:
2013 op_type = CSharp.Operator.OpType.Division; break;
2014 case Operator.Equality:
2015 op_type = CSharp.Operator.OpType.Equality; break;
2016 case Operator.ExclusiveOr:
2017 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2018 case Operator.GreaterThan:
2019 op_type = CSharp.Operator.OpType.GreaterThan; break;
2020 case Operator.GreaterThanOrEqual:
2021 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2022 case Operator.Inequality:
2023 op_type = CSharp.Operator.OpType.Inequality; break;
2024 case Operator.LeftShift:
2025 op_type = CSharp.Operator.OpType.LeftShift; break;
2026 case Operator.LessThan:
2027 op_type = CSharp.Operator.OpType.LessThan; break;
2028 case Operator.LessThanOrEqual:
2029 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2030 case Operator.Modulus:
2031 op_type = CSharp.Operator.OpType.Modulus; break;
2032 case Operator.Multiply:
2033 op_type = CSharp.Operator.OpType.Multiply; break;
2034 case Operator.RightShift:
2035 op_type = CSharp.Operator.OpType.RightShift; break;
2036 case Operator.Subtraction:
2037 op_type = CSharp.Operator.OpType.Subtraction; break;
2039 throw new InternalErrorException (op.ToString ());
2042 return CSharp.Operator.GetMetadataName (op_type);
2045 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2048 ILGenerator ig = ec.ig;
2051 case Operator.Multiply:
2053 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2054 opcode = OpCodes.Mul_Ovf;
2055 else if (!IsFloat (l))
2056 opcode = OpCodes.Mul_Ovf_Un;
2058 opcode = OpCodes.Mul;
2060 opcode = OpCodes.Mul;
2064 case Operator.Division:
2066 opcode = OpCodes.Div_Un;
2068 opcode = OpCodes.Div;
2071 case Operator.Modulus:
2073 opcode = OpCodes.Rem_Un;
2075 opcode = OpCodes.Rem;
2078 case Operator.Addition:
2080 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2081 opcode = OpCodes.Add_Ovf;
2082 else if (!IsFloat (l))
2083 opcode = OpCodes.Add_Ovf_Un;
2085 opcode = OpCodes.Add;
2087 opcode = OpCodes.Add;
2090 case Operator.Subtraction:
2092 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2093 opcode = OpCodes.Sub_Ovf;
2094 else if (!IsFloat (l))
2095 opcode = OpCodes.Sub_Ovf_Un;
2097 opcode = OpCodes.Sub;
2099 opcode = OpCodes.Sub;
2102 case Operator.RightShift:
2104 opcode = OpCodes.Shr_Un;
2106 opcode = OpCodes.Shr;
2109 case Operator.LeftShift:
2110 opcode = OpCodes.Shl;
2113 case Operator.Equality:
2114 opcode = OpCodes.Ceq;
2117 case Operator.Inequality:
2118 ig.Emit (OpCodes.Ceq);
2119 ig.Emit (OpCodes.Ldc_I4_0);
2121 opcode = OpCodes.Ceq;
2124 case Operator.LessThan:
2126 opcode = OpCodes.Clt_Un;
2128 opcode = OpCodes.Clt;
2131 case Operator.GreaterThan:
2133 opcode = OpCodes.Cgt_Un;
2135 opcode = OpCodes.Cgt;
2138 case Operator.LessThanOrEqual:
2139 if (IsUnsigned (l) || IsFloat (l))
2140 ig.Emit (OpCodes.Cgt_Un);
2142 ig.Emit (OpCodes.Cgt);
2143 ig.Emit (OpCodes.Ldc_I4_0);
2145 opcode = OpCodes.Ceq;
2148 case Operator.GreaterThanOrEqual:
2149 if (IsUnsigned (l) || IsFloat (l))
2150 ig.Emit (OpCodes.Clt_Un);
2152 ig.Emit (OpCodes.Clt);
2154 ig.Emit (OpCodes.Ldc_I4_0);
2156 opcode = OpCodes.Ceq;
2159 case Operator.BitwiseOr:
2160 opcode = OpCodes.Or;
2163 case Operator.BitwiseAnd:
2164 opcode = OpCodes.And;
2167 case Operator.ExclusiveOr:
2168 opcode = OpCodes.Xor;
2172 throw new InternalErrorException (oper.ToString ());
2178 static bool IsUnsigned (Type t)
2183 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2184 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2187 static bool IsFloat (Type t)
2189 return t == TypeManager.float_type || t == TypeManager.double_type;
2192 Expression ResolveOperator (EmitContext ec)
2195 Type r = right.Type;
2197 bool primitives_only = false;
2199 if (standard_operators == null)
2200 CreateStandardOperatorsTable ();
2203 // Handles predefined primitive types
2205 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2206 if ((oper & Operator.ShiftMask) == 0) {
2207 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2210 primitives_only = true;
2214 if (l.IsPointer || r.IsPointer)
2215 return ResolveOperatorPointer (ec, l, r);
2218 bool lenum = TypeManager.IsEnumType (l);
2219 bool renum = TypeManager.IsEnumType (r);
2220 if (lenum || renum) {
2221 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2223 // TODO: Can this be ambiguous
2229 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2230 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2232 expr = ResolveOperatorDelegate (ec, l, r);
2234 // TODO: Can this be ambiguous
2240 expr = ResolveUserOperator (ec, l, r);
2244 // Predefined reference types equality
2245 if ((oper & Operator.EqualityMask) != 0) {
2246 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2252 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2255 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2256 // if 'left' is not an enumeration constant, create one from the type of 'right'
2257 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2260 case Operator.BitwiseOr:
2261 case Operator.BitwiseAnd:
2262 case Operator.ExclusiveOr:
2263 case Operator.Equality:
2264 case Operator.Inequality:
2265 case Operator.LessThan:
2266 case Operator.LessThanOrEqual:
2267 case Operator.GreaterThan:
2268 case Operator.GreaterThanOrEqual:
2269 if (TypeManager.IsEnumType (left.Type))
2272 if (left.IsZeroInteger)
2273 return left.TryReduce (ec, right.Type, loc);
2277 case Operator.Addition:
2278 case Operator.Subtraction:
2281 case Operator.Multiply:
2282 case Operator.Division:
2283 case Operator.Modulus:
2284 case Operator.LeftShift:
2285 case Operator.RightShift:
2286 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2290 Error_OperatorCannotBeApplied (this.left, this.right);
2295 // The `|' operator used on types which were extended is dangerous
2297 void CheckBitwiseOrOnSignExtended ()
2299 OpcodeCast lcast = left as OpcodeCast;
2300 if (lcast != null) {
2301 if (IsUnsigned (lcast.UnderlyingType))
2305 OpcodeCast rcast = right as OpcodeCast;
2306 if (rcast != null) {
2307 if (IsUnsigned (rcast.UnderlyingType))
2311 if (lcast == null && rcast == null)
2314 // FIXME: consider constants
2316 Report.Warning (675, 3, loc,
2317 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2318 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2321 static void CreatePointerOperatorsTable ()
2323 ArrayList temp = new ArrayList ();
2326 // Pointer arithmetic:
2328 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2329 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2330 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2331 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2333 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2334 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2335 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2336 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2339 // T* operator + (int y, T* x);
2340 // T* operator + (uint y, T *x);
2341 // T* operator + (long y, T *x);
2342 // T* operator + (ulong y, T *x);
2344 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2345 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2346 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2347 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2350 // long operator - (T* x, T *y)
2352 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2354 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2357 static void CreateStandardOperatorsTable ()
2359 ArrayList temp = new ArrayList ();
2360 Type bool_type = TypeManager.bool_type;
2362 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2363 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2364 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2365 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2366 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2367 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2368 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2370 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2371 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2372 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2373 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2374 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2375 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2378 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2380 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2381 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2382 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2384 temp.Add (new PredefinedOperator (bool_type,
2385 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2387 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2388 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2389 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2390 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2392 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2396 // Rules used during binary numeric promotion
2398 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2403 Constant c = prim_expr as Constant;
2405 temp = c.ConvertImplicitly (type);
2412 if (type == TypeManager.uint32_type) {
2413 etype = prim_expr.Type;
2414 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2415 type = TypeManager.int64_type;
2417 if (type != second_expr.Type) {
2418 c = second_expr as Constant;
2420 temp = c.ConvertImplicitly (type);
2422 temp = Convert.ImplicitNumericConversion (second_expr, type);
2428 } else if (type == TypeManager.uint64_type) {
2430 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2432 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2433 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2437 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2446 // 7.2.6.2 Binary numeric promotions
2448 public bool DoBinaryOperatorPromotion (EmitContext ec)
2450 Type ltype = left.Type;
2451 Type rtype = right.Type;
2454 foreach (Type t in ConstantFold.binary_promotions) {
2456 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2459 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2462 Type int32 = TypeManager.int32_type;
2463 if (ltype != int32) {
2464 Constant c = left as Constant;
2466 temp = c.ConvertImplicitly (int32);
2468 temp = Convert.ImplicitNumericConversion (left, int32);
2475 if (rtype != int32) {
2476 Constant c = right as Constant;
2478 temp = c.ConvertImplicitly (int32);
2480 temp = Convert.ImplicitNumericConversion (right, int32);
2490 public override Expression DoResolve (EmitContext ec)
2495 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2496 left = ((ParenthesizedExpression) left).Expr;
2497 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2501 if (left.eclass == ExprClass.Type) {
2502 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2506 left = left.Resolve (ec);
2511 Constant lc = left as Constant;
2513 if (lc != null && lc.Type == TypeManager.bool_type &&
2514 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2515 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2517 // FIXME: resolve right expression as unreachable
2518 // right.Resolve (ec);
2520 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2524 right = right.Resolve (ec);
2528 eclass = ExprClass.Value;
2529 Constant rc = right as Constant;
2531 // The conversion rules are ignored in enum context but why
2532 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2533 left = lc = EnumLiftUp (ec, lc, rc, loc);
2537 right = rc = EnumLiftUp (ec, rc, lc, loc);
2542 if (rc != null && lc != null) {
2543 int prev_e = Report.Errors;
2544 Expression e = ConstantFold.BinaryFold (
2545 ec, oper, lc, rc, loc);
2546 if (e != null || Report.Errors != prev_e)
2549 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2550 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2552 if ((ResolveOperator (ec)) == null) {
2553 Error_OperatorCannotBeApplied (left, right);
2558 // The result is a constant with side-effect
2560 Constant side_effect = rc == null ?
2561 new SideEffectConstant (lc, right, loc) :
2562 new SideEffectConstant (rc, left, loc);
2564 return ReducedExpression.Create (side_effect, this);
2568 // Comparison warnings
2569 if ((oper & Operator.ComparisonMask) != 0) {
2570 if (left.Equals (right)) {
2571 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2573 CheckUselessComparison (lc, right.Type);
2574 CheckUselessComparison (rc, left.Type);
2577 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2578 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2579 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2580 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2582 return DoResolveCore (ec, left, right);
2585 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2587 Expression expr = ResolveOperator (ec);
2589 Error_OperatorCannotBeApplied (left_orig, right_orig);
2591 if (left == null || right == null)
2592 throw new InternalErrorException ("Invalid conversion");
2594 if (oper == Operator.BitwiseOr)
2595 CheckBitwiseOrOnSignExtended ();
2600 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2602 left.MutateHoistedGenericType (storey);
2603 right.MutateHoistedGenericType (storey);
2607 // D operator + (D x, D y)
2608 // D operator - (D x, D y)
2609 // bool operator == (D x, D y)
2610 // bool operator != (D x, D y)
2612 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2614 bool is_equality = (oper & Operator.EqualityMask) != 0;
2615 if (!TypeManager.IsEqual (l, r)) {
2617 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2618 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2623 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2624 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2635 // Resolve delegate equality as a user operator
2638 return ResolveUserOperator (ec, l, r);
2641 ArrayList args = new ArrayList (2);
2642 args.Add (new Argument (left, Argument.AType.Expression));
2643 args.Add (new Argument (right, Argument.AType.Expression));
2645 if (oper == Operator.Addition) {
2646 if (TypeManager.delegate_combine_delegate_delegate == null) {
2647 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2648 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2651 method = TypeManager.delegate_combine_delegate_delegate;
2653 if (TypeManager.delegate_remove_delegate_delegate == null) {
2654 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2655 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2658 method = TypeManager.delegate_remove_delegate_delegate;
2661 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2662 mg = mg.OverloadResolve (ec, ref args, false, loc);
2664 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2668 // Enumeration operators
2670 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2673 // bool operator == (E x, E y);
2674 // bool operator != (E x, E y);
2675 // bool operator < (E x, E y);
2676 // bool operator > (E x, E y);
2677 // bool operator <= (E x, E y);
2678 // bool operator >= (E x, E y);
2680 // E operator & (E x, E y);
2681 // E operator | (E x, E y);
2682 // E operator ^ (E x, E y);
2684 // U operator - (E e, E f)
2685 // E operator - (E e, U x)
2687 // E operator + (U x, E e)
2688 // E operator + (E e, U x)
2690 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2691 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2694 Expression ltemp = left;
2695 Expression rtemp = right;
2696 Type underlying_type;
2699 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2701 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2707 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2715 if (TypeManager.IsEqual (ltype, rtype)) {
2716 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2718 if (left is Constant)
2719 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2721 left = EmptyCast.Create (left, underlying_type);
2723 if (right is Constant)
2724 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2726 right = EmptyCast.Create (right, underlying_type);
2728 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2730 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2731 Constant c = right as Constant;
2732 if (c == null || !c.IsDefaultValue)
2735 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2738 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2741 if (left is Constant)
2742 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2744 left = EmptyCast.Create (left, underlying_type);
2747 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2749 if (oper != Operator.Addition) {
2750 Constant c = left as Constant;
2751 if (c == null || !c.IsDefaultValue)
2754 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2757 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2760 if (right is Constant)
2761 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2763 right = EmptyCast.Create (right, underlying_type);
2770 // C# specification uses explicit cast syntax which means binary promotion
2771 // should happen, however it seems that csc does not do that
2773 if (!DoBinaryOperatorPromotion (ec)) {
2779 Type res_type = null;
2780 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2781 Type promoted_type = lenum ? left.Type : right.Type;
2782 enum_conversion = Convert.ExplicitNumericConversion (
2783 new EmptyExpression (promoted_type), underlying_type);
2785 if (oper == Operator.Subtraction && renum && lenum)
2786 res_type = underlying_type;
2787 else if (oper == Operator.Addition && renum)
2793 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2794 if (!is_compound || expr == null)
2798 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2801 if (Convert.ImplicitConversionExists (ec, left, rtype))
2804 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2807 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2812 // 7.9.6 Reference type equality operators
2814 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2817 // operator != (object a, object b)
2818 // operator == (object a, object b)
2821 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2823 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2826 type = TypeManager.bool_type;
2827 GenericConstraints constraints;
2829 bool lgen = TypeManager.IsGenericParameter (l);
2831 if (TypeManager.IsEqual (l, r)) {
2834 // Only allow to compare same reference type parameter
2836 constraints = TypeManager.GetTypeParameterConstraints (l);
2837 if (constraints != null && constraints.IsReferenceType)
2843 if (l == TypeManager.anonymous_method_type)
2846 if (TypeManager.IsValueType (l))
2852 bool rgen = TypeManager.IsGenericParameter (r);
2855 // a, Both operands are reference-type values or the value null
2856 // b, One operand is a value of type T where T is a type-parameter and
2857 // the other operand is the value null. Furthermore T does not have the
2858 // value type constrain
2860 if (left is NullLiteral || right is NullLiteral) {
2862 constraints = TypeManager.GetTypeParameterConstraints (l);
2863 if (constraints != null && constraints.HasValueTypeConstraint)
2866 left = new BoxedCast (left, TypeManager.object_type);
2871 constraints = TypeManager.GetTypeParameterConstraints (r);
2872 if (constraints != null && constraints.HasValueTypeConstraint)
2875 right = new BoxedCast (right, TypeManager.object_type);
2881 // An interface is converted to the object before the
2882 // standard conversion is applied. It's not clear from the
2883 // standard but it looks like it works like that.
2886 constraints = TypeManager.GetTypeParameterConstraints (l);
2887 if (constraints == null || constraints.IsReferenceType)
2889 } else if (l.IsInterface) {
2890 l = TypeManager.object_type;
2891 } else if (l.IsValueType) {
2896 constraints = TypeManager.GetTypeParameterConstraints (r);
2897 if (constraints == null || constraints.IsReferenceType)
2899 } else if (r.IsInterface) {
2900 r = TypeManager.object_type;
2901 } else if (r.IsValueType) {
2906 const string ref_comparison = "Possible unintended reference comparison. " +
2907 "Consider casting the {0} side of the expression to `string' to compare the values";
2910 // A standard implicit conversion exists from the type of either
2911 // operand to the type of the other operand
2913 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2914 if (l == TypeManager.string_type)
2915 Report.Warning (253, 2, loc, ref_comparison, "right");
2920 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2921 if (r == TypeManager.string_type)
2922 Report.Warning (252, 2, loc, ref_comparison, "left");
2931 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2934 // bool operator == (void* x, void* y);
2935 // bool operator != (void* x, void* y);
2936 // bool operator < (void* x, void* y);
2937 // bool operator > (void* x, void* y);
2938 // bool operator <= (void* x, void* y);
2939 // bool operator >= (void* x, void* y);
2941 if ((oper & Operator.ComparisonMask) != 0) {
2944 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2951 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2957 type = TypeManager.bool_type;
2961 if (pointer_operators == null)
2962 CreatePointerOperatorsTable ();
2964 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2968 // Build-in operators method overloading
2970 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2972 PredefinedOperator best_operator = null;
2974 Type r = right.Type;
2975 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2977 foreach (PredefinedOperator po in operators) {
2978 if ((po.OperatorsMask & oper_mask) == 0)
2981 if (primitives_only) {
2982 if (!po.IsPrimitiveApplicable (l, r))
2985 if (!po.IsApplicable (ec, left, right))
2989 if (best_operator == null) {
2991 if (primitives_only)
2997 best_operator = po.ResolveBetterOperator (ec, best_operator);
2999 if (best_operator == null) {
3000 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3001 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3008 if (best_operator == null)
3011 Expression expr = best_operator.ConvertResult (ec, this);
3012 if (enum_type == null)
3016 // HACK: required by enum_conversion
3018 expr.Type = enum_type;
3019 return EmptyCast.Create (expr, enum_type);
3023 // Performs user-operator overloading
3025 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3028 if (oper == Operator.LogicalAnd)
3029 user_oper = Operator.BitwiseAnd;
3030 else if (oper == Operator.LogicalOr)
3031 user_oper = Operator.BitwiseOr;
3035 string op = GetOperatorMetadataName (user_oper);
3037 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3038 MethodGroupExpr right_operators = null;
3040 if (!TypeManager.IsEqual (r, l)) {
3041 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3042 if (right_operators == null && left_operators == null)
3044 } else if (left_operators == null) {
3048 ArrayList args = new ArrayList (2);
3049 Argument larg = new Argument (left);
3051 Argument rarg = new Argument (right);
3054 MethodGroupExpr union;
3057 // User-defined operator implementations always take precedence
3058 // over predefined operator implementations
3060 if (left_operators != null && right_operators != null) {
3061 if (IsPredefinedUserOperator (l, user_oper)) {
3062 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3064 union = left_operators;
3065 } else if (IsPredefinedUserOperator (r, user_oper)) {
3066 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3068 union = right_operators;
3070 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3072 } else if (left_operators != null) {
3073 union = left_operators;
3075 union = right_operators;
3078 union = union.OverloadResolve (ec, ref args, true, loc);
3082 Expression oper_expr;
3084 // TODO: CreateExpressionTree is allocated every time
3085 if (user_oper != oper) {
3086 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3087 oper == Operator.LogicalAnd, loc).Resolve (ec);
3089 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3092 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3093 // and not invoke user operator
3095 if ((oper & Operator.EqualityMask) != 0) {
3096 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3097 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3098 type = TypeManager.bool_type;
3099 if (left is NullLiteral || right is NullLiteral)
3100 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3101 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3103 // Two System.Delegate(s) are never equal
3115 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3120 private void CheckUselessComparison (Constant c, Type type)
3122 if (c == null || !IsTypeIntegral (type)
3123 || c is StringConstant
3124 || c is BoolConstant
3125 || c is FloatConstant
3126 || c is DoubleConstant
3127 || c is DecimalConstant
3133 if (c is ULongConstant) {
3134 ulong uvalue = ((ULongConstant) c).Value;
3135 if (uvalue > long.MaxValue) {
3136 if (type == TypeManager.byte_type ||
3137 type == TypeManager.sbyte_type ||
3138 type == TypeManager.short_type ||
3139 type == TypeManager.ushort_type ||
3140 type == TypeManager.int32_type ||
3141 type == TypeManager.uint32_type ||
3142 type == TypeManager.int64_type ||
3143 type == TypeManager.char_type)
3144 WarnUselessComparison (type);
3147 value = (long) uvalue;
3149 else if (c is ByteConstant)
3150 value = ((ByteConstant) c).Value;
3151 else if (c is SByteConstant)
3152 value = ((SByteConstant) c).Value;
3153 else if (c is ShortConstant)
3154 value = ((ShortConstant) c).Value;
3155 else if (c is UShortConstant)
3156 value = ((UShortConstant) c).Value;
3157 else if (c is IntConstant)
3158 value = ((IntConstant) c).Value;
3159 else if (c is UIntConstant)
3160 value = ((UIntConstant) c).Value;
3161 else if (c is LongConstant)
3162 value = ((LongConstant) c).Value;
3163 else if (c is CharConstant)
3164 value = ((CharConstant)c).Value;
3169 if (IsValueOutOfRange (value, type))
3170 WarnUselessComparison (type);
3173 static bool IsValueOutOfRange (long value, Type type)
3175 if (IsTypeUnsigned (type) && value < 0)
3177 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3178 type == TypeManager.byte_type && value >= 0x100 ||
3179 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3180 type == TypeManager.ushort_type && value >= 0x10000 ||
3181 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3182 type == TypeManager.uint32_type && value >= 0x100000000;
3185 static bool IsBuildInEqualityOperator (Type t)
3187 return t == TypeManager.object_type || t == TypeManager.string_type ||
3188 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3191 static bool IsPredefinedUserOperator (Type t, Operator op)
3194 // Some predefined types have user operators
3196 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3199 private static bool IsTypeIntegral (Type type)
3201 return type == TypeManager.uint64_type ||
3202 type == TypeManager.int64_type ||
3203 type == TypeManager.uint32_type ||
3204 type == TypeManager.int32_type ||
3205 type == TypeManager.ushort_type ||
3206 type == TypeManager.short_type ||
3207 type == TypeManager.sbyte_type ||
3208 type == TypeManager.byte_type ||
3209 type == TypeManager.char_type;
3212 private static bool IsTypeUnsigned (Type type)
3214 return type == TypeManager.uint64_type ||
3215 type == TypeManager.uint32_type ||
3216 type == TypeManager.ushort_type ||
3217 type == TypeManager.byte_type ||
3218 type == TypeManager.char_type;
3221 private void WarnUselessComparison (Type type)
3223 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}'",
3224 TypeManager.CSharpName (type));
3228 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3229 /// context of a conditional bool expression. This function will return
3230 /// false if it is was possible to use EmitBranchable, or true if it was.
3232 /// The expression's code is generated, and we will generate a branch to `target'
3233 /// if the resulting expression value is equal to isTrue
3235 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3237 ILGenerator ig = ec.ig;
3240 // This is more complicated than it looks, but its just to avoid
3241 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3242 // but on top of that we want for == and != to use a special path
3243 // if we are comparing against null
3245 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3246 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3249 // put the constant on the rhs, for simplicity
3251 if (left is Constant) {
3252 Expression swap = right;
3257 if (((Constant) right).IsZeroInteger) {
3258 left.EmitBranchable (ec, target, my_on_true);
3261 if (right.Type == TypeManager.bool_type) {
3262 // right is a boolean, and it's not 'false' => it is 'true'
3263 left.EmitBranchable (ec, target, !my_on_true);
3267 } else if (oper == Operator.LogicalAnd) {
3270 Label tests_end = ig.DefineLabel ();
3272 left.EmitBranchable (ec, tests_end, false);
3273 right.EmitBranchable (ec, target, true);
3274 ig.MarkLabel (tests_end);
3277 // This optimizes code like this
3278 // if (true && i > 4)
3280 if (!(left is Constant))
3281 left.EmitBranchable (ec, target, false);
3283 if (!(right is Constant))
3284 right.EmitBranchable (ec, target, false);
3289 } else if (oper == Operator.LogicalOr){
3291 left.EmitBranchable (ec, target, true);
3292 right.EmitBranchable (ec, target, true);
3295 Label tests_end = ig.DefineLabel ();
3296 left.EmitBranchable (ec, tests_end, true);
3297 right.EmitBranchable (ec, target, false);
3298 ig.MarkLabel (tests_end);
3303 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3304 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3305 oper == Operator.Equality || oper == Operator.Inequality)) {
3306 base.EmitBranchable (ec, target, on_true);
3314 bool is_float = IsFloat (t);
3315 bool is_unsigned = is_float || IsUnsigned (t);
3318 case Operator.Equality:
3320 ig.Emit (OpCodes.Beq, target);
3322 ig.Emit (OpCodes.Bne_Un, target);
3325 case Operator.Inequality:
3327 ig.Emit (OpCodes.Bne_Un, target);
3329 ig.Emit (OpCodes.Beq, target);
3332 case Operator.LessThan:
3334 if (is_unsigned && !is_float)
3335 ig.Emit (OpCodes.Blt_Un, target);
3337 ig.Emit (OpCodes.Blt, target);
3340 ig.Emit (OpCodes.Bge_Un, target);
3342 ig.Emit (OpCodes.Bge, target);
3345 case Operator.GreaterThan:
3347 if (is_unsigned && !is_float)
3348 ig.Emit (OpCodes.Bgt_Un, target);
3350 ig.Emit (OpCodes.Bgt, target);
3353 ig.Emit (OpCodes.Ble_Un, target);
3355 ig.Emit (OpCodes.Ble, target);
3358 case Operator.LessThanOrEqual:
3360 if (is_unsigned && !is_float)
3361 ig.Emit (OpCodes.Ble_Un, target);
3363 ig.Emit (OpCodes.Ble, target);
3366 ig.Emit (OpCodes.Bgt_Un, target);
3368 ig.Emit (OpCodes.Bgt, target);
3372 case Operator.GreaterThanOrEqual:
3374 if (is_unsigned && !is_float)
3375 ig.Emit (OpCodes.Bge_Un, target);
3377 ig.Emit (OpCodes.Bge, target);
3380 ig.Emit (OpCodes.Blt_Un, target);
3382 ig.Emit (OpCodes.Blt, target);
3385 throw new InternalErrorException (oper.ToString ());
3389 public override void Emit (EmitContext ec)
3391 EmitOperator (ec, left.Type);
3394 protected virtual void EmitOperator (EmitContext ec, Type l)
3396 ILGenerator ig = ec.ig;
3399 // Handle short-circuit operators differently
3402 if ((oper & Operator.LogicalMask) != 0) {
3403 Label load_result = ig.DefineLabel ();
3404 Label end = ig.DefineLabel ();
3406 bool is_or = oper == Operator.LogicalOr;
3407 left.EmitBranchable (ec, load_result, is_or);
3409 ig.Emit (OpCodes.Br_S, end);
3411 ig.MarkLabel (load_result);
3412 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3420 // Optimize zero-based operations
3422 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3424 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3425 Constant rc = right as Constant;
3426 if (rc != null && rc.IsDefaultValue) {
3432 EmitOperatorOpcode (ec, oper, l);
3435 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3436 // expression because that would wrap lifted binary operation
3438 if (enum_conversion != null)
3439 enum_conversion.Emit (ec);
3442 public override void EmitSideEffect (EmitContext ec)
3444 if ((oper & Operator.LogicalMask) != 0 ||
3445 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3446 base.EmitSideEffect (ec);
3448 left.EmitSideEffect (ec);
3449 right.EmitSideEffect (ec);
3453 protected override void CloneTo (CloneContext clonectx, Expression t)
3455 Binary target = (Binary) t;
3457 target.left = left.Clone (clonectx);
3458 target.right = right.Clone (clonectx);
3461 public override Expression CreateExpressionTree (EmitContext ec)
3463 return CreateExpressionTree (ec, null);
3466 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3469 bool lift_arg = false;
3472 case Operator.Addition:
3473 if (method == null && ec.CheckState && !IsFloat (type))
3474 method_name = "AddChecked";
3476 method_name = "Add";
3478 case Operator.BitwiseAnd:
3479 method_name = "And";
3481 case Operator.BitwiseOr:
3484 case Operator.Division:
3485 method_name = "Divide";
3487 case Operator.Equality:
3488 method_name = "Equal";
3491 case Operator.ExclusiveOr:
3492 method_name = "ExclusiveOr";
3494 case Operator.GreaterThan:
3495 method_name = "GreaterThan";
3498 case Operator.GreaterThanOrEqual:
3499 method_name = "GreaterThanOrEqual";
3502 case Operator.Inequality:
3503 method_name = "NotEqual";
3506 case Operator.LeftShift:
3507 method_name = "LeftShift";
3509 case Operator.LessThan:
3510 method_name = "LessThan";
3513 case Operator.LessThanOrEqual:
3514 method_name = "LessThanOrEqual";
3517 case Operator.LogicalAnd:
3518 method_name = "AndAlso";
3520 case Operator.LogicalOr:
3521 method_name = "OrElse";
3523 case Operator.Modulus:
3524 method_name = "Modulo";
3526 case Operator.Multiply:
3527 if (method == null && ec.CheckState && !IsFloat (type))
3528 method_name = "MultiplyChecked";
3530 method_name = "Multiply";
3532 case Operator.RightShift:
3533 method_name = "RightShift";
3535 case Operator.Subtraction:
3536 if (method == null && ec.CheckState && !IsFloat (type))
3537 method_name = "SubtractChecked";
3539 method_name = "Subtract";
3543 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3546 ArrayList args = new ArrayList (2);
3547 args.Add (new Argument (left.CreateExpressionTree (ec)));
3548 args.Add (new Argument (right.CreateExpressionTree (ec)));
3549 if (method != null) {
3551 args.Add (new Argument (new BoolConstant (false, loc)));
3553 args.Add (new Argument (method.CreateExpressionTree (ec)));
3556 return CreateExpressionFactoryCall (method_name, args);
3561 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3562 // b, c, d... may be strings or objects.
3564 public class StringConcat : Expression {
3565 ArrayList arguments;
3567 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3570 type = TypeManager.string_type;
3571 eclass = ExprClass.Value;
3573 arguments = new ArrayList (2);
3578 public override Expression CreateExpressionTree (EmitContext ec)
3580 Argument arg = (Argument) arguments [0];
3581 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3585 // Creates nested calls tree from an array of arguments used for IL emit
3587 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3589 ArrayList concat_args = new ArrayList (2);
3590 ArrayList add_args = new ArrayList (3);
3592 concat_args.Add (left);
3593 add_args.Add (new Argument (left_etree));
3595 concat_args.Add (arguments [pos]);
3596 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3598 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3602 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3606 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3608 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3609 if (++pos == arguments.Count)
3612 left = new Argument (new EmptyExpression (method.Type));
3613 return CreateExpressionAddCall (ec, left, expr, pos);
3616 public override Expression DoResolve (EmitContext ec)
3621 public void Append (EmitContext ec, Expression operand)
3626 StringConstant sc = operand as StringConstant;
3628 if (arguments.Count != 0) {
3629 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3630 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3631 if (last_expr_constant != null) {
3632 last_argument.Expr = new StringConstant (
3633 last_expr_constant.Value + sc.Value, sc.Location);
3639 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3641 StringConcat concat_oper = operand as StringConcat;
3642 if (concat_oper != null) {
3643 arguments.AddRange (concat_oper.arguments);
3648 arguments.Add (new Argument (operand));
3651 Expression CreateConcatMemberExpression ()
3653 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3656 public override void Emit (EmitContext ec)
3658 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3659 concat = concat.Resolve (ec);
3664 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3666 foreach (Argument a in arguments)
3667 a.Expr.MutateHoistedGenericType (storey);
3672 // User-defined conditional logical operator
3674 public class ConditionalLogicalOperator : UserOperatorCall {
3675 readonly bool is_and;
3678 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3679 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3680 : base (oper_method, arguments, expr_tree, loc)
3682 this.is_and = is_and;
3685 public override Expression DoResolve (EmitContext ec)
3687 MethodInfo method = (MethodInfo)mg;
3688 type = TypeManager.TypeToCoreType (method.ReturnType);
3689 AParametersCollection pd = TypeManager.GetParameterData (method);
3690 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3691 Report.Error (217, loc,
3692 "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",
3693 TypeManager.CSharpSignature (method));
3697 Expression left_dup = new EmptyExpression (type);
3698 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3699 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3700 if (op_true == null || op_false == null) {
3701 Report.Error (218, loc,
3702 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3703 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3707 oper = is_and ? op_false : op_true;
3708 eclass = ExprClass.Value;
3712 public override void Emit (EmitContext ec)
3714 ILGenerator ig = ec.ig;
3715 Label end_target = ig.DefineLabel ();
3718 // Emit and duplicate left argument
3720 ((Argument)arguments [0]).Expr.Emit (ec);
3721 ig.Emit (OpCodes.Dup);
3722 arguments.RemoveAt (0);
3724 oper.EmitBranchable (ec, end_target, true);
3726 ig.MarkLabel (end_target);
3730 public class PointerArithmetic : Expression {
3731 Expression left, right;
3735 // We assume that `l' is always a pointer
3737 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3746 public override Expression CreateExpressionTree (EmitContext ec)
3748 Error_PointerInsideExpressionTree ();
3752 public override Expression DoResolve (EmitContext ec)
3754 eclass = ExprClass.Variable;
3756 if (left.Type == TypeManager.void_ptr_type) {
3757 Error (242, "The operation in question is undefined on void pointers");
3764 public override void Emit (EmitContext ec)
3766 Type op_type = left.Type;
3767 ILGenerator ig = ec.ig;
3769 // It must be either array or fixed buffer
3771 if (TypeManager.HasElementType (op_type)) {
3772 element = TypeManager.GetElementType (op_type);
3774 FieldExpr fe = left as FieldExpr;
3776 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3781 int size = GetTypeSize (element);
3782 Type rtype = right.Type;
3784 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3786 // handle (pointer - pointer)
3790 ig.Emit (OpCodes.Sub);
3794 ig.Emit (OpCodes.Sizeof, element);
3796 IntLiteral.EmitInt (ig, size);
3797 ig.Emit (OpCodes.Div);
3799 ig.Emit (OpCodes.Conv_I8);
3802 // handle + and - on (pointer op int)
3806 Constant right_const = right as Constant;
3807 if (right_const != null) {
3809 // Optimize 0-based arithmetic
3811 if (right_const.IsDefaultValue)
3815 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3819 ig.Emit (OpCodes.Sizeof, element);
3820 right = EmptyExpression.Null;
3825 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3826 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3827 ig.Emit (OpCodes.Conv_I);
3828 } else if (rtype == TypeManager.uint32_type) {
3829 ig.Emit (OpCodes.Conv_U);
3832 if (right_const == null && size != 1){
3834 ig.Emit (OpCodes.Sizeof, element);
3836 IntLiteral.EmitInt (ig, size);
3837 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3838 ig.Emit (OpCodes.Conv_I8);
3840 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3843 if (rtype == TypeManager.int64_type)
3844 ig.Emit (OpCodes.Conv_I);
3845 else if (rtype == TypeManager.uint64_type)
3846 ig.Emit (OpCodes.Conv_U);
3848 Binary.EmitOperatorOpcode (ec, op, op_type);
3854 /// Implements the ternary conditional operator (?:)
3856 public class Conditional : Expression {
3857 Expression expr, true_expr, false_expr;
3859 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3862 this.true_expr = true_expr;
3863 this.false_expr = false_expr;
3864 this.loc = expr.Location;
3867 public Expression Expr {
3873 public Expression TrueExpr {
3879 public Expression FalseExpr {
3885 public override Expression CreateExpressionTree (EmitContext ec)
3887 ArrayList args = new ArrayList (3);
3888 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3889 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3890 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3891 return CreateExpressionFactoryCall ("Condition", args);
3894 public override Expression DoResolve (EmitContext ec)
3896 expr = expr.Resolve (ec);
3901 if (expr.Type != TypeManager.bool_type){
3902 expr = Expression.ResolveBoolean (
3909 Assign ass = expr as Assign;
3910 if (ass != null && ass.Source is Constant) {
3911 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3914 true_expr = true_expr.Resolve (ec);
3915 false_expr = false_expr.Resolve (ec);
3917 if (true_expr == null || false_expr == null)
3920 eclass = ExprClass.Value;
3921 Type true_type = true_expr.Type;
3922 Type false_type = false_expr.Type;
3926 // First, if an implicit conversion exists from true_expr
3927 // to false_expr, then the result type is of type false_expr.Type
3929 if (!TypeManager.IsEqual (true_type, false_type)) {
3930 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3933 // Check if both can convert implicitl to each other's type
3935 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3937 "Can not compute type of conditional expression " +
3938 "as `" + TypeManager.CSharpName (true_expr.Type) +
3939 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3940 "' convert implicitly to each other");
3945 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3948 Report.Error (173, loc,
3949 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3950 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3955 // Dead code optimalization
3956 Constant c = expr as Constant;
3958 bool is_false = c.IsDefaultValue;
3959 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3960 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3966 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3968 expr.MutateHoistedGenericType (storey);
3969 true_expr.MutateHoistedGenericType (storey);
3970 false_expr.MutateHoistedGenericType (storey);
3971 type = storey.MutateType (type);
3974 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3979 public override void Emit (EmitContext ec)
3981 ILGenerator ig = ec.ig;
3982 Label false_target = ig.DefineLabel ();
3983 Label end_target = ig.DefineLabel ();
3985 expr.EmitBranchable (ec, false_target, false);
3986 true_expr.Emit (ec);
3988 if (type.IsInterface) {
3989 LocalBuilder temp = ec.GetTemporaryLocal (type);
3990 ig.Emit (OpCodes.Stloc, temp);
3991 ig.Emit (OpCodes.Ldloc, temp);
3992 ec.FreeTemporaryLocal (temp, type);
3995 ig.Emit (OpCodes.Br, end_target);
3996 ig.MarkLabel (false_target);
3997 false_expr.Emit (ec);
3998 ig.MarkLabel (end_target);
4001 protected override void CloneTo (CloneContext clonectx, Expression t)
4003 Conditional target = (Conditional) t;
4005 target.expr = expr.Clone (clonectx);
4006 target.true_expr = true_expr.Clone (clonectx);
4007 target.false_expr = false_expr.Clone (clonectx);
4011 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4012 LocalTemporary temp;
4015 public abstract HoistedVariable HoistedVariable { get; }
4016 public abstract bool IsFixedVariable { get; }
4017 public abstract bool IsRef { get; }
4018 public abstract string Name { get; }
4019 public abstract void SetHasAddressTaken ();
4022 // Variable IL data, it has to be protected to encapsulate hoisted variables
4024 protected abstract ILocalVariable Variable { get; }
4027 // Variable flow-analysis data
4029 public abstract VariableInfo VariableInfo { get; }
4032 public void AddressOf (EmitContext ec, AddressOp mode)
4034 if (IsHoistedEmitRequired (ec)) {
4035 HoistedVariable.AddressOf (ec, mode);
4039 Variable.EmitAddressOf (ec);
4042 public override void Emit (EmitContext ec)
4047 public override void EmitSideEffect (EmitContext ec)
4053 // This method is used by parameters that are references, that are
4054 // being passed as references: we only want to pass the pointer (that
4055 // is already stored in the parameter, not the address of the pointer,
4056 // and not the value of the variable).
4058 public void EmitLoad (EmitContext ec)
4063 public void Emit (EmitContext ec, bool leave_copy)
4065 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4067 if (IsHoistedEmitRequired (ec)) {
4068 HoistedVariable.Emit (ec, leave_copy);
4076 // If we are a reference, we loaded on the stack a pointer
4077 // Now lets load the real value
4079 LoadFromPtr (ec.ig, type);
4083 ec.ig.Emit (OpCodes.Dup);
4086 temp = new LocalTemporary (Type);
4092 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4093 bool prepare_for_load)
4095 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4098 if (IsHoistedEmitRequired (ec)) {
4099 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4108 // HACK: variable is already emitted when source is an initializer
4109 if (source is NewInitialize) {
4117 ec.ig.Emit (OpCodes.Dup);
4119 temp = new LocalTemporary (Type);
4125 StoreFromPtr (ec.ig, type);
4127 Variable.EmitAssign (ec);
4135 public bool IsHoisted {
4136 get { return HoistedVariable != null; }
4139 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4142 // Default implementation return true when there is a hosted variable
4144 return HoistedVariable != null;
4147 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4149 type = storey.MutateType (type);
4156 public class LocalVariableReference : VariableReference {
4157 readonly string name;
4159 public LocalInfo local_info;
4162 public LocalVariableReference (Block block, string name, Location l)
4167 eclass = ExprClass.Variable;
4171 // Setting `is_readonly' to false will allow you to create a writable
4172 // reference to a read-only variable. This is used by foreach and using.
4174 public LocalVariableReference (Block block, string name, Location l,
4175 LocalInfo local_info, bool is_readonly)
4176 : this (block, name, l)
4178 this.local_info = local_info;
4179 this.is_readonly = is_readonly;
4182 public override VariableInfo VariableInfo {
4183 get { return local_info.VariableInfo; }
4186 public override HoistedVariable HoistedVariable {
4187 get { return local_info.HoistedVariableReference; }
4191 // A local variable is always fixed
4193 public override bool IsFixedVariable {
4194 get { return true; }
4197 public override bool IsRef {
4198 get { return false; }
4201 public bool IsReadOnly {
4202 get { return is_readonly; }
4205 public override string Name {
4206 get { return name; }
4209 public bool VerifyAssigned (EmitContext ec)
4211 VariableInfo variable_info = local_info.VariableInfo;
4212 return variable_info == null || variable_info.IsAssigned (ec, loc);
4215 void ResolveLocalInfo ()
4217 if (local_info == null) {
4218 local_info = Block.GetLocalInfo (Name);
4219 type = local_info.VariableType;
4220 is_readonly = local_info.ReadOnly;
4224 public override void SetHasAddressTaken ()
4226 local_info.AddressTaken = true;
4229 public override Expression CreateExpressionTree (EmitContext ec)
4231 ArrayList arg = new ArrayList (1);
4232 arg.Add (new Argument (this));
4233 return CreateExpressionFactoryCall ("Constant", arg);
4236 Expression DoResolveBase (EmitContext ec)
4238 type = local_info.VariableType;
4240 Expression e = Block.GetConstantExpression (Name);
4242 return e.Resolve (ec);
4244 VerifyAssigned (ec);
4247 // If we are referencing a variable from the external block
4248 // flag it for capturing
4250 if (ec.MustCaptureVariable (local_info)) {
4251 if (local_info.AddressTaken)
4252 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4254 if (ec.IsVariableCapturingRequired) {
4255 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4256 storey.CaptureLocalVariable (ec, local_info);
4263 public override Expression DoResolve (EmitContext ec)
4265 ResolveLocalInfo ();
4266 local_info.Used = true;
4268 if (type == null && local_info.Type is VarExpr) {
4269 local_info.VariableType = TypeManager.object_type;
4270 Error_VariableIsUsedBeforeItIsDeclared (Name);
4274 return DoResolveBase (ec);
4277 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4279 ResolveLocalInfo ();
4282 if (right_side == EmptyExpression.OutAccess)
4283 local_info.Used = true;
4285 // Infer implicitly typed local variable
4287 VarExpr ve = local_info.Type as VarExpr;
4289 if (!ve.InferType (ec, right_side))
4291 type = local_info.VariableType = ve.Type;
4298 if (right_side == EmptyExpression.OutAccess) {
4299 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4300 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4301 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4302 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4303 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4304 } else if (right_side == EmptyExpression.UnaryAddress) {
4305 code = 459; msg = "Cannot take the address of {1} `{0}'";
4307 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4309 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4310 } else if (VariableInfo != null) {
4311 VariableInfo.SetAssigned (ec);
4314 return DoResolveBase (ec);
4317 public override int GetHashCode ()
4319 return Name.GetHashCode ();
4322 public override bool Equals (object obj)
4324 LocalVariableReference lvr = obj as LocalVariableReference;
4328 return Name == lvr.Name && Block == lvr.Block;
4331 protected override ILocalVariable Variable {
4332 get { return local_info; }
4335 public override string ToString ()
4337 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4340 protected override void CloneTo (CloneContext clonectx, Expression t)
4342 LocalVariableReference target = (LocalVariableReference) t;
4344 target.Block = clonectx.LookupBlock (Block);
4345 if (local_info != null)
4346 target.local_info = clonectx.LookupVariable (local_info);
4351 /// This represents a reference to a parameter in the intermediate
4354 public class ParameterReference : VariableReference {
4355 readonly ToplevelParameterInfo pi;
4356 readonly ToplevelBlock referenced;
4358 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4361 this.referenced = referenced;
4365 public override bool IsRef {
4366 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4369 bool HasOutModifier {
4370 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4373 public override HoistedVariable HoistedVariable {
4374 get { return pi.Parameter.HoistedVariableReference; }
4378 // A ref or out parameter is classified as a moveable variable, even
4379 // if the argument given for the parameter is a fixed variable
4381 public override bool IsFixedVariable {
4382 get { return !IsRef; }
4385 public override string Name {
4386 get { return Parameter.Name; }
4389 public Parameter Parameter {
4390 get { return pi.Parameter; }
4393 public override VariableInfo VariableInfo {
4394 get { return pi.VariableInfo; }
4397 protected override ILocalVariable Variable {
4398 get { return Parameter; }
4401 public bool IsAssigned (EmitContext ec, Location loc)
4403 // HACK: Variables are not captured in probing mode
4404 if (ec.IsInProbingMode)
4407 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4410 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4414 public override void SetHasAddressTaken ()
4416 Parameter.HasAddressTaken = true;
4419 void SetAssigned (EmitContext ec)
4421 if (HasOutModifier && ec.DoFlowAnalysis)
4422 ec.CurrentBranching.SetAssigned (VariableInfo);
4425 bool DoResolveBase (EmitContext ec)
4427 type = pi.ParameterType;
4428 eclass = ExprClass.Variable;
4430 AnonymousExpression am = ec.CurrentAnonymousMethod;
4434 ToplevelBlock declared = pi.Block;
4435 if (declared != referenced) {
4437 Report.Error (1628, loc,
4438 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4439 Name, am.ContainerType);
4447 if (ec.IsVariableCapturingRequired) {
4448 if (pi.Parameter.HasAddressTaken)
4449 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4451 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4452 storey.CaptureParameter (ec, this);
4458 public override int GetHashCode ()
4460 return Name.GetHashCode ();
4463 public override bool Equals (object obj)
4465 ParameterReference pr = obj as ParameterReference;
4469 return Name == pr.Name && referenced == pr.referenced;
4472 protected override void CloneTo (CloneContext clonectx, Expression target)
4477 public override Expression CreateExpressionTree (EmitContext ec)
4479 if (IsHoistedEmitRequired (ec))
4480 return HoistedVariable.CreateExpressionTree (ec);
4482 return Parameter.ExpressionTreeVariableReference ();
4486 // Notice that for ref/out parameters, the type exposed is not the
4487 // same type exposed externally.
4490 // externally we expose "int&"
4491 // here we expose "int".
4493 // We record this in "is_ref". This means that the type system can treat
4494 // the type as it is expected, but when we generate the code, we generate
4495 // the alternate kind of code.
4497 public override Expression DoResolve (EmitContext ec)
4499 if (!DoResolveBase (ec))
4502 if (HasOutModifier && ec.DoFlowAnalysis &&
4503 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4509 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4511 if (!DoResolveBase (ec))
4514 // HACK: parameters are not captured when probing is on
4515 if (!ec.IsInProbingMode)
4521 static public void EmitLdArg (ILGenerator ig, int x)
4525 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4526 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4527 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4528 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4529 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4532 ig.Emit (OpCodes.Ldarg, x);
4537 /// Used for arguments to New(), Invocation()
4539 public class Argument {
4540 public enum AType : byte {
4547 public static readonly Argument[] Empty = new Argument [0];
4549 public readonly AType ArgType;
4550 public Expression Expr;
4552 public Argument (Expression expr, AType type)
4555 this.ArgType = type;
4558 public Argument (Expression expr)
4561 this.ArgType = AType.Expression;
4565 get { return Expr.Type; }
4568 public Parameter.Modifier Modifier
4573 return Parameter.Modifier.OUT;
4576 return Parameter.Modifier.REF;
4579 return Parameter.Modifier.NONE;
4584 public string GetSignatureForError ()
4586 if (Expr.eclass == ExprClass.MethodGroup)
4587 return Expr.ExprClassName;
4589 return TypeManager.CSharpName (Expr.Type);
4592 public bool ResolveMethodGroup (EmitContext ec)
4594 SimpleName sn = Expr as SimpleName;
4596 Expr = sn.GetMethodGroup ();
4598 // FIXME: csc doesn't report any error if you try to use `ref' or
4599 // `out' in a delegate creation expression.
4600 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4607 public bool Resolve (EmitContext ec, Location loc)
4612 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4613 // Verify that the argument is readable
4614 if (ArgType != AType.Out)
4615 Expr = Expr.Resolve (ec);
4617 // Verify that the argument is writeable
4618 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4619 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4621 return Expr != null;
4625 public void Emit (EmitContext ec)
4627 if (ArgType != AType.Ref && ArgType != AType.Out) {
4632 AddressOp mode = AddressOp.Store;
4633 if (ArgType == AType.Ref)
4634 mode |= AddressOp.Load;
4636 IMemoryLocation ml = (IMemoryLocation) Expr;
4637 ParameterReference pr = ml as ParameterReference;
4640 // ParameterReferences might already be references, so we want
4641 // to pass just the value
4643 if (pr != null && pr.IsRef)
4646 ml.AddressOf (ec, mode);
4649 public Argument Clone (CloneContext clonectx)
4651 return new Argument (Expr.Clone (clonectx), ArgType);
4656 /// Invocation of methods or delegates.
4658 public class Invocation : ExpressionStatement {
4659 protected ArrayList Arguments;
4660 protected Expression expr;
4661 protected MethodGroupExpr mg;
4662 bool arguments_resolved;
4665 // arguments is an ArrayList, but we do not want to typecast,
4666 // as it might be null.
4668 public Invocation (Expression expr, ArrayList arguments)
4670 SimpleName sn = expr as SimpleName;
4672 this.expr = sn.GetMethodGroup ();
4676 Arguments = arguments;
4678 loc = expr.Location;
4681 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4682 : this (expr, arguments)
4684 this.arguments_resolved = arguments_resolved;
4687 public override Expression CreateExpressionTree (EmitContext ec)
4692 // Special conversion for nested expression trees
4694 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4695 args = new ArrayList (1);
4696 args.Add (new Argument (this));
4697 return CreateExpressionFactoryCall ("Quote", args);
4700 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4702 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4705 args = new ArrayList (arg_count);
4708 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4710 args.Add (new Argument (new NullLiteral (loc)));
4712 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4715 // Use extension argument when exists
4718 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4720 args.Add (new Argument (e));
4723 if (Arguments != null) {
4724 foreach (Argument a in Arguments) {
4725 Expression e = a.Expr.CreateExpressionTree (ec);
4727 args.Add (new Argument (e));
4732 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4734 return CreateExpressionFactoryCall ("Call", args);
4737 public override Expression DoResolve (EmitContext ec)
4739 // Don't resolve already resolved expression
4740 if (eclass != ExprClass.Invalid)
4743 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4744 if (expr_resolved == null)
4747 mg = expr_resolved as MethodGroupExpr;
4749 Type expr_type = expr_resolved.Type;
4751 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4752 return (new DelegateInvocation (
4753 expr_resolved, Arguments, loc)).Resolve (ec);
4756 MemberExpr me = expr_resolved as MemberExpr;
4758 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4762 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4764 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4765 expr_resolved.GetSignatureForError ());
4769 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4773 // Next, evaluate all the expressions in the argument list
4775 if (Arguments != null && !arguments_resolved) {
4776 for (int i = 0; i < Arguments.Count; ++i)
4778 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4783 mg = DoResolveOverload (ec);
4787 MethodInfo method = (MethodInfo)mg;
4788 if (method != null) {
4789 type = TypeManager.TypeToCoreType (method.ReturnType);
4791 // TODO: this is a copy of mg.ResolveMemberAccess method
4792 Expression iexpr = mg.InstanceExpression;
4793 if (method.IsStatic) {
4794 if (iexpr == null ||
4795 iexpr is This || iexpr is EmptyExpression ||
4796 mg.IdenticalTypeName) {
4797 mg.InstanceExpression = null;
4799 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4805 if (type.IsPointer){
4813 // Only base will allow this invocation to happen.
4815 if (mg.IsBase && method.IsAbstract){
4816 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4820 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4822 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4824 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4828 IsSpecialMethodInvocation (method, loc);
4830 if (mg.InstanceExpression != null)
4831 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4833 eclass = ExprClass.Value;
4837 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4839 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4842 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4844 if (!TypeManager.IsSpecialMethod (method))
4847 Report.SymbolRelatedToPreviousError (method);
4848 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4849 TypeManager.CSharpSignature (method, true));
4855 /// Emits a list of resolved Arguments that are in the arguments
4858 /// The MethodBase argument might be null if the
4859 /// emission of the arguments is known not to contain
4860 /// a `params' field (for example in constructors or other routines
4861 /// that keep their arguments in this structure)
4863 /// if `dup_args' is true, a copy of the arguments will be left
4864 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4865 /// which will be duplicated before any other args. Only EmitCall
4866 /// should be using this interface.
4868 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4870 if (arguments == null)
4873 int top = arguments.Count;
4874 LocalTemporary [] temps = null;
4876 if (dup_args && top != 0)
4877 temps = new LocalTemporary [top];
4879 int argument_index = 0;
4881 for (int i = 0; i < top; i++) {
4882 a = (Argument) arguments [argument_index++];
4885 ec.ig.Emit (OpCodes.Dup);
4886 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4891 if (this_arg != null)
4894 for (int i = 0; i < top; i ++) {
4895 temps [i].Emit (ec);
4896 temps [i].Release (ec);
4901 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4903 AParametersCollection pd = TypeManager.GetParameterData (mb);
4905 Argument a = (Argument) arguments [pd.Count - 1];
4906 Arglist list = (Arglist) a.Expr;
4908 return list.ArgumentTypes;
4912 /// This checks the ConditionalAttribute on the method
4914 public static bool IsMethodExcluded (MethodBase method, Location loc)
4916 if (method.IsConstructor)
4919 method = TypeManager.DropGenericMethodArguments (method);
4920 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4921 IMethodData md = TypeManager.GetMethod (method);
4923 return md.IsExcluded ();
4925 // For some methods (generated by delegate class) GetMethod returns null
4926 // because they are not included in builder_to_method table
4930 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4934 /// is_base tells whether we want to force the use of the `call'
4935 /// opcode instead of using callvirt. Call is required to call
4936 /// a specific method, while callvirt will always use the most
4937 /// recent method in the vtable.
4939 /// is_static tells whether this is an invocation on a static method
4941 /// instance_expr is an expression that represents the instance
4942 /// it must be non-null if is_static is false.
4944 /// method is the method to invoke.
4946 /// Arguments is the list of arguments to pass to the method or constructor.
4948 public static void EmitCall (EmitContext ec, bool is_base,
4949 Expression instance_expr,
4950 MethodBase method, ArrayList Arguments, Location loc)
4952 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4955 // `dup_args' leaves an extra copy of the arguments on the stack
4956 // `omit_args' does not leave any arguments at all.
4957 // So, basically, you could make one call with `dup_args' set to true,
4958 // and then another with `omit_args' set to true, and the two calls
4959 // would have the same set of arguments. However, each argument would
4960 // only have been evaluated once.
4961 public static void EmitCall (EmitContext ec, bool is_base,
4962 Expression instance_expr,
4963 MethodBase method, ArrayList Arguments, Location loc,
4964 bool dup_args, bool omit_args)
4966 ILGenerator ig = ec.ig;
4967 bool struct_call = false;
4968 bool this_call = false;
4969 LocalTemporary this_arg = null;
4971 Type decl_type = method.DeclaringType;
4973 if (!ec.IsInObsoleteScope) {
4975 // This checks ObsoleteAttribute on the method and on the declaring type
4977 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4979 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4981 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4983 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4987 if (IsMethodExcluded (method, loc))
4990 bool is_static = method.IsStatic;
4992 if (instance_expr == EmptyExpression.Null) {
4993 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4997 this_call = instance_expr is This;
4998 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5002 // If this is ourselves, push "this"
5006 Type iexpr_type = instance_expr.Type;
5009 // Push the instance expression
5011 if (TypeManager.IsValueType (iexpr_type)) {
5013 // Special case: calls to a function declared in a
5014 // reference-type with a value-type argument need
5015 // to have their value boxed.
5016 if (decl_type.IsValueType ||
5017 TypeManager.IsGenericParameter (iexpr_type)) {
5019 // If the expression implements IMemoryLocation, then
5020 // we can optimize and use AddressOf on the
5023 // If not we have to use some temporary storage for
5025 if (instance_expr is IMemoryLocation) {
5026 ((IMemoryLocation)instance_expr).
5027 AddressOf (ec, AddressOp.LoadStore);
5029 LocalTemporary temp = new LocalTemporary (iexpr_type);
5030 instance_expr.Emit (ec);
5032 temp.AddressOf (ec, AddressOp.Load);
5035 // avoid the overhead of doing this all the time.
5037 t = TypeManager.GetReferenceType (iexpr_type);
5039 instance_expr.Emit (ec);
5040 ig.Emit (OpCodes.Box, instance_expr.Type);
5041 t = TypeManager.object_type;
5044 instance_expr.Emit (ec);
5045 t = instance_expr.Type;
5049 ig.Emit (OpCodes.Dup);
5050 if (Arguments != null && Arguments.Count != 0) {
5051 this_arg = new LocalTemporary (t);
5052 this_arg.Store (ec);
5059 EmitArguments (ec, Arguments, dup_args, this_arg);
5062 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5063 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5067 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5068 call_op = OpCodes.Call;
5070 call_op = OpCodes.Callvirt;
5072 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5073 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5074 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5081 // and DoFoo is not virtual, you can omit the callvirt,
5082 // because you don't need the null checking behavior.
5084 if (method is MethodInfo)
5085 ig.Emit (call_op, (MethodInfo) method);
5087 ig.Emit (call_op, (ConstructorInfo) method);
5090 public override void Emit (EmitContext ec)
5092 mg.EmitCall (ec, Arguments);
5095 public override void EmitStatement (EmitContext ec)
5100 // Pop the return value if there is one
5102 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5103 ec.ig.Emit (OpCodes.Pop);
5106 protected override void CloneTo (CloneContext clonectx, Expression t)
5108 Invocation target = (Invocation) t;
5110 if (Arguments != null) {
5111 target.Arguments = new ArrayList (Arguments.Count);
5112 foreach (Argument a in Arguments)
5113 target.Arguments.Add (a.Clone (clonectx));
5116 target.expr = expr.Clone (clonectx);
5119 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5121 mg.MutateHoistedGenericType (storey);
5122 if (Arguments != null) {
5123 foreach (Argument a in Arguments)
5124 a.Expr.MutateHoistedGenericType (storey);
5130 // It's either a cast or delegate invocation
5132 public class InvocationOrCast : ExpressionStatement
5135 Expression argument;
5137 public InvocationOrCast (Expression expr, Expression argument)
5140 this.argument = argument;
5141 this.loc = expr.Location;
5144 public override Expression CreateExpressionTree (EmitContext ec)
5146 throw new NotSupportedException ("ET");
5149 public override Expression DoResolve (EmitContext ec)
5151 Expression e = ResolveCore (ec);
5155 return e.Resolve (ec);
5158 Expression ResolveCore (EmitContext ec)
5161 // First try to resolve it as a cast.
5163 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5165 return new Cast (te, argument, loc);
5169 // This can either be a type or a delegate invocation.
5170 // Let's just resolve it and see what we'll get.
5172 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5177 // Ok, so it's a Cast.
5179 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5180 return new Cast (expr, argument, loc);
5183 if (expr.eclass == ExprClass.Namespace) {
5184 expr.Error_UnexpectedKind (null, "type", loc);
5189 // It's a delegate invocation.
5191 if (!TypeManager.IsDelegateType (expr.Type)) {
5192 Error (149, "Method name expected");
5196 ArrayList args = new ArrayList (1);
5197 args.Add (new Argument (argument, Argument.AType.Expression));
5198 return new DelegateInvocation (expr, args, loc);
5201 public override ExpressionStatement ResolveStatement (EmitContext ec)
5203 Expression e = ResolveCore (ec);
5207 ExpressionStatement s = e as ExpressionStatement;
5209 Error_InvalidExpressionStatement ();
5213 return s.ResolveStatement (ec);
5216 public override void Emit (EmitContext ec)
5218 throw new Exception ("Cannot happen");
5221 public override void EmitStatement (EmitContext ec)
5223 throw new Exception ("Cannot happen");
5226 protected override void CloneTo (CloneContext clonectx, Expression t)
5228 InvocationOrCast target = (InvocationOrCast) t;
5230 target.expr = expr.Clone (clonectx);
5231 target.argument = argument.Clone (clonectx);
5236 // This class is used to "disable" the code generation for the
5237 // temporary variable when initializing value types.
5239 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5240 public void AddressOf (EmitContext ec, AddressOp Mode)
5247 /// Implements the new expression
5249 public class New : ExpressionStatement, IMemoryLocation {
5250 ArrayList Arguments;
5253 // During bootstrap, it contains the RequestedType,
5254 // but if `type' is not null, it *might* contain a NewDelegate
5255 // (because of field multi-initialization)
5257 public Expression RequestedType;
5259 MethodGroupExpr method;
5262 // If set, the new expression is for a value_target, and
5263 // we will not leave anything on the stack.
5265 protected Expression value_target;
5266 protected bool value_target_set;
5267 bool is_type_parameter = false;
5269 public New (Expression requested_type, ArrayList arguments, Location l)
5271 RequestedType = requested_type;
5272 Arguments = arguments;
5276 public bool SetTargetVariable (Expression value)
5278 value_target = value;
5279 value_target_set = true;
5280 if (!(value_target is IMemoryLocation)){
5281 Error_UnexpectedKind (null, "variable", loc);
5288 // This function is used to disable the following code sequence for
5289 // value type initialization:
5291 // AddressOf (temporary)
5295 // Instead the provide will have provided us with the address on the
5296 // stack to store the results.
5298 static Expression MyEmptyExpression;
5300 public void DisableTemporaryValueType ()
5302 if (MyEmptyExpression == null)
5303 MyEmptyExpression = new EmptyAddressOf ();
5306 // To enable this, look into:
5307 // test-34 and test-89 and self bootstrapping.
5309 // For instance, we can avoid a copy by using `newobj'
5310 // instead of Call + Push-temp on value types.
5311 // value_target = MyEmptyExpression;
5316 /// Converts complex core type syntax like 'new int ()' to simple constant
5318 public static Constant Constantify (Type t)
5320 if (t == TypeManager.int32_type)
5321 return new IntConstant (0, Location.Null);
5322 if (t == TypeManager.uint32_type)
5323 return new UIntConstant (0, Location.Null);
5324 if (t == TypeManager.int64_type)
5325 return new LongConstant (0, Location.Null);
5326 if (t == TypeManager.uint64_type)
5327 return new ULongConstant (0, Location.Null);
5328 if (t == TypeManager.float_type)
5329 return new FloatConstant (0, Location.Null);
5330 if (t == TypeManager.double_type)
5331 return new DoubleConstant (0, Location.Null);
5332 if (t == TypeManager.short_type)
5333 return new ShortConstant (0, Location.Null);
5334 if (t == TypeManager.ushort_type)
5335 return new UShortConstant (0, Location.Null);
5336 if (t == TypeManager.sbyte_type)
5337 return new SByteConstant (0, Location.Null);
5338 if (t == TypeManager.byte_type)
5339 return new ByteConstant (0, Location.Null);
5340 if (t == TypeManager.char_type)
5341 return new CharConstant ('\0', Location.Null);
5342 if (t == TypeManager.bool_type)
5343 return new BoolConstant (false, Location.Null);
5344 if (t == TypeManager.decimal_type)
5345 return new DecimalConstant (0, Location.Null);
5346 if (TypeManager.IsEnumType (t))
5347 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5353 // Checks whether the type is an interface that has the
5354 // [ComImport, CoClass] attributes and must be treated
5357 public Expression CheckComImport (EmitContext ec)
5359 if (!type.IsInterface)
5363 // Turn the call into:
5364 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5366 Type real_class = AttributeTester.GetCoClassAttribute (type);
5367 if (real_class == null)
5370 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5371 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5372 return cast.Resolve (ec);
5375 public override Expression CreateExpressionTree (EmitContext ec)
5377 ArrayList args = Arguments == null ?
5378 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5380 if (method == null) {
5381 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5383 args.Add (new Argument (method.CreateExpressionTree (ec)));
5384 if (Arguments != null) {
5386 foreach (Argument a in Arguments) {
5387 expr = a.Expr.CreateExpressionTree (ec);
5389 args.Add (new Argument (expr));
5394 return CreateExpressionFactoryCall ("New", args);
5397 public override Expression DoResolve (EmitContext ec)
5400 // The New DoResolve might be called twice when initializing field
5401 // expressions (see EmitFieldInitializers, the call to
5402 // GetInitializerExpression will perform a resolve on the expression,
5403 // and later the assign will trigger another resolution
5405 // This leads to bugs (#37014)
5408 if (RequestedType is NewDelegate)
5409 return RequestedType;
5413 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5419 if (type == TypeManager.void_type) {
5420 Error_VoidInvalidInTheContext (loc);
5424 if (type.IsPointer) {
5425 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5426 TypeManager.CSharpName (type));
5430 if (Arguments == null) {
5431 Expression c = Constantify (type);
5436 if (TypeManager.IsDelegateType (type)) {
5437 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5441 if (type.IsGenericParameter) {
5442 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5444 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5445 Error (304, String.Format (
5446 "Cannot create an instance of the " +
5447 "variable type '{0}' because it " +
5448 "doesn't have the new() constraint",
5453 if ((Arguments != null) && (Arguments.Count != 0)) {
5454 Error (417, String.Format (
5455 "`{0}': cannot provide arguments " +
5456 "when creating an instance of a " +
5457 "variable type.", type));
5461 if (TypeManager.activator_create_instance == null) {
5462 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5463 if (activator_type != null) {
5464 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5465 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5469 is_type_parameter = true;
5470 eclass = ExprClass.Value;
5475 if (type.IsAbstract && type.IsSealed) {
5476 Report.SymbolRelatedToPreviousError (type);
5477 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5481 if (type.IsInterface || type.IsAbstract){
5482 if (!TypeManager.IsGenericType (type)) {
5483 RequestedType = CheckComImport (ec);
5484 if (RequestedType != null)
5485 return RequestedType;
5488 Report.SymbolRelatedToPreviousError (type);
5489 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5493 bool is_struct = type.IsValueType;
5494 eclass = ExprClass.Value;
5497 // SRE returns a match for .ctor () on structs (the object constructor),
5498 // so we have to manually ignore it.
5500 if (is_struct && Arguments == null)
5503 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5504 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5505 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5507 if (Arguments != null){
5508 foreach (Argument a in Arguments){
5509 if (!a.Resolve (ec, loc))
5517 method = ml as MethodGroupExpr;
5518 if (method == null) {
5519 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5523 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5530 bool DoEmitTypeParameter (EmitContext ec)
5533 ILGenerator ig = ec.ig;
5534 // IMemoryLocation ml;
5536 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5537 new Type [] { type });
5539 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5540 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5541 ig.Emit (OpCodes.Call, ci);
5545 // Allow DoEmit() to be called multiple times.
5546 // We need to create a new LocalTemporary each time since
5547 // you can't share LocalBuilders among ILGeneators.
5548 LocalTemporary temp = new LocalTemporary (type);
5550 Label label_activator = ig.DefineLabel ();
5551 Label label_end = ig.DefineLabel ();
5553 temp.AddressOf (ec, AddressOp.Store);
5554 ig.Emit (OpCodes.Initobj, type);
5557 ig.Emit (OpCodes.Box, type);
5558 ig.Emit (OpCodes.Brfalse, label_activator);
5560 temp.AddressOf (ec, AddressOp.Store);
5561 ig.Emit (OpCodes.Initobj, type);
5563 ig.Emit (OpCodes.Br, label_end);
5565 ig.MarkLabel (label_activator);
5567 ig.Emit (OpCodes.Call, ci);
5568 ig.MarkLabel (label_end);
5571 throw new InternalErrorException ();
5576 // This DoEmit can be invoked in two contexts:
5577 // * As a mechanism that will leave a value on the stack (new object)
5578 // * As one that wont (init struct)
5580 // You can control whether a value is required on the stack by passing
5581 // need_value_on_stack. The code *might* leave a value on the stack
5582 // so it must be popped manually
5584 // If we are dealing with a ValueType, we have a few
5585 // situations to deal with:
5587 // * The target is a ValueType, and we have been provided
5588 // the instance (this is easy, we are being assigned).
5590 // * The target of New is being passed as an argument,
5591 // to a boxing operation or a function that takes a
5594 // In this case, we need to create a temporary variable
5595 // that is the argument of New.
5597 // Returns whether a value is left on the stack
5599 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5601 bool is_value_type = TypeManager.IsValueType (type);
5602 ILGenerator ig = ec.ig;
5607 // Allow DoEmit() to be called multiple times.
5608 // We need to create a new LocalTemporary each time since
5609 // you can't share LocalBuilders among ILGeneators.
5610 if (!value_target_set)
5611 value_target = new LocalTemporary (type);
5613 ml = (IMemoryLocation) value_target;
5614 ml.AddressOf (ec, AddressOp.Store);
5618 method.EmitArguments (ec, Arguments);
5622 ig.Emit (OpCodes.Initobj, type);
5624 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5625 if (need_value_on_stack){
5626 value_target.Emit (ec);
5631 ConstructorInfo ci = (ConstructorInfo) method;
5633 if (TypeManager.IsGenericType (type))
5634 ci = TypeBuilder.GetConstructor (type, ci);
5636 ig.Emit (OpCodes.Newobj, ci);
5641 public override void Emit (EmitContext ec)
5643 if (is_type_parameter)
5644 DoEmitTypeParameter (ec);
5649 public override void EmitStatement (EmitContext ec)
5651 bool value_on_stack;
5653 if (is_type_parameter)
5654 value_on_stack = DoEmitTypeParameter (ec);
5656 value_on_stack = DoEmit (ec, false);
5659 ec.ig.Emit (OpCodes.Pop);
5663 public virtual bool HasInitializer {
5669 public void AddressOf (EmitContext ec, AddressOp Mode)
5671 if (is_type_parameter) {
5672 LocalTemporary temp = new LocalTemporary (type);
5673 DoEmitTypeParameter (ec);
5675 temp.AddressOf (ec, Mode);
5679 if (!type.IsValueType){
5681 // We throw an exception. So far, I believe we only need to support
5683 // foreach (int j in new StructType ())
5686 throw new Exception ("AddressOf should not be used for classes");
5689 if (!value_target_set)
5690 value_target = new LocalTemporary (type);
5691 IMemoryLocation ml = (IMemoryLocation) value_target;
5693 ml.AddressOf (ec, AddressOp.Store);
5694 if (method == null) {
5695 ec.ig.Emit (OpCodes.Initobj, type);
5697 method.EmitArguments (ec, Arguments);
5698 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5701 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5704 protected override void CloneTo (CloneContext clonectx, Expression t)
5706 New target = (New) t;
5708 target.RequestedType = RequestedType.Clone (clonectx);
5709 if (Arguments != null){
5710 target.Arguments = new ArrayList ();
5711 foreach (Argument a in Arguments){
5712 target.Arguments.Add (a.Clone (clonectx));
5717 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5719 if (method != null) {
5720 method.MutateHoistedGenericType (storey);
5721 if (Arguments != null) {
5722 foreach (Argument a in Arguments)
5723 a.Expr.MutateHoistedGenericType (storey);
5727 type = storey.MutateType (type);
5732 /// 14.5.10.2: Represents an array creation expression.
5736 /// There are two possible scenarios here: one is an array creation
5737 /// expression that specifies the dimensions and optionally the
5738 /// initialization data and the other which does not need dimensions
5739 /// specified but where initialization data is mandatory.
5741 public class ArrayCreation : Expression {
5742 FullNamedExpression requested_base_type;
5743 ArrayList initializers;
5746 // The list of Argument types.
5747 // This is used to construct the `newarray' or constructor signature
5749 protected ArrayList arguments;
5751 protected Type array_element_type;
5752 bool expect_initializers = false;
5753 int num_arguments = 0;
5754 protected int dimensions;
5755 protected readonly string rank;
5757 protected ArrayList array_data;
5761 // The number of constants in array initializers
5762 int const_initializers_count;
5763 bool only_constant_initializers;
5765 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5767 this.requested_base_type = requested_base_type;
5768 this.initializers = initializers;
5772 arguments = new ArrayList (exprs.Count);
5774 foreach (Expression e in exprs) {
5775 arguments.Add (new Argument (e, Argument.AType.Expression));
5780 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5782 this.requested_base_type = requested_base_type;
5783 this.initializers = initializers;
5787 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5789 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5791 //dimensions = tmp.Length - 1;
5792 expect_initializers = true;
5795 void Error_IncorrectArrayInitializer ()
5797 Error (178, "Invalid rank specifier: expected `,' or `]'");
5800 protected override void Error_NegativeArrayIndex (Location loc)
5802 Report.Error (248, loc, "Cannot create an array with a negative size");
5805 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5807 if (specified_dims) {
5808 Argument a = (Argument) arguments [idx];
5810 if (!a.Resolve (ec, loc))
5813 Constant c = a.Expr as Constant;
5815 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5819 Report.Error (150, a.Expr.Location, "A constant value is expected");
5823 int value = (int) c.GetValue ();
5825 if (value != probe.Count) {
5826 Error_IncorrectArrayInitializer ();
5830 bounds [idx] = value;
5833 int child_bounds = -1;
5834 only_constant_initializers = true;
5835 for (int i = 0; i < probe.Count; ++i) {
5836 object o = probe [i];
5837 if (o is ArrayList) {
5838 ArrayList sub_probe = o as ArrayList;
5839 int current_bounds = sub_probe.Count;
5841 if (child_bounds == -1)
5842 child_bounds = current_bounds;
5844 else if (child_bounds != current_bounds){
5845 Error_IncorrectArrayInitializer ();
5848 if (idx + 1 >= dimensions){
5849 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5853 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5857 if (child_bounds != -1){
5858 Error_IncorrectArrayInitializer ();
5862 Expression element = ResolveArrayElement (ec, (Expression) o);
5863 if (element == null)
5866 // Initializers with the default values can be ignored
5867 Constant c = element as Constant;
5869 if (c.IsDefaultInitializer (array_element_type)) {
5873 ++const_initializers_count;
5876 only_constant_initializers = false;
5879 array_data.Add (element);
5886 public override Expression CreateExpressionTree (EmitContext ec)
5890 if (array_data == null) {
5891 args = new ArrayList (arguments.Count + 1);
5892 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5893 foreach (Argument a in arguments) {
5894 if (arguments.Count == 1) {
5895 Constant c = a.Expr as Constant;
5896 if (c.IsDefaultValue)
5897 return CreateExpressionFactoryCall ("NewArrayInit", args);
5899 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5902 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5905 if (dimensions > 1) {
5906 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5910 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5911 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5912 if (array_data != null) {
5913 for (int i = 0; i < array_data.Count; ++i) {
5914 Expression e = (Expression) array_data [i];
5916 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5918 args.Add (new Argument (e.CreateExpressionTree (ec)));
5922 return CreateExpressionFactoryCall ("NewArrayInit", args);
5925 public void UpdateIndices ()
5928 for (ArrayList probe = initializers; probe != null;) {
5929 if (probe.Count > 0 && probe [0] is ArrayList) {
5930 Expression e = new IntConstant (probe.Count, Location.Null);
5931 arguments.Add (new Argument (e, Argument.AType.Expression));
5933 bounds [i++] = probe.Count;
5935 probe = (ArrayList) probe [0];
5938 Expression e = new IntConstant (probe.Count, Location.Null);
5939 arguments.Add (new Argument (e, Argument.AType.Expression));
5941 bounds [i++] = probe.Count;
5948 Expression first_emit;
5949 LocalTemporary first_emit_temp;
5951 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5953 element = element.Resolve (ec);
5954 if (element == null)
5957 if (element is CompoundAssign.Helper) {
5958 if (first_emit != null)
5959 throw new InternalErrorException ("Can only handle one mutator at a time");
5960 first_emit = element;
5961 element = first_emit_temp = new LocalTemporary (element.Type);
5964 return Convert.ImplicitConversionRequired (
5965 ec, element, array_element_type, loc);
5968 protected bool ResolveInitializers (EmitContext ec)
5970 if (initializers == null) {
5971 return !expect_initializers;
5975 // We use this to store all the date values in the order in which we
5976 // will need to store them in the byte blob later
5978 array_data = new ArrayList ();
5979 bounds = new System.Collections.Specialized.HybridDictionary ();
5981 if (arguments != null)
5982 return CheckIndices (ec, initializers, 0, true);
5984 arguments = new ArrayList ();
5986 if (!CheckIndices (ec, initializers, 0, false))
5995 // Resolved the type of the array
5997 bool ResolveArrayType (EmitContext ec)
5999 if (requested_base_type == null) {
6000 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6004 if (requested_base_type is VarExpr) {
6005 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6009 StringBuilder array_qualifier = new StringBuilder (rank);
6012 // `In the first form allocates an array instace of the type that results
6013 // from deleting each of the individual expression from the expression list'
6015 if (num_arguments > 0) {
6016 array_qualifier.Append ("[");
6017 for (int i = num_arguments-1; i > 0; i--)
6018 array_qualifier.Append (",");
6019 array_qualifier.Append ("]");
6025 TypeExpr array_type_expr;
6026 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6027 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6028 if (array_type_expr == null)
6031 type = array_type_expr.Type;
6032 array_element_type = TypeManager.GetElementType (type);
6033 dimensions = type.GetArrayRank ();
6038 public override Expression DoResolve (EmitContext ec)
6043 if (!ResolveArrayType (ec))
6047 // First step is to validate the initializers and fill
6048 // in any missing bits
6050 if (!ResolveInitializers (ec))
6053 if (arguments.Count != dimensions) {
6054 Error_IncorrectArrayInitializer ();
6057 foreach (Argument a in arguments){
6058 if (!a.Resolve (ec, loc))
6061 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6064 eclass = ExprClass.Value;
6068 MethodInfo GetArrayMethod (int arguments)
6070 ModuleBuilder mb = CodeGen.Module.Builder;
6072 Type[] arg_types = new Type[arguments];
6073 for (int i = 0; i < arguments; i++)
6074 arg_types[i] = TypeManager.int32_type;
6076 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6080 Report.Error (-6, "New invocation: Can not find a constructor for " +
6081 "this argument list");
6088 byte [] MakeByteBlob ()
6093 int count = array_data.Count;
6095 if (TypeManager.IsEnumType (array_element_type))
6096 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6098 factor = GetTypeSize (array_element_type);
6100 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6102 data = new byte [(count * factor + 3) & ~3];
6105 for (int i = 0; i < count; ++i) {
6106 object v = array_data [i];
6108 if (v is EnumConstant)
6109 v = ((EnumConstant) v).Child;
6111 if (v is Constant && !(v is StringConstant))
6112 v = ((Constant) v).GetValue ();
6118 if (array_element_type == TypeManager.int64_type){
6119 if (!(v is Expression)){
6120 long val = (long) v;
6122 for (int j = 0; j < factor; ++j) {
6123 data [idx + j] = (byte) (val & 0xFF);
6127 } else if (array_element_type == TypeManager.uint64_type){
6128 if (!(v is Expression)){
6129 ulong val = (ulong) v;
6131 for (int j = 0; j < factor; ++j) {
6132 data [idx + j] = (byte) (val & 0xFF);
6136 } else if (array_element_type == TypeManager.float_type) {
6137 if (!(v is Expression)){
6138 element = BitConverter.GetBytes ((float) v);
6140 for (int j = 0; j < factor; ++j)
6141 data [idx + j] = element [j];
6142 if (!BitConverter.IsLittleEndian)
6143 System.Array.Reverse (data, idx, 4);
6145 } else if (array_element_type == TypeManager.double_type) {
6146 if (!(v is Expression)){
6147 element = BitConverter.GetBytes ((double) v);
6149 for (int j = 0; j < factor; ++j)
6150 data [idx + j] = element [j];
6152 // FIXME: Handle the ARM float format.
6153 if (!BitConverter.IsLittleEndian)
6154 System.Array.Reverse (data, idx, 8);
6156 } else if (array_element_type == TypeManager.char_type){
6157 if (!(v is Expression)){
6158 int val = (int) ((char) v);
6160 data [idx] = (byte) (val & 0xff);
6161 data [idx+1] = (byte) (val >> 8);
6163 } else if (array_element_type == TypeManager.short_type){
6164 if (!(v is Expression)){
6165 int val = (int) ((short) v);
6167 data [idx] = (byte) (val & 0xff);
6168 data [idx+1] = (byte) (val >> 8);
6170 } else if (array_element_type == TypeManager.ushort_type){
6171 if (!(v is Expression)){
6172 int val = (int) ((ushort) v);
6174 data [idx] = (byte) (val & 0xff);
6175 data [idx+1] = (byte) (val >> 8);
6177 } else if (array_element_type == TypeManager.int32_type) {
6178 if (!(v is Expression)){
6181 data [idx] = (byte) (val & 0xff);
6182 data [idx+1] = (byte) ((val >> 8) & 0xff);
6183 data [idx+2] = (byte) ((val >> 16) & 0xff);
6184 data [idx+3] = (byte) (val >> 24);
6186 } else if (array_element_type == TypeManager.uint32_type) {
6187 if (!(v is Expression)){
6188 uint val = (uint) v;
6190 data [idx] = (byte) (val & 0xff);
6191 data [idx+1] = (byte) ((val >> 8) & 0xff);
6192 data [idx+2] = (byte) ((val >> 16) & 0xff);
6193 data [idx+3] = (byte) (val >> 24);
6195 } else if (array_element_type == TypeManager.sbyte_type) {
6196 if (!(v is Expression)){
6197 sbyte val = (sbyte) v;
6198 data [idx] = (byte) val;
6200 } else if (array_element_type == TypeManager.byte_type) {
6201 if (!(v is Expression)){
6202 byte val = (byte) v;
6203 data [idx] = (byte) val;
6205 } else if (array_element_type == TypeManager.bool_type) {
6206 if (!(v is Expression)){
6207 bool val = (bool) v;
6208 data [idx] = (byte) (val ? 1 : 0);
6210 } else if (array_element_type == TypeManager.decimal_type){
6211 if (!(v is Expression)){
6212 int [] bits = Decimal.GetBits ((decimal) v);
6215 // FIXME: For some reason, this doesn't work on the MS runtime.
6216 int [] nbits = new int [4];
6217 nbits [0] = bits [3];
6218 nbits [1] = bits [2];
6219 nbits [2] = bits [0];
6220 nbits [3] = bits [1];
6222 for (int j = 0; j < 4; j++){
6223 data [p++] = (byte) (nbits [j] & 0xff);
6224 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6225 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6226 data [p++] = (byte) (nbits [j] >> 24);
6230 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6238 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6240 array_element_type = storey.MutateType (array_element_type);
6241 type = storey.MutateType (type);
6242 if (arguments != null) {
6243 foreach (Argument a in arguments)
6244 a.Expr.MutateHoistedGenericType (storey);
6247 if (array_data != null) {
6248 foreach (Expression e in array_data)
6249 e.MutateHoistedGenericType (storey);
6254 // Emits the initializers for the array
6256 void EmitStaticInitializers (EmitContext ec)
6258 // FIXME: This should go to Resolve !
6259 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6260 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6261 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6262 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6263 if (TypeManager.void_initializearray_array_fieldhandle == null)
6268 // First, the static data
6271 ILGenerator ig = ec.ig;
6273 byte [] data = MakeByteBlob ();
6275 fb = RootContext.MakeStaticData (data);
6277 ig.Emit (OpCodes.Dup);
6278 ig.Emit (OpCodes.Ldtoken, fb);
6279 ig.Emit (OpCodes.Call,
6280 TypeManager.void_initializearray_array_fieldhandle);
6284 // Emits pieces of the array that can not be computed at compile
6285 // time (variables and string locations).
6287 // This always expect the top value on the stack to be the array
6289 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6291 ILGenerator ig = ec.ig;
6292 int dims = bounds.Count;
6293 int [] current_pos = new int [dims];
6295 MethodInfo set = null;
6298 Type [] args = new Type [dims + 1];
6300 for (int j = 0; j < dims; j++)
6301 args [j] = TypeManager.int32_type;
6302 args [dims] = array_element_type;
6304 set = CodeGen.Module.Builder.GetArrayMethod (
6306 CallingConventions.HasThis | CallingConventions.Standard,
6307 TypeManager.void_type, args);
6310 for (int i = 0; i < array_data.Count; i++){
6312 Expression e = (Expression)array_data [i];
6314 // Constant can be initialized via StaticInitializer
6315 if (e != null && !(!emitConstants && e is Constant)) {
6316 Type etype = e.Type;
6318 ig.Emit (OpCodes.Dup);
6320 for (int idx = 0; idx < dims; idx++)
6321 IntConstant.EmitInt (ig, current_pos [idx]);
6324 // If we are dealing with a struct, get the
6325 // address of it, so we can store it.
6327 if ((dims == 1) && etype.IsValueType &&
6328 (!TypeManager.IsBuiltinOrEnum (etype) ||
6329 etype == TypeManager.decimal_type)) {
6334 // Let new know that we are providing
6335 // the address where to store the results
6337 n.DisableTemporaryValueType ();
6340 ig.Emit (OpCodes.Ldelema, etype);
6346 bool is_stobj, has_type_arg;
6347 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6349 ig.Emit (OpCodes.Stobj, etype);
6350 else if (has_type_arg)
6351 ig.Emit (op, etype);
6355 ig.Emit (OpCodes.Call, set);
6362 for (int j = dims - 1; j >= 0; j--){
6364 if (current_pos [j] < (int) bounds [j])
6366 current_pos [j] = 0;
6371 public override void Emit (EmitContext ec)
6373 ILGenerator ig = ec.ig;
6375 if (first_emit != null) {
6376 first_emit.Emit (ec);
6377 first_emit_temp.Store (ec);
6380 foreach (Argument a in arguments)
6383 if (arguments.Count == 1)
6384 ig.Emit (OpCodes.Newarr, array_element_type);
6386 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6389 if (initializers == null)
6392 // Emit static initializer for arrays which have contain more than 4 items and
6393 // the static initializer will initialize at least 25% of array values.
6394 // NOTE: const_initializers_count does not contain default constant values.
6395 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6396 TypeManager.IsPrimitiveType (array_element_type)) {
6397 EmitStaticInitializers (ec);
6399 if (!only_constant_initializers)
6400 EmitDynamicInitializers (ec, false);
6402 EmitDynamicInitializers (ec, true);
6405 if (first_emit_temp != null)
6406 first_emit_temp.Release (ec);
6409 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6411 if (arguments.Count != 1) {
6412 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6413 return base.GetAttributableValue (ec, null, out value);
6416 if (array_data == null) {
6417 Constant c = (Constant)((Argument)arguments [0]).Expr;
6418 if (c.IsDefaultValue) {
6419 value = Array.CreateInstance (array_element_type, 0);
6422 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6423 return base.GetAttributableValue (ec, null, out value);
6426 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6427 object element_value;
6428 for (int i = 0; i < ret.Length; ++i)
6430 Expression e = (Expression)array_data [i];
6432 // Is null when an initializer is optimized (value == predefined value)
6436 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6440 ret.SetValue (element_value, i);
6446 protected override void CloneTo (CloneContext clonectx, Expression t)
6448 ArrayCreation target = (ArrayCreation) t;
6450 if (requested_base_type != null)
6451 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6453 if (arguments != null){
6454 target.arguments = new ArrayList (arguments.Count);
6455 foreach (Argument a in arguments)
6456 target.arguments.Add (a.Clone (clonectx));
6459 if (initializers != null){
6460 target.initializers = new ArrayList (initializers.Count);
6461 foreach (object initializer in initializers)
6462 if (initializer is ArrayList) {
6463 ArrayList this_al = (ArrayList)initializer;
6464 ArrayList al = new ArrayList (this_al.Count);
6465 target.initializers.Add (al);
6466 foreach (Expression e in this_al)
6467 al.Add (e.Clone (clonectx));
6469 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6476 // Represents an implicitly typed array epxression
6478 public class ImplicitlyTypedArrayCreation : ArrayCreation
6480 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6481 : base (null, rank, initializers, loc)
6483 if (RootContext.Version <= LanguageVersion.ISO_2)
6484 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6486 if (rank.Length > 2) {
6487 while (rank [++dimensions] == ',');
6493 public override Expression DoResolve (EmitContext ec)
6498 if (!ResolveInitializers (ec))
6501 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6502 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6503 arguments.Count != dimensions) {
6504 Error_NoBestType ();
6509 // At this point we found common base type for all initializer elements
6510 // but we have to be sure that all static initializer elements are of
6513 UnifyInitializerElement (ec);
6515 type = TypeManager.GetConstructedType (array_element_type, rank);
6516 eclass = ExprClass.Value;
6520 void Error_NoBestType ()
6522 Report.Error (826, loc,
6523 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6527 // Converts static initializer only
6529 void UnifyInitializerElement (EmitContext ec)
6531 for (int i = 0; i < array_data.Count; ++i) {
6532 Expression e = (Expression)array_data[i];
6534 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6538 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6540 element = element.Resolve (ec);
6541 if (element == null)
6544 if (array_element_type == null) {
6545 array_element_type = element.Type;
6549 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6553 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6554 array_element_type = element.Type;
6558 Error_NoBestType ();
6563 public sealed class CompilerGeneratedThis : This
6565 public static This Instance = new CompilerGeneratedThis ();
6567 private CompilerGeneratedThis ()
6568 : base (Location.Null)
6572 public CompilerGeneratedThis (Type type, Location loc)
6578 public override Expression DoResolve (EmitContext ec)
6580 eclass = ExprClass.Variable;
6582 type = ec.ContainerType;
6586 public override HoistedVariable HoistedVariable {
6587 get { return null; }
6592 /// Represents the `this' construct
6595 public class This : VariableReference
6597 sealed class ThisVariable : ILocalVariable
6599 public static readonly ILocalVariable Instance = new ThisVariable ();
6601 public void Emit (EmitContext ec)
6603 ec.ig.Emit (OpCodes.Ldarg_0);
6606 public void EmitAssign (EmitContext ec)
6608 throw new InvalidOperationException ();
6611 public void EmitAddressOf (EmitContext ec)
6613 ec.ig.Emit (OpCodes.Ldarg_0);
6618 VariableInfo variable_info;
6621 public This (Block block, Location loc)
6627 public This (Location loc)
6632 public override VariableInfo VariableInfo {
6633 get { return variable_info; }
6636 public override bool IsFixedVariable {
6637 get { return !TypeManager.IsValueType (type); }
6640 protected override bool IsHoistedEmitRequired (EmitContext ec)
6643 // Handle 'this' differently, it cannot be assigned hence
6644 // when we are not inside anonymous method we can emit direct access
6646 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6649 public override HoistedVariable HoistedVariable {
6650 get { return TopToplevelBlock.HoistedThisVariable; }
6653 public override bool IsRef {
6654 get { return is_struct; }
6657 protected override ILocalVariable Variable {
6658 get { return ThisVariable.Instance; }
6661 // TODO: Move to ToplevelBlock
6662 ToplevelBlock TopToplevelBlock {
6664 ToplevelBlock tl = block.Toplevel;
6665 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6670 public static bool IsThisAvailable (EmitContext ec)
6672 if (ec.IsStatic || ec.IsInFieldInitializer)
6675 if (ec.CurrentAnonymousMethod == null)
6678 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6684 public bool ResolveBase (EmitContext ec)
6686 if (eclass != ExprClass.Invalid)
6689 eclass = ExprClass.Variable;
6691 if (ec.TypeContainer.CurrentType != null)
6692 type = ec.TypeContainer.CurrentType;
6694 type = ec.ContainerType;
6696 if (!IsThisAvailable (ec)) {
6698 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6700 Report.Error (1673, loc,
6701 "Anonymous methods inside structs cannot access instance members of `this'. " +
6702 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6706 is_struct = ec.TypeContainer is Struct;
6708 if (block != null) {
6709 if (block.Toplevel.ThisVariable != null)
6710 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6712 AnonymousExpression am = ec.CurrentAnonymousMethod;
6715 // this is hoisted to very top level block
6717 if (ec.IsVariableCapturingRequired) {
6718 // TODO: it could be optimized
6719 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6720 if (HoistedVariable == null) {
6721 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6731 // Called from Invocation to check if the invocation is correct
6733 public override void CheckMarshalByRefAccess (EmitContext ec)
6735 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6736 !variable_info.IsAssigned (ec)) {
6737 Error (188, "The `this' object cannot be used before all of its " +
6738 "fields are assigned to");
6739 variable_info.SetAssigned (ec);
6743 public override Expression CreateExpressionTree (EmitContext ec)
6745 ArrayList args = new ArrayList (2);
6746 args.Add (new Argument (this));
6747 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6748 return CreateExpressionFactoryCall ("Constant", args);
6751 public override Expression DoResolve (EmitContext ec)
6753 if (!ResolveBase (ec))
6757 if (ec.IsInFieldInitializer) {
6758 Error (27, "Keyword `this' is not available in the current context");
6765 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6767 if (!ResolveBase (ec))
6770 if (variable_info != null)
6771 variable_info.SetAssigned (ec);
6773 if (ec.TypeContainer is Class){
6774 if (right_side == EmptyExpression.UnaryAddress)
6775 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6776 else if (right_side == EmptyExpression.OutAccess)
6777 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6779 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6785 public override int GetHashCode()
6787 return block.GetHashCode ();
6790 public override string Name {
6791 get { return "this"; }
6794 public override bool Equals (object obj)
6796 This t = obj as This;
6800 return block == t.block;
6803 protected override void CloneTo (CloneContext clonectx, Expression t)
6805 This target = (This) t;
6807 target.block = clonectx.LookupBlock (block);
6810 public void RemoveHoisting ()
6812 TopToplevelBlock.HoistedThisVariable = null;
6815 public override void SetHasAddressTaken ()
6822 /// Represents the `__arglist' construct
6824 public class ArglistAccess : Expression
6826 public ArglistAccess (Location loc)
6831 public override Expression CreateExpressionTree (EmitContext ec)
6833 throw new NotSupportedException ("ET");
6836 public override Expression DoResolve (EmitContext ec)
6838 eclass = ExprClass.Variable;
6839 type = TypeManager.runtime_argument_handle_type;
6841 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6843 Error (190, "The __arglist construct is valid only within " +
6844 "a variable argument method");
6851 public override void Emit (EmitContext ec)
6853 ec.ig.Emit (OpCodes.Arglist);
6856 protected override void CloneTo (CloneContext clonectx, Expression target)
6863 /// Represents the `__arglist (....)' construct
6865 public class Arglist : Expression
6867 Argument[] Arguments;
6869 public Arglist (Location loc)
6870 : this (Argument.Empty, loc)
6874 public Arglist (Argument[] args, Location l)
6880 public Type[] ArgumentTypes {
6882 Type[] retval = new Type [Arguments.Length];
6883 for (int i = 0; i < Arguments.Length; i++)
6884 retval [i] = Arguments [i].Type;
6889 public override Expression CreateExpressionTree (EmitContext ec)
6891 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6895 public override Expression DoResolve (EmitContext ec)
6897 eclass = ExprClass.Variable;
6898 type = TypeManager.runtime_argument_handle_type;
6900 foreach (Argument arg in Arguments) {
6901 if (!arg.Resolve (ec, loc))
6908 public override void Emit (EmitContext ec)
6910 foreach (Argument arg in Arguments)
6914 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6916 foreach (Argument arg in Arguments)
6917 arg.Expr.MutateHoistedGenericType (storey);
6920 protected override void CloneTo (CloneContext clonectx, Expression t)
6922 Arglist target = (Arglist) t;
6924 target.Arguments = new Argument [Arguments.Length];
6925 for (int i = 0; i < Arguments.Length; i++)
6926 target.Arguments [i] = Arguments [i].Clone (clonectx);
6931 /// Implements the typeof operator
6933 public class TypeOf : Expression {
6934 Expression QueriedType;
6935 protected Type typearg;
6937 public TypeOf (Expression queried_type, Location l)
6939 QueriedType = queried_type;
6943 public override Expression CreateExpressionTree (EmitContext ec)
6945 ArrayList args = new ArrayList (2);
6946 args.Add (new Argument (this));
6947 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6948 return CreateExpressionFactoryCall ("Constant", args);
6951 public override Expression DoResolve (EmitContext ec)
6953 if (eclass != ExprClass.Invalid)
6956 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6960 typearg = texpr.Type;
6962 if (typearg == TypeManager.void_type) {
6963 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6967 if (typearg.IsPointer && !ec.InUnsafe){
6972 type = TypeManager.type_type;
6974 return DoResolveBase ();
6977 protected Expression DoResolveBase ()
6979 if (TypeManager.system_type_get_type_from_handle == null) {
6980 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6981 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6984 // Even though what is returned is a type object, it's treated as a value by the compiler.
6985 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6986 eclass = ExprClass.Value;
6990 public override void Emit (EmitContext ec)
6992 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6993 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6996 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6998 if (TypeManager.ContainsGenericParameters (typearg) &&
6999 !TypeManager.IsGenericTypeDefinition (typearg)) {
7000 Report.SymbolRelatedToPreviousError (typearg);
7001 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7002 TypeManager.CSharpName (typearg));
7007 if (value_type == TypeManager.object_type) {
7008 value = (object)typearg;
7015 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7017 typearg = storey.MutateType (typearg);
7020 public Type TypeArgument {
7026 protected override void CloneTo (CloneContext clonectx, Expression t)
7028 TypeOf target = (TypeOf) t;
7029 if (QueriedType != null)
7030 target.QueriedType = QueriedType.Clone (clonectx);
7035 /// Implements the `typeof (void)' operator
7037 public class TypeOfVoid : TypeOf {
7038 public TypeOfVoid (Location l) : base (null, l)
7043 public override Expression DoResolve (EmitContext ec)
7045 type = TypeManager.type_type;
7046 typearg = TypeManager.void_type;
7048 return DoResolveBase ();
7052 class TypeOfMethodInfo : TypeOfMethod
7054 public TypeOfMethodInfo (MethodBase method, Location loc)
7055 : base (method, loc)
7059 public override Expression DoResolve (EmitContext ec)
7061 type = typeof (MethodInfo);
7062 return base.DoResolve (ec);
7065 public override void Emit (EmitContext ec)
7067 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7069 ec.ig.Emit (OpCodes.Castclass, type);
7073 class TypeOfConstructorInfo : TypeOfMethod
7075 public TypeOfConstructorInfo (MethodBase method, Location loc)
7076 : base (method, loc)
7080 public override Expression DoResolve (EmitContext ec)
7082 type = typeof (ConstructorInfo);
7083 return base.DoResolve (ec);
7086 public override void Emit (EmitContext ec)
7088 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7090 ec.ig.Emit (OpCodes.Castclass, type);
7094 abstract class TypeOfMethod : Expression
7096 protected readonly MethodBase method;
7098 protected TypeOfMethod (MethodBase method, Location loc)
7100 this.method = method;
7104 public override Expression CreateExpressionTree (EmitContext ec)
7106 ArrayList args = new ArrayList (2);
7107 args.Add (new Argument (this));
7108 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7109 return CreateExpressionFactoryCall ("Constant", args);
7112 public override Expression DoResolve (EmitContext ec)
7114 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7115 MethodInfo mi = is_generic ?
7116 TypeManager.methodbase_get_type_from_handle_generic :
7117 TypeManager.methodbase_get_type_from_handle;
7120 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7121 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7123 if (t == null || handle_type == null)
7126 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7128 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7129 new Type[] { handle_type } );
7132 TypeManager.methodbase_get_type_from_handle_generic = mi;
7134 TypeManager.methodbase_get_type_from_handle = mi;
7137 eclass = ExprClass.Value;
7141 public override void Emit (EmitContext ec)
7143 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7146 mi = TypeManager.methodbase_get_type_from_handle_generic;
7147 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7149 mi = TypeManager.methodbase_get_type_from_handle;
7152 ec.ig.Emit (OpCodes.Call, mi);
7156 internal class TypeOfField : Expression
7158 readonly FieldInfo field;
7160 public TypeOfField (FieldInfo field, Location loc)
7166 public override Expression CreateExpressionTree (EmitContext ec)
7168 throw new NotSupportedException ("ET");
7171 public override Expression DoResolve (EmitContext ec)
7173 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7174 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7175 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7177 if (t != null && handle_type != null)
7178 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7179 "GetFieldFromHandle", loc, handle_type);
7182 type = typeof (FieldInfo);
7183 eclass = ExprClass.Value;
7187 public override void Emit (EmitContext ec)
7189 ec.ig.Emit (OpCodes.Ldtoken, field);
7190 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7195 /// Implements the sizeof expression
7197 public class SizeOf : Expression {
7198 readonly Expression QueriedType;
7201 public SizeOf (Expression queried_type, Location l)
7203 this.QueriedType = queried_type;
7207 public override Expression CreateExpressionTree (EmitContext ec)
7209 Error_PointerInsideExpressionTree ();
7213 public override Expression DoResolve (EmitContext ec)
7215 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7219 type_queried = texpr.Type;
7220 if (TypeManager.IsEnumType (type_queried))
7221 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7223 if (type_queried == TypeManager.void_type) {
7224 Expression.Error_VoidInvalidInTheContext (loc);
7228 int size_of = GetTypeSize (type_queried);
7230 return new IntConstant (size_of, loc);
7233 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7238 Report.Error (233, loc,
7239 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7240 TypeManager.CSharpName (type_queried));
7243 type = TypeManager.int32_type;
7244 eclass = ExprClass.Value;
7248 public override void Emit (EmitContext ec)
7250 int size = GetTypeSize (type_queried);
7253 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7255 IntConstant.EmitInt (ec.ig, size);
7258 protected override void CloneTo (CloneContext clonectx, Expression t)
7264 /// Implements the qualified-alias-member (::) expression.
7266 public class QualifiedAliasMember : MemberAccess
7268 readonly string alias;
7269 public static readonly string GlobalAlias = "global";
7271 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7272 : base (null, identifier, targs, l)
7277 public QualifiedAliasMember (string alias, string identifier, Location l)
7278 : base (null, identifier, l)
7283 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7285 if (alias == GlobalAlias) {
7286 expr = RootNamespace.Global;
7287 return base.ResolveAsTypeStep (ec, silent);
7290 int errors = Report.Errors;
7291 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7293 if (errors == Report.Errors)
7294 Report.Error (432, loc, "Alias `{0}' not found", alias);
7298 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7302 if (expr.eclass == ExprClass.Type) {
7304 Report.Error (431, loc,
7305 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7313 public override Expression DoResolve (EmitContext ec)
7315 return ResolveAsTypeStep (ec, false);
7318 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7320 Report.Error (687, loc,
7321 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7322 GetSignatureForError ());
7325 public override string GetSignatureForError ()
7328 if (targs != null) {
7329 name = TypeManager.RemoveGenericArity (Name) + "<" +
7330 targs.GetSignatureForError () + ">";
7333 return alias + "::" + name;
7336 protected override void CloneTo (CloneContext clonectx, Expression t)
7343 /// Implements the member access expression
7345 public class MemberAccess : ATypeNameExpression {
7346 protected Expression expr;
7348 public MemberAccess (Expression expr, string id)
7349 : base (id, expr.Location)
7354 public MemberAccess (Expression expr, string identifier, Location loc)
7355 : base (identifier, loc)
7360 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7361 : base (identifier, args, loc)
7366 // TODO: this method has very poor performace for Enum fields and
7367 // probably for other constants as well
7368 Expression DoResolve (EmitContext ec, Expression right_side)
7371 throw new Exception ();
7374 // Resolve the expression with flow analysis turned off, we'll do the definite
7375 // assignment checks later. This is because we don't know yet what the expression
7376 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7377 // definite assignment check on the actual field and not on the whole struct.
7380 SimpleName original = expr as SimpleName;
7381 Expression expr_resolved = expr.Resolve (ec,
7382 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7383 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7385 if (expr_resolved == null)
7388 string LookupIdentifier = MemberName.MakeName (Name, targs);
7390 if (expr_resolved is Namespace) {
7391 Namespace ns = (Namespace) expr_resolved;
7392 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7394 if ((retval != null) && (targs != null))
7395 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7399 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7403 Type expr_type = expr_resolved.Type;
7404 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7405 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7406 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7410 Constant c = expr_resolved as Constant;
7411 if (c != null && c.GetValue () == null) {
7412 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7413 "System.NullReferenceException");
7416 if (targs != null) {
7417 if (!targs.Resolve (ec))
7421 Expression member_lookup;
7422 member_lookup = MemberLookup (
7423 ec.ContainerType, expr_type, expr_type, Name, loc);
7425 if ((member_lookup == null) && (targs != null)) {
7426 member_lookup = MemberLookup (
7427 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7430 if (member_lookup == null) {
7431 ExprClass expr_eclass = expr_resolved.eclass;
7434 // Extension methods are not allowed on all expression types
7436 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7437 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7438 expr_eclass == ExprClass.EventAccess) {
7439 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7440 if (ex_method_lookup != null) {
7441 ex_method_lookup.ExtensionExpression = expr_resolved;
7443 if (targs != null) {
7444 ex_method_lookup.SetTypeArguments (targs);
7447 return ex_method_lookup.DoResolve (ec);
7451 expr = expr_resolved;
7452 Error_MemberLookupFailed (
7453 ec.ContainerType, expr_type, expr_type, Name, null,
7454 AllMemberTypes, AllBindingFlags);
7458 TypeExpr texpr = member_lookup as TypeExpr;
7459 if (texpr != null) {
7460 if (!(expr_resolved is TypeExpr) &&
7461 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7462 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7463 Name, member_lookup.GetSignatureForError ());
7467 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7468 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7469 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7474 ConstructedType ct = expr_resolved as ConstructedType;
7477 // When looking up a nested type in a generic instance
7478 // via reflection, we always get a generic type definition
7479 // and not a generic instance - so we have to do this here.
7481 // See gtest-172-lib.cs and gtest-172.cs for an example.
7483 ct = new ConstructedType (
7484 member_lookup.Type, ct.TypeArguments, loc);
7486 return ct.ResolveAsTypeStep (ec, false);
7489 return member_lookup;
7492 MemberExpr me = (MemberExpr) member_lookup;
7493 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7497 if (targs != null) {
7498 me.SetTypeArguments (targs);
7501 if (original != null && !TypeManager.IsValueType (expr_type)) {
7502 if (me.IsInstance) {
7503 LocalVariableReference var = expr_resolved as LocalVariableReference;
7504 if (var != null && !var.VerifyAssigned (ec))
7509 // The following DoResolve/DoResolveLValue will do the definite assignment
7512 if (right_side != null)
7513 return me.DoResolveLValue (ec, right_side);
7515 return me.DoResolve (ec);
7518 public override Expression DoResolve (EmitContext ec)
7520 return DoResolve (ec, null);
7523 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7525 return DoResolve (ec, right_side);
7528 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7530 return ResolveNamespaceOrType (ec, silent);
7533 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7535 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7537 if (new_expr == null)
7540 string LookupIdentifier = MemberName.MakeName (Name, targs);
7542 if (new_expr is Namespace) {
7543 Namespace ns = (Namespace) new_expr;
7544 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7546 if ((retval != null) && (targs != null))
7547 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7549 if (!silent && retval == null)
7550 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7554 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7555 if (tnew_expr == null)
7558 Type expr_type = tnew_expr.Type;
7560 if (expr_type.IsPointer){
7561 Error (23, "The `.' operator can not be applied to pointer operands (" +
7562 TypeManager.CSharpName (expr_type) + ")");
7566 Expression member_lookup = MemberLookup (
7567 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7568 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7569 if (member_lookup == null) {
7573 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7577 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7582 TypeArguments the_args = targs;
7583 Type declaring_type = texpr.Type.DeclaringType;
7584 if (TypeManager.HasGenericArguments (declaring_type)) {
7585 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7586 expr_type = expr_type.BaseType;
7589 TypeArguments new_args = new TypeArguments (loc);
7590 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7591 new_args.Add (new TypeExpression (decl, loc));
7594 new_args.Add (targs);
7596 the_args = new_args;
7599 if (the_args != null) {
7600 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7601 return ctype.ResolveAsTypeStep (rc, false);
7608 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7610 Expression member_lookup = MemberLookup (
7611 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7612 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7614 if (member_lookup != null) {
7615 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7616 if (expr_type == null)
7619 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7623 member_lookup = MemberLookup (
7624 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7625 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7627 if (member_lookup == null) {
7628 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7629 Name, expr_type.GetSignatureForError ());
7631 // TODO: Report.SymbolRelatedToPreviousError
7632 member_lookup.Error_UnexpectedKind (null, "type", loc);
7636 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7638 if (RootContext.Version > LanguageVersion.ISO_2 &&
7639 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7640 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7641 "extension method `{1}' of type `{0}' could be found " +
7642 "(are you missing a using directive or an assembly reference?)",
7643 TypeManager.CSharpName (type), name);
7647 base.Error_TypeDoesNotContainDefinition (type, name);
7650 public override string GetSignatureForError ()
7652 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7655 protected override void CloneTo (CloneContext clonectx, Expression t)
7657 MemberAccess target = (MemberAccess) t;
7659 target.expr = expr.Clone (clonectx);
7664 /// Implements checked expressions
7666 public class CheckedExpr : Expression {
7668 public Expression Expr;
7670 public CheckedExpr (Expression e, Location l)
7676 public override Expression CreateExpressionTree (EmitContext ec)
7678 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7679 return Expr.CreateExpressionTree (ec);
7682 public override Expression DoResolve (EmitContext ec)
7684 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7685 Expr = Expr.Resolve (ec);
7690 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7693 eclass = Expr.eclass;
7698 public override void Emit (EmitContext ec)
7700 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7704 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7706 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7707 Expr.EmitBranchable (ec, target, on_true);
7710 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7712 Expr.MutateHoistedGenericType (storey);
7715 protected override void CloneTo (CloneContext clonectx, Expression t)
7717 CheckedExpr target = (CheckedExpr) t;
7719 target.Expr = Expr.Clone (clonectx);
7724 /// Implements the unchecked expression
7726 public class UnCheckedExpr : Expression {
7728 public Expression Expr;
7730 public UnCheckedExpr (Expression e, Location l)
7736 public override Expression CreateExpressionTree (EmitContext ec)
7738 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7739 return Expr.CreateExpressionTree (ec);
7742 public override Expression DoResolve (EmitContext ec)
7744 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7745 Expr = Expr.Resolve (ec);
7750 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7753 eclass = Expr.eclass;
7758 public override void Emit (EmitContext ec)
7760 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7764 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7766 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7767 Expr.EmitBranchable (ec, target, on_true);
7770 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7772 Expr.MutateHoistedGenericType (storey);
7775 protected override void CloneTo (CloneContext clonectx, Expression t)
7777 UnCheckedExpr target = (UnCheckedExpr) t;
7779 target.Expr = Expr.Clone (clonectx);
7784 /// An Element Access expression.
7786 /// During semantic analysis these are transformed into
7787 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7789 public class ElementAccess : Expression {
7790 public ArrayList Arguments;
7791 public Expression Expr;
7793 public ElementAccess (Expression e, ArrayList e_list)
7801 Arguments = new ArrayList (e_list.Count);
7802 foreach (Expression tmp in e_list)
7803 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7806 bool CommonResolve (EmitContext ec)
7808 Expr = Expr.Resolve (ec);
7810 if (Arguments == null)
7813 foreach (Argument a in Arguments){
7814 if (!a.Resolve (ec, loc))
7818 return Expr != null;
7821 public override Expression CreateExpressionTree (EmitContext ec)
7823 ArrayList args = new ArrayList (Arguments.Count + 1);
7824 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7825 foreach (Argument a in Arguments)
7826 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7828 return CreateExpressionFactoryCall ("ArrayIndex", args);
7831 Expression MakePointerAccess (EmitContext ec, Type t)
7833 if (Arguments.Count != 1){
7834 Error (196, "A pointer must be indexed by only one value");
7838 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7841 return new Indirection (p, loc).Resolve (ec);
7844 public override Expression DoResolve (EmitContext ec)
7846 if (!CommonResolve (ec))
7850 // We perform some simple tests, and then to "split" the emit and store
7851 // code we create an instance of a different class, and return that.
7853 // I am experimenting with this pattern.
7857 if (t == TypeManager.array_type){
7858 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7863 return (new ArrayAccess (this, loc)).Resolve (ec);
7865 return MakePointerAccess (ec, t);
7867 FieldExpr fe = Expr as FieldExpr;
7869 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7871 return MakePointerAccess (ec, ff.ElementType);
7874 return (new IndexerAccess (this, loc)).Resolve (ec);
7877 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7879 if (!CommonResolve (ec))
7884 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7887 return MakePointerAccess (ec, type);
7889 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7890 Error_CannotModifyIntermediateExpressionValue (ec);
7892 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7895 public override void Emit (EmitContext ec)
7897 throw new Exception ("Should never be reached");
7900 public override string GetSignatureForError ()
7902 return Expr.GetSignatureForError ();
7905 protected override void CloneTo (CloneContext clonectx, Expression t)
7907 ElementAccess target = (ElementAccess) t;
7909 target.Expr = Expr.Clone (clonectx);
7910 target.Arguments = new ArrayList (Arguments.Count);
7911 foreach (Argument a in Arguments)
7912 target.Arguments.Add (a.Clone (clonectx));
7917 /// Implements array access
7919 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7921 // Points to our "data" repository
7925 LocalTemporary temp;
7929 public ArrayAccess (ElementAccess ea_data, Location l)
7935 public override Expression CreateExpressionTree (EmitContext ec)
7937 return ea.CreateExpressionTree (ec);
7940 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7942 return DoResolve (ec);
7945 public override Expression DoResolve (EmitContext ec)
7948 ExprClass eclass = ea.Expr.eclass;
7950 // As long as the type is valid
7951 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7952 eclass == ExprClass.Value)) {
7953 ea.Expr.Error_UnexpectedKind ("variable or value");
7958 if (eclass != ExprClass.Invalid)
7961 Type t = ea.Expr.Type;
7962 int rank = ea.Arguments.Count;
7963 if (t.GetArrayRank () != rank) {
7964 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7965 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7969 type = TypeManager.GetElementType (t);
7970 if (type.IsPointer && !ec.InUnsafe) {
7971 UnsafeError (ea.Location);
7975 foreach (Argument a in ea.Arguments) {
7976 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7979 eclass = ExprClass.Variable;
7985 /// Emits the right opcode to load an object of Type `t'
7986 /// from an array of T
7988 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7991 MethodInfo get = FetchGetMethod ();
7992 ig.Emit (OpCodes.Call, get);
7996 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7997 ig.Emit (OpCodes.Ldelem_U1);
7998 else if (type == TypeManager.sbyte_type)
7999 ig.Emit (OpCodes.Ldelem_I1);
8000 else if (type == TypeManager.short_type)
8001 ig.Emit (OpCodes.Ldelem_I2);
8002 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8003 ig.Emit (OpCodes.Ldelem_U2);
8004 else if (type == TypeManager.int32_type)
8005 ig.Emit (OpCodes.Ldelem_I4);
8006 else if (type == TypeManager.uint32_type)
8007 ig.Emit (OpCodes.Ldelem_U4);
8008 else if (type == TypeManager.uint64_type)
8009 ig.Emit (OpCodes.Ldelem_I8);
8010 else if (type == TypeManager.int64_type)
8011 ig.Emit (OpCodes.Ldelem_I8);
8012 else if (type == TypeManager.float_type)
8013 ig.Emit (OpCodes.Ldelem_R4);
8014 else if (type == TypeManager.double_type)
8015 ig.Emit (OpCodes.Ldelem_R8);
8016 else if (type == TypeManager.intptr_type)
8017 ig.Emit (OpCodes.Ldelem_I);
8018 else if (TypeManager.IsEnumType (type)){
8019 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8020 } else if (type.IsValueType){
8021 ig.Emit (OpCodes.Ldelema, type);
8022 ig.Emit (OpCodes.Ldobj, type);
8024 } else if (type.IsGenericParameter) {
8025 ig.Emit (OpCodes.Ldelem, type);
8027 } else if (type.IsPointer)
8028 ig.Emit (OpCodes.Ldelem_I);
8030 ig.Emit (OpCodes.Ldelem_Ref);
8033 protected override void Error_NegativeArrayIndex (Location loc)
8035 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8039 /// Returns the right opcode to store an object of Type `t'
8040 /// from an array of T.
8042 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8044 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8045 has_type_arg = false; is_stobj = false;
8046 t = TypeManager.TypeToCoreType (t);
8047 if (TypeManager.IsEnumType (t))
8048 t = TypeManager.GetEnumUnderlyingType (t);
8049 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8050 t == TypeManager.bool_type)
8051 return OpCodes.Stelem_I1;
8052 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8053 t == TypeManager.char_type)
8054 return OpCodes.Stelem_I2;
8055 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8056 return OpCodes.Stelem_I4;
8057 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8058 return OpCodes.Stelem_I8;
8059 else if (t == TypeManager.float_type)
8060 return OpCodes.Stelem_R4;
8061 else if (t == TypeManager.double_type)
8062 return OpCodes.Stelem_R8;
8063 else if (t == TypeManager.intptr_type) {
8064 has_type_arg = true;
8066 return OpCodes.Stobj;
8067 } else if (t.IsValueType) {
8068 has_type_arg = true;
8070 return OpCodes.Stobj;
8072 } else if (t.IsGenericParameter) {
8073 has_type_arg = true;
8074 return OpCodes.Stelem;
8077 } else if (t.IsPointer)
8078 return OpCodes.Stelem_I;
8080 return OpCodes.Stelem_Ref;
8083 MethodInfo FetchGetMethod ()
8085 ModuleBuilder mb = CodeGen.Module.Builder;
8086 int arg_count = ea.Arguments.Count;
8087 Type [] args = new Type [arg_count];
8090 for (int i = 0; i < arg_count; i++){
8091 //args [i++] = a.Type;
8092 args [i] = TypeManager.int32_type;
8095 get = mb.GetArrayMethod (
8096 ea.Expr.Type, "Get",
8097 CallingConventions.HasThis |
8098 CallingConventions.Standard,
8104 MethodInfo FetchAddressMethod ()
8106 ModuleBuilder mb = CodeGen.Module.Builder;
8107 int arg_count = ea.Arguments.Count;
8108 Type [] args = new Type [arg_count];
8112 ret_type = TypeManager.GetReferenceType (type);
8114 for (int i = 0; i < arg_count; i++){
8115 //args [i++] = a.Type;
8116 args [i] = TypeManager.int32_type;
8119 address = mb.GetArrayMethod (
8120 ea.Expr.Type, "Address",
8121 CallingConventions.HasThis |
8122 CallingConventions.Standard,
8129 // Load the array arguments into the stack.
8131 void LoadArrayAndArguments (EmitContext ec)
8135 for (int i = 0; i < ea.Arguments.Count; ++i) {
8136 ((Argument)ea.Arguments [i]).Emit (ec);
8140 public void Emit (EmitContext ec, bool leave_copy)
8142 int rank = ea.Expr.Type.GetArrayRank ();
8143 ILGenerator ig = ec.ig;
8146 LoadFromPtr (ig, this.type);
8148 LoadArrayAndArguments (ec);
8149 EmitLoadOpcode (ig, type, rank);
8153 ig.Emit (OpCodes.Dup);
8154 temp = new LocalTemporary (this.type);
8159 public override void Emit (EmitContext ec)
8164 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8166 int rank = ea.Expr.Type.GetArrayRank ();
8167 ILGenerator ig = ec.ig;
8168 Type t = source.Type;
8169 prepared = prepare_for_load;
8172 AddressOf (ec, AddressOp.LoadStore);
8173 ec.ig.Emit (OpCodes.Dup);
8175 LoadArrayAndArguments (ec);
8179 bool is_stobj, has_type_arg;
8180 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8184 // The stobj opcode used by value types will need
8185 // an address on the stack, not really an array/array
8189 ig.Emit (OpCodes.Ldelema, t);
8194 ec.ig.Emit (OpCodes.Dup);
8195 temp = new LocalTemporary (this.type);
8200 StoreFromPtr (ig, t);
8202 ig.Emit (OpCodes.Stobj, t);
8203 else if (has_type_arg)
8210 ec.ig.Emit (OpCodes.Dup);
8211 temp = new LocalTemporary (this.type);
8216 StoreFromPtr (ig, t);
8218 int arg_count = ea.Arguments.Count;
8219 Type [] args = new Type [arg_count + 1];
8220 for (int i = 0; i < arg_count; i++) {
8221 //args [i++] = a.Type;
8222 args [i] = TypeManager.int32_type;
8224 args [arg_count] = type;
8226 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8227 ea.Expr.Type, "Set",
8228 CallingConventions.HasThis |
8229 CallingConventions.Standard,
8230 TypeManager.void_type, args);
8232 ig.Emit (OpCodes.Call, set);
8242 public void AddressOf (EmitContext ec, AddressOp mode)
8244 int rank = ea.Expr.Type.GetArrayRank ();
8245 ILGenerator ig = ec.ig;
8247 LoadArrayAndArguments (ec);
8250 ig.Emit (OpCodes.Ldelema, type);
8252 MethodInfo address = FetchAddressMethod ();
8253 ig.Emit (OpCodes.Call, address);
8257 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8259 type = storey.MutateType (type);
8264 /// Expressions that represent an indexer call.
8266 public class IndexerAccess : Expression, IAssignMethod
8268 class IndexerMethodGroupExpr : MethodGroupExpr
8270 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8273 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8276 public override string Name {
8282 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8285 // Here is the trick, decrease number of arguments by 1 when only
8286 // available property method is setter. This makes overload resolution
8287 // work correctly for indexers.
8290 if (method.Name [0] == 'g')
8291 return parameters.Count;
8293 return parameters.Count - 1;
8299 // Contains either property getter or setter
8300 public ArrayList Methods;
8301 public ArrayList Properties;
8307 void Append (Type caller_type, MemberInfo [] mi)
8312 foreach (PropertyInfo property in mi) {
8313 MethodInfo accessor = property.GetGetMethod (true);
8314 if (accessor == null)
8315 accessor = property.GetSetMethod (true);
8317 if (Methods == null) {
8318 Methods = new ArrayList ();
8319 Properties = new ArrayList ();
8322 Methods.Add (accessor);
8323 Properties.Add (property);
8327 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8329 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8331 return TypeManager.MemberLookup (
8332 caller_type, caller_type, lookup_type, MemberTypes.Property,
8333 BindingFlags.Public | BindingFlags.Instance |
8334 BindingFlags.DeclaredOnly, p_name, null);
8337 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8339 Indexers ix = new Indexers ();
8342 if (lookup_type.IsGenericParameter) {
8343 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8347 if (gc.HasClassConstraint)
8348 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8350 Type[] ifaces = gc.InterfaceConstraints;
8351 foreach (Type itype in ifaces)
8352 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8358 Type copy = lookup_type;
8359 while (copy != TypeManager.object_type && copy != null){
8360 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8361 copy = copy.BaseType;
8364 if (lookup_type.IsInterface) {
8365 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8366 if (ifaces != null) {
8367 foreach (Type itype in ifaces)
8368 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8383 // Points to our "data" repository
8385 MethodInfo get, set;
8386 bool is_base_indexer;
8388 LocalTemporary temp;
8389 LocalTemporary prepared_value;
8390 Expression set_expr;
8392 protected Type indexer_type;
8393 protected Type current_type;
8394 protected Expression instance_expr;
8395 protected ArrayList arguments;
8397 public IndexerAccess (ElementAccess ea, Location loc)
8398 : this (ea.Expr, false, loc)
8400 this.arguments = ea.Arguments;
8403 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8406 this.instance_expr = instance_expr;
8407 this.is_base_indexer = is_base_indexer;
8408 this.eclass = ExprClass.Value;
8412 static string GetAccessorName (AccessorType at)
8414 if (at == AccessorType.Set)
8417 if (at == AccessorType.Get)
8420 throw new NotImplementedException (at.ToString ());
8423 public override Expression CreateExpressionTree (EmitContext ec)
8425 ArrayList args = new ArrayList (arguments.Count + 2);
8426 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8427 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8428 foreach (Argument a in arguments)
8429 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8431 return CreateExpressionFactoryCall ("Call", args);
8434 protected virtual bool CommonResolve (EmitContext ec)
8436 indexer_type = instance_expr.Type;
8437 current_type = ec.ContainerType;
8442 public override Expression DoResolve (EmitContext ec)
8444 return ResolveAccessor (ec, AccessorType.Get);
8447 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8449 if (right_side == EmptyExpression.OutAccess) {
8450 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8451 GetSignatureForError ());
8455 // if the indexer returns a value type, and we try to set a field in it
8456 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8457 Error_CannotModifyIntermediateExpressionValue (ec);
8460 Expression e = ResolveAccessor (ec, AccessorType.Set);
8464 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8468 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8470 if (!CommonResolve (ec))
8473 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8474 if (ilist.Methods == null) {
8475 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8476 TypeManager.CSharpName (indexer_type));
8480 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8481 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8485 MethodInfo mi = (MethodInfo) mg;
8486 PropertyInfo pi = null;
8487 for (int i = 0; i < ilist.Methods.Count; ++i) {
8488 if (ilist.Methods [i] == mi) {
8489 pi = (PropertyInfo) ilist.Properties [i];
8494 type = TypeManager.TypeToCoreType (pi.PropertyType);
8495 if (type.IsPointer && !ec.InUnsafe)
8498 MethodInfo accessor;
8499 if (accessorType == AccessorType.Get) {
8500 accessor = get = pi.GetGetMethod (true);
8502 accessor = set = pi.GetSetMethod (true);
8503 if (accessor == null && pi.GetGetMethod (true) != null) {
8504 Report.SymbolRelatedToPreviousError (pi);
8505 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8506 TypeManager.GetFullNameSignature (pi));
8511 if (accessor == null) {
8512 Report.SymbolRelatedToPreviousError (pi);
8513 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8514 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8519 // Only base will allow this invocation to happen.
8521 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8522 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8525 bool must_do_cs1540_check;
8526 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8528 set = pi.GetSetMethod (true);
8530 get = pi.GetGetMethod (true);
8532 if (set != null && get != null &&
8533 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8534 Report.SymbolRelatedToPreviousError (accessor);
8535 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8536 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8538 Report.SymbolRelatedToPreviousError (pi);
8539 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8543 instance_expr.CheckMarshalByRefAccess (ec);
8544 eclass = ExprClass.IndexerAccess;
8548 public void Emit (EmitContext ec, bool leave_copy)
8551 prepared_value.Emit (ec);
8553 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8554 arguments, loc, false, false);
8558 ec.ig.Emit (OpCodes.Dup);
8559 temp = new LocalTemporary (Type);
8565 // source is ignored, because we already have a copy of it from the
8566 // LValue resolution and we have already constructed a pre-cached
8567 // version of the arguments (ea.set_arguments);
8569 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8571 prepared = prepare_for_load;
8572 Expression value = set_expr;
8575 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8576 arguments, loc, true, false);
8578 prepared_value = new LocalTemporary (type);
8579 prepared_value.Store (ec);
8581 prepared_value.Release (ec);
8584 ec.ig.Emit (OpCodes.Dup);
8585 temp = new LocalTemporary (Type);
8588 } else if (leave_copy) {
8589 temp = new LocalTemporary (Type);
8595 arguments.Add (new Argument (value, Argument.AType.Expression));
8596 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8604 public override void Emit (EmitContext ec)
8609 public override string GetSignatureForError ()
8611 return TypeManager.CSharpSignature (get != null ? get : set, false);
8614 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8617 get = storey.MutateGenericMethod (get);
8619 set = storey.MutateGenericMethod (set);
8621 instance_expr.MutateHoistedGenericType (storey);
8622 foreach (Argument a in arguments)
8623 a.Expr.MutateHoistedGenericType (storey);
8625 type = storey.MutateType (type);
8628 protected override void CloneTo (CloneContext clonectx, Expression t)
8630 IndexerAccess target = (IndexerAccess) t;
8632 if (arguments != null){
8633 target.arguments = new ArrayList ();
8634 foreach (Argument a in arguments)
8635 target.arguments.Add (a.Clone (clonectx));
8637 if (instance_expr != null)
8638 target.instance_expr = instance_expr.Clone (clonectx);
8643 /// The base operator for method names
8645 public class BaseAccess : Expression {
8646 public readonly string Identifier;
8649 public BaseAccess (string member, Location l)
8651 this.Identifier = member;
8655 public BaseAccess (string member, TypeArguments args, Location l)
8661 public override Expression CreateExpressionTree (EmitContext ec)
8663 throw new NotSupportedException ("ET");
8666 public override Expression DoResolve (EmitContext ec)
8668 Expression c = CommonResolve (ec);
8674 // MethodGroups use this opportunity to flag an error on lacking ()
8676 if (!(c is MethodGroupExpr))
8677 return c.Resolve (ec);
8681 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8683 Expression c = CommonResolve (ec);
8689 // MethodGroups use this opportunity to flag an error on lacking ()
8691 if (! (c is MethodGroupExpr))
8692 return c.DoResolveLValue (ec, right_side);
8697 Expression CommonResolve (EmitContext ec)
8699 Expression member_lookup;
8700 Type current_type = ec.ContainerType;
8701 Type base_type = current_type.BaseType;
8703 if (!This.IsThisAvailable (ec)) {
8705 Error (1511, "Keyword `base' is not available in a static method");
8707 Error (1512, "Keyword `base' is not available in the current context");
8712 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8713 AllMemberTypes, AllBindingFlags, loc);
8714 if (member_lookup == null) {
8715 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8716 null, AllMemberTypes, AllBindingFlags);
8723 left = new TypeExpression (base_type, loc);
8725 left = ec.GetThis (loc);
8727 MemberExpr me = (MemberExpr) member_lookup;
8728 me = me.ResolveMemberAccess (ec, left, loc, null);
8735 me.SetTypeArguments (args);
8741 public override void Emit (EmitContext ec)
8743 throw new Exception ("Should never be called");
8746 protected override void CloneTo (CloneContext clonectx, Expression t)
8748 BaseAccess target = (BaseAccess) t;
8751 target.args = args.Clone ();
8756 /// The base indexer operator
8758 public class BaseIndexerAccess : IndexerAccess {
8759 public BaseIndexerAccess (ArrayList args, Location loc)
8760 : base (null, true, loc)
8762 arguments = new ArrayList ();
8763 foreach (Expression tmp in args)
8764 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8767 protected override bool CommonResolve (EmitContext ec)
8769 instance_expr = ec.GetThis (loc);
8771 current_type = ec.ContainerType.BaseType;
8772 indexer_type = current_type;
8774 foreach (Argument a in arguments){
8775 if (!a.Resolve (ec, loc))
8782 public override Expression CreateExpressionTree (EmitContext ec)
8784 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8785 return base.CreateExpressionTree (ec);
8790 /// This class exists solely to pass the Type around and to be a dummy
8791 /// that can be passed to the conversion functions (this is used by
8792 /// foreach implementation to typecast the object return value from
8793 /// get_Current into the proper type. All code has been generated and
8794 /// we only care about the side effect conversions to be performed
8796 /// This is also now used as a placeholder where a no-action expression
8797 /// is needed (the `New' class).
8799 public class EmptyExpression : Expression {
8800 public static readonly Expression Null = new EmptyExpression ();
8802 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8803 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8804 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8805 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8807 static EmptyExpression temp = new EmptyExpression ();
8808 public static EmptyExpression Grab ()
8810 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8815 public static void Release (EmptyExpression e)
8820 // TODO: should be protected
8821 public EmptyExpression ()
8823 type = TypeManager.object_type;
8824 eclass = ExprClass.Value;
8825 loc = Location.Null;
8828 public EmptyExpression (Type t)
8831 eclass = ExprClass.Value;
8832 loc = Location.Null;
8835 public override Expression CreateExpressionTree (EmitContext ec)
8837 throw new NotSupportedException ("ET");
8840 public override Expression DoResolve (EmitContext ec)
8845 public override void Emit (EmitContext ec)
8847 // nothing, as we only exist to not do anything.
8850 public override void EmitSideEffect (EmitContext ec)
8855 // This is just because we might want to reuse this bad boy
8856 // instead of creating gazillions of EmptyExpressions.
8857 // (CanImplicitConversion uses it)
8859 public void SetType (Type t)
8866 // Empty statement expression
8868 public sealed class EmptyExpressionStatement : ExpressionStatement
8870 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8872 private EmptyExpressionStatement ()
8874 type = TypeManager.object_type;
8875 eclass = ExprClass.Value;
8876 loc = Location.Null;
8879 public override Expression CreateExpressionTree (EmitContext ec)
8884 public override void EmitStatement (EmitContext ec)
8889 public override Expression DoResolve (EmitContext ec)
8894 public override void Emit (EmitContext ec)
8900 public class UserCast : Expression {
8904 public UserCast (MethodInfo method, Expression source, Location l)
8906 this.method = method;
8907 this.source = source;
8908 type = TypeManager.TypeToCoreType (method.ReturnType);
8909 eclass = ExprClass.Value;
8913 public Expression Source {
8919 public override Expression CreateExpressionTree (EmitContext ec)
8921 ArrayList args = new ArrayList (3);
8922 args.Add (new Argument (source.CreateExpressionTree (ec)));
8923 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8924 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8925 return CreateExpressionFactoryCall ("Convert", args);
8928 public override Expression DoResolve (EmitContext ec)
8931 // We are born fully resolved
8936 public override void Emit (EmitContext ec)
8939 ec.ig.Emit (OpCodes.Call, method);
8942 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8944 source.MutateHoistedGenericType (storey);
8945 method = storey.MutateGenericMethod (method);
8950 // This class is used to "construct" the type during a typecast
8951 // operation. Since the Type.GetType class in .NET can parse
8952 // the type specification, we just use this to construct the type
8953 // one bit at a time.
8955 public class ComposedCast : TypeExpr {
8956 FullNamedExpression left;
8959 public ComposedCast (FullNamedExpression left, string dim)
8960 : this (left, dim, left.Location)
8964 public ComposedCast (FullNamedExpression left, string dim, Location l)
8971 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8973 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8977 Type ltype = lexpr.Type;
8978 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8979 Error_VoidInvalidInTheContext (loc);
8984 if ((dim.Length > 0) && (dim [0] == '?')) {
8985 TypeExpr nullable = new Nullable.NullableType (left, loc);
8987 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8988 return nullable.ResolveAsTypeTerminal (ec, false);
8992 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8995 if (dim.Length != 0 && dim [0] == '[') {
8996 if (TypeManager.IsSpecialType (ltype)) {
8997 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9001 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9002 Report.SymbolRelatedToPreviousError (ltype);
9003 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9004 TypeManager.CSharpName (ltype));
9009 type = TypeManager.GetConstructedType (ltype, dim);
9014 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9016 if (type.IsPointer && !ec.IsInUnsafeScope){
9020 eclass = ExprClass.Type;
9024 public override string GetSignatureForError ()
9026 return left.GetSignatureForError () + dim;
9029 protected override void CloneTo (CloneContext clonectx, Expression t)
9031 ComposedCast target = (ComposedCast) t;
9033 target.left = (FullNamedExpression)left.Clone (clonectx);
9037 public class FixedBufferPtr : Expression {
9040 public FixedBufferPtr (Expression array, Type array_type, Location l)
9045 type = TypeManager.GetPointerType (array_type);
9046 eclass = ExprClass.Value;
9049 public override Expression CreateExpressionTree (EmitContext ec)
9051 Error_PointerInsideExpressionTree ();
9055 public override void Emit(EmitContext ec)
9060 public override Expression DoResolve (EmitContext ec)
9063 // We are born fully resolved
9071 // This class is used to represent the address of an array, used
9072 // only by the Fixed statement, this generates "&a [0]" construct
9073 // for fixed (char *pa = a)
9075 public class ArrayPtr : FixedBufferPtr {
9078 public ArrayPtr (Expression array, Type array_type, Location l):
9079 base (array, array_type, l)
9081 this.array_type = array_type;
9084 public override void Emit (EmitContext ec)
9088 ILGenerator ig = ec.ig;
9089 IntLiteral.EmitInt (ig, 0);
9090 ig.Emit (OpCodes.Ldelema, array_type);
9095 // Encapsulates a conversion rules required for array indexes
9097 public class ArrayIndexCast : TypeCast
9099 public ArrayIndexCast (Expression expr)
9100 : base (expr, expr.Type)
9104 public override Expression CreateExpressionTree (EmitContext ec)
9106 ArrayList args = new ArrayList (2);
9107 args.Add (new Argument (child.CreateExpressionTree (ec)));
9108 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9109 return CreateExpressionFactoryCall ("ConvertChecked", args);
9112 public override void Emit (EmitContext ec)
9116 if (type == TypeManager.int32_type)
9119 if (type == TypeManager.uint32_type)
9120 ec.ig.Emit (OpCodes.Conv_U);
9121 else if (type == TypeManager.int64_type)
9122 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9123 else if (type == TypeManager.uint64_type)
9124 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9126 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9131 // Implements the `stackalloc' keyword
9133 public class StackAlloc : Expression {
9138 public StackAlloc (Expression type, Expression count, Location l)
9145 public override Expression CreateExpressionTree (EmitContext ec)
9147 throw new NotSupportedException ("ET");
9150 public override Expression DoResolve (EmitContext ec)
9152 count = count.Resolve (ec);
9156 if (count.Type != TypeManager.uint32_type){
9157 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9162 Constant c = count as Constant;
9163 if (c != null && c.IsNegative) {
9164 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9168 if (ec.InCatch || ec.InFinally) {
9169 Error (255, "Cannot use stackalloc in finally or catch");
9173 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9179 if (!TypeManager.VerifyUnManaged (otype, loc))
9182 type = TypeManager.GetPointerType (otype);
9183 eclass = ExprClass.Value;
9188 public override void Emit (EmitContext ec)
9190 int size = GetTypeSize (otype);
9191 ILGenerator ig = ec.ig;
9196 ig.Emit (OpCodes.Sizeof, otype);
9198 IntConstant.EmitInt (ig, size);
9200 ig.Emit (OpCodes.Mul_Ovf_Un);
9201 ig.Emit (OpCodes.Localloc);
9204 protected override void CloneTo (CloneContext clonectx, Expression t)
9206 StackAlloc target = (StackAlloc) t;
9207 target.count = count.Clone (clonectx);
9208 target.t = t.Clone (clonectx);
9213 // An object initializer expression
9215 public class ElementInitializer : Assign
9217 public readonly string Name;
9219 public ElementInitializer (string name, Expression initializer, Location loc)
9220 : base (null, initializer, loc)
9225 protected override void CloneTo (CloneContext clonectx, Expression t)
9227 ElementInitializer target = (ElementInitializer) t;
9228 target.source = source.Clone (clonectx);
9231 public override Expression CreateExpressionTree (EmitContext ec)
9233 ArrayList args = new ArrayList (2);
9234 FieldExpr fe = target as FieldExpr;
9236 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9238 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9240 args.Add (new Argument (source.CreateExpressionTree (ec)));
9241 return CreateExpressionFactoryCall (
9242 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9246 public override Expression DoResolve (EmitContext ec)
9249 return EmptyExpressionStatement.Instance;
9251 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9252 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9258 me.InstanceExpression = ec.CurrentInitializerVariable;
9260 if (source is CollectionOrObjectInitializers) {
9261 Expression previous = ec.CurrentInitializerVariable;
9262 ec.CurrentInitializerVariable = target;
9263 source = source.Resolve (ec);
9264 ec.CurrentInitializerVariable = previous;
9268 eclass = source.eclass;
9273 Expression expr = base.DoResolve (ec);
9278 // Ignore field initializers with default value
9280 Constant c = source as Constant;
9281 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9282 return EmptyExpressionStatement.Instance;
9287 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9289 MemberInfo member = members [0];
9290 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9291 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9292 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9294 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9295 TypeManager.GetFullNameSignature (member));
9300 public override void EmitStatement (EmitContext ec)
9302 if (source is CollectionOrObjectInitializers)
9305 base.EmitStatement (ec);
9310 // A collection initializer expression
9312 public class CollectionElementInitializer : Invocation
9314 public class ElementInitializerArgument : Argument
9316 public ElementInitializerArgument (Expression e)
9322 public CollectionElementInitializer (Expression argument)
9323 : base (null, new ArrayList (1), true)
9325 Arguments.Add (argument);
9326 this.loc = argument.Location;
9329 public CollectionElementInitializer (ArrayList arguments, Location loc)
9330 : base (null, arguments, true)
9335 public override Expression CreateExpressionTree (EmitContext ec)
9337 ArrayList args = new ArrayList (2);
9338 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9340 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9341 foreach (Argument a in Arguments)
9342 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9344 args.Add (new Argument (new ArrayCreation (
9345 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9346 return CreateExpressionFactoryCall ("ElementInit", args);
9349 protected override void CloneTo (CloneContext clonectx, Expression t)
9351 CollectionElementInitializer target = (CollectionElementInitializer) t;
9353 target.Arguments = new ArrayList (Arguments.Count);
9354 foreach (Expression e in Arguments)
9355 target.Arguments.Add (e.Clone (clonectx));
9358 public override Expression DoResolve (EmitContext ec)
9360 if (eclass != ExprClass.Invalid)
9363 // TODO: We could call a constructor which takes element count argument,
9364 // for known types like List<T>, Dictionary<T, U>
9366 for (int i = 0; i < Arguments.Count; ++i) {
9367 Expression expr = Arguments [i] as Expression;
9371 expr = expr.Resolve (ec);
9375 Arguments [i] = new ElementInitializerArgument (expr);
9378 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9380 return base.DoResolve (ec);
9385 // A block of object or collection initializers
9387 public class CollectionOrObjectInitializers : ExpressionStatement
9389 ArrayList initializers;
9391 public static readonly CollectionOrObjectInitializers Empty =
9392 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9394 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9396 this.initializers = initializers;
9400 public bool IsEmpty {
9402 return initializers.Count == 0;
9406 public bool IsCollectionInitializer {
9408 return type == typeof (CollectionOrObjectInitializers);
9412 protected override void CloneTo (CloneContext clonectx, Expression target)
9414 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9416 t.initializers = new ArrayList (initializers.Count);
9417 foreach (Expression e in initializers)
9418 t.initializers.Add (e.Clone (clonectx));
9421 public override Expression CreateExpressionTree (EmitContext ec)
9423 ArrayList expr_initializers = new ArrayList (initializers.Count);
9424 foreach (Expression e in initializers) {
9425 Expression expr = e.CreateExpressionTree (ec);
9427 expr_initializers.Add (expr);
9430 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9433 public override Expression DoResolve (EmitContext ec)
9435 if (eclass != ExprClass.Invalid)
9438 bool is_elements_initialization = false;
9439 ArrayList element_names = null;
9440 for (int i = 0; i < initializers.Count; ++i) {
9441 Expression initializer = (Expression) initializers [i];
9442 ElementInitializer element_initializer = initializer as ElementInitializer;
9445 if (element_initializer != null) {
9446 is_elements_initialization = true;
9447 element_names = new ArrayList (initializers.Count);
9448 element_names.Add (element_initializer.Name);
9450 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9451 TypeManager.ienumerable_type)) {
9452 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9453 "object initializer because type `{1}' does not implement `{2}' interface",
9454 ec.CurrentInitializerVariable.GetSignatureForError (),
9455 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9456 TypeManager.CSharpName (TypeManager.ienumerable_type));
9461 if (is_elements_initialization == (element_initializer == null)) {
9462 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9463 is_elements_initialization ? "object initializer" : "collection initializer");
9467 if (is_elements_initialization) {
9468 if (element_names.Contains (element_initializer.Name)) {
9469 Report.Error (1912, element_initializer.Location,
9470 "An object initializer includes more than one member `{0}' initialization",
9471 element_initializer.Name);
9473 element_names.Add (element_initializer.Name);
9478 Expression e = initializer.Resolve (ec);
9479 if (e == EmptyExpressionStatement.Instance)
9480 initializers.RemoveAt (i--);
9482 initializers [i] = e;
9485 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9486 eclass = ExprClass.Variable;
9490 public override void Emit (EmitContext ec)
9495 public override void EmitStatement (EmitContext ec)
9497 foreach (ExpressionStatement e in initializers)
9498 e.EmitStatement (ec);
9501 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9503 foreach (Expression e in initializers)
9504 e.MutateHoistedGenericType (storey);
9509 // New expression with element/object initializers
9511 public class NewInitialize : New
9514 // This class serves as a proxy for variable initializer target instances.
9515 // A real variable is assigned later when we resolve left side of an
9518 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9520 NewInitialize new_instance;
9522 public InitializerTargetExpression (NewInitialize newInstance)
9524 this.type = newInstance.type;
9525 this.loc = newInstance.loc;
9526 this.eclass = newInstance.eclass;
9527 this.new_instance = newInstance;
9530 public override Expression CreateExpressionTree (EmitContext ec)
9532 // Should not be reached
9533 throw new NotSupportedException ("ET");
9536 public override Expression DoResolve (EmitContext ec)
9541 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9546 public override void Emit (EmitContext ec)
9548 new_instance.value_target.Emit (ec);
9551 #region IMemoryLocation Members
9553 public void AddressOf (EmitContext ec, AddressOp mode)
9555 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9561 CollectionOrObjectInitializers initializers;
9563 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9564 : base (requested_type, arguments, l)
9566 this.initializers = initializers;
9569 protected override void CloneTo (CloneContext clonectx, Expression t)
9571 base.CloneTo (clonectx, t);
9573 NewInitialize target = (NewInitialize) t;
9574 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9577 public override Expression CreateExpressionTree (EmitContext ec)
9579 ArrayList args = new ArrayList (2);
9580 args.Add (new Argument (base.CreateExpressionTree (ec)));
9581 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9583 return CreateExpressionFactoryCall (
9584 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9588 public override Expression DoResolve (EmitContext ec)
9590 if (eclass != ExprClass.Invalid)
9593 Expression e = base.DoResolve (ec);
9597 // Empty initializer can be optimized to simple new
9598 if (initializers.IsEmpty)
9601 Expression previous = ec.CurrentInitializerVariable;
9602 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9603 initializers.Resolve (ec);
9604 ec.CurrentInitializerVariable = previous;
9608 public override void Emit (EmitContext ec)
9613 // If target is non-hoisted variable, let's use it
9615 VariableReference variable = value_target as VariableReference;
9616 if (variable != null && variable.HoistedVariable == null) {
9618 StoreFromPtr (ec.ig, type);
9620 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9623 if (value_target == null || value_target_set)
9624 value_target = new LocalTemporary (type);
9626 ((LocalTemporary) value_target).Store (ec);
9629 initializers.Emit (ec);
9631 if (variable == null) {
9632 value_target.Emit (ec);
9633 value_target = null;
9637 public override void EmitStatement (EmitContext ec)
9639 if (initializers.IsEmpty) {
9640 base.EmitStatement (ec);
9646 if (value_target == null) {
9647 LocalTemporary variable = new LocalTemporary (type);
9648 variable.Store (ec);
9649 value_target = variable;
9652 initializers.EmitStatement (ec);
9655 public override bool HasInitializer {
9657 return !initializers.IsEmpty;
9661 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9663 base.MutateHoistedGenericType (storey);
9664 initializers.MutateHoistedGenericType (storey);
9668 public class AnonymousTypeDeclaration : Expression
9670 ArrayList parameters;
9671 readonly TypeContainer parent;
9672 static readonly ArrayList EmptyParameters = new ArrayList (0);
9674 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9676 this.parameters = parameters;
9677 this.parent = parent;
9681 protected override void CloneTo (CloneContext clonectx, Expression target)
9683 if (parameters == null)
9686 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9687 t.parameters = new ArrayList (parameters.Count);
9688 foreach (AnonymousTypeParameter atp in parameters)
9689 t.parameters.Add (atp.Clone (clonectx));
9692 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9694 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9698 type = AnonymousTypeClass.Create (parent, parameters, loc);
9703 type.DefineMembers ();
9708 RootContext.ToplevelTypes.AddAnonymousType (type);
9712 public override Expression CreateExpressionTree (EmitContext ec)
9714 throw new NotSupportedException ("ET");
9717 public override Expression DoResolve (EmitContext ec)
9719 AnonymousTypeClass anonymous_type;
9721 if (parameters == null) {
9722 anonymous_type = CreateAnonymousType (EmptyParameters);
9723 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9724 null, loc).Resolve (ec);
9728 ArrayList arguments = new ArrayList (parameters.Count);
9729 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9730 for (int i = 0; i < parameters.Count; ++i) {
9731 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9737 arguments.Add (new Argument (e));
9738 t_args [i] = new TypeExpression (e.Type, e.Location);
9744 anonymous_type = CreateAnonymousType (parameters);
9745 if (anonymous_type == null)
9748 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9749 new TypeArguments (loc, t_args), loc);
9751 return new New (te, arguments, loc).Resolve (ec);
9754 public override void Emit (EmitContext ec)
9756 throw new InternalErrorException ("Should not be reached");
9760 public class AnonymousTypeParameter : Expression
9762 public readonly string Name;
9763 Expression initializer;
9765 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9769 this.initializer = initializer;
9772 public AnonymousTypeParameter (Parameter parameter)
9774 this.Name = parameter.Name;
9775 this.loc = parameter.Location;
9776 this.initializer = new SimpleName (Name, loc);
9779 protected override void CloneTo (CloneContext clonectx, Expression target)
9781 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9782 t.initializer = initializer.Clone (clonectx);
9785 public override Expression CreateExpressionTree (EmitContext ec)
9787 throw new NotSupportedException ("ET");
9790 public override bool Equals (object o)
9792 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9793 return other != null && Name == other.Name;
9796 public override int GetHashCode ()
9798 return Name.GetHashCode ();
9801 public override Expression DoResolve (EmitContext ec)
9803 Expression e = initializer.Resolve (ec);
9807 if (e.eclass == ExprClass.MethodGroup) {
9808 Error_InvalidInitializer (e.ExprClassName);
9813 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9814 type == TypeManager.anonymous_method_type || type.IsPointer) {
9815 Error_InvalidInitializer (e.GetSignatureForError ());
9822 protected virtual void Error_InvalidInitializer (string initializer)
9824 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9828 public override void Emit (EmitContext ec)
9830 throw new InternalErrorException ("Should not be reached");