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 SideEffectConstant) {
151 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
152 return r == null ? null : new SideEffectConstant (r, e, r.Location);
155 Type expr_type = e.Type;
158 case Operator.UnaryPlus:
159 // Unary numeric promotions
160 if (expr_type == TypeManager.byte_type)
161 return new IntConstant (((ByteConstant)e).Value, e.Location);
162 if (expr_type == TypeManager.sbyte_type)
163 return new IntConstant (((SByteConstant)e).Value, e.Location);
164 if (expr_type == TypeManager.short_type)
165 return new IntConstant (((ShortConstant)e).Value, e.Location);
166 if (expr_type == TypeManager.ushort_type)
167 return new IntConstant (((UShortConstant)e).Value, e.Location);
168 if (expr_type == TypeManager.char_type)
169 return new IntConstant (((CharConstant)e).Value, e.Location);
171 // Predefined operators
172 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
173 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
174 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
175 expr_type == TypeManager.decimal_type)
182 case Operator.UnaryNegation:
183 // Unary numeric promotions
184 if (expr_type == TypeManager.byte_type)
185 return new IntConstant (-((ByteConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.sbyte_type)
187 return new IntConstant (-((SByteConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.short_type)
189 return new IntConstant (-((ShortConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.ushort_type)
191 return new IntConstant (-((UShortConstant)e).Value, e.Location);
192 if (expr_type == TypeManager.char_type)
193 return new IntConstant (-((CharConstant)e).Value, e.Location);
195 // Predefined operators
196 if (expr_type == TypeManager.int32_type) {
197 int value = ((IntConstant)e).Value;
198 if (value == int.MinValue) {
199 if (ec.ConstantCheckState) {
200 ConstantFold.Error_CompileTimeOverflow (loc);
205 return new IntConstant (-value, e.Location);
207 if (expr_type == TypeManager.int64_type) {
208 long value = ((LongConstant)e).Value;
209 if (value == long.MinValue) {
210 if (ec.ConstantCheckState) {
211 ConstantFold.Error_CompileTimeOverflow (loc);
216 return new LongConstant (-value, e.Location);
219 if (expr_type == TypeManager.uint32_type) {
220 UIntLiteral uil = e as UIntLiteral;
222 if (uil.Value == 2147483648)
223 return new IntLiteral (int.MinValue, e.Location);
224 return new LongLiteral (-uil.Value, e.Location);
226 return new LongConstant (-((UIntConstant)e).Value, e.Location);
229 if (expr_type == TypeManager.uint64_type) {
230 ULongLiteral ull = e as ULongLiteral;
231 if (ull != null && ull.Value == 9223372036854775808)
232 return new LongLiteral (long.MinValue, e.Location);
236 if (expr_type == TypeManager.float_type) {
237 FloatLiteral fl = e as FloatLiteral;
238 // For better error reporting
240 fl.Value = -fl.Value;
243 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.double_type) {
246 DoubleLiteral dl = e as DoubleLiteral;
247 // For better error reporting
249 dl.Value = -dl.Value;
253 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
255 if (expr_type == TypeManager.decimal_type)
256 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
260 case Operator.LogicalNot:
261 if (expr_type != TypeManager.bool_type)
264 bool b = (bool)e.GetValue ();
265 return new BoolConstant (!b, e.Location);
267 case Operator.OnesComplement:
268 // Unary numeric promotions
269 if (expr_type == TypeManager.byte_type)
270 return new IntConstant (~((ByteConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.sbyte_type)
272 return new IntConstant (~((SByteConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.short_type)
274 return new IntConstant (~((ShortConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.ushort_type)
276 return new IntConstant (~((UShortConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.char_type)
278 return new IntConstant (~((CharConstant)e).Value, e.Location);
280 // Predefined operators
281 if (expr_type == TypeManager.int32_type)
282 return new IntConstant (~((IntConstant)e).Value, e.Location);
283 if (expr_type == TypeManager.uint32_type)
284 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
285 if (expr_type == TypeManager.int64_type)
286 return new LongConstant (~((LongConstant)e).Value, e.Location);
287 if (expr_type == TypeManager.uint64_type){
288 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
290 if (e is EnumConstant) {
291 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
293 e = new EnumConstant (e, expr_type);
298 throw new Exception ("Can not constant fold: " + Oper.ToString());
301 protected Expression ResolveOperator (EmitContext ec, Expression expr)
303 eclass = ExprClass.Value;
305 if (predefined_operators == null)
306 CreatePredefinedOperatorsTable ();
308 Type expr_type = expr.Type;
309 Expression best_expr;
312 // Primitive types first
314 if (TypeManager.IsPrimitiveType (expr_type)) {
315 best_expr = ResolvePrimitivePredefinedType (expr);
316 if (best_expr == null)
319 type = best_expr.Type;
325 // E operator ~(E x);
327 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
328 return ResolveEnumOperator (ec, expr);
330 return ResolveUserType (ec, expr);
333 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
335 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
336 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
337 if (best_expr == null)
341 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
343 return EmptyCast.Create (this, type);
346 public override Expression CreateExpressionTree (EmitContext ec)
348 return CreateExpressionTree (ec, null);
351 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
355 case Operator.AddressOf:
356 Error_PointerInsideExpressionTree ();
358 case Operator.UnaryNegation:
359 if (ec.CheckState && user_op == null && !IsFloat (type))
360 method_name = "NegateChecked";
362 method_name = "Negate";
364 case Operator.OnesComplement:
365 case Operator.LogicalNot:
368 case Operator.UnaryPlus:
369 method_name = "UnaryPlus";
372 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375 ArrayList args = new ArrayList (2);
376 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
378 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
379 return CreateExpressionFactoryCall (method_name, args);
382 static void CreatePredefinedOperatorsTable ()
384 predefined_operators = new Type [(int) Operator.TOP] [];
387 // 7.6.1 Unary plus operator
389 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
390 TypeManager.int32_type, TypeManager.uint32_type,
391 TypeManager.int64_type, TypeManager.uint64_type,
392 TypeManager.float_type, TypeManager.double_type,
393 TypeManager.decimal_type
397 // 7.6.2 Unary minus operator
399 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
400 TypeManager.int32_type,
401 TypeManager.int64_type,
402 TypeManager.float_type, TypeManager.double_type,
403 TypeManager.decimal_type
407 // 7.6.3 Logical negation operator
409 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
410 TypeManager.bool_type
414 // 7.6.4 Bitwise complement operator
416 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
417 TypeManager.int32_type, TypeManager.uint32_type,
418 TypeManager.int64_type, TypeManager.uint64_type
423 // Unary numeric promotions
425 static Expression DoNumericPromotion (Operator op, Expression expr)
427 Type expr_type = expr.Type;
428 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
429 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
430 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
431 expr_type == TypeManager.char_type)
432 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
434 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
435 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
440 public override Expression DoResolve (EmitContext ec)
442 if (Oper == Operator.AddressOf) {
443 return ResolveAddressOf (ec);
446 Expr = Expr.Resolve (ec);
450 if (TypeManager.IsNullableValueType (Expr.Type))
451 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
454 // Attempt to use a constant folding operation.
456 Constant cexpr = Expr as Constant;
458 cexpr = TryReduceConstant (ec, cexpr);
463 Expression expr = ResolveOperator (ec, Expr);
465 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
468 // Reduce unary operator on predefined types
470 if (expr == this && Oper == Operator.UnaryPlus)
476 public override Expression DoResolveLValue (EmitContext ec, Expression right)
481 public override void Emit (EmitContext ec)
483 EmitOperator (ec, type);
486 protected void EmitOperator (EmitContext ec, Type type)
488 ILGenerator ig = ec.ig;
491 case Operator.UnaryPlus:
495 case Operator.UnaryNegation:
496 if (ec.CheckState && !IsFloat (type)) {
497 ig.Emit (OpCodes.Ldc_I4_0);
498 if (type == TypeManager.int64_type)
499 ig.Emit (OpCodes.Conv_U8);
501 ig.Emit (OpCodes.Sub_Ovf);
504 ig.Emit (OpCodes.Neg);
509 case Operator.LogicalNot:
511 ig.Emit (OpCodes.Ldc_I4_0);
512 ig.Emit (OpCodes.Ceq);
515 case Operator.OnesComplement:
517 ig.Emit (OpCodes.Not);
520 case Operator.AddressOf:
521 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
525 throw new Exception ("This should not happen: Operator = "
530 // Same trick as in Binary expression
532 if (enum_conversion != null)
533 enum_conversion.Emit (ec);
536 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
538 if (Oper == Operator.LogicalNot)
539 Expr.EmitBranchable (ec, target, !on_true);
541 base.EmitBranchable (ec, target, on_true);
544 public override void EmitSideEffect (EmitContext ec)
546 Expr.EmitSideEffect (ec);
549 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
551 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
552 oper, TypeManager.CSharpName (t));
555 static bool IsFloat (Type t)
557 return t == TypeManager.float_type || t == TypeManager.double_type;
561 // Returns a stringified representation of the Operator
563 public static string OperName (Operator oper)
566 case Operator.UnaryPlus:
568 case Operator.UnaryNegation:
570 case Operator.LogicalNot:
572 case Operator.OnesComplement:
574 case Operator.AddressOf:
578 throw new NotImplementedException (oper.ToString ());
581 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
583 type = storey.MutateType (type);
584 Expr.MutateHoistedGenericType (storey);
587 Expression ResolveAddressOf (EmitContext ec)
592 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
593 if (Expr == null || Expr.eclass != ExprClass.Variable) {
594 Error (211, "Cannot take the address of the given expression");
598 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
602 IVariableReference vr = Expr as IVariableReference;
605 VariableInfo vi = vr.VariableInfo;
607 if (vi.LocalInfo != null)
608 vi.LocalInfo.Used = true;
611 // A variable is considered definitely assigned if you take its address.
616 is_fixed = vr.IsFixedVariable;
617 vr.SetHasAddressTaken ();
620 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
624 // A pointer-indirection is always fixed
626 is_fixed = Expr is Indirection;
629 if (!is_fixed && !ec.InFixedInitializer) {
630 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
633 type = TypeManager.GetPointerType (Expr.Type);
634 eclass = ExprClass.Value;
638 Expression ResolvePrimitivePredefinedType (Expression expr)
640 expr = DoNumericPromotion (Oper, expr);
641 Type expr_type = expr.Type;
642 Type[] predefined = predefined_operators [(int) Oper];
643 foreach (Type t in predefined) {
651 // Perform user-operator overload resolution
653 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
655 CSharp.Operator.OpType op_type;
657 case Operator.LogicalNot:
658 op_type = CSharp.Operator.OpType.LogicalNot; break;
659 case Operator.OnesComplement:
660 op_type = CSharp.Operator.OpType.OnesComplement; break;
661 case Operator.UnaryNegation:
662 op_type = CSharp.Operator.OpType.UnaryNegation; break;
663 case Operator.UnaryPlus:
664 op_type = CSharp.Operator.OpType.UnaryPlus; break;
666 throw new InternalErrorException (Oper.ToString ());
669 string op_name = CSharp.Operator.GetMetadataName (op_type);
670 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
674 ArrayList args = new ArrayList (1);
675 args.Add (new Argument (expr));
676 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
681 Expr = ((Argument) args [0]).Expr;
682 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
686 // Unary user type overload resolution
688 Expression ResolveUserType (EmitContext ec, Expression expr)
690 Expression best_expr = ResolveUserOperator (ec, expr);
691 if (best_expr != null)
694 Type[] predefined = predefined_operators [(int) Oper];
695 foreach (Type t in predefined) {
696 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
697 if (oper_expr == null)
701 // decimal type is predefined but has user-operators
703 if (oper_expr.Type == TypeManager.decimal_type)
704 oper_expr = ResolveUserType (ec, oper_expr);
706 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
708 if (oper_expr == null)
711 if (best_expr == null) {
712 best_expr = oper_expr;
716 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
718 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
719 OperName (Oper), TypeManager.CSharpName (expr.Type));
724 best_expr = oper_expr;
727 if (best_expr == null)
731 // HACK: Decimal user-operator is included in standard operators
733 if (best_expr.Type == TypeManager.decimal_type)
737 type = best_expr.Type;
741 protected override void CloneTo (CloneContext clonectx, Expression t)
743 Unary target = (Unary) t;
745 target.Expr = Expr.Clone (clonectx);
750 // Unary operators are turned into Indirection expressions
751 // after semantic analysis (this is so we can take the address
752 // of an indirection).
754 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
756 LocalTemporary temporary;
759 public Indirection (Expression expr, Location l)
765 public override Expression CreateExpressionTree (EmitContext ec)
767 Error_PointerInsideExpressionTree ();
771 protected override void CloneTo (CloneContext clonectx, Expression t)
773 Indirection target = (Indirection) t;
774 target.expr = expr.Clone (clonectx);
777 public override void Emit (EmitContext ec)
782 LoadFromPtr (ec.ig, Type);
785 public void Emit (EmitContext ec, bool leave_copy)
789 ec.ig.Emit (OpCodes.Dup);
790 temporary = new LocalTemporary (expr.Type);
791 temporary.Store (ec);
795 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
797 prepared = prepare_for_load;
801 if (prepare_for_load)
802 ec.ig.Emit (OpCodes.Dup);
806 ec.ig.Emit (OpCodes.Dup);
807 temporary = new LocalTemporary (expr.Type);
808 temporary.Store (ec);
811 StoreFromPtr (ec.ig, type);
813 if (temporary != null) {
815 temporary.Release (ec);
819 public void AddressOf (EmitContext ec, AddressOp Mode)
824 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
826 return DoResolve (ec);
829 public override Expression DoResolve (EmitContext ec)
831 expr = expr.Resolve (ec);
838 if (!expr.Type.IsPointer) {
839 Error (193, "The * or -> operator must be applied to a pointer");
843 if (expr.Type == TypeManager.void_ptr_type) {
844 Error (242, "The operation in question is undefined on void pointers");
848 type = TypeManager.GetElementType (expr.Type);
849 eclass = ExprClass.Variable;
853 public override string ToString ()
855 return "*(" + expr + ")";
860 /// Unary Mutator expressions (pre and post ++ and --)
864 /// UnaryMutator implements ++ and -- expressions. It derives from
865 /// ExpressionStatement becuase the pre/post increment/decrement
866 /// operators can be used in a statement context.
868 /// FIXME: Idea, we could split this up in two classes, one simpler
869 /// for the common case, and one with the extra fields for more complex
870 /// classes (indexers require temporary access; overloaded require method)
873 public class UnaryMutator : ExpressionStatement {
875 public enum Mode : byte {
882 PreDecrement = IsDecrement,
883 PostIncrement = IsPost,
884 PostDecrement = IsPost | IsDecrement
888 bool is_expr = false;
889 bool recurse = false;
894 // This is expensive for the simplest case.
896 UserOperatorCall method;
898 public UnaryMutator (Mode m, Expression e, Location l)
905 static string OperName (Mode mode)
907 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
912 /// Returns whether an object of type `t' can be incremented
913 /// or decremented with add/sub (ie, basically whether we can
914 /// use pre-post incr-decr operations on it, but it is not a
915 /// System.Decimal, which we require operator overloading to catch)
917 static bool IsIncrementableNumber (Type t)
919 return (t == TypeManager.sbyte_type) ||
920 (t == TypeManager.byte_type) ||
921 (t == TypeManager.short_type) ||
922 (t == TypeManager.ushort_type) ||
923 (t == TypeManager.int32_type) ||
924 (t == TypeManager.uint32_type) ||
925 (t == TypeManager.int64_type) ||
926 (t == TypeManager.uint64_type) ||
927 (t == TypeManager.char_type) ||
928 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
929 (t == TypeManager.float_type) ||
930 (t == TypeManager.double_type) ||
931 (t.IsPointer && t != TypeManager.void_ptr_type);
934 Expression ResolveOperator (EmitContext ec)
939 // Step 1: Perform Operator Overload location
944 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
945 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
947 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
949 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
952 ArrayList args = new ArrayList (1);
953 args.Add (new Argument (expr, Argument.AType.Expression));
954 mg = mg.OverloadResolve (ec, ref args, false, loc);
958 method = new UserOperatorCall (mg, args, null, loc);
959 Convert.ImplicitConversionRequired (ec, method, type, loc);
963 if (!IsIncrementableNumber (type)) {
964 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
965 TypeManager.CSharpName (type) + "'");
970 // The operand of the prefix/postfix increment decrement operators
971 // should be an expression that is classified as a variable,
972 // a property access or an indexer access
974 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
975 expr = expr.ResolveLValue (ec, expr, Location);
977 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
983 public override Expression CreateExpressionTree (EmitContext ec)
985 return new SimpleAssign (this, this).CreateExpressionTree (ec);
988 public override Expression DoResolve (EmitContext ec)
990 expr = expr.Resolve (ec);
995 eclass = ExprClass.Value;
998 if (TypeManager.IsNullableValueType (expr.Type))
999 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1002 return ResolveOperator (ec);
1006 // Loads the proper "1" into the stack based on the type, then it emits the
1007 // opcode for the operation requested
1009 void LoadOneAndEmitOp (EmitContext ec, Type t)
1012 // Measure if getting the typecode and using that is more/less efficient
1013 // that comparing types. t.GetTypeCode() is an internal call.
1015 ILGenerator ig = ec.ig;
1017 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1018 LongConstant.EmitLong (ig, 1);
1019 else if (t == TypeManager.double_type)
1020 ig.Emit (OpCodes.Ldc_R8, 1.0);
1021 else if (t == TypeManager.float_type)
1022 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1023 else if (t.IsPointer){
1024 Type et = TypeManager.GetElementType (t);
1025 int n = GetTypeSize (et);
1028 ig.Emit (OpCodes.Sizeof, et);
1030 IntConstant.EmitInt (ig, n);
1031 ig.Emit (OpCodes.Conv_I);
1034 ig.Emit (OpCodes.Ldc_I4_1);
1037 // Now emit the operation
1040 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1041 Binary.EmitOperatorOpcode (ec, op, t);
1043 if (t == TypeManager.sbyte_type){
1045 ig.Emit (OpCodes.Conv_Ovf_I1);
1047 ig.Emit (OpCodes.Conv_I1);
1048 } else if (t == TypeManager.byte_type){
1050 ig.Emit (OpCodes.Conv_Ovf_U1);
1052 ig.Emit (OpCodes.Conv_U1);
1053 } else if (t == TypeManager.short_type){
1055 ig.Emit (OpCodes.Conv_Ovf_I2);
1057 ig.Emit (OpCodes.Conv_I2);
1058 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1060 ig.Emit (OpCodes.Conv_Ovf_U2);
1062 ig.Emit (OpCodes.Conv_U2);
1067 void EmitCode (EmitContext ec, bool is_expr)
1070 this.is_expr = is_expr;
1071 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1074 public override void Emit (EmitContext ec)
1077 // We use recurse to allow ourselfs to be the source
1078 // of an assignment. This little hack prevents us from
1079 // having to allocate another expression
1082 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1084 LoadOneAndEmitOp (ec, expr.Type);
1086 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1091 EmitCode (ec, true);
1094 public override void EmitStatement (EmitContext ec)
1096 EmitCode (ec, false);
1099 protected override void CloneTo (CloneContext clonectx, Expression t)
1101 UnaryMutator target = (UnaryMutator) t;
1103 target.expr = expr.Clone (clonectx);
1108 /// Base class for the `Is' and `As' classes.
1112 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1115 public abstract class Probe : Expression {
1116 public Expression ProbeType;
1117 protected Expression expr;
1118 protected TypeExpr probe_type_expr;
1120 public Probe (Expression expr, Expression probe_type, Location l)
1122 ProbeType = probe_type;
1127 public Expression Expr {
1133 public override Expression DoResolve (EmitContext ec)
1135 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1136 if (probe_type_expr == null)
1139 expr = expr.Resolve (ec);
1143 if (probe_type_expr.Type == TypeManager.void_type) {
1144 // TODO: Void is missing location (ProbeType.Location)
1145 Error_VoidInvalidInTheContext (Location);
1149 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1150 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1154 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1155 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1160 if (expr.Type == TypeManager.anonymous_method_type) {
1161 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1169 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1171 expr.MutateHoistedGenericType (storey);
1172 probe_type_expr.MutateHoistedGenericType (storey);
1175 protected abstract string OperatorName { get; }
1177 protected override void CloneTo (CloneContext clonectx, Expression t)
1179 Probe target = (Probe) t;
1181 target.expr = expr.Clone (clonectx);
1182 target.ProbeType = ProbeType.Clone (clonectx);
1188 /// Implementation of the `is' operator.
1190 public class Is : Probe {
1191 Nullable.Unwrap expr_unwrap;
1193 public Is (Expression expr, Expression probe_type, Location l)
1194 : base (expr, probe_type, l)
1198 public override Expression CreateExpressionTree (EmitContext ec)
1200 ArrayList args = new ArrayList (2);
1201 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1202 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1203 return CreateExpressionFactoryCall ("TypeIs", args);
1206 public override void Emit (EmitContext ec)
1208 ILGenerator ig = ec.ig;
1209 if (expr_unwrap != null) {
1210 expr_unwrap.EmitCheck (ec);
1215 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1216 ig.Emit (OpCodes.Ldnull);
1217 ig.Emit (OpCodes.Cgt_Un);
1220 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1222 ILGenerator ig = ec.ig;
1223 if (expr_unwrap != null) {
1224 expr_unwrap.EmitCheck (ec);
1227 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1229 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1232 Expression CreateConstantResult (bool result)
1235 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1236 TypeManager.CSharpName (probe_type_expr.Type));
1238 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1244 public override Expression DoResolve (EmitContext ec)
1246 if (base.DoResolve (ec) == null)
1250 bool d_is_nullable = false;
1253 // If E is a method group or the null literal, or if the type of E is a reference
1254 // type or a nullable type and the value of E is null, the result is false
1256 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1257 return CreateConstantResult (false);
1259 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1260 d = TypeManager.GetTypeArguments (d) [0];
1261 d_is_nullable = true;
1264 type = TypeManager.bool_type;
1265 eclass = ExprClass.Value;
1266 Type t = probe_type_expr.Type;
1267 bool t_is_nullable = false;
1268 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1269 t = TypeManager.GetTypeArguments (t) [0];
1270 t_is_nullable = true;
1273 if (t.IsValueType) {
1276 // D and T are the same value types but D can be null
1278 if (d_is_nullable && !t_is_nullable) {
1279 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1284 // The result is true if D and T are the same value types
1286 return CreateConstantResult (true);
1289 if (TypeManager.IsGenericParameter (d))
1290 return ResolveGenericParameter (t, d);
1293 // An unboxing conversion exists
1295 if (Convert.ExplicitReferenceConversionExists (d, t))
1298 if (TypeManager.IsGenericParameter (t))
1299 return ResolveGenericParameter (d, t);
1301 if (d.IsValueType) {
1303 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1304 return CreateConstantResult (true);
1306 if (TypeManager.IsGenericParameter (d))
1307 return ResolveGenericParameter (t, d);
1309 if (TypeManager.ContainsGenericParameters (d))
1312 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1313 Convert.ExplicitReferenceConversionExists (d, t)) {
1319 return CreateConstantResult (false);
1322 Expression ResolveGenericParameter (Type d, Type t)
1325 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1326 if (constraints != null) {
1327 if (constraints.IsReferenceType && d.IsValueType)
1328 return CreateConstantResult (false);
1330 if (constraints.IsValueType && !d.IsValueType)
1331 return CreateConstantResult (TypeManager.IsEqual (d, t));
1334 if (!TypeManager.IsReferenceType (expr.Type))
1335 expr = new BoxedCast (expr, d);
1343 protected override string OperatorName {
1344 get { return "is"; }
1349 /// Implementation of the `as' operator.
1351 public class As : Probe {
1353 Expression resolved_type;
1355 public As (Expression expr, Expression probe_type, Location l)
1356 : base (expr, probe_type, l)
1360 public override Expression CreateExpressionTree (EmitContext ec)
1362 ArrayList args = new ArrayList (2);
1363 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1364 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1365 return CreateExpressionFactoryCall ("TypeAs", args);
1368 public override void Emit (EmitContext ec)
1370 ILGenerator ig = ec.ig;
1375 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1378 if (TypeManager.IsNullableType (type))
1379 ig.Emit (OpCodes.Unbox_Any, type);
1383 public override Expression DoResolve (EmitContext ec)
1385 if (resolved_type == null) {
1386 resolved_type = base.DoResolve (ec);
1388 if (resolved_type == null)
1392 type = probe_type_expr.Type;
1393 eclass = ExprClass.Value;
1394 Type etype = expr.Type;
1396 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1397 if (probe_type_expr is TypeParameterExpr) {
1398 Report.Error (413, loc,
1399 "The `as' operator cannot be used with a non-reference type parameter `{0}'",
1400 probe_type_expr.GetSignatureForError ());
1402 Report.Error (77, loc,
1403 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1404 TypeManager.CSharpName (type));
1409 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1410 return Nullable.LiftedNull.CreateFromExpression (this);
1413 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1420 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1421 if (TypeManager.IsGenericParameter (etype))
1422 expr = new BoxedCast (expr, etype);
1428 if (TypeManager.ContainsGenericParameters (etype) ||
1429 TypeManager.ContainsGenericParameters (type)) {
1430 expr = new BoxedCast (expr, etype);
1435 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1436 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1441 protected override string OperatorName {
1442 get { return "as"; }
1445 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1447 return expr.GetAttributableValue (ec, value_type, out value);
1452 /// This represents a typecast in the source language.
1454 /// FIXME: Cast expressions have an unusual set of parsing
1455 /// rules, we need to figure those out.
1457 public class Cast : Expression {
1458 Expression target_type;
1461 public Cast (Expression cast_type, Expression expr)
1462 : this (cast_type, expr, cast_type.Location)
1466 public Cast (Expression cast_type, Expression expr, Location loc)
1468 this.target_type = cast_type;
1472 if (target_type == TypeManager.system_void_expr)
1473 Error_VoidInvalidInTheContext (loc);
1476 public Expression TargetType {
1477 get { return target_type; }
1480 public Expression Expr {
1481 get { return expr; }
1484 public override Expression CreateExpressionTree (EmitContext ec)
1486 throw new NotSupportedException ("ET");
1489 public override Expression DoResolve (EmitContext ec)
1491 expr = expr.Resolve (ec);
1495 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1501 if (type.IsAbstract && type.IsSealed) {
1502 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1506 eclass = ExprClass.Value;
1508 Constant c = expr as Constant;
1510 c = c.TryReduce (ec, type, loc);
1515 if (type.IsPointer && !ec.InUnsafe) {
1519 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1523 public override void Emit (EmitContext ec)
1525 throw new Exception ("Should not happen");
1528 protected override void CloneTo (CloneContext clonectx, Expression t)
1530 Cast target = (Cast) t;
1532 target.target_type = target_type.Clone (clonectx);
1533 target.expr = expr.Clone (clonectx);
1538 // C# 2.0 Default value expression
1540 public class DefaultValueExpression : Expression
1544 public DefaultValueExpression (Expression expr, Location loc)
1550 public override Expression CreateExpressionTree (EmitContext ec)
1552 ArrayList args = new ArrayList (2);
1553 args.Add (new Argument (this));
1554 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1555 return CreateExpressionFactoryCall ("Constant", args);
1558 public override Expression DoResolve (EmitContext ec)
1560 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1566 if (type == TypeManager.void_type) {
1567 Error_VoidInvalidInTheContext (loc);
1571 if (TypeManager.IsReferenceType (type)) {
1572 return new EmptyConstantCast (new NullLiteral (Location), type);
1575 // return ReducedExpression.Create (new NullLiteral (Location), this);
1578 Constant c = New.Constantify (type);
1582 eclass = ExprClass.Variable;
1586 public override void Emit (EmitContext ec)
1588 LocalTemporary temp_storage = new LocalTemporary(type);
1590 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1591 ec.ig.Emit(OpCodes.Initobj, type);
1592 temp_storage.Emit(ec);
1595 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1597 type = storey.MutateType (type);
1600 protected override void CloneTo (CloneContext clonectx, Expression t)
1602 DefaultValueExpression target = (DefaultValueExpression) t;
1604 target.expr = expr.Clone (clonectx);
1609 /// Binary operators
1611 public class Binary : Expression {
1613 protected class PredefinedOperator {
1614 protected readonly Type left;
1615 protected readonly Type right;
1616 public readonly Operator OperatorsMask;
1617 public Type ReturnType;
1619 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1620 : this (ltype, rtype, op_mask, ltype)
1624 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1625 : this (type, type, op_mask, return_type)
1629 public PredefinedOperator (Type type, Operator op_mask)
1630 : this (type, type, op_mask, type)
1634 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1636 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1637 throw new InternalErrorException ("Only masked values can be used");
1641 this.OperatorsMask = op_mask;
1642 this.ReturnType = return_type;
1645 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1647 b.type = ReturnType;
1649 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1650 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1653 // A user operators does not support multiple user conversions, but decimal type
1654 // is considered to be predefined type therefore we apply predefined operators rules
1655 // and then look for decimal user-operator implementation
1657 if (left == TypeManager.decimal_type)
1658 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1663 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1666 // We are dealing with primitive types only
1668 return left == ltype && ltype == rtype;
1671 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1673 if (TypeManager.IsEqual (left, lexpr.Type) &&
1674 TypeManager.IsEqual (right, rexpr.Type))
1677 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1678 Convert.ImplicitConversionExists (ec, rexpr, right);
1681 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1684 if (left != null && best_operator.left != null) {
1685 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1689 // When second arguments are same as the first one, the result is same
1691 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1692 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1695 if (result == 0 || result > 2)
1698 return result == 1 ? best_operator : this;
1702 class PredefinedStringOperator : PredefinedOperator {
1703 public PredefinedStringOperator (Type type, Operator op_mask)
1704 : base (type, op_mask, type)
1706 ReturnType = TypeManager.string_type;
1709 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1710 : base (ltype, rtype, op_mask)
1712 ReturnType = TypeManager.string_type;
1715 public override Expression ConvertResult (EmitContext ec, Binary b)
1718 // Use original expression for nullable arguments
1720 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1722 b.left = unwrap.Original;
1724 unwrap = b.right as Nullable.Unwrap;
1726 b.right = unwrap.Original;
1728 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1729 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1732 // Start a new concat expression using converted expression
1734 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1738 class PredefinedShiftOperator : PredefinedOperator {
1739 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1740 base (ltype, TypeManager.int32_type, op_mask)
1744 public override Expression ConvertResult (EmitContext ec, Binary b)
1746 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1748 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1750 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1753 // b = b.left >> b.right & (0x1f|0x3f)
1755 b.right = new Binary (Operator.BitwiseAnd,
1756 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1759 // Expression tree representation does not use & mask
1761 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1762 b.type = ReturnType;
1767 class PredefinedPointerOperator : PredefinedOperator {
1768 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1769 : base (ltype, rtype, op_mask)
1773 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1774 : base (ltype, rtype, op_mask, retType)
1778 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1779 : base (type, op_mask, return_type)
1783 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1786 if (!lexpr.Type.IsPointer)
1789 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1793 if (right == null) {
1794 if (!rexpr.Type.IsPointer)
1797 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1804 public override Expression ConvertResult (EmitContext ec, Binary b)
1807 b.left = EmptyCast.Create (b.left, left);
1808 } else if (right != null) {
1809 b.right = EmptyCast.Create (b.right, right);
1812 Type r_type = ReturnType;
1813 if (r_type == null) {
1815 r_type = b.left.Type;
1817 r_type = b.right.Type;
1820 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1825 public enum Operator {
1826 Multiply = 0 | ArithmeticMask,
1827 Division = 1 | ArithmeticMask,
1828 Modulus = 2 | ArithmeticMask,
1829 Addition = 3 | ArithmeticMask | AdditionMask,
1830 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1832 LeftShift = 5 | ShiftMask,
1833 RightShift = 6 | ShiftMask,
1835 LessThan = 7 | ComparisonMask | RelationalMask,
1836 GreaterThan = 8 | ComparisonMask | RelationalMask,
1837 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1838 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1839 Equality = 11 | ComparisonMask | EqualityMask,
1840 Inequality = 12 | ComparisonMask | EqualityMask,
1842 BitwiseAnd = 13 | BitwiseMask,
1843 ExclusiveOr = 14 | BitwiseMask,
1844 BitwiseOr = 15 | BitwiseMask,
1846 LogicalAnd = 16 | LogicalMask,
1847 LogicalOr = 17 | LogicalMask,
1852 ValuesOnlyMask = ArithmeticMask - 1,
1853 ArithmeticMask = 1 << 5,
1855 ComparisonMask = 1 << 7,
1856 EqualityMask = 1 << 8,
1857 BitwiseMask = 1 << 9,
1858 LogicalMask = 1 << 10,
1859 AdditionMask = 1 << 11,
1860 SubtractionMask = 1 << 12,
1861 RelationalMask = 1 << 13
1864 readonly Operator oper;
1865 protected Expression left, right;
1866 readonly bool is_compound;
1867 Expression enum_conversion;
1869 static PredefinedOperator [] standard_operators;
1870 static PredefinedOperator [] pointer_operators;
1872 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1873 : this (oper, left, right)
1875 this.is_compound = isCompound;
1878 public Binary (Operator oper, Expression left, Expression right)
1883 this.loc = left.Location;
1886 public Operator Oper {
1893 /// Returns a stringified representation of the Operator
1895 string OperName (Operator oper)
1899 case Operator.Multiply:
1902 case Operator.Division:
1905 case Operator.Modulus:
1908 case Operator.Addition:
1911 case Operator.Subtraction:
1914 case Operator.LeftShift:
1917 case Operator.RightShift:
1920 case Operator.LessThan:
1923 case Operator.GreaterThan:
1926 case Operator.LessThanOrEqual:
1929 case Operator.GreaterThanOrEqual:
1932 case Operator.Equality:
1935 case Operator.Inequality:
1938 case Operator.BitwiseAnd:
1941 case Operator.BitwiseOr:
1944 case Operator.ExclusiveOr:
1947 case Operator.LogicalOr:
1950 case Operator.LogicalAnd:
1954 s = oper.ToString ();
1964 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1966 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1969 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1972 // TODO: This should be handled as Type of method group in CSharpName
1973 if (left.eclass == ExprClass.MethodGroup)
1974 l = left.ExprClassName;
1976 l = TypeManager.CSharpName (left.Type);
1978 if (right.eclass == ExprClass.MethodGroup)
1979 r = right.ExprClassName;
1981 r = TypeManager.CSharpName (right.Type);
1983 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1987 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1989 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
1992 static string GetOperatorMetadataName (Operator op)
1994 CSharp.Operator.OpType op_type;
1996 case Operator.Addition:
1997 op_type = CSharp.Operator.OpType.Addition; break;
1998 case Operator.BitwiseAnd:
1999 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2000 case Operator.BitwiseOr:
2001 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2002 case Operator.Division:
2003 op_type = CSharp.Operator.OpType.Division; break;
2004 case Operator.Equality:
2005 op_type = CSharp.Operator.OpType.Equality; break;
2006 case Operator.ExclusiveOr:
2007 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2008 case Operator.GreaterThan:
2009 op_type = CSharp.Operator.OpType.GreaterThan; break;
2010 case Operator.GreaterThanOrEqual:
2011 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2012 case Operator.Inequality:
2013 op_type = CSharp.Operator.OpType.Inequality; break;
2014 case Operator.LeftShift:
2015 op_type = CSharp.Operator.OpType.LeftShift; break;
2016 case Operator.LessThan:
2017 op_type = CSharp.Operator.OpType.LessThan; break;
2018 case Operator.LessThanOrEqual:
2019 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2020 case Operator.Modulus:
2021 op_type = CSharp.Operator.OpType.Modulus; break;
2022 case Operator.Multiply:
2023 op_type = CSharp.Operator.OpType.Multiply; break;
2024 case Operator.RightShift:
2025 op_type = CSharp.Operator.OpType.RightShift; break;
2026 case Operator.Subtraction:
2027 op_type = CSharp.Operator.OpType.Subtraction; break;
2029 throw new InternalErrorException (op.ToString ());
2032 return CSharp.Operator.GetMetadataName (op_type);
2035 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2038 ILGenerator ig = ec.ig;
2041 case Operator.Multiply:
2043 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2044 opcode = OpCodes.Mul_Ovf;
2045 else if (!IsFloat (l))
2046 opcode = OpCodes.Mul_Ovf_Un;
2048 opcode = OpCodes.Mul;
2050 opcode = OpCodes.Mul;
2054 case Operator.Division:
2056 opcode = OpCodes.Div_Un;
2058 opcode = OpCodes.Div;
2061 case Operator.Modulus:
2063 opcode = OpCodes.Rem_Un;
2065 opcode = OpCodes.Rem;
2068 case Operator.Addition:
2070 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2071 opcode = OpCodes.Add_Ovf;
2072 else if (!IsFloat (l))
2073 opcode = OpCodes.Add_Ovf_Un;
2075 opcode = OpCodes.Add;
2077 opcode = OpCodes.Add;
2080 case Operator.Subtraction:
2082 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2083 opcode = OpCodes.Sub_Ovf;
2084 else if (!IsFloat (l))
2085 opcode = OpCodes.Sub_Ovf_Un;
2087 opcode = OpCodes.Sub;
2089 opcode = OpCodes.Sub;
2092 case Operator.RightShift:
2094 opcode = OpCodes.Shr_Un;
2096 opcode = OpCodes.Shr;
2099 case Operator.LeftShift:
2100 opcode = OpCodes.Shl;
2103 case Operator.Equality:
2104 opcode = OpCodes.Ceq;
2107 case Operator.Inequality:
2108 ig.Emit (OpCodes.Ceq);
2109 ig.Emit (OpCodes.Ldc_I4_0);
2111 opcode = OpCodes.Ceq;
2114 case Operator.LessThan:
2116 opcode = OpCodes.Clt_Un;
2118 opcode = OpCodes.Clt;
2121 case Operator.GreaterThan:
2123 opcode = OpCodes.Cgt_Un;
2125 opcode = OpCodes.Cgt;
2128 case Operator.LessThanOrEqual:
2129 if (IsUnsigned (l) || IsFloat (l))
2130 ig.Emit (OpCodes.Cgt_Un);
2132 ig.Emit (OpCodes.Cgt);
2133 ig.Emit (OpCodes.Ldc_I4_0);
2135 opcode = OpCodes.Ceq;
2138 case Operator.GreaterThanOrEqual:
2139 if (IsUnsigned (l) || IsFloat (l))
2140 ig.Emit (OpCodes.Clt_Un);
2142 ig.Emit (OpCodes.Clt);
2144 ig.Emit (OpCodes.Ldc_I4_0);
2146 opcode = OpCodes.Ceq;
2149 case Operator.BitwiseOr:
2150 opcode = OpCodes.Or;
2153 case Operator.BitwiseAnd:
2154 opcode = OpCodes.And;
2157 case Operator.ExclusiveOr:
2158 opcode = OpCodes.Xor;
2162 throw new InternalErrorException (oper.ToString ());
2168 static bool IsUnsigned (Type t)
2173 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2174 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2177 static bool IsFloat (Type t)
2179 return t == TypeManager.float_type || t == TypeManager.double_type;
2182 Expression ResolveOperator (EmitContext ec)
2185 Type r = right.Type;
2187 bool primitives_only = false;
2189 if (standard_operators == null)
2190 CreateStandardOperatorsTable ();
2193 // Handles predefined primitive types
2195 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2196 if ((oper & Operator.ShiftMask) == 0) {
2197 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2200 primitives_only = true;
2204 if (l.IsPointer || r.IsPointer)
2205 return ResolveOperatorPointer (ec, l, r);
2208 bool lenum = TypeManager.IsEnumType (l);
2209 bool renum = TypeManager.IsEnumType (r);
2210 if (lenum || renum) {
2211 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2213 // TODO: Can this be ambiguous
2219 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2220 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2222 expr = ResolveOperatorDelegate (ec, l, r);
2224 // TODO: Can this be ambiguous
2230 expr = ResolveUserOperator (ec, l, r);
2234 // Predefined reference types equality
2235 if ((oper & Operator.EqualityMask) != 0) {
2236 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2242 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2245 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2246 // if 'left' is not an enumeration constant, create one from the type of 'right'
2247 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2250 case Operator.BitwiseOr:
2251 case Operator.BitwiseAnd:
2252 case Operator.ExclusiveOr:
2253 case Operator.Equality:
2254 case Operator.Inequality:
2255 case Operator.LessThan:
2256 case Operator.LessThanOrEqual:
2257 case Operator.GreaterThan:
2258 case Operator.GreaterThanOrEqual:
2259 if (TypeManager.IsEnumType (left.Type))
2262 if (left.IsZeroInteger)
2263 return left.TryReduce (ec, right.Type, loc);
2267 case Operator.Addition:
2268 case Operator.Subtraction:
2271 case Operator.Multiply:
2272 case Operator.Division:
2273 case Operator.Modulus:
2274 case Operator.LeftShift:
2275 case Operator.RightShift:
2276 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2280 Error_OperatorCannotBeApplied (this.left, this.right);
2285 // The `|' operator used on types which were extended is dangerous
2287 void CheckBitwiseOrOnSignExtended ()
2289 OpcodeCast lcast = left as OpcodeCast;
2290 if (lcast != null) {
2291 if (IsUnsigned (lcast.UnderlyingType))
2295 OpcodeCast rcast = right as OpcodeCast;
2296 if (rcast != null) {
2297 if (IsUnsigned (rcast.UnderlyingType))
2301 if (lcast == null && rcast == null)
2304 // FIXME: consider constants
2306 Report.Warning (675, 3, loc,
2307 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2308 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2311 static void CreatePointerOperatorsTable ()
2313 ArrayList temp = new ArrayList ();
2316 // Pointer arithmetic:
2318 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2319 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2320 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2321 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2323 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2324 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2325 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2326 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2329 // T* operator + (int y, T* x);
2330 // T* operator + (uint y, T *x);
2331 // T* operator + (long y, T *x);
2332 // T* operator + (ulong y, T *x);
2334 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2335 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2336 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2337 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2340 // long operator - (T* x, T *y)
2342 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2344 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2347 static void CreateStandardOperatorsTable ()
2349 ArrayList temp = new ArrayList ();
2350 Type bool_type = TypeManager.bool_type;
2352 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2353 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2354 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2355 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2356 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2357 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2358 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2360 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2361 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2362 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2363 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2364 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2365 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2366 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2368 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2370 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2371 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2372 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2374 temp.Add (new PredefinedOperator (bool_type,
2375 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2377 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2378 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2379 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2380 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2382 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2386 // Rules used during binary numeric promotion
2388 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2393 Constant c = prim_expr as Constant;
2395 temp = c.ConvertImplicitly (type);
2402 if (type == TypeManager.uint32_type) {
2403 etype = prim_expr.Type;
2404 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2405 type = TypeManager.int64_type;
2407 if (type != second_expr.Type) {
2408 c = second_expr as Constant;
2410 temp = c.ConvertImplicitly (type);
2412 temp = Convert.ImplicitNumericConversion (second_expr, type);
2418 } else if (type == TypeManager.uint64_type) {
2420 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2422 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2423 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2427 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2436 // 7.2.6.2 Binary numeric promotions
2438 public bool DoBinaryOperatorPromotion (EmitContext ec)
2440 Type ltype = left.Type;
2441 Type rtype = right.Type;
2444 foreach (Type t in ConstantFold.binary_promotions) {
2446 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2449 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2452 Type int32 = TypeManager.int32_type;
2453 if (ltype != int32) {
2454 Constant c = left as Constant;
2456 temp = c.ConvertImplicitly (int32);
2458 temp = Convert.ImplicitNumericConversion (left, int32);
2465 if (rtype != int32) {
2466 Constant c = right as Constant;
2468 temp = c.ConvertImplicitly (int32);
2470 temp = Convert.ImplicitNumericConversion (right, int32);
2480 public override Expression DoResolve (EmitContext ec)
2485 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2486 left = ((ParenthesizedExpression) left).Expr;
2487 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2491 if (left.eclass == ExprClass.Type) {
2492 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2496 left = left.Resolve (ec);
2501 Constant lc = left as Constant;
2503 if (lc != null && lc.Type == TypeManager.bool_type &&
2504 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2505 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2507 // FIXME: resolve right expression as unreachable
2508 // right.Resolve (ec);
2510 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2514 right = right.Resolve (ec);
2518 eclass = ExprClass.Value;
2519 Constant rc = right as Constant;
2521 // The conversion rules are ignored in enum context but why
2522 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2523 left = lc = EnumLiftUp (ec, lc, rc, loc);
2527 right = rc = EnumLiftUp (ec, rc, lc, loc);
2532 if (rc != null && lc != null) {
2533 int prev_e = Report.Errors;
2534 Expression e = ConstantFold.BinaryFold (
2535 ec, oper, lc, rc, loc);
2536 if (e != null || Report.Errors != prev_e)
2539 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2540 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2542 if ((ResolveOperator (ec)) == null) {
2543 Error_OperatorCannotBeApplied (left, right);
2552 // The result is a constant with side-effect
2553 return new SideEffectConstant (lc, right, loc);
2557 // Comparison warnings
2558 if ((oper & Operator.ComparisonMask) != 0) {
2559 if (left.Equals (right)) {
2560 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2562 CheckUselessComparison (lc, right.Type);
2563 CheckUselessComparison (rc, left.Type);
2566 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2567 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2568 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2569 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2571 return DoResolveCore (ec, left, right);
2574 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2576 Expression expr = ResolveOperator (ec);
2578 Error_OperatorCannotBeApplied (left_orig, right_orig);
2580 if (left == null || right == null)
2581 throw new InternalErrorException ("Invalid conversion");
2583 if (oper == Operator.BitwiseOr)
2584 CheckBitwiseOrOnSignExtended ();
2589 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2591 left.MutateHoistedGenericType (storey);
2592 right.MutateHoistedGenericType (storey);
2596 // D operator + (D x, D y)
2597 // D operator - (D x, D y)
2598 // bool operator == (D x, D y)
2599 // bool operator != (D x, D y)
2601 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2603 bool is_equality = (oper & Operator.EqualityMask) != 0;
2604 if (!TypeManager.IsEqual (l, r)) {
2606 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2607 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2612 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2613 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2624 // Resolve delegate equality as a user operator
2627 return ResolveUserOperator (ec, l, r);
2630 ArrayList args = new ArrayList (2);
2631 args.Add (new Argument (left, Argument.AType.Expression));
2632 args.Add (new Argument (right, Argument.AType.Expression));
2634 if (oper == Operator.Addition) {
2635 if (TypeManager.delegate_combine_delegate_delegate == null) {
2636 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2637 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2640 method = TypeManager.delegate_combine_delegate_delegate;
2642 if (TypeManager.delegate_remove_delegate_delegate == null) {
2643 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2644 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2647 method = TypeManager.delegate_remove_delegate_delegate;
2650 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2651 mg = mg.OverloadResolve (ec, ref args, false, loc);
2653 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2657 // Enumeration operators
2659 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2662 // bool operator == (E x, E y);
2663 // bool operator != (E x, E y);
2664 // bool operator < (E x, E y);
2665 // bool operator > (E x, E y);
2666 // bool operator <= (E x, E y);
2667 // bool operator >= (E x, E y);
2669 // E operator & (E x, E y);
2670 // E operator | (E x, E y);
2671 // E operator ^ (E x, E y);
2673 // U operator - (E e, E f)
2674 // E operator - (E e, U x)
2676 // E operator + (U x, E e)
2677 // E operator + (E e, U x)
2679 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2680 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2683 Expression ltemp = left;
2684 Expression rtemp = right;
2685 Type underlying_type;
2688 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2690 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2696 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2704 if (TypeManager.IsEqual (ltype, rtype)) {
2705 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2707 if (left is Constant)
2708 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2710 left = EmptyCast.Create (left, underlying_type);
2712 if (right is Constant)
2713 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2715 right = EmptyCast.Create (right, underlying_type);
2717 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2719 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2720 Constant c = right as Constant;
2721 if (c == null || !c.IsDefaultValue)
2724 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2727 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2730 if (left is Constant)
2731 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2733 left = EmptyCast.Create (left, underlying_type);
2736 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2738 if (oper != Operator.Addition) {
2739 Constant c = left as Constant;
2740 if (c == null || !c.IsDefaultValue)
2743 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2746 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2749 if (right is Constant)
2750 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2752 right = EmptyCast.Create (right, underlying_type);
2759 // C# specification uses explicit cast syntax which means binary promotion
2760 // should happen, however it seems that csc does not do that
2762 if (!DoBinaryOperatorPromotion (ec)) {
2768 Type res_type = null;
2769 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2770 Type promoted_type = lenum ? left.Type : right.Type;
2771 enum_conversion = Convert.ExplicitNumericConversion (
2772 new EmptyExpression (promoted_type), underlying_type);
2774 if (oper == Operator.Subtraction && renum && lenum)
2775 res_type = underlying_type;
2776 else if (oper == Operator.Addition && renum)
2782 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2783 if (!is_compound || expr == null)
2787 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2790 if (Convert.ImplicitConversionExists (ec, left, rtype))
2793 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2796 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2801 // 7.9.6 Reference type equality operators
2803 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2806 // operator != (object a, object b)
2807 // operator == (object a, object b)
2810 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2812 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2815 type = TypeManager.bool_type;
2816 GenericConstraints constraints;
2818 bool lgen = TypeManager.IsGenericParameter (l);
2820 if (TypeManager.IsEqual (l, r)) {
2823 // Only allow to compare same reference type parameter
2825 constraints = TypeManager.GetTypeParameterConstraints (l);
2826 if (constraints != null && constraints.IsReferenceType)
2832 if (l == TypeManager.anonymous_method_type)
2835 if (TypeManager.IsValueType (l))
2841 bool rgen = TypeManager.IsGenericParameter (r);
2844 // a, Both operands are reference-type values or the value null
2845 // b, One operand is a value of type T where T is a type-parameter and
2846 // the other operand is the value null. Furthermore T does not have the
2847 // value type constrain
2849 if (left is NullLiteral || right is NullLiteral) {
2851 constraints = TypeManager.GetTypeParameterConstraints (l);
2852 if (constraints != null && constraints.HasValueTypeConstraint)
2855 left = new BoxedCast (left, TypeManager.object_type);
2860 constraints = TypeManager.GetTypeParameterConstraints (r);
2861 if (constraints != null && constraints.HasValueTypeConstraint)
2864 right = new BoxedCast (right, TypeManager.object_type);
2870 // An interface is converted to the object before the
2871 // standard conversion is applied. It's not clear from the
2872 // standard but it looks like it works like that.
2875 constraints = TypeManager.GetTypeParameterConstraints (l);
2876 if (constraints == null || constraints.IsReferenceType)
2878 } else if (l.IsInterface) {
2879 l = TypeManager.object_type;
2880 } else if (l.IsValueType) {
2885 constraints = TypeManager.GetTypeParameterConstraints (r);
2886 if (constraints == null || constraints.IsReferenceType)
2888 } else if (r.IsInterface) {
2889 r = TypeManager.object_type;
2890 } else if (r.IsValueType) {
2895 const string ref_comparison = "Possible unintended reference comparison. " +
2896 "Consider casting the {0} side of the expression to `string' to compare the values";
2899 // A standard implicit conversion exists from the type of either
2900 // operand to the type of the other operand
2902 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2903 if (l == TypeManager.string_type)
2904 Report.Warning (253, 2, loc, ref_comparison, "right");
2909 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2910 if (r == TypeManager.string_type)
2911 Report.Warning (252, 2, loc, ref_comparison, "left");
2920 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2923 // bool operator == (void* x, void* y);
2924 // bool operator != (void* x, void* y);
2925 // bool operator < (void* x, void* y);
2926 // bool operator > (void* x, void* y);
2927 // bool operator <= (void* x, void* y);
2928 // bool operator >= (void* x, void* y);
2930 if ((oper & Operator.ComparisonMask) != 0) {
2933 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2940 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2946 type = TypeManager.bool_type;
2950 if (pointer_operators == null)
2951 CreatePointerOperatorsTable ();
2953 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2957 // Build-in operators method overloading
2959 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2961 PredefinedOperator best_operator = null;
2963 Type r = right.Type;
2964 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2966 foreach (PredefinedOperator po in operators) {
2967 if ((po.OperatorsMask & oper_mask) == 0)
2970 if (primitives_only) {
2971 if (!po.IsPrimitiveApplicable (l, r))
2974 if (!po.IsApplicable (ec, left, right))
2978 if (best_operator == null) {
2980 if (primitives_only)
2986 best_operator = po.ResolveBetterOperator (ec, best_operator);
2988 if (best_operator == null) {
2989 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2990 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2997 if (best_operator == null)
3000 Expression expr = best_operator.ConvertResult (ec, this);
3001 if (enum_type == null)
3005 // HACK: required by enum_conversion
3007 expr.Type = enum_type;
3008 return EmptyCast.Create (expr, enum_type);
3012 // Performs user-operator overloading
3014 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3017 if (oper == Operator.LogicalAnd)
3018 user_oper = Operator.BitwiseAnd;
3019 else if (oper == Operator.LogicalOr)
3020 user_oper = Operator.BitwiseOr;
3024 string op = GetOperatorMetadataName (user_oper);
3026 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3027 MethodGroupExpr right_operators = null;
3029 if (!TypeManager.IsEqual (r, l)) {
3030 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3031 if (right_operators == null && left_operators == null)
3033 } else if (left_operators == null) {
3037 ArrayList args = new ArrayList (2);
3038 Argument larg = new Argument (left);
3040 Argument rarg = new Argument (right);
3043 MethodGroupExpr union;
3046 // User-defined operator implementations always take precedence
3047 // over predefined operator implementations
3049 if (left_operators != null && right_operators != null) {
3050 if (IsPredefinedUserOperator (l, user_oper)) {
3051 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3053 union = left_operators;
3054 } else if (IsPredefinedUserOperator (r, user_oper)) {
3055 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3057 union = right_operators;
3059 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3061 } else if (left_operators != null) {
3062 union = left_operators;
3064 union = right_operators;
3067 union = union.OverloadResolve (ec, ref args, true, loc);
3071 Expression oper_expr;
3073 // TODO: CreateExpressionTree is allocated every time
3074 if (user_oper != oper) {
3075 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3076 oper == Operator.LogicalAnd, loc).Resolve (ec);
3078 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3081 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3082 // and not invoke user operator
3084 if ((oper & Operator.EqualityMask) != 0) {
3085 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3086 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3087 type = TypeManager.bool_type;
3088 if (left is NullLiteral || right is NullLiteral)
3089 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3090 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3092 // Two System.Delegate(s) are never equal
3104 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3109 private void CheckUselessComparison (Constant c, Type type)
3111 if (c == null || !IsTypeIntegral (type)
3112 || c is StringConstant
3113 || c is BoolConstant
3114 || c is FloatConstant
3115 || c is DoubleConstant
3116 || c is DecimalConstant
3122 if (c is ULongConstant) {
3123 ulong uvalue = ((ULongConstant) c).Value;
3124 if (uvalue > long.MaxValue) {
3125 if (type == TypeManager.byte_type ||
3126 type == TypeManager.sbyte_type ||
3127 type == TypeManager.short_type ||
3128 type == TypeManager.ushort_type ||
3129 type == TypeManager.int32_type ||
3130 type == TypeManager.uint32_type ||
3131 type == TypeManager.int64_type ||
3132 type == TypeManager.char_type)
3133 WarnUselessComparison (type);
3136 value = (long) uvalue;
3138 else if (c is ByteConstant)
3139 value = ((ByteConstant) c).Value;
3140 else if (c is SByteConstant)
3141 value = ((SByteConstant) c).Value;
3142 else if (c is ShortConstant)
3143 value = ((ShortConstant) c).Value;
3144 else if (c is UShortConstant)
3145 value = ((UShortConstant) c).Value;
3146 else if (c is IntConstant)
3147 value = ((IntConstant) c).Value;
3148 else if (c is UIntConstant)
3149 value = ((UIntConstant) c).Value;
3150 else if (c is LongConstant)
3151 value = ((LongConstant) c).Value;
3152 else if (c is CharConstant)
3153 value = ((CharConstant)c).Value;
3158 if (IsValueOutOfRange (value, type))
3159 WarnUselessComparison (type);
3162 static bool IsValueOutOfRange (long value, Type type)
3164 if (IsTypeUnsigned (type) && value < 0)
3166 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3167 type == TypeManager.byte_type && value >= 0x100 ||
3168 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3169 type == TypeManager.ushort_type && value >= 0x10000 ||
3170 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3171 type == TypeManager.uint32_type && value >= 0x100000000;
3174 static bool IsBuildInEqualityOperator (Type t)
3176 return t == TypeManager.object_type || t == TypeManager.string_type ||
3177 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3180 static bool IsPredefinedUserOperator (Type t, Operator op)
3183 // Some predefined types have user operators
3185 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3188 private static bool IsTypeIntegral (Type type)
3190 return type == TypeManager.uint64_type ||
3191 type == TypeManager.int64_type ||
3192 type == TypeManager.uint32_type ||
3193 type == TypeManager.int32_type ||
3194 type == TypeManager.ushort_type ||
3195 type == TypeManager.short_type ||
3196 type == TypeManager.sbyte_type ||
3197 type == TypeManager.byte_type ||
3198 type == TypeManager.char_type;
3201 private static bool IsTypeUnsigned (Type type)
3203 return type == TypeManager.uint64_type ||
3204 type == TypeManager.uint32_type ||
3205 type == TypeManager.ushort_type ||
3206 type == TypeManager.byte_type ||
3207 type == TypeManager.char_type;
3210 private void WarnUselessComparison (Type type)
3212 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}'",
3213 TypeManager.CSharpName (type));
3217 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3218 /// context of a conditional bool expression. This function will return
3219 /// false if it is was possible to use EmitBranchable, or true if it was.
3221 /// The expression's code is generated, and we will generate a branch to `target'
3222 /// if the resulting expression value is equal to isTrue
3224 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3226 ILGenerator ig = ec.ig;
3229 // This is more complicated than it looks, but its just to avoid
3230 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3231 // but on top of that we want for == and != to use a special path
3232 // if we are comparing against null
3234 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3235 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3238 // put the constant on the rhs, for simplicity
3240 if (left is Constant) {
3241 Expression swap = right;
3246 if (((Constant) right).IsZeroInteger) {
3247 left.EmitBranchable (ec, target, my_on_true);
3250 if (right.Type == TypeManager.bool_type) {
3251 // right is a boolean, and it's not 'false' => it is 'true'
3252 left.EmitBranchable (ec, target, !my_on_true);
3256 } else if (oper == Operator.LogicalAnd) {
3259 Label tests_end = ig.DefineLabel ();
3261 left.EmitBranchable (ec, tests_end, false);
3262 right.EmitBranchable (ec, target, true);
3263 ig.MarkLabel (tests_end);
3266 // This optimizes code like this
3267 // if (true && i > 4)
3269 if (!(left is Constant))
3270 left.EmitBranchable (ec, target, false);
3272 if (!(right is Constant))
3273 right.EmitBranchable (ec, target, false);
3278 } else if (oper == Operator.LogicalOr){
3280 left.EmitBranchable (ec, target, true);
3281 right.EmitBranchable (ec, target, true);
3284 Label tests_end = ig.DefineLabel ();
3285 left.EmitBranchable (ec, tests_end, true);
3286 right.EmitBranchable (ec, target, false);
3287 ig.MarkLabel (tests_end);
3292 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3293 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3294 oper == Operator.Equality || oper == Operator.Inequality)) {
3295 base.EmitBranchable (ec, target, on_true);
3303 bool is_unsigned = IsUnsigned (t) || IsFloat (t);
3306 case Operator.Equality:
3308 ig.Emit (OpCodes.Beq, target);
3310 ig.Emit (OpCodes.Bne_Un, target);
3313 case Operator.Inequality:
3315 ig.Emit (OpCodes.Bne_Un, target);
3317 ig.Emit (OpCodes.Beq, target);
3320 case Operator.LessThan:
3323 ig.Emit (OpCodes.Blt_Un, target);
3325 ig.Emit (OpCodes.Blt, target);
3328 ig.Emit (OpCodes.Bge_Un, target);
3330 ig.Emit (OpCodes.Bge, target);
3333 case Operator.GreaterThan:
3336 ig.Emit (OpCodes.Bgt_Un, target);
3338 ig.Emit (OpCodes.Bgt, target);
3341 ig.Emit (OpCodes.Ble_Un, target);
3343 ig.Emit (OpCodes.Ble, target);
3346 case Operator.LessThanOrEqual:
3349 ig.Emit (OpCodes.Ble_Un, target);
3351 ig.Emit (OpCodes.Ble, target);
3354 ig.Emit (OpCodes.Bgt_Un, target);
3356 ig.Emit (OpCodes.Bgt, target);
3360 case Operator.GreaterThanOrEqual:
3363 ig.Emit (OpCodes.Bge_Un, target);
3365 ig.Emit (OpCodes.Bge, target);
3368 ig.Emit (OpCodes.Blt_Un, target);
3370 ig.Emit (OpCodes.Blt, target);
3373 throw new InternalErrorException (oper.ToString ());
3377 public override void Emit (EmitContext ec)
3379 EmitOperator (ec, left.Type);
3382 protected virtual void EmitOperator (EmitContext ec, Type l)
3384 ILGenerator ig = ec.ig;
3387 // Handle short-circuit operators differently
3390 if ((oper & Operator.LogicalMask) != 0) {
3391 Label load_result = ig.DefineLabel ();
3392 Label end = ig.DefineLabel ();
3394 bool is_or = oper == Operator.LogicalOr;
3395 left.EmitBranchable (ec, load_result, is_or);
3397 ig.Emit (OpCodes.Br_S, end);
3399 ig.MarkLabel (load_result);
3400 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3408 // Optimize zero-based operations
3410 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3412 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3413 Constant rc = right as Constant;
3414 if (rc != null && rc.IsDefaultValue) {
3420 EmitOperatorOpcode (ec, oper, l);
3423 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3424 // expression because that would wrap lifted binary operation
3426 if (enum_conversion != null)
3427 enum_conversion.Emit (ec);
3430 public override void EmitSideEffect (EmitContext ec)
3432 if ((oper & Operator.LogicalMask) != 0 ||
3433 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3434 base.EmitSideEffect (ec);
3436 left.EmitSideEffect (ec);
3437 right.EmitSideEffect (ec);
3441 protected override void CloneTo (CloneContext clonectx, Expression t)
3443 Binary target = (Binary) t;
3445 target.left = left.Clone (clonectx);
3446 target.right = right.Clone (clonectx);
3449 public override Expression CreateExpressionTree (EmitContext ec)
3451 return CreateExpressionTree (ec, null);
3454 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3457 bool lift_arg = false;
3460 case Operator.Addition:
3461 if (method == null && ec.CheckState && !IsFloat (type))
3462 method_name = "AddChecked";
3464 method_name = "Add";
3466 case Operator.BitwiseAnd:
3467 method_name = "And";
3469 case Operator.BitwiseOr:
3472 case Operator.Division:
3473 method_name = "Divide";
3475 case Operator.Equality:
3476 method_name = "Equal";
3479 case Operator.ExclusiveOr:
3480 method_name = "ExclusiveOr";
3482 case Operator.GreaterThan:
3483 method_name = "GreaterThan";
3486 case Operator.GreaterThanOrEqual:
3487 method_name = "GreaterThanOrEqual";
3490 case Operator.Inequality:
3491 method_name = "NotEqual";
3494 case Operator.LeftShift:
3495 method_name = "LeftShift";
3497 case Operator.LessThan:
3498 method_name = "LessThan";
3501 case Operator.LessThanOrEqual:
3502 method_name = "LessThanOrEqual";
3505 case Operator.LogicalAnd:
3506 method_name = "AndAlso";
3508 case Operator.LogicalOr:
3509 method_name = "OrElse";
3511 case Operator.Modulus:
3512 method_name = "Modulo";
3514 case Operator.Multiply:
3515 if (method == null && ec.CheckState && !IsFloat (type))
3516 method_name = "MultiplyChecked";
3518 method_name = "Multiply";
3520 case Operator.RightShift:
3521 method_name = "RightShift";
3523 case Operator.Subtraction:
3524 if (method == null && ec.CheckState && !IsFloat (type))
3525 method_name = "SubtractChecked";
3527 method_name = "Subtract";
3531 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3534 ArrayList args = new ArrayList (2);
3535 args.Add (new Argument (left.CreateExpressionTree (ec)));
3536 args.Add (new Argument (right.CreateExpressionTree (ec)));
3537 if (method != null) {
3539 args.Add (new Argument (new BoolConstant (false, loc)));
3541 args.Add (new Argument (method.CreateExpressionTree (ec)));
3544 return CreateExpressionFactoryCall (method_name, args);
3549 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3550 // b, c, d... may be strings or objects.
3552 public class StringConcat : Expression {
3553 ArrayList arguments;
3555 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3558 type = TypeManager.string_type;
3559 eclass = ExprClass.Value;
3561 arguments = new ArrayList (2);
3566 public override Expression CreateExpressionTree (EmitContext ec)
3568 Argument arg = (Argument) arguments [0];
3569 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3573 // Creates nested calls tree from an array of arguments used for IL emit
3575 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3577 ArrayList concat_args = new ArrayList (2);
3578 ArrayList add_args = new ArrayList (3);
3580 concat_args.Add (left);
3581 add_args.Add (new Argument (left_etree));
3583 concat_args.Add (arguments [pos]);
3584 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3586 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3590 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3594 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3596 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3597 if (++pos == arguments.Count)
3600 left = new Argument (new EmptyExpression (method.Type));
3601 return CreateExpressionAddCall (ec, left, expr, pos);
3604 public override Expression DoResolve (EmitContext ec)
3609 public void Append (EmitContext ec, Expression operand)
3614 StringConstant sc = operand as StringConstant;
3616 if (arguments.Count != 0) {
3617 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3618 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3619 if (last_expr_constant != null) {
3620 last_argument.Expr = new StringConstant (
3621 last_expr_constant.Value + sc.Value, sc.Location);
3627 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3629 StringConcat concat_oper = operand as StringConcat;
3630 if (concat_oper != null) {
3631 arguments.AddRange (concat_oper.arguments);
3636 arguments.Add (new Argument (operand));
3639 Expression CreateConcatMemberExpression ()
3641 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3644 public override void Emit (EmitContext ec)
3646 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3647 concat = concat.Resolve (ec);
3654 // User-defined conditional logical operator
3656 public class ConditionalLogicalOperator : UserOperatorCall {
3657 readonly bool is_and;
3660 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3661 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3662 : base (oper_method, arguments, expr_tree, loc)
3664 this.is_and = is_and;
3667 public override Expression DoResolve (EmitContext ec)
3669 MethodInfo method = (MethodInfo)mg;
3670 type = TypeManager.TypeToCoreType (method.ReturnType);
3671 ParameterData pd = TypeManager.GetParameterData (method);
3672 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3673 Report.Error (217, loc,
3674 "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",
3675 TypeManager.CSharpSignature (method));
3679 Expression left_dup = new EmptyExpression (type);
3680 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3681 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3682 if (op_true == null || op_false == null) {
3683 Report.Error (218, loc,
3684 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3685 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3689 oper = is_and ? op_false : op_true;
3690 eclass = ExprClass.Value;
3694 public override void Emit (EmitContext ec)
3696 ILGenerator ig = ec.ig;
3697 Label end_target = ig.DefineLabel ();
3700 // Emit and duplicate left argument
3702 ((Argument)arguments [0]).Expr.Emit (ec);
3703 ig.Emit (OpCodes.Dup);
3704 arguments.RemoveAt (0);
3706 oper.EmitBranchable (ec, end_target, true);
3708 ig.MarkLabel (end_target);
3712 public class PointerArithmetic : Expression {
3713 Expression left, right;
3717 // We assume that `l' is always a pointer
3719 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3728 public override Expression CreateExpressionTree (EmitContext ec)
3730 Error_PointerInsideExpressionTree ();
3734 public override Expression DoResolve (EmitContext ec)
3736 eclass = ExprClass.Variable;
3738 if (left.Type == TypeManager.void_ptr_type) {
3739 Error (242, "The operation in question is undefined on void pointers");
3746 public override void Emit (EmitContext ec)
3748 Type op_type = left.Type;
3749 ILGenerator ig = ec.ig;
3751 // It must be either array or fixed buffer
3753 if (TypeManager.HasElementType (op_type)) {
3754 element = TypeManager.GetElementType (op_type);
3756 FieldExpr fe = left as FieldExpr;
3758 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3763 int size = GetTypeSize (element);
3764 Type rtype = right.Type;
3766 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3768 // handle (pointer - pointer)
3772 ig.Emit (OpCodes.Sub);
3776 ig.Emit (OpCodes.Sizeof, element);
3778 IntLiteral.EmitInt (ig, size);
3779 ig.Emit (OpCodes.Div);
3781 ig.Emit (OpCodes.Conv_I8);
3784 // handle + and - on (pointer op int)
3788 Constant right_const = right as Constant;
3789 if (right_const != null) {
3791 // Optimize 0-based arithmetic
3793 if (right_const.IsDefaultValue)
3797 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3801 ig.Emit (OpCodes.Sizeof, element);
3802 right = EmptyExpression.Null;
3807 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3808 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3809 ig.Emit (OpCodes.Conv_I);
3810 } else if (rtype == TypeManager.uint32_type) {
3811 ig.Emit (OpCodes.Conv_U);
3814 if (right_const == null && size != 1){
3816 ig.Emit (OpCodes.Sizeof, element);
3818 IntLiteral.EmitInt (ig, size);
3819 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3820 ig.Emit (OpCodes.Conv_I8);
3822 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3825 if (rtype == TypeManager.int64_type)
3826 ig.Emit (OpCodes.Conv_I);
3827 else if (rtype == TypeManager.uint64_type)
3828 ig.Emit (OpCodes.Conv_U);
3830 Binary.EmitOperatorOpcode (ec, op, op_type);
3836 /// Implements the ternary conditional operator (?:)
3838 public class Conditional : Expression {
3839 Expression expr, true_expr, false_expr;
3841 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3844 this.true_expr = true_expr;
3845 this.false_expr = false_expr;
3846 this.loc = expr.Location;
3849 public Expression Expr {
3855 public Expression TrueExpr {
3861 public Expression FalseExpr {
3867 public override Expression CreateExpressionTree (EmitContext ec)
3869 ArrayList args = new ArrayList (3);
3870 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3871 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3872 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3873 return CreateExpressionFactoryCall ("Condition", args);
3876 public override Expression DoResolve (EmitContext ec)
3878 expr = expr.Resolve (ec);
3883 if (expr.Type != TypeManager.bool_type){
3884 expr = Expression.ResolveBoolean (
3891 Assign ass = expr as Assign;
3892 if (ass != null && ass.Source is Constant) {
3893 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3896 true_expr = true_expr.Resolve (ec);
3897 false_expr = false_expr.Resolve (ec);
3899 if (true_expr == null || false_expr == null)
3902 eclass = ExprClass.Value;
3903 Type true_type = true_expr.Type;
3904 Type false_type = false_expr.Type;
3908 // First, if an implicit conversion exists from true_expr
3909 // to false_expr, then the result type is of type false_expr.Type
3911 if (!TypeManager.IsEqual (true_type, false_type)) {
3912 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3915 // Check if both can convert implicitl to each other's type
3917 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3919 "Can not compute type of conditional expression " +
3920 "as `" + TypeManager.CSharpName (true_expr.Type) +
3921 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3922 "' convert implicitly to each other");
3927 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3930 Report.Error (173, loc,
3931 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3932 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3937 // Dead code optimalization
3938 Constant c = expr as Constant;
3940 bool is_false = c.IsDefaultValue;
3941 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3942 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3948 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3950 expr.MutateHoistedGenericType (storey);
3951 true_expr.MutateHoistedGenericType (storey);
3952 false_expr.MutateHoistedGenericType (storey);
3953 type = storey.MutateType (type);
3956 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3961 public override void Emit (EmitContext ec)
3963 ILGenerator ig = ec.ig;
3964 Label false_target = ig.DefineLabel ();
3965 Label end_target = ig.DefineLabel ();
3967 expr.EmitBranchable (ec, false_target, false);
3968 true_expr.Emit (ec);
3970 if (type.IsInterface) {
3971 LocalBuilder temp = ec.GetTemporaryLocal (type);
3972 ig.Emit (OpCodes.Stloc, temp);
3973 ig.Emit (OpCodes.Ldloc, temp);
3974 ec.FreeTemporaryLocal (temp, type);
3977 ig.Emit (OpCodes.Br, end_target);
3978 ig.MarkLabel (false_target);
3979 false_expr.Emit (ec);
3980 ig.MarkLabel (end_target);
3983 protected override void CloneTo (CloneContext clonectx, Expression t)
3985 Conditional target = (Conditional) t;
3987 target.expr = expr.Clone (clonectx);
3988 target.true_expr = true_expr.Clone (clonectx);
3989 target.false_expr = false_expr.Clone (clonectx);
3993 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
3994 LocalTemporary temp;
3997 public abstract HoistedVariable HoistedVariable { get; }
3998 public abstract bool IsFixedVariable { get; }
3999 public abstract bool IsRef { get; }
4000 public abstract string Name { get; }
4001 public abstract void SetHasAddressTaken ();
4004 // Variable IL data, it has to be protected to encapsulate hoisted variables
4006 protected abstract ILocalVariable Variable { get; }
4009 // Variable flow-analysis data
4011 public abstract VariableInfo VariableInfo { get; }
4014 public void AddressOf (EmitContext ec, AddressOp mode)
4016 if (IsHoistedEmitRequired (ec)) {
4017 HoistedVariable.AddressOf (ec, mode);
4021 Variable.EmitAddressOf (ec);
4024 public override void Emit (EmitContext ec)
4029 public override void EmitSideEffect (EmitContext ec)
4035 // This method is used by parameters that are references, that are
4036 // being passed as references: we only want to pass the pointer (that
4037 // is already stored in the parameter, not the address of the pointer,
4038 // and not the value of the variable).
4040 public void EmitLoad (EmitContext ec)
4045 public void Emit (EmitContext ec, bool leave_copy)
4047 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4049 if (IsHoistedEmitRequired (ec)) {
4050 HoistedVariable.Emit (ec, leave_copy);
4058 // If we are a reference, we loaded on the stack a pointer
4059 // Now lets load the real value
4061 LoadFromPtr (ec.ig, type);
4065 ec.ig.Emit (OpCodes.Dup);
4068 temp = new LocalTemporary (Type);
4074 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4075 bool prepare_for_load)
4077 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4080 if (IsHoistedEmitRequired (ec)) {
4081 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4090 // HACK: variable is already emitted when source is an initializer
4091 if (source is NewInitialize) {
4099 ec.ig.Emit (OpCodes.Dup);
4101 temp = new LocalTemporary (Type);
4107 StoreFromPtr (ec.ig, type);
4109 Variable.EmitAssign (ec);
4117 public bool IsHoisted {
4118 get { return HoistedVariable != null; }
4121 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4124 // Default implementation return true when there is a hosted variable
4126 return HoistedVariable != null;
4129 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4131 type = storey.MutateType (type);
4138 public class LocalVariableReference : VariableReference {
4139 readonly string name;
4141 public LocalInfo local_info;
4144 public LocalVariableReference (Block block, string name, Location l)
4149 eclass = ExprClass.Variable;
4153 // Setting `is_readonly' to false will allow you to create a writable
4154 // reference to a read-only variable. This is used by foreach and using.
4156 public LocalVariableReference (Block block, string name, Location l,
4157 LocalInfo local_info, bool is_readonly)
4158 : this (block, name, l)
4160 this.local_info = local_info;
4161 this.is_readonly = is_readonly;
4164 public override VariableInfo VariableInfo {
4165 get { return local_info.VariableInfo; }
4168 public override HoistedVariable HoistedVariable {
4169 get { return local_info.HoistedVariableReference; }
4173 // A local variable is always fixed
4175 public override bool IsFixedVariable {
4176 get { return true; }
4179 public override bool IsRef {
4180 get { return false; }
4183 public bool IsReadOnly {
4184 get { return is_readonly; }
4187 public override string Name {
4188 get { return name; }
4191 public bool VerifyAssigned (EmitContext ec)
4193 VariableInfo variable_info = local_info.VariableInfo;
4194 return variable_info == null || variable_info.IsAssigned (ec, loc);
4197 void ResolveLocalInfo ()
4199 if (local_info == null) {
4200 local_info = Block.GetLocalInfo (Name);
4201 type = local_info.VariableType;
4202 is_readonly = local_info.ReadOnly;
4206 public override void SetHasAddressTaken ()
4208 local_info.AddressTaken = true;
4211 public override Expression CreateExpressionTree (EmitContext ec)
4213 ArrayList arg = new ArrayList (1);
4214 arg.Add (new Argument (this));
4215 return CreateExpressionFactoryCall ("Constant", arg);
4218 Expression DoResolveBase (EmitContext ec)
4220 type = local_info.VariableType;
4222 Expression e = Block.GetConstantExpression (Name);
4224 return e.Resolve (ec);
4226 VerifyAssigned (ec);
4229 // If we are referencing a variable from the external block
4230 // flag it for capturing
4232 if (ec.MustCaptureVariable (local_info)) {
4233 if (local_info.AddressTaken)
4234 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4236 if (ec.IsVariableCapturingRequired) {
4237 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4238 storey.CaptureLocalVariable (ec, local_info);
4245 public override Expression DoResolve (EmitContext ec)
4247 ResolveLocalInfo ();
4248 local_info.Used = true;
4250 if (type == null && local_info.Type is VarExpr) {
4251 local_info.VariableType = TypeManager.object_type;
4252 Error_VariableIsUsedBeforeItIsDeclared (Name);
4256 return DoResolveBase (ec);
4259 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4261 ResolveLocalInfo ();
4264 if (right_side == EmptyExpression.OutAccess)
4265 local_info.Used = true;
4267 // Infer implicitly typed local variable
4269 VarExpr ve = local_info.Type as VarExpr;
4271 if (!ve.InferType (ec, right_side))
4273 type = local_info.VariableType = ve.Type;
4280 if (right_side == EmptyExpression.OutAccess) {
4281 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4282 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4283 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4284 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4285 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4286 } else if (right_side == EmptyExpression.UnaryAddress) {
4287 code = 459; msg = "Cannot take the address of {1} `{0}'";
4289 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4291 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4292 } else if (VariableInfo != null) {
4293 VariableInfo.SetAssigned (ec);
4296 return DoResolveBase (ec);
4299 public override int GetHashCode ()
4301 return Name.GetHashCode ();
4304 public override bool Equals (object obj)
4306 LocalVariableReference lvr = obj as LocalVariableReference;
4310 return Name == lvr.Name && Block == lvr.Block;
4313 protected override ILocalVariable Variable {
4314 get { return local_info; }
4317 public override string ToString ()
4319 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4322 protected override void CloneTo (CloneContext clonectx, Expression t)
4324 LocalVariableReference target = (LocalVariableReference) t;
4326 target.Block = clonectx.LookupBlock (Block);
4327 if (local_info != null)
4328 target.local_info = clonectx.LookupVariable (local_info);
4333 /// This represents a reference to a parameter in the intermediate
4336 public class ParameterReference : VariableReference {
4337 readonly ToplevelParameterInfo pi;
4338 readonly ToplevelBlock referenced;
4340 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4343 this.referenced = referenced;
4347 public override bool IsRef {
4348 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4351 bool HasOutModifier {
4352 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4355 public override HoistedVariable HoistedVariable {
4356 get { return pi.Parameter.HoistedVariableReference; }
4360 // A ref or out parameter is classified as a moveable variable, even
4361 // if the argument given for the parameter is a fixed variable
4363 public override bool IsFixedVariable {
4364 get { return !IsRef; }
4367 public override string Name {
4368 get { return Parameter.Name; }
4371 public Parameter Parameter {
4372 get { return pi.Parameter; }
4375 public override VariableInfo VariableInfo {
4376 get { return pi.VariableInfo; }
4379 protected override ILocalVariable Variable {
4380 get { return Parameter; }
4383 public bool IsAssigned (EmitContext ec, Location loc)
4385 // HACK: Variables are not captured in probing mode
4386 if (ec.IsInProbingMode)
4389 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4392 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4396 public override void SetHasAddressTaken ()
4398 Parameter.HasAddressTaken = true;
4401 void SetAssigned (EmitContext ec)
4403 if (HasOutModifier && ec.DoFlowAnalysis)
4404 ec.CurrentBranching.SetAssigned (VariableInfo);
4407 bool DoResolveBase (EmitContext ec)
4409 Parameter par = Parameter;
4410 type = par.ParameterType;
4411 eclass = ExprClass.Variable;
4413 AnonymousExpression am = ec.CurrentAnonymousMethod;
4417 ToplevelBlock declared = pi.Block;
4418 if (declared != referenced) {
4420 Report.Error (1628, loc,
4421 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4422 Name, am.ContainerType);
4430 if (ec.IsVariableCapturingRequired) {
4431 if (pi.Parameter.HasAddressTaken)
4432 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4434 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4435 storey.CaptureParameter (ec, this);
4441 public override int GetHashCode ()
4443 return Name.GetHashCode ();
4446 public override bool Equals (object obj)
4448 ParameterReference pr = obj as ParameterReference;
4452 return Name == pr.Name && referenced == pr.referenced;
4455 protected override void CloneTo (CloneContext clonectx, Expression target)
4460 public override Expression CreateExpressionTree (EmitContext ec)
4462 if (IsHoistedEmitRequired (ec))
4463 return HoistedVariable.CreateExpressionTree (ec);
4465 return Parameter.ExpressionTreeVariableReference ();
4469 // Notice that for ref/out parameters, the type exposed is not the
4470 // same type exposed externally.
4473 // externally we expose "int&"
4474 // here we expose "int".
4476 // We record this in "is_ref". This means that the type system can treat
4477 // the type as it is expected, but when we generate the code, we generate
4478 // the alternate kind of code.
4480 public override Expression DoResolve (EmitContext ec)
4482 if (!DoResolveBase (ec))
4485 if (HasOutModifier && ec.DoFlowAnalysis &&
4486 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4492 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4494 if (!DoResolveBase (ec))
4497 // HACK: parameters are not captured when probing is on
4498 if (!ec.IsInProbingMode)
4504 static public void EmitLdArg (ILGenerator ig, int x)
4508 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4509 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4510 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4511 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4512 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4515 ig.Emit (OpCodes.Ldarg, x);
4520 /// Used for arguments to New(), Invocation()
4522 public class Argument {
4523 public enum AType : byte {
4530 public static readonly Argument[] Empty = new Argument [0];
4532 public readonly AType ArgType;
4533 public Expression Expr;
4535 public Argument (Expression expr, AType type)
4538 this.ArgType = type;
4541 public Argument (Expression expr)
4544 this.ArgType = AType.Expression;
4549 if (ArgType == AType.Ref || ArgType == AType.Out)
4550 return TypeManager.GetReferenceType (Expr.Type);
4556 public Parameter.Modifier Modifier
4561 return Parameter.Modifier.OUT;
4564 return Parameter.Modifier.REF;
4567 return Parameter.Modifier.NONE;
4572 public string GetSignatureForError ()
4574 if (Expr.eclass == ExprClass.MethodGroup)
4575 return Expr.ExprClassName;
4577 return TypeManager.CSharpName (Expr.Type);
4580 public bool ResolveMethodGroup (EmitContext ec)
4582 SimpleName sn = Expr as SimpleName;
4584 Expr = sn.GetMethodGroup ();
4586 // FIXME: csc doesn't report any error if you try to use `ref' or
4587 // `out' in a delegate creation expression.
4588 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4595 public bool Resolve (EmitContext ec, Location loc)
4600 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4601 // Verify that the argument is readable
4602 if (ArgType != AType.Out)
4603 Expr = Expr.Resolve (ec);
4605 // Verify that the argument is writeable
4606 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4607 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4609 return Expr != null;
4613 public void Emit (EmitContext ec)
4615 if (ArgType != AType.Ref && ArgType != AType.Out) {
4620 AddressOp mode = AddressOp.Store;
4621 if (ArgType == AType.Ref)
4622 mode |= AddressOp.Load;
4624 IMemoryLocation ml = (IMemoryLocation) Expr;
4625 ParameterReference pr = ml as ParameterReference;
4628 // ParameterReferences might already be references, so we want
4629 // to pass just the value
4631 if (pr != null && pr.IsRef)
4634 ml.AddressOf (ec, mode);
4637 public Argument Clone (CloneContext clonectx)
4639 return new Argument (Expr.Clone (clonectx), ArgType);
4644 /// Invocation of methods or delegates.
4646 public class Invocation : ExpressionStatement {
4647 protected ArrayList Arguments;
4648 protected Expression expr;
4649 protected MethodGroupExpr mg;
4650 bool arguments_resolved;
4653 // arguments is an ArrayList, but we do not want to typecast,
4654 // as it might be null.
4656 public Invocation (Expression expr, ArrayList arguments)
4658 SimpleName sn = expr as SimpleName;
4660 this.expr = sn.GetMethodGroup ();
4664 Arguments = arguments;
4666 loc = expr.Location;
4669 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4670 : this (expr, arguments)
4672 this.arguments_resolved = arguments_resolved;
4675 public override Expression CreateExpressionTree (EmitContext ec)
4680 // Special conversion for nested expression trees
4682 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4683 args = new ArrayList (1);
4684 args.Add (new Argument (this));
4685 return CreateExpressionFactoryCall ("Quote", args);
4688 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4690 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4693 args = new ArrayList (arg_count);
4696 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4698 args.Add (new Argument (new NullLiteral (loc)));
4700 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4703 // Use extension argument when exists
4706 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4708 args.Add (new Argument (e));
4711 if (Arguments != null) {
4712 foreach (Argument a in Arguments) {
4713 Expression e = a.Expr.CreateExpressionTree (ec);
4715 args.Add (new Argument (e));
4720 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4722 return CreateExpressionFactoryCall ("Call", args);
4725 public override Expression DoResolve (EmitContext ec)
4727 // Don't resolve already resolved expression
4728 if (eclass != ExprClass.Invalid)
4731 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4732 if (expr_resolved == null)
4735 mg = expr_resolved as MethodGroupExpr;
4737 Type expr_type = expr_resolved.Type;
4739 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4740 return (new DelegateInvocation (
4741 expr_resolved, Arguments, loc)).Resolve (ec);
4744 MemberExpr me = expr_resolved as MemberExpr;
4746 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4750 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4752 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4753 expr_resolved.GetSignatureForError ());
4757 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4761 // Next, evaluate all the expressions in the argument list
4763 if (Arguments != null && !arguments_resolved) {
4764 for (int i = 0; i < Arguments.Count; ++i)
4766 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4771 mg = DoResolveOverload (ec);
4775 MethodInfo method = (MethodInfo)mg;
4776 if (method != null) {
4777 type = TypeManager.TypeToCoreType (method.ReturnType);
4779 // TODO: this is a copy of mg.ResolveMemberAccess method
4780 Expression iexpr = mg.InstanceExpression;
4781 if (method.IsStatic) {
4782 if (iexpr == null ||
4783 iexpr is This || iexpr is EmptyExpression ||
4784 mg.IdenticalTypeName) {
4785 mg.InstanceExpression = null;
4787 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4793 if (type.IsPointer){
4801 // Only base will allow this invocation to happen.
4803 if (mg.IsBase && method.IsAbstract){
4804 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4808 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4810 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4812 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4816 IsSpecialMethodInvocation (method, loc);
4818 if (mg.InstanceExpression != null)
4819 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4821 eclass = ExprClass.Value;
4825 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4827 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4830 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4832 if (!TypeManager.IsSpecialMethod (method))
4835 Report.SymbolRelatedToPreviousError (method);
4836 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4837 TypeManager.CSharpSignature (method, true));
4843 /// Emits a list of resolved Arguments that are in the arguments
4846 /// The MethodBase argument might be null if the
4847 /// emission of the arguments is known not to contain
4848 /// a `params' field (for example in constructors or other routines
4849 /// that keep their arguments in this structure)
4851 /// if `dup_args' is true, a copy of the arguments will be left
4852 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4853 /// which will be duplicated before any other args. Only EmitCall
4854 /// should be using this interface.
4856 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4858 if (arguments == null)
4861 int top = arguments.Count;
4862 LocalTemporary [] temps = null;
4864 if (dup_args && top != 0)
4865 temps = new LocalTemporary [top];
4867 int argument_index = 0;
4869 for (int i = 0; i < top; i++) {
4870 a = (Argument) arguments [argument_index++];
4873 ec.ig.Emit (OpCodes.Dup);
4874 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4879 if (this_arg != null)
4882 for (int i = 0; i < top; i ++) {
4883 temps [i].Emit (ec);
4884 temps [i].Release (ec);
4889 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4891 ParameterData pd = TypeManager.GetParameterData (mb);
4893 if (arguments == null)
4894 return Type.EmptyTypes;
4896 Argument a = (Argument) arguments [pd.Count - 1];
4897 Arglist list = (Arglist) a.Expr;
4899 return list.ArgumentTypes;
4903 /// This checks the ConditionalAttribute on the method
4905 public static bool IsMethodExcluded (MethodBase method, Location loc)
4907 if (method.IsConstructor)
4910 method = TypeManager.DropGenericMethodArguments (method);
4911 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4912 IMethodData md = TypeManager.GetMethod (method);
4914 return md.IsExcluded ();
4916 // For some methods (generated by delegate class) GetMethod returns null
4917 // because they are not included in builder_to_method table
4921 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4925 /// is_base tells whether we want to force the use of the `call'
4926 /// opcode instead of using callvirt. Call is required to call
4927 /// a specific method, while callvirt will always use the most
4928 /// recent method in the vtable.
4930 /// is_static tells whether this is an invocation on a static method
4932 /// instance_expr is an expression that represents the instance
4933 /// it must be non-null if is_static is false.
4935 /// method is the method to invoke.
4937 /// Arguments is the list of arguments to pass to the method or constructor.
4939 public static void EmitCall (EmitContext ec, bool is_base,
4940 Expression instance_expr,
4941 MethodBase method, ArrayList Arguments, Location loc)
4943 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4946 // `dup_args' leaves an extra copy of the arguments on the stack
4947 // `omit_args' does not leave any arguments at all.
4948 // So, basically, you could make one call with `dup_args' set to true,
4949 // and then another with `omit_args' set to true, and the two calls
4950 // would have the same set of arguments. However, each argument would
4951 // only have been evaluated once.
4952 public static void EmitCall (EmitContext ec, bool is_base,
4953 Expression instance_expr,
4954 MethodBase method, ArrayList Arguments, Location loc,
4955 bool dup_args, bool omit_args)
4957 ILGenerator ig = ec.ig;
4958 bool struct_call = false;
4959 bool this_call = false;
4960 LocalTemporary this_arg = null;
4962 Type decl_type = method.DeclaringType;
4964 if (!ec.IsInObsoleteScope) {
4966 // This checks ObsoleteAttribute on the method and on the declaring type
4968 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4970 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4972 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4974 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4978 if (IsMethodExcluded (method, loc))
4981 bool is_static = method.IsStatic;
4983 if (instance_expr == EmptyExpression.Null) {
4984 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4988 this_call = instance_expr is This;
4989 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4993 // If this is ourselves, push "this"
4997 Type iexpr_type = instance_expr.Type;
5000 // Push the instance expression
5002 if (TypeManager.IsValueType (iexpr_type)) {
5004 // Special case: calls to a function declared in a
5005 // reference-type with a value-type argument need
5006 // to have their value boxed.
5007 if (decl_type.IsValueType ||
5008 TypeManager.IsGenericParameter (iexpr_type)) {
5010 // If the expression implements IMemoryLocation, then
5011 // we can optimize and use AddressOf on the
5014 // If not we have to use some temporary storage for
5016 if (instance_expr is IMemoryLocation) {
5017 ((IMemoryLocation)instance_expr).
5018 AddressOf (ec, AddressOp.LoadStore);
5020 LocalTemporary temp = new LocalTemporary (iexpr_type);
5021 instance_expr.Emit (ec);
5023 temp.AddressOf (ec, AddressOp.Load);
5026 // avoid the overhead of doing this all the time.
5028 t = TypeManager.GetReferenceType (iexpr_type);
5030 instance_expr.Emit (ec);
5031 ig.Emit (OpCodes.Box, instance_expr.Type);
5032 t = TypeManager.object_type;
5035 instance_expr.Emit (ec);
5036 t = instance_expr.Type;
5040 ig.Emit (OpCodes.Dup);
5041 if (Arguments != null && Arguments.Count != 0) {
5042 this_arg = new LocalTemporary (t);
5043 this_arg.Store (ec);
5050 EmitArguments (ec, Arguments, dup_args, this_arg);
5053 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5054 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5058 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5059 call_op = OpCodes.Call;
5061 call_op = OpCodes.Callvirt;
5063 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5064 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5065 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5072 // and DoFoo is not virtual, you can omit the callvirt,
5073 // because you don't need the null checking behavior.
5075 if (method is MethodInfo)
5076 ig.Emit (call_op, (MethodInfo) method);
5078 ig.Emit (call_op, (ConstructorInfo) method);
5081 public override void Emit (EmitContext ec)
5083 mg.EmitCall (ec, Arguments);
5086 public override void EmitStatement (EmitContext ec)
5091 // Pop the return value if there is one
5093 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5094 ec.ig.Emit (OpCodes.Pop);
5097 protected override void CloneTo (CloneContext clonectx, Expression t)
5099 Invocation target = (Invocation) t;
5101 if (Arguments != null) {
5102 target.Arguments = new ArrayList (Arguments.Count);
5103 foreach (Argument a in Arguments)
5104 target.Arguments.Add (a.Clone (clonectx));
5107 target.expr = expr.Clone (clonectx);
5110 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5112 mg.MutateHoistedGenericType (storey);
5113 if (Arguments != null) {
5114 foreach (Argument a in Arguments)
5115 a.Expr.MutateHoistedGenericType (storey);
5120 public class InvocationOrCast : ExpressionStatement
5123 Expression argument;
5125 public InvocationOrCast (Expression expr, Expression argument)
5128 this.argument = argument;
5129 this.loc = expr.Location;
5132 public override Expression CreateExpressionTree (EmitContext ec)
5134 throw new NotSupportedException ("ET");
5137 public override Expression DoResolve (EmitContext ec)
5140 // First try to resolve it as a cast.
5142 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5143 if ((te != null) && (te.eclass == ExprClass.Type)) {
5144 Cast cast = new Cast (te, argument, loc);
5145 return cast.Resolve (ec);
5149 // This can either be a type or a delegate invocation.
5150 // Let's just resolve it and see what we'll get.
5152 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5157 // Ok, so it's a Cast.
5159 if (expr.eclass == ExprClass.Type) {
5160 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5161 return cast.Resolve (ec);
5165 // It's a delegate invocation.
5167 if (!TypeManager.IsDelegateType (expr.Type)) {
5168 Error (149, "Method name expected");
5172 ArrayList args = new ArrayList ();
5173 args.Add (new Argument (argument, Argument.AType.Expression));
5174 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5175 return invocation.Resolve (ec);
5178 public override ExpressionStatement ResolveStatement (EmitContext ec)
5181 // First try to resolve it as a cast.
5183 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5184 if ((te != null) && (te.eclass == ExprClass.Type)) {
5185 Error_InvalidExpressionStatement ();
5190 // This can either be a type or a delegate invocation.
5191 // Let's just resolve it and see what we'll get.
5193 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5194 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5195 Error_InvalidExpressionStatement ();
5200 // It's a delegate invocation.
5202 if (!TypeManager.IsDelegateType (expr.Type)) {
5203 Error (149, "Method name expected");
5207 ArrayList args = new ArrayList ();
5208 args.Add (new Argument (argument, Argument.AType.Expression));
5209 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5210 return invocation.ResolveStatement (ec);
5213 public override void Emit (EmitContext ec)
5215 throw new Exception ("Cannot happen");
5218 public override void EmitStatement (EmitContext ec)
5220 throw new Exception ("Cannot happen");
5223 protected override void CloneTo (CloneContext clonectx, Expression t)
5225 InvocationOrCast target = (InvocationOrCast) t;
5227 target.expr = expr.Clone (clonectx);
5228 target.argument = argument.Clone (clonectx);
5233 // This class is used to "disable" the code generation for the
5234 // temporary variable when initializing value types.
5236 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5237 public void AddressOf (EmitContext ec, AddressOp Mode)
5244 /// Implements the new expression
5246 public class New : ExpressionStatement, IMemoryLocation {
5247 ArrayList Arguments;
5250 // During bootstrap, it contains the RequestedType,
5251 // but if `type' is not null, it *might* contain a NewDelegate
5252 // (because of field multi-initialization)
5254 public Expression RequestedType;
5256 MethodGroupExpr method;
5259 // If set, the new expression is for a value_target, and
5260 // we will not leave anything on the stack.
5262 protected Expression value_target;
5263 protected bool value_target_set;
5264 bool is_type_parameter = false;
5266 public New (Expression requested_type, ArrayList arguments, Location l)
5268 RequestedType = requested_type;
5269 Arguments = arguments;
5273 public bool SetTargetVariable (Expression value)
5275 value_target = value;
5276 value_target_set = true;
5277 if (!(value_target is IMemoryLocation)){
5278 Error_UnexpectedKind (null, "variable", loc);
5285 // This function is used to disable the following code sequence for
5286 // value type initialization:
5288 // AddressOf (temporary)
5292 // Instead the provide will have provided us with the address on the
5293 // stack to store the results.
5295 static Expression MyEmptyExpression;
5297 public void DisableTemporaryValueType ()
5299 if (MyEmptyExpression == null)
5300 MyEmptyExpression = new EmptyAddressOf ();
5303 // To enable this, look into:
5304 // test-34 and test-89 and self bootstrapping.
5306 // For instance, we can avoid a copy by using `newobj'
5307 // instead of Call + Push-temp on value types.
5308 // value_target = MyEmptyExpression;
5313 /// Converts complex core type syntax like 'new int ()' to simple constant
5315 public static Constant Constantify (Type t)
5317 if (t == TypeManager.int32_type)
5318 return new IntConstant (0, Location.Null);
5319 if (t == TypeManager.uint32_type)
5320 return new UIntConstant (0, Location.Null);
5321 if (t == TypeManager.int64_type)
5322 return new LongConstant (0, Location.Null);
5323 if (t == TypeManager.uint64_type)
5324 return new ULongConstant (0, Location.Null);
5325 if (t == TypeManager.float_type)
5326 return new FloatConstant (0, Location.Null);
5327 if (t == TypeManager.double_type)
5328 return new DoubleConstant (0, Location.Null);
5329 if (t == TypeManager.short_type)
5330 return new ShortConstant (0, Location.Null);
5331 if (t == TypeManager.ushort_type)
5332 return new UShortConstant (0, Location.Null);
5333 if (t == TypeManager.sbyte_type)
5334 return new SByteConstant (0, Location.Null);
5335 if (t == TypeManager.byte_type)
5336 return new ByteConstant (0, Location.Null);
5337 if (t == TypeManager.char_type)
5338 return new CharConstant ('\0', Location.Null);
5339 if (t == TypeManager.bool_type)
5340 return new BoolConstant (false, Location.Null);
5341 if (t == TypeManager.decimal_type)
5342 return new DecimalConstant (0, Location.Null);
5343 if (TypeManager.IsEnumType (t))
5344 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5350 // Checks whether the type is an interface that has the
5351 // [ComImport, CoClass] attributes and must be treated
5354 public Expression CheckComImport (EmitContext ec)
5356 if (!type.IsInterface)
5360 // Turn the call into:
5361 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5363 Type real_class = AttributeTester.GetCoClassAttribute (type);
5364 if (real_class == null)
5367 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5368 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5369 return cast.Resolve (ec);
5372 public override Expression CreateExpressionTree (EmitContext ec)
5374 ArrayList args = Arguments == null ?
5375 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5377 if (method == null) {
5378 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5380 args.Add (new Argument (method.CreateExpressionTree (ec)));
5381 if (Arguments != null) {
5383 foreach (Argument a in Arguments) {
5384 expr = a.Expr.CreateExpressionTree (ec);
5386 args.Add (new Argument (expr));
5391 return CreateExpressionFactoryCall ("New", args);
5394 public override Expression DoResolve (EmitContext ec)
5397 // The New DoResolve might be called twice when initializing field
5398 // expressions (see EmitFieldInitializers, the call to
5399 // GetInitializerExpression will perform a resolve on the expression,
5400 // and later the assign will trigger another resolution
5402 // This leads to bugs (#37014)
5405 if (RequestedType is NewDelegate)
5406 return RequestedType;
5410 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5416 if (type == TypeManager.void_type) {
5417 Error_VoidInvalidInTheContext (loc);
5421 if (type.IsPointer) {
5422 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5423 TypeManager.CSharpName (type));
5427 if (Arguments == null) {
5428 Expression c = Constantify (type);
5433 if (TypeManager.IsDelegateType (type)) {
5434 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5438 if (type.IsGenericParameter) {
5439 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5441 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5442 Error (304, String.Format (
5443 "Cannot create an instance of the " +
5444 "variable type '{0}' because it " +
5445 "doesn't have the new() constraint",
5450 if ((Arguments != null) && (Arguments.Count != 0)) {
5451 Error (417, String.Format (
5452 "`{0}': cannot provide arguments " +
5453 "when creating an instance of a " +
5454 "variable type.", type));
5458 if (TypeManager.activator_create_instance == null) {
5459 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5460 if (activator_type != null) {
5461 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5462 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5466 is_type_parameter = true;
5467 eclass = ExprClass.Value;
5472 if (type.IsAbstract && type.IsSealed) {
5473 Report.SymbolRelatedToPreviousError (type);
5474 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5478 if (type.IsInterface || type.IsAbstract){
5479 if (!TypeManager.IsGenericType (type)) {
5480 RequestedType = CheckComImport (ec);
5481 if (RequestedType != null)
5482 return RequestedType;
5485 Report.SymbolRelatedToPreviousError (type);
5486 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5490 bool is_struct = type.IsValueType;
5491 eclass = ExprClass.Value;
5494 // SRE returns a match for .ctor () on structs (the object constructor),
5495 // so we have to manually ignore it.
5497 if (is_struct && Arguments == null)
5500 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5501 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5502 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5504 if (Arguments != null){
5505 foreach (Argument a in Arguments){
5506 if (!a.Resolve (ec, loc))
5514 method = ml as MethodGroupExpr;
5515 if (method == null) {
5516 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5520 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5527 bool DoEmitTypeParameter (EmitContext ec)
5530 ILGenerator ig = ec.ig;
5531 // IMemoryLocation ml;
5533 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5534 new Type [] { type });
5536 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5537 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5538 ig.Emit (OpCodes.Call, ci);
5542 // Allow DoEmit() to be called multiple times.
5543 // We need to create a new LocalTemporary each time since
5544 // you can't share LocalBuilders among ILGeneators.
5545 LocalTemporary temp = new LocalTemporary (type);
5547 Label label_activator = ig.DefineLabel ();
5548 Label label_end = ig.DefineLabel ();
5550 temp.AddressOf (ec, AddressOp.Store);
5551 ig.Emit (OpCodes.Initobj, type);
5554 ig.Emit (OpCodes.Box, type);
5555 ig.Emit (OpCodes.Brfalse, label_activator);
5557 temp.AddressOf (ec, AddressOp.Store);
5558 ig.Emit (OpCodes.Initobj, type);
5560 ig.Emit (OpCodes.Br, label_end);
5562 ig.MarkLabel (label_activator);
5564 ig.Emit (OpCodes.Call, ci);
5565 ig.MarkLabel (label_end);
5568 throw new InternalErrorException ();
5573 // This DoEmit can be invoked in two contexts:
5574 // * As a mechanism that will leave a value on the stack (new object)
5575 // * As one that wont (init struct)
5577 // You can control whether a value is required on the stack by passing
5578 // need_value_on_stack. The code *might* leave a value on the stack
5579 // so it must be popped manually
5581 // If we are dealing with a ValueType, we have a few
5582 // situations to deal with:
5584 // * The target is a ValueType, and we have been provided
5585 // the instance (this is easy, we are being assigned).
5587 // * The target of New is being passed as an argument,
5588 // to a boxing operation or a function that takes a
5591 // In this case, we need to create a temporary variable
5592 // that is the argument of New.
5594 // Returns whether a value is left on the stack
5596 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5598 bool is_value_type = TypeManager.IsValueType (type);
5599 ILGenerator ig = ec.ig;
5604 // Allow DoEmit() to be called multiple times.
5605 // We need to create a new LocalTemporary each time since
5606 // you can't share LocalBuilders among ILGeneators.
5607 if (!value_target_set)
5608 value_target = new LocalTemporary (type);
5610 ml = (IMemoryLocation) value_target;
5611 ml.AddressOf (ec, AddressOp.Store);
5615 method.EmitArguments (ec, Arguments);
5619 ig.Emit (OpCodes.Initobj, type);
5621 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5622 if (need_value_on_stack){
5623 value_target.Emit (ec);
5628 ConstructorInfo ci = (ConstructorInfo) method;
5630 if (TypeManager.IsGenericType (type))
5631 ci = TypeBuilder.GetConstructor (type, ci);
5633 ig.Emit (OpCodes.Newobj, ci);
5638 public override void Emit (EmitContext ec)
5640 if (is_type_parameter)
5641 DoEmitTypeParameter (ec);
5646 public override void EmitStatement (EmitContext ec)
5648 bool value_on_stack;
5650 if (is_type_parameter)
5651 value_on_stack = DoEmitTypeParameter (ec);
5653 value_on_stack = DoEmit (ec, false);
5656 ec.ig.Emit (OpCodes.Pop);
5660 public virtual bool HasInitializer {
5666 public void AddressOf (EmitContext ec, AddressOp Mode)
5668 if (is_type_parameter) {
5669 LocalTemporary temp = new LocalTemporary (type);
5670 DoEmitTypeParameter (ec);
5672 temp.AddressOf (ec, Mode);
5676 if (!type.IsValueType){
5678 // We throw an exception. So far, I believe we only need to support
5680 // foreach (int j in new StructType ())
5683 throw new Exception ("AddressOf should not be used for classes");
5686 if (!value_target_set)
5687 value_target = new LocalTemporary (type);
5688 IMemoryLocation ml = (IMemoryLocation) value_target;
5690 ml.AddressOf (ec, AddressOp.Store);
5691 if (method == null) {
5692 ec.ig.Emit (OpCodes.Initobj, type);
5694 method.EmitArguments (ec, Arguments);
5695 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5698 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5701 protected override void CloneTo (CloneContext clonectx, Expression t)
5703 New target = (New) t;
5705 target.RequestedType = RequestedType.Clone (clonectx);
5706 if (Arguments != null){
5707 target.Arguments = new ArrayList ();
5708 foreach (Argument a in Arguments){
5709 target.Arguments.Add (a.Clone (clonectx));
5714 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5716 if (method != null) {
5717 method.MutateHoistedGenericType (storey);
5718 if (Arguments != null) {
5719 foreach (Argument a in Arguments)
5720 a.Expr.MutateHoistedGenericType (storey);
5724 type = storey.MutateType (type);
5729 /// 14.5.10.2: Represents an array creation expression.
5733 /// There are two possible scenarios here: one is an array creation
5734 /// expression that specifies the dimensions and optionally the
5735 /// initialization data and the other which does not need dimensions
5736 /// specified but where initialization data is mandatory.
5738 public class ArrayCreation : Expression {
5739 FullNamedExpression requested_base_type;
5740 ArrayList initializers;
5743 // The list of Argument types.
5744 // This is used to construct the `newarray' or constructor signature
5746 protected ArrayList arguments;
5748 protected Type array_element_type;
5749 bool expect_initializers = false;
5750 int num_arguments = 0;
5751 protected int dimensions;
5752 protected readonly string rank;
5754 protected ArrayList array_data;
5758 // The number of constants in array initializers
5759 int const_initializers_count;
5760 bool only_constant_initializers;
5762 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5764 this.requested_base_type = requested_base_type;
5765 this.initializers = initializers;
5769 arguments = new ArrayList (exprs.Count);
5771 foreach (Expression e in exprs) {
5772 arguments.Add (new Argument (e, Argument.AType.Expression));
5777 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5779 this.requested_base_type = requested_base_type;
5780 this.initializers = initializers;
5784 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5786 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5788 //dimensions = tmp.Length - 1;
5789 expect_initializers = true;
5792 void Error_IncorrectArrayInitializer ()
5794 Error (178, "Invalid rank specifier: expected `,' or `]'");
5797 protected override void Error_NegativeArrayIndex (Location loc)
5799 Report.Error (248, loc, "Cannot create an array with a negative size");
5802 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5804 if (specified_dims) {
5805 Argument a = (Argument) arguments [idx];
5807 if (!a.Resolve (ec, loc))
5810 Constant c = a.Expr as Constant;
5812 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5816 Report.Error (150, a.Expr.Location, "A constant value is expected");
5820 int value = (int) c.GetValue ();
5822 if (value != probe.Count) {
5823 Error_IncorrectArrayInitializer ();
5827 bounds [idx] = value;
5830 int child_bounds = -1;
5831 only_constant_initializers = true;
5832 for (int i = 0; i < probe.Count; ++i) {
5833 object o = probe [i];
5834 if (o is ArrayList) {
5835 ArrayList sub_probe = o as ArrayList;
5836 int current_bounds = sub_probe.Count;
5838 if (child_bounds == -1)
5839 child_bounds = current_bounds;
5841 else if (child_bounds != current_bounds){
5842 Error_IncorrectArrayInitializer ();
5845 if (idx + 1 >= dimensions){
5846 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5850 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5854 if (child_bounds != -1){
5855 Error_IncorrectArrayInitializer ();
5859 Expression element = ResolveArrayElement (ec, (Expression) o);
5860 if (element == null)
5863 // Initializers with the default values can be ignored
5864 Constant c = element as Constant;
5866 if (c.IsDefaultInitializer (array_element_type)) {
5870 ++const_initializers_count;
5873 only_constant_initializers = false;
5876 array_data.Add (element);
5883 public override Expression CreateExpressionTree (EmitContext ec)
5887 if (array_data == null) {
5888 args = new ArrayList (arguments.Count + 1);
5889 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5890 foreach (Argument a in arguments) {
5891 if (arguments.Count == 1) {
5892 Constant c = a.Expr as Constant;
5893 if (c.IsDefaultValue)
5894 return CreateExpressionFactoryCall ("NewArrayInit", args);
5896 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5899 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5902 if (dimensions > 1) {
5903 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5907 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5908 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5909 if (array_data != null) {
5910 for (int i = 0; i < array_data.Count; ++i) {
5911 Expression e = (Expression) array_data [i];
5913 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5915 args.Add (new Argument (e.CreateExpressionTree (ec)));
5919 return CreateExpressionFactoryCall ("NewArrayInit", args);
5922 public void UpdateIndices ()
5925 for (ArrayList probe = initializers; probe != null;) {
5926 if (probe.Count > 0 && probe [0] is ArrayList) {
5927 Expression e = new IntConstant (probe.Count, Location.Null);
5928 arguments.Add (new Argument (e, Argument.AType.Expression));
5930 bounds [i++] = probe.Count;
5932 probe = (ArrayList) probe [0];
5935 Expression e = new IntConstant (probe.Count, Location.Null);
5936 arguments.Add (new Argument (e, Argument.AType.Expression));
5938 bounds [i++] = probe.Count;
5945 Expression first_emit;
5946 LocalTemporary first_emit_temp;
5948 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5950 element = element.Resolve (ec);
5951 if (element == null)
5954 if (element is CompoundAssign.Helper) {
5955 if (first_emit != null)
5956 throw new InternalErrorException ("Can only handle one mutator at a time");
5957 first_emit = element;
5958 element = first_emit_temp = new LocalTemporary (element.Type);
5961 return Convert.ImplicitConversionRequired (
5962 ec, element, array_element_type, loc);
5965 protected bool ResolveInitializers (EmitContext ec)
5967 if (initializers == null) {
5968 return !expect_initializers;
5972 // We use this to store all the date values in the order in which we
5973 // will need to store them in the byte blob later
5975 array_data = new ArrayList ();
5976 bounds = new System.Collections.Specialized.HybridDictionary ();
5978 if (arguments != null)
5979 return CheckIndices (ec, initializers, 0, true);
5981 arguments = new ArrayList ();
5983 if (!CheckIndices (ec, initializers, 0, false))
5992 // Resolved the type of the array
5994 bool ResolveArrayType (EmitContext ec)
5996 if (requested_base_type == null) {
5997 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6001 StringBuilder array_qualifier = new StringBuilder (rank);
6004 // `In the first form allocates an array instace of the type that results
6005 // from deleting each of the individual expression from the expression list'
6007 if (num_arguments > 0) {
6008 array_qualifier.Append ("[");
6009 for (int i = num_arguments-1; i > 0; i--)
6010 array_qualifier.Append (",");
6011 array_qualifier.Append ("]");
6017 TypeExpr array_type_expr;
6018 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6019 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6020 if (array_type_expr == null)
6023 type = array_type_expr.Type;
6024 array_element_type = TypeManager.GetElementType (type);
6025 dimensions = type.GetArrayRank ();
6030 public override Expression DoResolve (EmitContext ec)
6035 if (!ResolveArrayType (ec))
6039 // First step is to validate the initializers and fill
6040 // in any missing bits
6042 if (!ResolveInitializers (ec))
6045 if (arguments.Count != dimensions) {
6046 Error_IncorrectArrayInitializer ();
6049 foreach (Argument a in arguments){
6050 if (!a.Resolve (ec, loc))
6053 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6056 eclass = ExprClass.Value;
6060 MethodInfo GetArrayMethod (int arguments)
6062 ModuleBuilder mb = CodeGen.Module.Builder;
6064 Type[] arg_types = new Type[arguments];
6065 for (int i = 0; i < arguments; i++)
6066 arg_types[i] = TypeManager.int32_type;
6068 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6072 Report.Error (-6, "New invocation: Can not find a constructor for " +
6073 "this argument list");
6080 byte [] MakeByteBlob ()
6085 int count = array_data.Count;
6087 if (TypeManager.IsEnumType (array_element_type))
6088 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6090 factor = GetTypeSize (array_element_type);
6092 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6094 data = new byte [(count * factor + 3) & ~3];
6097 for (int i = 0; i < count; ++i) {
6098 object v = array_data [i];
6100 if (v is EnumConstant)
6101 v = ((EnumConstant) v).Child;
6103 if (v is Constant && !(v is StringConstant))
6104 v = ((Constant) v).GetValue ();
6110 if (array_element_type == TypeManager.int64_type){
6111 if (!(v is Expression)){
6112 long val = (long) v;
6114 for (int j = 0; j < factor; ++j) {
6115 data [idx + j] = (byte) (val & 0xFF);
6119 } else if (array_element_type == TypeManager.uint64_type){
6120 if (!(v is Expression)){
6121 ulong val = (ulong) v;
6123 for (int j = 0; j < factor; ++j) {
6124 data [idx + j] = (byte) (val & 0xFF);
6128 } else if (array_element_type == TypeManager.float_type) {
6129 if (!(v is Expression)){
6130 element = BitConverter.GetBytes ((float) v);
6132 for (int j = 0; j < factor; ++j)
6133 data [idx + j] = element [j];
6134 if (!BitConverter.IsLittleEndian)
6135 System.Array.Reverse (data, idx, 4);
6137 } else if (array_element_type == TypeManager.double_type) {
6138 if (!(v is Expression)){
6139 element = BitConverter.GetBytes ((double) v);
6141 for (int j = 0; j < factor; ++j)
6142 data [idx + j] = element [j];
6144 // FIXME: Handle the ARM float format.
6145 if (!BitConverter.IsLittleEndian)
6146 System.Array.Reverse (data, idx, 8);
6148 } else if (array_element_type == TypeManager.char_type){
6149 if (!(v is Expression)){
6150 int val = (int) ((char) v);
6152 data [idx] = (byte) (val & 0xff);
6153 data [idx+1] = (byte) (val >> 8);
6155 } else if (array_element_type == TypeManager.short_type){
6156 if (!(v is Expression)){
6157 int val = (int) ((short) v);
6159 data [idx] = (byte) (val & 0xff);
6160 data [idx+1] = (byte) (val >> 8);
6162 } else if (array_element_type == TypeManager.ushort_type){
6163 if (!(v is Expression)){
6164 int val = (int) ((ushort) v);
6166 data [idx] = (byte) (val & 0xff);
6167 data [idx+1] = (byte) (val >> 8);
6169 } else if (array_element_type == TypeManager.int32_type) {
6170 if (!(v is Expression)){
6173 data [idx] = (byte) (val & 0xff);
6174 data [idx+1] = (byte) ((val >> 8) & 0xff);
6175 data [idx+2] = (byte) ((val >> 16) & 0xff);
6176 data [idx+3] = (byte) (val >> 24);
6178 } else if (array_element_type == TypeManager.uint32_type) {
6179 if (!(v is Expression)){
6180 uint val = (uint) v;
6182 data [idx] = (byte) (val & 0xff);
6183 data [idx+1] = (byte) ((val >> 8) & 0xff);
6184 data [idx+2] = (byte) ((val >> 16) & 0xff);
6185 data [idx+3] = (byte) (val >> 24);
6187 } else if (array_element_type == TypeManager.sbyte_type) {
6188 if (!(v is Expression)){
6189 sbyte val = (sbyte) v;
6190 data [idx] = (byte) val;
6192 } else if (array_element_type == TypeManager.byte_type) {
6193 if (!(v is Expression)){
6194 byte val = (byte) v;
6195 data [idx] = (byte) val;
6197 } else if (array_element_type == TypeManager.bool_type) {
6198 if (!(v is Expression)){
6199 bool val = (bool) v;
6200 data [idx] = (byte) (val ? 1 : 0);
6202 } else if (array_element_type == TypeManager.decimal_type){
6203 if (!(v is Expression)){
6204 int [] bits = Decimal.GetBits ((decimal) v);
6207 // FIXME: For some reason, this doesn't work on the MS runtime.
6208 int [] nbits = new int [4];
6209 nbits [0] = bits [3];
6210 nbits [1] = bits [2];
6211 nbits [2] = bits [0];
6212 nbits [3] = bits [1];
6214 for (int j = 0; j < 4; j++){
6215 data [p++] = (byte) (nbits [j] & 0xff);
6216 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6217 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6218 data [p++] = (byte) (nbits [j] >> 24);
6222 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6230 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6232 array_element_type = storey.MutateType (array_element_type);
6233 type = storey.MutateType (type);
6234 if (arguments != null) {
6235 foreach (Argument a in arguments)
6236 a.Expr.MutateHoistedGenericType (storey);
6239 if (array_data != null) {
6240 foreach (Expression e in array_data)
6241 e.MutateHoistedGenericType (storey);
6246 // Emits the initializers for the array
6248 void EmitStaticInitializers (EmitContext ec)
6250 // FIXME: This should go to Resolve !
6251 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6252 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6253 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6254 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6255 if (TypeManager.void_initializearray_array_fieldhandle == null)
6260 // First, the static data
6263 ILGenerator ig = ec.ig;
6265 byte [] data = MakeByteBlob ();
6267 fb = RootContext.MakeStaticData (data);
6269 ig.Emit (OpCodes.Dup);
6270 ig.Emit (OpCodes.Ldtoken, fb);
6271 ig.Emit (OpCodes.Call,
6272 TypeManager.void_initializearray_array_fieldhandle);
6276 // Emits pieces of the array that can not be computed at compile
6277 // time (variables and string locations).
6279 // This always expect the top value on the stack to be the array
6281 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6283 ILGenerator ig = ec.ig;
6284 int dims = bounds.Count;
6285 int [] current_pos = new int [dims];
6287 MethodInfo set = null;
6290 Type [] args = new Type [dims + 1];
6292 for (int j = 0; j < dims; j++)
6293 args [j] = TypeManager.int32_type;
6294 args [dims] = array_element_type;
6296 set = CodeGen.Module.Builder.GetArrayMethod (
6298 CallingConventions.HasThis | CallingConventions.Standard,
6299 TypeManager.void_type, args);
6302 for (int i = 0; i < array_data.Count; i++){
6304 Expression e = (Expression)array_data [i];
6306 // Constant can be initialized via StaticInitializer
6307 if (e != null && !(!emitConstants && e is Constant)) {
6308 Type etype = e.Type;
6310 ig.Emit (OpCodes.Dup);
6312 for (int idx = 0; idx < dims; idx++)
6313 IntConstant.EmitInt (ig, current_pos [idx]);
6316 // If we are dealing with a struct, get the
6317 // address of it, so we can store it.
6319 if ((dims == 1) && etype.IsValueType &&
6320 (!TypeManager.IsBuiltinOrEnum (etype) ||
6321 etype == TypeManager.decimal_type)) {
6326 // Let new know that we are providing
6327 // the address where to store the results
6329 n.DisableTemporaryValueType ();
6332 ig.Emit (OpCodes.Ldelema, etype);
6338 bool is_stobj, has_type_arg;
6339 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6341 ig.Emit (OpCodes.Stobj, etype);
6342 else if (has_type_arg)
6343 ig.Emit (op, etype);
6347 ig.Emit (OpCodes.Call, set);
6354 for (int j = dims - 1; j >= 0; j--){
6356 if (current_pos [j] < (int) bounds [j])
6358 current_pos [j] = 0;
6363 public override void Emit (EmitContext ec)
6365 ILGenerator ig = ec.ig;
6367 if (first_emit != null) {
6368 first_emit.Emit (ec);
6369 first_emit_temp.Store (ec);
6372 foreach (Argument a in arguments)
6375 if (arguments.Count == 1)
6376 ig.Emit (OpCodes.Newarr, array_element_type);
6378 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6381 if (initializers == null)
6384 // Emit static initializer for arrays which have contain more than 4 items and
6385 // the static initializer will initialize at least 25% of array values.
6386 // NOTE: const_initializers_count does not contain default constant values.
6387 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6388 TypeManager.IsPrimitiveType (array_element_type)) {
6389 EmitStaticInitializers (ec);
6391 if (!only_constant_initializers)
6392 EmitDynamicInitializers (ec, false);
6394 EmitDynamicInitializers (ec, true);
6397 if (first_emit_temp != null)
6398 first_emit_temp.Release (ec);
6401 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6403 if (arguments.Count != 1) {
6404 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6405 return base.GetAttributableValue (ec, null, out value);
6408 if (array_data == null) {
6409 Constant c = (Constant)((Argument)arguments [0]).Expr;
6410 if (c.IsDefaultValue) {
6411 value = Array.CreateInstance (array_element_type, 0);
6414 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6415 return base.GetAttributableValue (ec, null, out value);
6418 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6419 object element_value;
6420 for (int i = 0; i < ret.Length; ++i)
6422 Expression e = (Expression)array_data [i];
6424 // Is null when an initializer is optimized (value == predefined value)
6428 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6432 ret.SetValue (element_value, i);
6438 protected override void CloneTo (CloneContext clonectx, Expression t)
6440 ArrayCreation target = (ArrayCreation) t;
6442 if (requested_base_type != null)
6443 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6445 if (arguments != null){
6446 target.arguments = new ArrayList (arguments.Count);
6447 foreach (Argument a in arguments)
6448 target.arguments.Add (a.Clone (clonectx));
6451 if (initializers != null){
6452 target.initializers = new ArrayList (initializers.Count);
6453 foreach (object initializer in initializers)
6454 if (initializer is ArrayList) {
6455 ArrayList this_al = (ArrayList)initializer;
6456 ArrayList al = new ArrayList (this_al.Count);
6457 target.initializers.Add (al);
6458 foreach (Expression e in this_al)
6459 al.Add (e.Clone (clonectx));
6461 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6468 // Represents an implicitly typed array epxression
6470 public class ImplicitlyTypedArrayCreation : ArrayCreation
6472 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6473 : base (null, rank, initializers, loc)
6475 if (RootContext.Version <= LanguageVersion.ISO_2)
6476 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6478 if (rank.Length > 2) {
6479 while (rank [++dimensions] == ',');
6485 public override Expression DoResolve (EmitContext ec)
6490 if (!ResolveInitializers (ec))
6493 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6494 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6495 arguments.Count != dimensions) {
6496 Error_NoBestType ();
6501 // At this point we found common base type for all initializer elements
6502 // but we have to be sure that all static initializer elements are of
6505 UnifyInitializerElement (ec);
6507 type = TypeManager.GetConstructedType (array_element_type, rank);
6508 eclass = ExprClass.Value;
6512 void Error_NoBestType ()
6514 Report.Error (826, loc,
6515 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6519 // Converts static initializer only
6521 void UnifyInitializerElement (EmitContext ec)
6523 for (int i = 0; i < array_data.Count; ++i) {
6524 Expression e = (Expression)array_data[i];
6526 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6530 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6532 element = element.Resolve (ec);
6533 if (element == null)
6536 if (array_element_type == null) {
6537 array_element_type = element.Type;
6541 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6545 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6546 array_element_type = element.Type;
6550 Error_NoBestType ();
6555 public sealed class CompilerGeneratedThis : This
6557 public static This Instance = new CompilerGeneratedThis ();
6559 private CompilerGeneratedThis ()
6560 : base (Location.Null)
6564 public CompilerGeneratedThis (Type type, Location loc)
6570 public override Expression DoResolve (EmitContext ec)
6572 eclass = ExprClass.Variable;
6574 type = ec.ContainerType;
6578 public override HoistedVariable HoistedVariable {
6579 get { return null; }
6584 /// Represents the `this' construct
6587 public class This : VariableReference
6589 sealed class ThisVariable : ILocalVariable
6591 public static readonly ILocalVariable Instance = new ThisVariable ();
6593 public void Emit (EmitContext ec)
6595 ec.ig.Emit (OpCodes.Ldarg_0);
6598 public void EmitAssign (EmitContext ec)
6600 throw new InvalidOperationException ();
6603 public void EmitAddressOf (EmitContext ec)
6605 ec.ig.Emit (OpCodes.Ldarg_0);
6610 VariableInfo variable_info;
6613 public This (Block block, Location loc)
6619 public This (Location loc)
6624 public override VariableInfo VariableInfo {
6625 get { return variable_info; }
6628 public override bool IsFixedVariable {
6629 get { return !TypeManager.IsValueType (type); }
6632 protected override bool IsHoistedEmitRequired (EmitContext ec)
6635 // Handle 'this' differently, it cannot be assigned hence
6636 // when we are not inside anonymous method we can emit direct access
6638 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6641 public override HoistedVariable HoistedVariable {
6642 get { return TopToplevelBlock.HoistedThisVariable; }
6645 public override bool IsRef {
6646 get { return is_struct; }
6649 protected override ILocalVariable Variable {
6650 get { return ThisVariable.Instance; }
6653 // TODO: Move to ToplevelBlock
6654 ToplevelBlock TopToplevelBlock {
6656 ToplevelBlock tl = block.Toplevel;
6657 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6662 public static bool IsThisAvailable (EmitContext ec)
6664 if (ec.IsStatic || ec.IsInFieldInitializer)
6667 if (ec.CurrentAnonymousMethod == null)
6670 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6676 public bool ResolveBase (EmitContext ec)
6678 eclass = ExprClass.Variable;
6680 if (ec.TypeContainer.CurrentType != null)
6681 type = ec.TypeContainer.CurrentType;
6683 type = ec.ContainerType;
6685 if (!IsThisAvailable (ec)) {
6687 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6689 Report.Error (1673, loc,
6690 "Anonymous methods inside structs cannot access instance members of `this'. " +
6691 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6695 is_struct = ec.TypeContainer is Struct;
6697 if (block != null) {
6698 if (block.Toplevel.ThisVariable != null)
6699 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6701 AnonymousExpression am = ec.CurrentAnonymousMethod;
6704 // this is hoisted to very top level block
6706 if (ec.IsVariableCapturingRequired) {
6707 // TODO: it could be optimized
6708 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6709 if (HoistedVariable == null) {
6710 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6720 // Called from Invocation to check if the invocation is correct
6722 public override void CheckMarshalByRefAccess (EmitContext ec)
6724 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6725 !variable_info.IsAssigned (ec)) {
6726 Error (188, "The `this' object cannot be used before all of its " +
6727 "fields are assigned to");
6728 variable_info.SetAssigned (ec);
6732 public override Expression CreateExpressionTree (EmitContext ec)
6734 ArrayList args = new ArrayList (2);
6735 args.Add (new Argument (this));
6736 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6737 return CreateExpressionFactoryCall ("Constant", args);
6740 public override Expression DoResolve (EmitContext ec)
6742 if (!ResolveBase (ec))
6746 if (ec.IsInFieldInitializer) {
6747 Error (27, "Keyword `this' is not available in the current context");
6754 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6756 if (!ResolveBase (ec))
6759 if (variable_info != null)
6760 variable_info.SetAssigned (ec);
6762 if (ec.TypeContainer is Class){
6763 if (right_side == EmptyExpression.UnaryAddress)
6764 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6765 else if (right_side == EmptyExpression.OutAccess)
6766 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6768 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6774 public override int GetHashCode()
6776 return block.GetHashCode ();
6779 public override string Name {
6780 get { return "this"; }
6783 public override bool Equals (object obj)
6785 This t = obj as This;
6789 return block == t.block;
6792 protected override void CloneTo (CloneContext clonectx, Expression t)
6794 This target = (This) t;
6796 target.block = clonectx.LookupBlock (block);
6799 public void RemoveHoisting ()
6801 TopToplevelBlock.HoistedThisVariable = null;
6804 public override void SetHasAddressTaken ()
6811 /// Represents the `__arglist' construct
6813 public class ArglistAccess : Expression
6815 public ArglistAccess (Location loc)
6820 public override Expression CreateExpressionTree (EmitContext ec)
6822 throw new NotSupportedException ("ET");
6825 public override Expression DoResolve (EmitContext ec)
6827 eclass = ExprClass.Variable;
6828 type = TypeManager.runtime_argument_handle_type;
6830 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6832 Error (190, "The __arglist construct is valid only within " +
6833 "a variable argument method");
6840 public override void Emit (EmitContext ec)
6842 ec.ig.Emit (OpCodes.Arglist);
6845 protected override void CloneTo (CloneContext clonectx, Expression target)
6852 /// Represents the `__arglist (....)' construct
6854 public class Arglist : Expression
6856 Argument[] Arguments;
6858 public Arglist (Location loc)
6859 : this (Argument.Empty, loc)
6863 public Arglist (Argument[] args, Location l)
6869 public Type[] ArgumentTypes {
6871 Type[] retval = new Type [Arguments.Length];
6872 for (int i = 0; i < Arguments.Length; i++)
6873 retval [i] = Arguments [i].Type;
6878 public override Expression CreateExpressionTree (EmitContext ec)
6880 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6884 public override Expression DoResolve (EmitContext ec)
6886 eclass = ExprClass.Variable;
6887 type = TypeManager.runtime_argument_handle_type;
6889 foreach (Argument arg in Arguments) {
6890 if (!arg.Resolve (ec, loc))
6897 public override void Emit (EmitContext ec)
6899 foreach (Argument arg in Arguments)
6903 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6905 foreach (Argument arg in Arguments)
6906 arg.Expr.MutateHoistedGenericType (storey);
6909 protected override void CloneTo (CloneContext clonectx, Expression t)
6911 Arglist target = (Arglist) t;
6913 target.Arguments = new Argument [Arguments.Length];
6914 for (int i = 0; i < Arguments.Length; i++)
6915 target.Arguments [i] = Arguments [i].Clone (clonectx);
6920 /// Implements the typeof operator
6922 public class TypeOf : Expression {
6923 Expression QueriedType;
6924 protected Type typearg;
6926 public TypeOf (Expression queried_type, Location l)
6928 QueriedType = queried_type;
6932 public override Expression CreateExpressionTree (EmitContext ec)
6934 ArrayList args = new ArrayList (2);
6935 args.Add (new Argument (this));
6936 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6937 return CreateExpressionFactoryCall ("Constant", args);
6940 public override Expression DoResolve (EmitContext ec)
6942 if (eclass != ExprClass.Invalid)
6945 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6949 typearg = texpr.Type;
6951 if (typearg == TypeManager.void_type) {
6952 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6956 if (typearg.IsPointer && !ec.InUnsafe){
6961 type = TypeManager.type_type;
6963 return DoResolveBase ();
6966 protected Expression DoResolveBase ()
6968 if (TypeManager.system_type_get_type_from_handle == null) {
6969 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6970 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6973 // Even though what is returned is a type object, it's treated as a value by the compiler.
6974 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6975 eclass = ExprClass.Value;
6979 public override void Emit (EmitContext ec)
6981 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6982 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6985 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6987 if (TypeManager.ContainsGenericParameters (typearg) &&
6988 !TypeManager.IsGenericTypeDefinition (typearg)) {
6989 Report.SymbolRelatedToPreviousError (typearg);
6990 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6991 TypeManager.CSharpName (typearg));
6996 if (value_type == TypeManager.object_type) {
6997 value = (object)typearg;
7004 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7006 typearg = storey.MutateType (typearg);
7009 public Type TypeArgument {
7015 protected override void CloneTo (CloneContext clonectx, Expression t)
7017 TypeOf target = (TypeOf) t;
7018 if (QueriedType != null)
7019 target.QueriedType = QueriedType.Clone (clonectx);
7024 /// Implements the `typeof (void)' operator
7026 public class TypeOfVoid : TypeOf {
7027 public TypeOfVoid (Location l) : base (null, l)
7032 public override Expression DoResolve (EmitContext ec)
7034 type = TypeManager.type_type;
7035 typearg = TypeManager.void_type;
7037 return DoResolveBase ();
7041 class TypeOfMethodInfo : TypeOfMethod
7043 public TypeOfMethodInfo (MethodBase method, Location loc)
7044 : base (method, loc)
7048 public override Expression DoResolve (EmitContext ec)
7050 type = typeof (MethodInfo);
7051 return base.DoResolve (ec);
7054 public override void Emit (EmitContext ec)
7056 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7058 ec.ig.Emit (OpCodes.Castclass, type);
7062 class TypeOfConstructorInfo : TypeOfMethod
7064 public TypeOfConstructorInfo (MethodBase method, Location loc)
7065 : base (method, loc)
7069 public override Expression DoResolve (EmitContext ec)
7071 type = typeof (ConstructorInfo);
7072 return base.DoResolve (ec);
7075 public override void Emit (EmitContext ec)
7077 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7079 ec.ig.Emit (OpCodes.Castclass, type);
7083 abstract class TypeOfMethod : Expression
7085 protected readonly MethodBase method;
7087 protected TypeOfMethod (MethodBase method, Location loc)
7089 this.method = method;
7093 public override Expression CreateExpressionTree (EmitContext ec)
7095 ArrayList args = new ArrayList (2);
7096 args.Add (new Argument (this));
7097 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7098 return CreateExpressionFactoryCall ("Constant", args);
7101 public override Expression DoResolve (EmitContext ec)
7103 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7104 MethodInfo mi = is_generic ?
7105 TypeManager.methodbase_get_type_from_handle_generic :
7106 TypeManager.methodbase_get_type_from_handle;
7109 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7110 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7112 if (t == null || handle_type == null)
7115 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7117 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7118 new Type[] { handle_type } );
7121 TypeManager.methodbase_get_type_from_handle_generic = mi;
7123 TypeManager.methodbase_get_type_from_handle = mi;
7126 eclass = ExprClass.Value;
7130 public override void Emit (EmitContext ec)
7132 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7135 mi = TypeManager.methodbase_get_type_from_handle_generic;
7136 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7138 mi = TypeManager.methodbase_get_type_from_handle;
7141 ec.ig.Emit (OpCodes.Call, mi);
7145 internal class TypeOfField : Expression
7147 readonly FieldInfo field;
7149 public TypeOfField (FieldInfo field, Location loc)
7155 public override Expression CreateExpressionTree (EmitContext ec)
7157 throw new NotSupportedException ("ET");
7160 public override Expression DoResolve (EmitContext ec)
7162 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7163 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7164 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7166 if (t != null && handle_type != null)
7167 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7168 "GetFieldFromHandle", loc, handle_type);
7171 type = typeof (FieldInfo);
7172 eclass = ExprClass.Value;
7176 public override void Emit (EmitContext ec)
7178 ec.ig.Emit (OpCodes.Ldtoken, field);
7179 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7184 /// Implements the sizeof expression
7186 public class SizeOf : Expression {
7187 readonly Expression QueriedType;
7190 public SizeOf (Expression queried_type, Location l)
7192 this.QueriedType = queried_type;
7196 public override Expression CreateExpressionTree (EmitContext ec)
7198 Error_PointerInsideExpressionTree ();
7202 public override Expression DoResolve (EmitContext ec)
7204 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7208 type_queried = texpr.Type;
7209 if (TypeManager.IsEnumType (type_queried))
7210 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7212 if (type_queried == TypeManager.void_type) {
7213 Expression.Error_VoidInvalidInTheContext (loc);
7217 int size_of = GetTypeSize (type_queried);
7219 return new IntConstant (size_of, loc);
7222 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7227 Report.Error (233, loc,
7228 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7229 TypeManager.CSharpName (type_queried));
7232 type = TypeManager.int32_type;
7233 eclass = ExprClass.Value;
7237 public override void Emit (EmitContext ec)
7239 int size = GetTypeSize (type_queried);
7242 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7244 IntConstant.EmitInt (ec.ig, size);
7247 protected override void CloneTo (CloneContext clonectx, Expression t)
7253 /// Implements the qualified-alias-member (::) expression.
7255 public class QualifiedAliasMember : MemberAccess
7257 readonly string alias;
7258 public static readonly string GlobalAlias = "global";
7260 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7261 : base (null, identifier, targs, l)
7266 public QualifiedAliasMember (string alias, string identifier, Location l)
7267 : base (null, identifier, l)
7272 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7274 if (alias == GlobalAlias) {
7275 expr = RootNamespace.Global;
7276 return base.ResolveAsTypeStep (ec, silent);
7279 int errors = Report.Errors;
7280 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7282 if (errors == Report.Errors)
7283 Report.Error (432, loc, "Alias `{0}' not found", alias);
7287 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7291 if (expr.eclass == ExprClass.Type) {
7293 Report.Error (431, loc,
7294 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7302 public override Expression DoResolve (EmitContext ec)
7304 return ResolveAsTypeStep (ec, false);
7307 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7309 Report.Error (687, loc,
7310 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7311 GetSignatureForError ());
7314 public override string GetSignatureForError ()
7317 if (targs != null) {
7318 name = TypeManager.RemoveGenericArity (Name) + "<" +
7319 targs.GetSignatureForError () + ">";
7322 return alias + "::" + name;
7325 protected override void CloneTo (CloneContext clonectx, Expression t)
7332 /// Implements the member access expression
7334 public class MemberAccess : ATypeNameExpression {
7335 protected Expression expr;
7337 public MemberAccess (Expression expr, string id)
7338 : base (id, expr.Location)
7343 public MemberAccess (Expression expr, string identifier, Location loc)
7344 : base (identifier, loc)
7349 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7350 : base (identifier, args, loc)
7355 // TODO: this method has very poor performace for Enum fields and
7356 // probably for other constants as well
7357 Expression DoResolve (EmitContext ec, Expression right_side)
7360 throw new Exception ();
7363 // Resolve the expression with flow analysis turned off, we'll do the definite
7364 // assignment checks later. This is because we don't know yet what the expression
7365 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7366 // definite assignment check on the actual field and not on the whole struct.
7369 SimpleName original = expr as SimpleName;
7370 Expression expr_resolved = expr.Resolve (ec,
7371 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7372 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7374 if (expr_resolved == null)
7377 string LookupIdentifier = MemberName.MakeName (Name, targs);
7379 if (expr_resolved is Namespace) {
7380 Namespace ns = (Namespace) expr_resolved;
7381 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7383 if ((retval != null) && (targs != null))
7384 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7388 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7392 Type expr_type = expr_resolved.Type;
7393 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7394 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7395 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7399 Constant c = expr_resolved as Constant;
7400 if (c != null && c.GetValue () == null) {
7401 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7402 "System.NullReferenceException");
7405 if (targs != null) {
7406 if (!targs.Resolve (ec))
7410 Expression member_lookup;
7411 member_lookup = MemberLookup (
7412 ec.ContainerType, expr_type, expr_type, Name, loc);
7414 if ((member_lookup == null) && (targs != null)) {
7415 member_lookup = MemberLookup (
7416 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7419 if (member_lookup == null) {
7420 ExprClass expr_eclass = expr_resolved.eclass;
7423 // Extension methods are not allowed on all expression types
7425 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7426 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7427 expr_eclass == ExprClass.EventAccess) {
7428 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7429 if (ex_method_lookup != null) {
7430 ex_method_lookup.ExtensionExpression = expr_resolved;
7432 if (targs != null) {
7433 ex_method_lookup.SetTypeArguments (targs);
7436 return ex_method_lookup.DoResolve (ec);
7440 expr = expr_resolved;
7441 Error_MemberLookupFailed (
7442 ec.ContainerType, expr_type, expr_type, Name, null,
7443 AllMemberTypes, AllBindingFlags);
7447 TypeExpr texpr = member_lookup as TypeExpr;
7448 if (texpr != null) {
7449 if (!(expr_resolved is TypeExpr) &&
7450 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7451 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7452 Name, member_lookup.GetSignatureForError ());
7456 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7457 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7458 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7463 ConstructedType ct = expr_resolved as ConstructedType;
7466 // When looking up a nested type in a generic instance
7467 // via reflection, we always get a generic type definition
7468 // and not a generic instance - so we have to do this here.
7470 // See gtest-172-lib.cs and gtest-172.cs for an example.
7472 ct = new ConstructedType (
7473 member_lookup.Type, ct.TypeArguments, loc);
7475 return ct.ResolveAsTypeStep (ec, false);
7478 return member_lookup;
7481 MemberExpr me = (MemberExpr) member_lookup;
7482 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7486 if (targs != null) {
7487 me.SetTypeArguments (targs);
7490 if (original != null && !TypeManager.IsValueType (expr_type)) {
7491 if (me.IsInstance) {
7492 LocalVariableReference var = expr_resolved as LocalVariableReference;
7493 if (var != null && !var.VerifyAssigned (ec))
7498 // The following DoResolve/DoResolveLValue will do the definite assignment
7501 if (right_side != null)
7502 return me.DoResolveLValue (ec, right_side);
7504 return me.DoResolve (ec);
7507 public override Expression DoResolve (EmitContext ec)
7509 return DoResolve (ec, null);
7512 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7514 return DoResolve (ec, right_side);
7517 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7519 return ResolveNamespaceOrType (ec, silent);
7522 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7524 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7526 if (new_expr == null)
7529 string LookupIdentifier = MemberName.MakeName (Name, targs);
7531 if (new_expr is Namespace) {
7532 Namespace ns = (Namespace) new_expr;
7533 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7535 if ((retval != null) && (targs != null))
7536 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7538 if (!silent && retval == null)
7539 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7543 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7544 if (tnew_expr == null)
7547 Type expr_type = tnew_expr.Type;
7549 if (expr_type.IsPointer){
7550 Error (23, "The `.' operator can not be applied to pointer operands (" +
7551 TypeManager.CSharpName (expr_type) + ")");
7555 Expression member_lookup = MemberLookup (
7556 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7557 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7558 if (member_lookup == null) {
7562 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7566 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7571 TypeArguments the_args = targs;
7572 Type declaring_type = texpr.Type.DeclaringType;
7573 if (TypeManager.HasGenericArguments (declaring_type)) {
7574 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7575 expr_type = expr_type.BaseType;
7578 TypeArguments new_args = new TypeArguments (loc);
7579 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7580 new_args.Add (new TypeExpression (decl, loc));
7583 new_args.Add (targs);
7585 the_args = new_args;
7588 if (the_args != null) {
7589 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7590 return ctype.ResolveAsTypeStep (rc, false);
7597 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7599 Expression member_lookup = MemberLookup (
7600 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7601 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7603 if (member_lookup != null) {
7604 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7605 if (expr_type == null)
7608 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7612 member_lookup = MemberLookup (
7613 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7614 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7616 if (member_lookup == null) {
7617 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7618 Name, expr_type.GetSignatureForError ());
7620 // TODO: Report.SymbolRelatedToPreviousError
7621 member_lookup.Error_UnexpectedKind (null, "type", loc);
7625 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7627 if (RootContext.Version > LanguageVersion.ISO_2 &&
7628 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7629 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7630 "extension method `{1}' of type `{0}' could be found " +
7631 "(are you missing a using directive or an assembly reference?)",
7632 TypeManager.CSharpName (type), name);
7636 base.Error_TypeDoesNotContainDefinition (type, name);
7639 public override string GetSignatureForError ()
7641 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7644 protected override void CloneTo (CloneContext clonectx, Expression t)
7646 MemberAccess target = (MemberAccess) t;
7648 target.expr = expr.Clone (clonectx);
7653 /// Implements checked expressions
7655 public class CheckedExpr : Expression {
7657 public Expression Expr;
7659 public CheckedExpr (Expression e, Location l)
7665 public override Expression CreateExpressionTree (EmitContext ec)
7667 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7668 return Expr.CreateExpressionTree (ec);
7671 public override Expression DoResolve (EmitContext ec)
7673 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7674 Expr = Expr.Resolve (ec);
7679 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7682 eclass = Expr.eclass;
7687 public override void Emit (EmitContext ec)
7689 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7693 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7695 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7696 Expr.EmitBranchable (ec, target, on_true);
7699 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7701 Expr.MutateHoistedGenericType (storey);
7704 protected override void CloneTo (CloneContext clonectx, Expression t)
7706 CheckedExpr target = (CheckedExpr) t;
7708 target.Expr = Expr.Clone (clonectx);
7713 /// Implements the unchecked expression
7715 public class UnCheckedExpr : Expression {
7717 public Expression Expr;
7719 public UnCheckedExpr (Expression e, Location l)
7725 public override Expression CreateExpressionTree (EmitContext ec)
7727 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7728 return Expr.CreateExpressionTree (ec);
7731 public override Expression DoResolve (EmitContext ec)
7733 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7734 Expr = Expr.Resolve (ec);
7739 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7742 eclass = Expr.eclass;
7747 public override void Emit (EmitContext ec)
7749 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7753 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7755 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7756 Expr.EmitBranchable (ec, target, on_true);
7759 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7761 Expr.MutateHoistedGenericType (storey);
7764 protected override void CloneTo (CloneContext clonectx, Expression t)
7766 UnCheckedExpr target = (UnCheckedExpr) t;
7768 target.Expr = Expr.Clone (clonectx);
7773 /// An Element Access expression.
7775 /// During semantic analysis these are transformed into
7776 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7778 public class ElementAccess : Expression {
7779 public ArrayList Arguments;
7780 public Expression Expr;
7782 public ElementAccess (Expression e, ArrayList e_list)
7790 Arguments = new ArrayList (e_list.Count);
7791 foreach (Expression tmp in e_list)
7792 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7795 bool CommonResolve (EmitContext ec)
7797 Expr = Expr.Resolve (ec);
7799 if (Arguments == null)
7802 foreach (Argument a in Arguments){
7803 if (!a.Resolve (ec, loc))
7807 return Expr != null;
7810 public override Expression CreateExpressionTree (EmitContext ec)
7812 ArrayList args = new ArrayList (Arguments.Count + 1);
7813 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7814 foreach (Argument a in Arguments)
7815 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7817 return CreateExpressionFactoryCall ("ArrayIndex", args);
7820 Expression MakePointerAccess (EmitContext ec, Type t)
7822 if (Arguments.Count != 1){
7823 Error (196, "A pointer must be indexed by only one value");
7827 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7830 return new Indirection (p, loc).Resolve (ec);
7833 public override Expression DoResolve (EmitContext ec)
7835 if (!CommonResolve (ec))
7839 // We perform some simple tests, and then to "split" the emit and store
7840 // code we create an instance of a different class, and return that.
7842 // I am experimenting with this pattern.
7846 if (t == TypeManager.array_type){
7847 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7852 return (new ArrayAccess (this, loc)).Resolve (ec);
7854 return MakePointerAccess (ec, t);
7856 FieldExpr fe = Expr as FieldExpr;
7858 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7860 return MakePointerAccess (ec, ff.ElementType);
7863 return (new IndexerAccess (this, loc)).Resolve (ec);
7866 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7868 if (!CommonResolve (ec))
7873 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7876 return MakePointerAccess (ec, type);
7878 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7879 Error_CannotModifyIntermediateExpressionValue (ec);
7881 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7884 public override void Emit (EmitContext ec)
7886 throw new Exception ("Should never be reached");
7889 public override string GetSignatureForError ()
7891 return Expr.GetSignatureForError ();
7894 protected override void CloneTo (CloneContext clonectx, Expression t)
7896 ElementAccess target = (ElementAccess) t;
7898 target.Expr = Expr.Clone (clonectx);
7899 target.Arguments = new ArrayList (Arguments.Count);
7900 foreach (Argument a in Arguments)
7901 target.Arguments.Add (a.Clone (clonectx));
7906 /// Implements array access
7908 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7910 // Points to our "data" repository
7914 LocalTemporary temp;
7918 public ArrayAccess (ElementAccess ea_data, Location l)
7924 public override Expression CreateExpressionTree (EmitContext ec)
7926 return ea.CreateExpressionTree (ec);
7929 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7931 return DoResolve (ec);
7934 public override Expression DoResolve (EmitContext ec)
7937 ExprClass eclass = ea.Expr.eclass;
7939 // As long as the type is valid
7940 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7941 eclass == ExprClass.Value)) {
7942 ea.Expr.Error_UnexpectedKind ("variable or value");
7947 if (eclass != ExprClass.Invalid)
7950 Type t = ea.Expr.Type;
7951 int rank = ea.Arguments.Count;
7952 if (t.GetArrayRank () != rank) {
7953 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7954 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7958 type = TypeManager.GetElementType (t);
7959 if (type.IsPointer && !ec.InUnsafe) {
7960 UnsafeError (ea.Location);
7964 foreach (Argument a in ea.Arguments) {
7965 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7968 eclass = ExprClass.Variable;
7974 /// Emits the right opcode to load an object of Type `t'
7975 /// from an array of T
7977 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7980 MethodInfo get = FetchGetMethod ();
7981 ig.Emit (OpCodes.Call, get);
7985 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7986 ig.Emit (OpCodes.Ldelem_U1);
7987 else if (type == TypeManager.sbyte_type)
7988 ig.Emit (OpCodes.Ldelem_I1);
7989 else if (type == TypeManager.short_type)
7990 ig.Emit (OpCodes.Ldelem_I2);
7991 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7992 ig.Emit (OpCodes.Ldelem_U2);
7993 else if (type == TypeManager.int32_type)
7994 ig.Emit (OpCodes.Ldelem_I4);
7995 else if (type == TypeManager.uint32_type)
7996 ig.Emit (OpCodes.Ldelem_U4);
7997 else if (type == TypeManager.uint64_type)
7998 ig.Emit (OpCodes.Ldelem_I8);
7999 else if (type == TypeManager.int64_type)
8000 ig.Emit (OpCodes.Ldelem_I8);
8001 else if (type == TypeManager.float_type)
8002 ig.Emit (OpCodes.Ldelem_R4);
8003 else if (type == TypeManager.double_type)
8004 ig.Emit (OpCodes.Ldelem_R8);
8005 else if (type == TypeManager.intptr_type)
8006 ig.Emit (OpCodes.Ldelem_I);
8007 else if (TypeManager.IsEnumType (type)){
8008 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8009 } else if (type.IsValueType){
8010 ig.Emit (OpCodes.Ldelema, type);
8011 ig.Emit (OpCodes.Ldobj, type);
8013 } else if (type.IsGenericParameter) {
8014 ig.Emit (OpCodes.Ldelem, type);
8016 } else if (type.IsPointer)
8017 ig.Emit (OpCodes.Ldelem_I);
8019 ig.Emit (OpCodes.Ldelem_Ref);
8022 protected override void Error_NegativeArrayIndex (Location loc)
8024 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8028 /// Returns the right opcode to store an object of Type `t'
8029 /// from an array of T.
8031 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8033 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8034 has_type_arg = false; is_stobj = false;
8035 t = TypeManager.TypeToCoreType (t);
8036 if (TypeManager.IsEnumType (t))
8037 t = TypeManager.GetEnumUnderlyingType (t);
8038 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8039 t == TypeManager.bool_type)
8040 return OpCodes.Stelem_I1;
8041 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8042 t == TypeManager.char_type)
8043 return OpCodes.Stelem_I2;
8044 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8045 return OpCodes.Stelem_I4;
8046 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8047 return OpCodes.Stelem_I8;
8048 else if (t == TypeManager.float_type)
8049 return OpCodes.Stelem_R4;
8050 else if (t == TypeManager.double_type)
8051 return OpCodes.Stelem_R8;
8052 else if (t == TypeManager.intptr_type) {
8053 has_type_arg = true;
8055 return OpCodes.Stobj;
8056 } else if (t.IsValueType) {
8057 has_type_arg = true;
8059 return OpCodes.Stobj;
8061 } else if (t.IsGenericParameter) {
8062 has_type_arg = true;
8063 return OpCodes.Stelem;
8066 } else if (t.IsPointer)
8067 return OpCodes.Stelem_I;
8069 return OpCodes.Stelem_Ref;
8072 MethodInfo FetchGetMethod ()
8074 ModuleBuilder mb = CodeGen.Module.Builder;
8075 int arg_count = ea.Arguments.Count;
8076 Type [] args = new Type [arg_count];
8079 for (int i = 0; i < arg_count; i++){
8080 //args [i++] = a.Type;
8081 args [i] = TypeManager.int32_type;
8084 get = mb.GetArrayMethod (
8085 ea.Expr.Type, "Get",
8086 CallingConventions.HasThis |
8087 CallingConventions.Standard,
8093 MethodInfo FetchAddressMethod ()
8095 ModuleBuilder mb = CodeGen.Module.Builder;
8096 int arg_count = ea.Arguments.Count;
8097 Type [] args = new Type [arg_count];
8101 ret_type = TypeManager.GetReferenceType (type);
8103 for (int i = 0; i < arg_count; i++){
8104 //args [i++] = a.Type;
8105 args [i] = TypeManager.int32_type;
8108 address = mb.GetArrayMethod (
8109 ea.Expr.Type, "Address",
8110 CallingConventions.HasThis |
8111 CallingConventions.Standard,
8118 // Load the array arguments into the stack.
8120 void LoadArrayAndArguments (EmitContext ec)
8124 for (int i = 0; i < ea.Arguments.Count; ++i) {
8125 ((Argument)ea.Arguments [i]).Emit (ec);
8129 public void Emit (EmitContext ec, bool leave_copy)
8131 int rank = ea.Expr.Type.GetArrayRank ();
8132 ILGenerator ig = ec.ig;
8135 LoadFromPtr (ig, this.type);
8137 LoadArrayAndArguments (ec);
8138 EmitLoadOpcode (ig, type, rank);
8142 ig.Emit (OpCodes.Dup);
8143 temp = new LocalTemporary (this.type);
8148 public override void Emit (EmitContext ec)
8153 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8155 int rank = ea.Expr.Type.GetArrayRank ();
8156 ILGenerator ig = ec.ig;
8157 Type t = source.Type;
8158 prepared = prepare_for_load;
8161 AddressOf (ec, AddressOp.LoadStore);
8162 ec.ig.Emit (OpCodes.Dup);
8164 LoadArrayAndArguments (ec);
8168 bool is_stobj, has_type_arg;
8169 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8173 // The stobj opcode used by value types will need
8174 // an address on the stack, not really an array/array
8178 ig.Emit (OpCodes.Ldelema, t);
8183 ec.ig.Emit (OpCodes.Dup);
8184 temp = new LocalTemporary (this.type);
8189 StoreFromPtr (ig, t);
8191 ig.Emit (OpCodes.Stobj, t);
8192 else if (has_type_arg)
8199 ec.ig.Emit (OpCodes.Dup);
8200 temp = new LocalTemporary (this.type);
8205 StoreFromPtr (ig, t);
8207 int arg_count = ea.Arguments.Count;
8208 Type [] args = new Type [arg_count + 1];
8209 for (int i = 0; i < arg_count; i++) {
8210 //args [i++] = a.Type;
8211 args [i] = TypeManager.int32_type;
8213 args [arg_count] = type;
8215 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8216 ea.Expr.Type, "Set",
8217 CallingConventions.HasThis |
8218 CallingConventions.Standard,
8219 TypeManager.void_type, args);
8221 ig.Emit (OpCodes.Call, set);
8231 public void AddressOf (EmitContext ec, AddressOp mode)
8233 int rank = ea.Expr.Type.GetArrayRank ();
8234 ILGenerator ig = ec.ig;
8236 LoadArrayAndArguments (ec);
8239 ig.Emit (OpCodes.Ldelema, type);
8241 MethodInfo address = FetchAddressMethod ();
8242 ig.Emit (OpCodes.Call, address);
8246 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8248 type = storey.MutateType (type);
8253 /// Expressions that represent an indexer call.
8255 public class IndexerAccess : Expression, IAssignMethod
8257 class IndexerMethodGroupExpr : MethodGroupExpr
8259 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8262 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8265 public override string Name {
8271 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
8274 // Here is the trick, decrease number of arguments by 1 when only
8275 // available property method is setter. This makes overload resolution
8276 // work correctly for indexers.
8279 if (method.Name [0] == 'g')
8280 return parameters.Count;
8282 return parameters.Count - 1;
8288 // Contains either property getter or setter
8289 public ArrayList Methods;
8290 public ArrayList Properties;
8296 void Append (Type caller_type, MemberInfo [] mi)
8301 foreach (PropertyInfo property in mi) {
8302 MethodInfo accessor = property.GetGetMethod (true);
8303 if (accessor == null)
8304 accessor = property.GetSetMethod (true);
8306 if (Methods == null) {
8307 Methods = new ArrayList ();
8308 Properties = new ArrayList ();
8311 Methods.Add (accessor);
8312 Properties.Add (property);
8316 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8318 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8320 return TypeManager.MemberLookup (
8321 caller_type, caller_type, lookup_type, MemberTypes.Property,
8322 BindingFlags.Public | BindingFlags.Instance |
8323 BindingFlags.DeclaredOnly, p_name, null);
8326 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8328 Indexers ix = new Indexers ();
8331 if (lookup_type.IsGenericParameter) {
8332 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8336 if (gc.HasClassConstraint)
8337 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8339 Type[] ifaces = gc.InterfaceConstraints;
8340 foreach (Type itype in ifaces)
8341 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8347 Type copy = lookup_type;
8348 while (copy != TypeManager.object_type && copy != null){
8349 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8350 copy = copy.BaseType;
8353 if (lookup_type.IsInterface) {
8354 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8355 if (ifaces != null) {
8356 foreach (Type itype in ifaces)
8357 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8372 // Points to our "data" repository
8374 MethodInfo get, set;
8375 bool is_base_indexer;
8377 LocalTemporary temp;
8378 LocalTemporary prepared_value;
8379 Expression set_expr;
8381 protected Type indexer_type;
8382 protected Type current_type;
8383 protected Expression instance_expr;
8384 protected ArrayList arguments;
8386 public IndexerAccess (ElementAccess ea, Location loc)
8387 : this (ea.Expr, false, loc)
8389 this.arguments = ea.Arguments;
8392 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8395 this.instance_expr = instance_expr;
8396 this.is_base_indexer = is_base_indexer;
8397 this.eclass = ExprClass.Value;
8401 static string GetAccessorName (AccessorType at)
8403 if (at == AccessorType.Set)
8406 if (at == AccessorType.Get)
8409 throw new NotImplementedException (at.ToString ());
8412 public override Expression CreateExpressionTree (EmitContext ec)
8414 ArrayList args = new ArrayList (arguments.Count + 2);
8415 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8416 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8417 foreach (Argument a in arguments)
8418 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8420 return CreateExpressionFactoryCall ("Call", args);
8423 protected virtual bool CommonResolve (EmitContext ec)
8425 indexer_type = instance_expr.Type;
8426 current_type = ec.ContainerType;
8431 public override Expression DoResolve (EmitContext ec)
8433 return ResolveAccessor (ec, AccessorType.Get);
8436 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8438 if (right_side == EmptyExpression.OutAccess) {
8439 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8440 GetSignatureForError ());
8444 // if the indexer returns a value type, and we try to set a field in it
8445 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8446 Error_CannotModifyIntermediateExpressionValue (ec);
8449 Expression e = ResolveAccessor (ec, AccessorType.Set);
8453 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8457 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8459 if (!CommonResolve (ec))
8462 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8463 if (ilist.Methods == null) {
8464 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8465 TypeManager.CSharpName (indexer_type));
8469 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8470 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8474 MethodInfo mi = (MethodInfo) mg;
8475 PropertyInfo pi = null;
8476 for (int i = 0; i < ilist.Methods.Count; ++i) {
8477 if (ilist.Methods [i] == mi) {
8478 pi = (PropertyInfo) ilist.Properties [i];
8483 type = TypeManager.TypeToCoreType (pi.PropertyType);
8484 if (type.IsPointer && !ec.InUnsafe)
8487 MethodInfo accessor;
8488 if (accessorType == AccessorType.Get) {
8489 accessor = get = pi.GetGetMethod (true);
8491 accessor = set = pi.GetSetMethod (true);
8492 if (accessor == null && pi.GetGetMethod (true) != null) {
8493 Report.SymbolRelatedToPreviousError (pi);
8494 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8495 TypeManager.GetFullNameSignature (pi));
8500 if (accessor == null) {
8501 Report.SymbolRelatedToPreviousError (pi);
8502 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8503 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8508 // Only base will allow this invocation to happen.
8510 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8511 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8514 bool must_do_cs1540_check;
8515 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8517 set = pi.GetSetMethod (true);
8519 get = pi.GetGetMethod (true);
8521 if (set != null && get != null &&
8522 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8523 Report.SymbolRelatedToPreviousError (accessor);
8524 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8525 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8527 Report.SymbolRelatedToPreviousError (pi);
8528 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8532 instance_expr.CheckMarshalByRefAccess (ec);
8533 eclass = ExprClass.IndexerAccess;
8537 public void Emit (EmitContext ec, bool leave_copy)
8540 prepared_value.Emit (ec);
8542 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8543 arguments, loc, false, false);
8547 ec.ig.Emit (OpCodes.Dup);
8548 temp = new LocalTemporary (Type);
8554 // source is ignored, because we already have a copy of it from the
8555 // LValue resolution and we have already constructed a pre-cached
8556 // version of the arguments (ea.set_arguments);
8558 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8560 prepared = prepare_for_load;
8561 Expression value = set_expr;
8564 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8565 arguments, loc, true, false);
8567 prepared_value = new LocalTemporary (type);
8568 prepared_value.Store (ec);
8570 prepared_value.Release (ec);
8573 ec.ig.Emit (OpCodes.Dup);
8574 temp = new LocalTemporary (Type);
8577 } else if (leave_copy) {
8578 temp = new LocalTemporary (Type);
8584 arguments.Add (new Argument (value, Argument.AType.Expression));
8585 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8593 public override void Emit (EmitContext ec)
8598 public override string GetSignatureForError ()
8600 return TypeManager.CSharpSignature (get != null ? get : set, false);
8603 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8606 get = storey.MutateGenericMethod (get);
8608 set = storey.MutateGenericMethod (set);
8610 instance_expr.MutateHoistedGenericType (storey);
8611 foreach (Argument a in arguments)
8612 a.Expr.MutateHoistedGenericType (storey);
8614 type = storey.MutateType (type);
8617 protected override void CloneTo (CloneContext clonectx, Expression t)
8619 IndexerAccess target = (IndexerAccess) t;
8621 if (arguments != null){
8622 target.arguments = new ArrayList ();
8623 foreach (Argument a in arguments)
8624 target.arguments.Add (a.Clone (clonectx));
8626 if (instance_expr != null)
8627 target.instance_expr = instance_expr.Clone (clonectx);
8632 /// The base operator for method names
8634 public class BaseAccess : Expression {
8635 public readonly string Identifier;
8638 public BaseAccess (string member, Location l)
8640 this.Identifier = member;
8644 public BaseAccess (string member, TypeArguments args, Location l)
8650 public override Expression CreateExpressionTree (EmitContext ec)
8652 throw new NotSupportedException ("ET");
8655 public override Expression DoResolve (EmitContext ec)
8657 Expression c = CommonResolve (ec);
8663 // MethodGroups use this opportunity to flag an error on lacking ()
8665 if (!(c is MethodGroupExpr))
8666 return c.Resolve (ec);
8670 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8672 Expression c = CommonResolve (ec);
8678 // MethodGroups use this opportunity to flag an error on lacking ()
8680 if (! (c is MethodGroupExpr))
8681 return c.DoResolveLValue (ec, right_side);
8686 Expression CommonResolve (EmitContext ec)
8688 Expression member_lookup;
8689 Type current_type = ec.ContainerType;
8690 Type base_type = current_type.BaseType;
8692 if (!This.IsThisAvailable (ec)) {
8694 Error (1511, "Keyword `base' is not available in a static method");
8696 Error (1512, "Keyword `base' is not available in the current context");
8701 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8702 AllMemberTypes, AllBindingFlags, loc);
8703 if (member_lookup == null) {
8704 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8705 null, AllMemberTypes, AllBindingFlags);
8712 left = new TypeExpression (base_type, loc);
8714 left = ec.GetThis (loc);
8716 MemberExpr me = (MemberExpr) member_lookup;
8717 me = me.ResolveMemberAccess (ec, left, loc, null);
8724 me.SetTypeArguments (args);
8730 public override void Emit (EmitContext ec)
8732 throw new Exception ("Should never be called");
8735 protected override void CloneTo (CloneContext clonectx, Expression t)
8737 BaseAccess target = (BaseAccess) t;
8740 target.args = args.Clone ();
8745 /// The base indexer operator
8747 public class BaseIndexerAccess : IndexerAccess {
8748 public BaseIndexerAccess (ArrayList args, Location loc)
8749 : base (null, true, loc)
8751 arguments = new ArrayList ();
8752 foreach (Expression tmp in args)
8753 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8756 protected override bool CommonResolve (EmitContext ec)
8758 instance_expr = ec.GetThis (loc);
8760 current_type = ec.ContainerType.BaseType;
8761 indexer_type = current_type;
8763 foreach (Argument a in arguments){
8764 if (!a.Resolve (ec, loc))
8771 public override Expression CreateExpressionTree (EmitContext ec)
8773 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8774 return base.CreateExpressionTree (ec);
8779 /// This class exists solely to pass the Type around and to be a dummy
8780 /// that can be passed to the conversion functions (this is used by
8781 /// foreach implementation to typecast the object return value from
8782 /// get_Current into the proper type. All code has been generated and
8783 /// we only care about the side effect conversions to be performed
8785 /// This is also now used as a placeholder where a no-action expression
8786 /// is needed (the `New' class).
8788 public class EmptyExpression : Expression {
8789 public static readonly EmptyExpression Null = new EmptyExpression ();
8791 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8792 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8793 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8794 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8796 static EmptyExpression temp = new EmptyExpression ();
8797 public static EmptyExpression Grab ()
8799 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8804 public static void Release (EmptyExpression e)
8809 // TODO: should be protected
8810 public EmptyExpression ()
8812 type = TypeManager.object_type;
8813 eclass = ExprClass.Value;
8814 loc = Location.Null;
8817 public EmptyExpression (Type t)
8820 eclass = ExprClass.Value;
8821 loc = Location.Null;
8824 public override Expression CreateExpressionTree (EmitContext ec)
8826 throw new NotSupportedException ("ET");
8829 public override Expression DoResolve (EmitContext ec)
8834 public override void Emit (EmitContext ec)
8836 // nothing, as we only exist to not do anything.
8839 public override void EmitSideEffect (EmitContext ec)
8844 // This is just because we might want to reuse this bad boy
8845 // instead of creating gazillions of EmptyExpressions.
8846 // (CanImplicitConversion uses it)
8848 public void SetType (Type t)
8855 // Empty statement expression
8857 public sealed class EmptyExpressionStatement : ExpressionStatement
8859 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8861 private EmptyExpressionStatement ()
8863 type = TypeManager.object_type;
8864 eclass = ExprClass.Value;
8865 loc = Location.Null;
8868 public override Expression CreateExpressionTree (EmitContext ec)
8873 public override void EmitStatement (EmitContext ec)
8878 public override Expression DoResolve (EmitContext ec)
8883 public override void Emit (EmitContext ec)
8889 public class UserCast : Expression {
8893 public UserCast (MethodInfo method, Expression source, Location l)
8895 this.method = method;
8896 this.source = source;
8897 type = TypeManager.TypeToCoreType (method.ReturnType);
8898 eclass = ExprClass.Value;
8902 public Expression Source {
8908 public override Expression CreateExpressionTree (EmitContext ec)
8910 ArrayList args = new ArrayList (3);
8911 args.Add (new Argument (source.CreateExpressionTree (ec)));
8912 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8913 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8914 return CreateExpressionFactoryCall ("Convert", args);
8917 public override Expression DoResolve (EmitContext ec)
8920 // We are born fully resolved
8925 public override void Emit (EmitContext ec)
8928 ec.ig.Emit (OpCodes.Call, method);
8931 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8933 source.MutateHoistedGenericType (storey);
8934 method = storey.MutateGenericMethod (method);
8939 // This class is used to "construct" the type during a typecast
8940 // operation. Since the Type.GetType class in .NET can parse
8941 // the type specification, we just use this to construct the type
8942 // one bit at a time.
8944 public class ComposedCast : TypeExpr {
8945 FullNamedExpression left;
8948 public ComposedCast (FullNamedExpression left, string dim)
8949 : this (left, dim, left.Location)
8953 public ComposedCast (FullNamedExpression left, string dim, Location l)
8960 public Expression RemoveNullable ()
8962 if (dim.EndsWith ("?")) {
8963 dim = dim.Substring (0, dim.Length - 1);
8964 if (dim.Length == 0)
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 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type) {
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");