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)
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 Expression DoResolveLValue (EmitContext ec, Expression right_side)
111 return Expr.DoResolveLValue (ec, right_side);
114 public override void Emit (EmitContext ec)
116 throw new Exception ("Should not happen");
119 protected override void CloneTo (CloneContext clonectx, Expression t)
121 ParenthesizedExpression target = (ParenthesizedExpression) t;
123 target.Expr = Expr.Clone (clonectx);
128 // Unary implements unary expressions.
130 public class Unary : Expression {
131 public enum Operator : byte {
132 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
136 static Type [] [] predefined_operators;
138 public readonly Operator Oper;
139 public Expression Expr;
140 Expression enum_conversion;
142 public Unary (Operator op, Expression expr)
150 // This routine will attempt to simplify the unary expression when the
151 // argument is a constant.
153 Constant TryReduceConstant (EmitContext ec, Constant e)
155 if (e is EmptyConstantCast)
156 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
158 if (e is SideEffectConstant) {
159 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
160 return r == null ? null : new SideEffectConstant (r, e, r.Location);
163 Type expr_type = e.Type;
166 case Operator.UnaryPlus:
167 // Unary numeric promotions
168 if (expr_type == TypeManager.byte_type)
169 return new IntConstant (((ByteConstant)e).Value, e.Location);
170 if (expr_type == TypeManager.sbyte_type)
171 return new IntConstant (((SByteConstant)e).Value, e.Location);
172 if (expr_type == TypeManager.short_type)
173 return new IntConstant (((ShortConstant)e).Value, e.Location);
174 if (expr_type == TypeManager.ushort_type)
175 return new IntConstant (((UShortConstant)e).Value, e.Location);
176 if (expr_type == TypeManager.char_type)
177 return new IntConstant (((CharConstant)e).Value, e.Location);
179 // Predefined operators
180 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
181 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
182 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
183 expr_type == TypeManager.decimal_type) {
189 case Operator.UnaryNegation:
190 // Unary numeric promotions
191 if (expr_type == TypeManager.byte_type)
192 return new IntConstant (-((ByteConstant)e).Value, e.Location);
193 if (expr_type == TypeManager.sbyte_type)
194 return new IntConstant (-((SByteConstant)e).Value, e.Location);
195 if (expr_type == TypeManager.short_type)
196 return new IntConstant (-((ShortConstant)e).Value, e.Location);
197 if (expr_type == TypeManager.ushort_type)
198 return new IntConstant (-((UShortConstant)e).Value, e.Location);
199 if (expr_type == TypeManager.char_type)
200 return new IntConstant (-((CharConstant)e).Value, e.Location);
202 // Predefined operators
203 if (expr_type == TypeManager.int32_type) {
204 int value = ((IntConstant)e).Value;
205 if (value == int.MinValue) {
206 if (ec.ConstantCheckState) {
207 ConstantFold.Error_CompileTimeOverflow (loc);
212 return new IntConstant (-value, e.Location);
214 if (expr_type == TypeManager.int64_type) {
215 long value = ((LongConstant)e).Value;
216 if (value == long.MinValue) {
217 if (ec.ConstantCheckState) {
218 ConstantFold.Error_CompileTimeOverflow (loc);
223 return new LongConstant (-value, e.Location);
226 if (expr_type == TypeManager.uint32_type) {
227 UIntLiteral uil = e as UIntLiteral;
229 if (uil.Value == 2147483648)
230 return new IntLiteral (int.MinValue, e.Location);
231 return new LongLiteral (-uil.Value, e.Location);
233 return new LongConstant (-((UIntConstant)e).Value, e.Location);
236 if (expr_type == TypeManager.uint64_type) {
237 ULongLiteral ull = e as ULongLiteral;
238 if (ull != null && ull.Value == 9223372036854775808)
239 return new LongLiteral (long.MinValue, e.Location);
243 if (expr_type == TypeManager.float_type) {
244 FloatLiteral fl = e as FloatLiteral;
245 // For better error reporting
247 fl.Value = -fl.Value;
250 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
252 if (expr_type == TypeManager.double_type) {
253 DoubleLiteral dl = e as DoubleLiteral;
254 // For better error reporting
256 dl.Value = -dl.Value;
260 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
262 if (expr_type == TypeManager.decimal_type)
263 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
267 case Operator.LogicalNot:
268 if (expr_type != TypeManager.bool_type)
271 bool b = (bool)e.GetValue ();
272 return new BoolConstant (!b, e.Location);
274 case Operator.OnesComplement:
275 // Unary numeric promotions
276 if (expr_type == TypeManager.byte_type)
277 return new IntConstant (~((ByteConstant)e).Value, e.Location);
278 if (expr_type == TypeManager.sbyte_type)
279 return new IntConstant (~((SByteConstant)e).Value, e.Location);
280 if (expr_type == TypeManager.short_type)
281 return new IntConstant (~((ShortConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.ushort_type)
283 return new IntConstant (~((UShortConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.char_type)
285 return new IntConstant (~((CharConstant)e).Value, e.Location);
287 // Predefined operators
288 if (expr_type == TypeManager.int32_type)
289 return new IntConstant (~((IntConstant)e).Value, e.Location);
290 if (expr_type == TypeManager.uint32_type)
291 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
292 if (expr_type == TypeManager.int64_type)
293 return new LongConstant (~((LongConstant)e).Value, e.Location);
294 if (expr_type == TypeManager.uint64_type){
295 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
297 if (e is EnumConstant) {
298 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
300 e = new EnumConstant (e, expr_type);
305 throw new Exception ("Can not constant fold: " + Oper.ToString());
308 protected Expression ResolveOperator (EmitContext ec, Expression expr)
310 eclass = ExprClass.Value;
312 if (predefined_operators == null)
313 CreatePredefinedOperatorsTable ();
315 Type expr_type = expr.Type;
316 Expression best_expr;
319 // Primitive types first
321 if (TypeManager.IsPrimitiveType (expr_type)) {
322 best_expr = ResolvePrimitivePredefinedType (expr);
323 if (best_expr == null)
326 type = best_expr.Type;
332 // E operator ~(E x);
334 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
335 return ResolveEnumOperator (ec, expr);
337 return ResolveUserType (ec, expr);
340 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
342 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
343 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
344 if (best_expr == null)
348 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
350 return EmptyCast.Create (this, type);
353 public override Expression CreateExpressionTree (EmitContext ec)
355 return CreateExpressionTree (ec, null);
358 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
362 case Operator.AddressOf:
363 Error_PointerInsideExpressionTree ();
365 case Operator.UnaryNegation:
366 if (ec.CheckState && user_op == null && !IsFloat (type))
367 method_name = "NegateChecked";
369 method_name = "Negate";
371 case Operator.OnesComplement:
372 case Operator.LogicalNot:
375 case Operator.UnaryPlus:
376 method_name = "UnaryPlus";
379 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
382 ArrayList args = new ArrayList (2);
383 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
385 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
386 return CreateExpressionFactoryCall (method_name, args);
389 static void CreatePredefinedOperatorsTable ()
391 predefined_operators = new Type [(int) Operator.TOP] [];
394 // 7.6.1 Unary plus operator
396 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
397 TypeManager.int32_type, TypeManager.uint32_type,
398 TypeManager.int64_type, TypeManager.uint64_type,
399 TypeManager.float_type, TypeManager.double_type,
400 TypeManager.decimal_type
404 // 7.6.2 Unary minus operator
406 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
407 TypeManager.int32_type,
408 TypeManager.int64_type,
409 TypeManager.float_type, TypeManager.double_type,
410 TypeManager.decimal_type
414 // 7.6.3 Logical negation operator
416 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
417 TypeManager.bool_type
421 // 7.6.4 Bitwise complement operator
423 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
424 TypeManager.int32_type, TypeManager.uint32_type,
425 TypeManager.int64_type, TypeManager.uint64_type
430 // Unary numeric promotions
432 static Expression DoNumericPromotion (Operator op, Expression expr)
434 Type expr_type = expr.Type;
435 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
436 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
437 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
438 expr_type == TypeManager.char_type)
439 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
441 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
442 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
447 public override Expression DoResolve (EmitContext ec)
449 if (Oper == Operator.AddressOf) {
450 return ResolveAddressOf (ec);
453 Expr = Expr.Resolve (ec);
457 if (TypeManager.IsNullableValueType (Expr.Type))
458 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
461 // Attempt to use a constant folding operation.
463 Constant cexpr = Expr as Constant;
465 cexpr = TryReduceConstant (ec, cexpr);
470 Expression expr = ResolveOperator (ec, Expr);
472 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
475 // Reduce unary operator on predefined types
477 if (expr == this && Oper == Operator.UnaryPlus)
483 public override Expression DoResolveLValue (EmitContext ec, Expression right)
488 public override void Emit (EmitContext ec)
490 EmitOperator (ec, type);
493 protected void EmitOperator (EmitContext ec, Type type)
495 ILGenerator ig = ec.ig;
498 case Operator.UnaryPlus:
502 case Operator.UnaryNegation:
503 if (ec.CheckState && !IsFloat (type)) {
504 ig.Emit (OpCodes.Ldc_I4_0);
505 if (type == TypeManager.int64_type)
506 ig.Emit (OpCodes.Conv_U8);
508 ig.Emit (OpCodes.Sub_Ovf);
511 ig.Emit (OpCodes.Neg);
516 case Operator.LogicalNot:
518 ig.Emit (OpCodes.Ldc_I4_0);
519 ig.Emit (OpCodes.Ceq);
522 case Operator.OnesComplement:
524 ig.Emit (OpCodes.Not);
527 case Operator.AddressOf:
528 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
532 throw new Exception ("This should not happen: Operator = "
537 // Same trick as in Binary expression
539 if (enum_conversion != null)
540 enum_conversion.Emit (ec);
543 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
545 if (Oper == Operator.LogicalNot)
546 Expr.EmitBranchable (ec, target, !on_true);
548 base.EmitBranchable (ec, target, on_true);
551 public override void EmitSideEffect (EmitContext ec)
553 Expr.EmitSideEffect (ec);
556 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
558 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
559 oper, TypeManager.CSharpName (t));
562 static bool IsFloat (Type t)
564 return t == TypeManager.float_type || t == TypeManager.double_type;
568 // Returns a stringified representation of the Operator
570 public static string OperName (Operator oper)
573 case Operator.UnaryPlus:
575 case Operator.UnaryNegation:
577 case Operator.LogicalNot:
579 case Operator.OnesComplement:
581 case Operator.AddressOf:
585 throw new NotImplementedException (oper.ToString ());
588 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
590 type = storey.MutateType (type);
591 Expr.MutateHoistedGenericType (storey);
594 Expression ResolveAddressOf (EmitContext ec)
599 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
600 if (Expr == null || Expr.eclass != ExprClass.Variable) {
601 Error (211, "Cannot take the address of the given expression");
605 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
609 IVariableReference vr = Expr as IVariableReference;
612 VariableInfo vi = vr.VariableInfo;
614 if (vi.LocalInfo != null)
615 vi.LocalInfo.Used = true;
618 // A variable is considered definitely assigned if you take its address.
623 is_fixed = vr.IsFixed;
624 vr.SetHasAddressTaken ();
627 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
630 IFixedExpression fe = Expr as IFixedExpression;
631 is_fixed = fe != null && fe.IsFixed;
634 if (!is_fixed && !ec.InFixedInitializer) {
635 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
638 type = TypeManager.GetPointerType (Expr.Type);
639 eclass = ExprClass.Value;
643 Expression ResolvePrimitivePredefinedType (Expression expr)
645 expr = DoNumericPromotion (Oper, expr);
646 Type expr_type = expr.Type;
647 Type[] predefined = predefined_operators [(int) Oper];
648 foreach (Type t in predefined) {
656 // Perform user-operator overload resolution
658 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
660 CSharp.Operator.OpType op_type;
662 case Operator.LogicalNot:
663 op_type = CSharp.Operator.OpType.LogicalNot; break;
664 case Operator.OnesComplement:
665 op_type = CSharp.Operator.OpType.OnesComplement; break;
666 case Operator.UnaryNegation:
667 op_type = CSharp.Operator.OpType.UnaryNegation; break;
668 case Operator.UnaryPlus:
669 op_type = CSharp.Operator.OpType.UnaryPlus; break;
671 throw new InternalErrorException (Oper.ToString ());
674 string op_name = CSharp.Operator.GetMetadataName (op_type);
675 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
679 ArrayList args = new ArrayList (1);
680 args.Add (new Argument (expr));
681 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
686 Expr = ((Argument) args [0]).Expr;
687 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
691 // Unary user type overload resolution
693 Expression ResolveUserType (EmitContext ec, Expression expr)
695 Expression best_expr = ResolveUserOperator (ec, expr);
696 if (best_expr != null)
699 Type[] predefined = predefined_operators [(int) Oper];
700 foreach (Type t in predefined) {
701 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
702 if (oper_expr == null)
706 // decimal type is predefined but has user-operators
708 if (oper_expr.Type == TypeManager.decimal_type)
709 oper_expr = ResolveUserType (ec, oper_expr);
711 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
713 if (oper_expr == null)
716 if (best_expr == null) {
717 best_expr = oper_expr;
721 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
723 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
724 OperName (Oper), TypeManager.CSharpName (expr.Type));
729 best_expr = oper_expr;
732 if (best_expr == null)
736 // HACK: Decimal user-operator is included in standard operators
738 if (best_expr.Type == TypeManager.decimal_type)
742 type = best_expr.Type;
746 protected override void CloneTo (CloneContext clonectx, Expression t)
748 Unary target = (Unary) t;
750 target.Expr = Expr.Clone (clonectx);
755 // Unary operators are turned into Indirection expressions
756 // after semantic analysis (this is so we can take the address
757 // of an indirection).
759 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
761 LocalTemporary temporary;
764 public Indirection (Expression expr, Location l)
770 public override Expression CreateExpressionTree (EmitContext ec)
772 Error_PointerInsideExpressionTree ();
776 protected override void CloneTo (CloneContext clonectx, Expression t)
778 Indirection target = (Indirection) t;
779 target.expr = expr.Clone (clonectx);
782 public override void Emit (EmitContext ec)
787 LoadFromPtr (ec.ig, Type);
790 public void Emit (EmitContext ec, bool leave_copy)
794 ec.ig.Emit (OpCodes.Dup);
795 temporary = new LocalTemporary (expr.Type);
796 temporary.Store (ec);
800 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
802 prepared = prepare_for_load;
806 if (prepare_for_load)
807 ec.ig.Emit (OpCodes.Dup);
811 ec.ig.Emit (OpCodes.Dup);
812 temporary = new LocalTemporary (expr.Type);
813 temporary.Store (ec);
816 StoreFromPtr (ec.ig, type);
818 if (temporary != null) {
820 temporary.Release (ec);
824 public void AddressOf (EmitContext ec, AddressOp Mode)
829 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
831 return DoResolve (ec);
834 public override Expression DoResolve (EmitContext ec)
836 expr = expr.Resolve (ec);
843 if (!expr.Type.IsPointer) {
844 Error (193, "The * or -> operator must be applied to a pointer");
848 if (expr.Type == TypeManager.void_ptr_type) {
849 Error (242, "The operation in question is undefined on void pointers");
853 type = TypeManager.GetElementType (expr.Type);
854 eclass = ExprClass.Variable;
858 public bool IsFixed {
862 public override string ToString ()
864 return "*(" + expr + ")";
869 /// Unary Mutator expressions (pre and post ++ and --)
873 /// UnaryMutator implements ++ and -- expressions. It derives from
874 /// ExpressionStatement becuase the pre/post increment/decrement
875 /// operators can be used in a statement context.
877 /// FIXME: Idea, we could split this up in two classes, one simpler
878 /// for the common case, and one with the extra fields for more complex
879 /// classes (indexers require temporary access; overloaded require method)
882 public class UnaryMutator : ExpressionStatement {
884 public enum Mode : byte {
891 PreDecrement = IsDecrement,
892 PostIncrement = IsPost,
893 PostDecrement = IsPost | IsDecrement
897 bool is_expr = false;
898 bool recurse = false;
903 // This is expensive for the simplest case.
905 UserOperatorCall method;
907 public UnaryMutator (Mode m, Expression e)
914 static string OperName (Mode mode)
916 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
921 /// Returns whether an object of type `t' can be incremented
922 /// or decremented with add/sub (ie, basically whether we can
923 /// use pre-post incr-decr operations on it, but it is not a
924 /// System.Decimal, which we require operator overloading to catch)
926 static bool IsIncrementableNumber (Type t)
928 return (t == TypeManager.sbyte_type) ||
929 (t == TypeManager.byte_type) ||
930 (t == TypeManager.short_type) ||
931 (t == TypeManager.ushort_type) ||
932 (t == TypeManager.int32_type) ||
933 (t == TypeManager.uint32_type) ||
934 (t == TypeManager.int64_type) ||
935 (t == TypeManager.uint64_type) ||
936 (t == TypeManager.char_type) ||
937 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
938 (t == TypeManager.float_type) ||
939 (t == TypeManager.double_type) ||
940 (t.IsPointer && t != TypeManager.void_ptr_type);
943 Expression ResolveOperator (EmitContext ec)
948 // The operand of the prefix/postfix increment decrement operators
949 // should be an expression that is classified as a variable,
950 // a property access or an indexer access
952 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
953 expr = expr.ResolveLValue (ec, expr, Location);
955 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
959 // Step 1: Perform Operator Overload location
964 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
965 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
967 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
969 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
972 ArrayList args = new ArrayList (1);
973 args.Add (new Argument (expr, Argument.AType.Expression));
974 mg = mg.OverloadResolve (ec, ref args, false, loc);
978 method = new UserOperatorCall (mg, args, null, loc);
979 Convert.ImplicitConversionRequired (ec, method, type, loc);
983 if (!IsIncrementableNumber (type)) {
984 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
985 TypeManager.CSharpName (type) + "'");
992 public override Expression CreateExpressionTree (EmitContext ec)
994 return new SimpleAssign (this, this).CreateExpressionTree (ec);
997 public override Expression DoResolve (EmitContext ec)
999 expr = expr.Resolve (ec);
1004 eclass = ExprClass.Value;
1007 if (TypeManager.IsNullableValueType (expr.Type))
1008 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1011 return ResolveOperator (ec);
1015 // Loads the proper "1" into the stack based on the type, then it emits the
1016 // opcode for the operation requested
1018 void LoadOneAndEmitOp (EmitContext ec, Type t)
1021 // Measure if getting the typecode and using that is more/less efficient
1022 // that comparing types. t.GetTypeCode() is an internal call.
1024 ILGenerator ig = ec.ig;
1026 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1027 LongConstant.EmitLong (ig, 1);
1028 else if (t == TypeManager.double_type)
1029 ig.Emit (OpCodes.Ldc_R8, 1.0);
1030 else if (t == TypeManager.float_type)
1031 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1032 else if (t.IsPointer){
1033 Type et = TypeManager.GetElementType (t);
1034 int n = GetTypeSize (et);
1037 ig.Emit (OpCodes.Sizeof, et);
1039 IntConstant.EmitInt (ig, n);
1040 ig.Emit (OpCodes.Conv_I);
1043 ig.Emit (OpCodes.Ldc_I4_1);
1046 // Now emit the operation
1049 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1050 Binary.EmitOperatorOpcode (ec, op, t);
1052 if (t == TypeManager.sbyte_type){
1054 ig.Emit (OpCodes.Conv_Ovf_I1);
1056 ig.Emit (OpCodes.Conv_I1);
1057 } else if (t == TypeManager.byte_type){
1059 ig.Emit (OpCodes.Conv_Ovf_U1);
1061 ig.Emit (OpCodes.Conv_U1);
1062 } else if (t == TypeManager.short_type){
1064 ig.Emit (OpCodes.Conv_Ovf_I2);
1066 ig.Emit (OpCodes.Conv_I2);
1067 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1069 ig.Emit (OpCodes.Conv_Ovf_U2);
1071 ig.Emit (OpCodes.Conv_U2);
1076 void EmitCode (EmitContext ec, bool is_expr)
1079 this.is_expr = is_expr;
1080 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1083 public override void Emit (EmitContext ec)
1086 // We use recurse to allow ourselfs to be the source
1087 // of an assignment. This little hack prevents us from
1088 // having to allocate another expression
1091 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1093 LoadOneAndEmitOp (ec, expr.Type);
1095 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1100 EmitCode (ec, true);
1103 public override void EmitStatement (EmitContext ec)
1105 EmitCode (ec, false);
1108 protected override void CloneTo (CloneContext clonectx, Expression t)
1110 UnaryMutator target = (UnaryMutator) t;
1112 target.expr = expr.Clone (clonectx);
1117 /// Base class for the `Is' and `As' classes.
1121 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1124 public abstract class Probe : Expression {
1125 public Expression ProbeType;
1126 protected Expression expr;
1127 protected TypeExpr probe_type_expr;
1129 public Probe (Expression expr, Expression probe_type, Location l)
1131 ProbeType = probe_type;
1136 public Expression Expr {
1142 public override Expression DoResolve (EmitContext ec)
1144 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1145 if (probe_type_expr == null)
1148 expr = expr.Resolve (ec);
1152 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1153 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1157 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1158 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1163 if (expr.Type == TypeManager.anonymous_method_type) {
1164 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1172 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1174 expr.MutateHoistedGenericType (storey);
1175 probe_type_expr.MutateHoistedGenericType (storey);
1178 protected abstract string OperatorName { get; }
1180 protected override void CloneTo (CloneContext clonectx, Expression t)
1182 Probe target = (Probe) t;
1184 target.expr = expr.Clone (clonectx);
1185 target.ProbeType = ProbeType.Clone (clonectx);
1191 /// Implementation of the `is' operator.
1193 public class Is : Probe {
1194 Nullable.Unwrap expr_unwrap;
1196 public Is (Expression expr, Expression probe_type, Location l)
1197 : base (expr, probe_type, l)
1201 public override Expression CreateExpressionTree (EmitContext ec)
1203 ArrayList args = new ArrayList (2);
1204 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1205 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1206 return CreateExpressionFactoryCall ("TypeIs", args);
1209 public override void Emit (EmitContext ec)
1211 ILGenerator ig = ec.ig;
1212 if (expr_unwrap != null) {
1213 expr_unwrap.EmitCheck (ec);
1218 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1219 ig.Emit (OpCodes.Ldnull);
1220 ig.Emit (OpCodes.Cgt_Un);
1223 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1225 ILGenerator ig = ec.ig;
1226 if (expr_unwrap != null) {
1227 expr_unwrap.EmitCheck (ec);
1230 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1232 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1235 Expression CreateConstantResult (bool result)
1238 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1242 TypeManager.CSharpName (probe_type_expr.Type));
1244 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1247 public override Expression DoResolve (EmitContext ec)
1249 if (base.DoResolve (ec) == null)
1253 bool d_is_nullable = false;
1256 // If E is a method group or the null literal, or if the type of E is a reference
1257 // type or a nullable type and the value of E is null, the result is false
1259 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1260 return CreateConstantResult (false);
1262 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1263 d = TypeManager.GetTypeArguments (d) [0];
1264 d_is_nullable = true;
1267 type = TypeManager.bool_type;
1268 eclass = ExprClass.Value;
1269 Type t = probe_type_expr.Type;
1270 bool t_is_nullable = false;
1271 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1272 t = TypeManager.GetTypeArguments (t) [0];
1273 t_is_nullable = true;
1276 if (t.IsValueType) {
1279 // D and T are the same value types but D can be null
1281 if (d_is_nullable && !t_is_nullable) {
1282 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1287 // The result is true if D and T are the same value types
1289 return CreateConstantResult (true);
1292 if (TypeManager.IsGenericParameter (d))
1293 return ResolveGenericParameter (t, d);
1296 // An unboxing conversion exists
1298 if (Convert.ExplicitReferenceConversionExists (d, t))
1301 if (TypeManager.IsGenericParameter (t))
1302 return ResolveGenericParameter (d, t);
1304 if (d.IsValueType) {
1306 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1307 return CreateConstantResult (true);
1309 if (TypeManager.IsGenericParameter (d))
1310 return ResolveGenericParameter (t, d);
1312 if (TypeManager.ContainsGenericParameters (d))
1315 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1316 Convert.ExplicitReferenceConversionExists (d, t)) {
1322 return CreateConstantResult (false);
1325 Expression ResolveGenericParameter (Type d, Type t)
1328 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1329 if (constraints != null) {
1330 if (constraints.IsReferenceType && d.IsValueType)
1331 return CreateConstantResult (false);
1333 if (constraints.IsValueType && !d.IsValueType)
1334 return CreateConstantResult (TypeManager.IsEqual (d, t));
1337 if (!TypeManager.IsReferenceType (expr.Type))
1338 expr = new BoxedCast (expr, d);
1346 protected override string OperatorName {
1347 get { return "is"; }
1352 /// Implementation of the `as' operator.
1354 public class As : Probe {
1356 Expression resolved_type;
1358 public As (Expression expr, Expression probe_type, Location l)
1359 : base (expr, probe_type, l)
1363 public override Expression CreateExpressionTree (EmitContext ec)
1365 ArrayList args = new ArrayList (2);
1366 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1367 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1368 return CreateExpressionFactoryCall ("TypeAs", args);
1371 public override void Emit (EmitContext ec)
1373 ILGenerator ig = ec.ig;
1378 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1381 if (TypeManager.IsNullableType (type))
1382 ig.Emit (OpCodes.Unbox_Any, type);
1386 public override Expression DoResolve (EmitContext ec)
1388 // Because expr is modified
1389 if (eclass != ExprClass.Invalid)
1392 if (resolved_type == null) {
1393 resolved_type = base.DoResolve (ec);
1395 if (resolved_type == null)
1399 type = probe_type_expr.Type;
1400 eclass = ExprClass.Value;
1401 Type etype = expr.Type;
1403 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1404 if (probe_type_expr is TypeParameterExpr) {
1405 Report.Error (413, loc,
1406 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1407 probe_type_expr.GetSignatureForError ());
1409 Report.Error (77, loc,
1410 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1411 TypeManager.CSharpName (type));
1416 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1417 return Nullable.LiftedNull.CreateFromExpression (this);
1420 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1427 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1428 if (TypeManager.IsGenericParameter (etype))
1429 expr = new BoxedCast (expr, etype);
1435 if (TypeManager.ContainsGenericParameters (etype) ||
1436 TypeManager.ContainsGenericParameters (type)) {
1437 expr = new BoxedCast (expr, etype);
1442 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1443 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1448 protected override string OperatorName {
1449 get { return "as"; }
1452 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1454 return expr.GetAttributableValue (ec, value_type, out value);
1459 /// This represents a typecast in the source language.
1461 /// FIXME: Cast expressions have an unusual set of parsing
1462 /// rules, we need to figure those out.
1464 public class Cast : Expression {
1465 Expression target_type;
1468 public Cast (Expression cast_type, Expression expr)
1469 : this (cast_type, expr, cast_type.Location)
1473 public Cast (Expression cast_type, Expression expr, Location loc)
1475 this.target_type = cast_type;
1480 public Expression TargetType {
1481 get { return target_type; }
1484 public Expression Expr {
1485 get { return expr; }
1488 public override Expression CreateExpressionTree (EmitContext ec)
1490 throw new NotSupportedException ("ET");
1493 public override Expression DoResolve (EmitContext ec)
1495 expr = expr.Resolve (ec);
1499 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1505 if (type.IsAbstract && type.IsSealed) {
1506 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1510 eclass = ExprClass.Value;
1512 Constant c = expr as Constant;
1514 c = c.TryReduce (ec, type, loc);
1519 if (type.IsPointer && !ec.InUnsafe) {
1523 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1527 public override void Emit (EmitContext ec)
1529 throw new Exception ("Should not happen");
1532 protected override void CloneTo (CloneContext clonectx, Expression t)
1534 Cast target = (Cast) t;
1536 target.target_type = target_type.Clone (clonectx);
1537 target.expr = expr.Clone (clonectx);
1542 // C# 2.0 Default value expression
1544 public class DefaultValueExpression : Expression
1548 public DefaultValueExpression (Expression expr, Location loc)
1554 public override Expression CreateExpressionTree (EmitContext ec)
1556 ArrayList args = new ArrayList (2);
1557 args.Add (new Argument (this));
1558 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1559 return CreateExpressionFactoryCall ("Constant", args);
1562 public override Expression DoResolve (EmitContext ec)
1564 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1570 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1571 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1575 return new NullLiteral (Location).ConvertImplicitly (type);
1577 if (TypeManager.IsReferenceType (type)) {
1578 return new EmptyConstantCast (new NullLiteral (Location), type);
1581 // return ReducedExpression.Create (new NullLiteral (Location), this);
1584 Constant c = New.Constantify (type);
1588 eclass = ExprClass.Variable;
1592 public override void Emit (EmitContext ec)
1594 LocalTemporary temp_storage = new LocalTemporary(type);
1596 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1597 ec.ig.Emit(OpCodes.Initobj, type);
1598 temp_storage.Emit(ec);
1601 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1603 type = storey.MutateType (type);
1606 protected override void CloneTo (CloneContext clonectx, Expression t)
1608 DefaultValueExpression target = (DefaultValueExpression) t;
1610 target.expr = expr.Clone (clonectx);
1615 /// Binary operators
1617 public class Binary : Expression {
1619 protected class PredefinedOperator {
1620 protected readonly Type left;
1621 protected readonly Type right;
1622 public readonly Operator OperatorsMask;
1623 public Type ReturnType;
1625 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1626 : this (ltype, rtype, op_mask, ltype)
1630 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1631 : this (type, type, op_mask, return_type)
1635 public PredefinedOperator (Type type, Operator op_mask)
1636 : this (type, type, op_mask, type)
1640 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1642 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1643 throw new InternalErrorException ("Only masked values can be used");
1647 this.OperatorsMask = op_mask;
1648 this.ReturnType = return_type;
1651 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1653 b.type = ReturnType;
1655 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1656 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1659 // A user operators does not support multiple user conversions, but decimal type
1660 // is considered to be predefined type therefore we apply predefined operators rules
1661 // and then look for decimal user-operator implementation
1663 if (left == TypeManager.decimal_type)
1664 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1669 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1672 // We are dealing with primitive types only
1674 return left == ltype && ltype == rtype;
1677 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1679 if (TypeManager.IsEqual (left, lexpr.Type) &&
1680 TypeManager.IsEqual (right, rexpr.Type))
1683 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1684 Convert.ImplicitConversionExists (ec, rexpr, right);
1687 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1690 if (left != null && best_operator.left != null) {
1691 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1695 // When second arguments are same as the first one, the result is same
1697 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1698 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1701 if (result == 0 || result > 2)
1704 return result == 1 ? best_operator : this;
1708 class PredefinedStringOperator : PredefinedOperator {
1709 public PredefinedStringOperator (Type type, Operator op_mask)
1710 : base (type, op_mask, type)
1712 ReturnType = TypeManager.string_type;
1715 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1716 : base (ltype, rtype, op_mask)
1718 ReturnType = TypeManager.string_type;
1721 public override Expression ConvertResult (EmitContext ec, Binary b)
1724 // Use original expression for nullable arguments
1726 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1728 b.left = unwrap.Original;
1730 unwrap = b.right as Nullable.Unwrap;
1732 b.right = unwrap.Original;
1734 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1735 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1738 // Start a new concat expression using converted expression
1740 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1744 class PredefinedShiftOperator : PredefinedOperator {
1745 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1746 base (ltype, TypeManager.int32_type, op_mask)
1750 public override Expression ConvertResult (EmitContext ec, Binary b)
1752 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1754 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1756 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1759 // b = b.left >> b.right & (0x1f|0x3f)
1761 b.right = new Binary (Operator.BitwiseAnd,
1762 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1765 // Expression tree representation does not use & mask
1767 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1768 b.type = ReturnType;
1773 class PredefinedPointerOperator : PredefinedOperator {
1774 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1775 : base (ltype, rtype, op_mask)
1779 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1780 : base (ltype, rtype, op_mask, retType)
1784 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1785 : base (type, op_mask, return_type)
1789 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1792 if (!lexpr.Type.IsPointer)
1795 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1799 if (right == null) {
1800 if (!rexpr.Type.IsPointer)
1803 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1810 public override Expression ConvertResult (EmitContext ec, Binary b)
1813 b.left = EmptyCast.Create (b.left, left);
1814 } else if (right != null) {
1815 b.right = EmptyCast.Create (b.right, right);
1818 Type r_type = ReturnType;
1819 Expression left_arg, right_arg;
1820 if (r_type == null) {
1823 right_arg = b.right;
1824 r_type = b.left.Type;
1828 r_type = b.right.Type;
1832 right_arg = b.right;
1835 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1840 public enum Operator {
1841 Multiply = 0 | ArithmeticMask,
1842 Division = 1 | ArithmeticMask,
1843 Modulus = 2 | ArithmeticMask,
1844 Addition = 3 | ArithmeticMask | AdditionMask,
1845 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1847 LeftShift = 5 | ShiftMask,
1848 RightShift = 6 | ShiftMask,
1850 LessThan = 7 | ComparisonMask | RelationalMask,
1851 GreaterThan = 8 | ComparisonMask | RelationalMask,
1852 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1853 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1854 Equality = 11 | ComparisonMask | EqualityMask,
1855 Inequality = 12 | ComparisonMask | EqualityMask,
1857 BitwiseAnd = 13 | BitwiseMask,
1858 ExclusiveOr = 14 | BitwiseMask,
1859 BitwiseOr = 15 | BitwiseMask,
1861 LogicalAnd = 16 | LogicalMask,
1862 LogicalOr = 17 | LogicalMask,
1867 ValuesOnlyMask = ArithmeticMask - 1,
1868 ArithmeticMask = 1 << 5,
1870 ComparisonMask = 1 << 7,
1871 EqualityMask = 1 << 8,
1872 BitwiseMask = 1 << 9,
1873 LogicalMask = 1 << 10,
1874 AdditionMask = 1 << 11,
1875 SubtractionMask = 1 << 12,
1876 RelationalMask = 1 << 13
1879 readonly Operator oper;
1880 protected Expression left, right;
1881 readonly bool is_compound;
1882 Expression enum_conversion;
1884 static PredefinedOperator [] standard_operators;
1885 static PredefinedOperator [] pointer_operators;
1887 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1888 : this (oper, left, right)
1890 this.is_compound = isCompound;
1893 public Binary (Operator oper, Expression left, Expression right)
1898 this.loc = left.Location;
1901 public Operator Oper {
1908 /// Returns a stringified representation of the Operator
1910 string OperName (Operator oper)
1914 case Operator.Multiply:
1917 case Operator.Division:
1920 case Operator.Modulus:
1923 case Operator.Addition:
1926 case Operator.Subtraction:
1929 case Operator.LeftShift:
1932 case Operator.RightShift:
1935 case Operator.LessThan:
1938 case Operator.GreaterThan:
1941 case Operator.LessThanOrEqual:
1944 case Operator.GreaterThanOrEqual:
1947 case Operator.Equality:
1950 case Operator.Inequality:
1953 case Operator.BitwiseAnd:
1956 case Operator.BitwiseOr:
1959 case Operator.ExclusiveOr:
1962 case Operator.LogicalOr:
1965 case Operator.LogicalAnd:
1969 s = oper.ToString ();
1979 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1981 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1984 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1987 // TODO: This should be handled as Type of method group in CSharpName
1988 if (left.eclass == ExprClass.MethodGroup)
1989 l = left.ExprClassName;
1991 l = TypeManager.CSharpName (left.Type);
1993 if (right.eclass == ExprClass.MethodGroup)
1994 r = right.ExprClassName;
1996 r = TypeManager.CSharpName (right.Type);
1998 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2002 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2004 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2007 static string GetOperatorMetadataName (Operator op)
2009 CSharp.Operator.OpType op_type;
2011 case Operator.Addition:
2012 op_type = CSharp.Operator.OpType.Addition; break;
2013 case Operator.BitwiseAnd:
2014 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2015 case Operator.BitwiseOr:
2016 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2017 case Operator.Division:
2018 op_type = CSharp.Operator.OpType.Division; break;
2019 case Operator.Equality:
2020 op_type = CSharp.Operator.OpType.Equality; break;
2021 case Operator.ExclusiveOr:
2022 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2023 case Operator.GreaterThan:
2024 op_type = CSharp.Operator.OpType.GreaterThan; break;
2025 case Operator.GreaterThanOrEqual:
2026 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2027 case Operator.Inequality:
2028 op_type = CSharp.Operator.OpType.Inequality; break;
2029 case Operator.LeftShift:
2030 op_type = CSharp.Operator.OpType.LeftShift; break;
2031 case Operator.LessThan:
2032 op_type = CSharp.Operator.OpType.LessThan; break;
2033 case Operator.LessThanOrEqual:
2034 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2035 case Operator.Modulus:
2036 op_type = CSharp.Operator.OpType.Modulus; break;
2037 case Operator.Multiply:
2038 op_type = CSharp.Operator.OpType.Multiply; break;
2039 case Operator.RightShift:
2040 op_type = CSharp.Operator.OpType.RightShift; break;
2041 case Operator.Subtraction:
2042 op_type = CSharp.Operator.OpType.Subtraction; break;
2044 throw new InternalErrorException (op.ToString ());
2047 return CSharp.Operator.GetMetadataName (op_type);
2050 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2053 ILGenerator ig = ec.ig;
2056 case Operator.Multiply:
2058 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2059 opcode = OpCodes.Mul_Ovf;
2060 else if (!IsFloat (l))
2061 opcode = OpCodes.Mul_Ovf_Un;
2063 opcode = OpCodes.Mul;
2065 opcode = OpCodes.Mul;
2069 case Operator.Division:
2071 opcode = OpCodes.Div_Un;
2073 opcode = OpCodes.Div;
2076 case Operator.Modulus:
2078 opcode = OpCodes.Rem_Un;
2080 opcode = OpCodes.Rem;
2083 case Operator.Addition:
2085 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2086 opcode = OpCodes.Add_Ovf;
2087 else if (!IsFloat (l))
2088 opcode = OpCodes.Add_Ovf_Un;
2090 opcode = OpCodes.Add;
2092 opcode = OpCodes.Add;
2095 case Operator.Subtraction:
2097 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2098 opcode = OpCodes.Sub_Ovf;
2099 else if (!IsFloat (l))
2100 opcode = OpCodes.Sub_Ovf_Un;
2102 opcode = OpCodes.Sub;
2104 opcode = OpCodes.Sub;
2107 case Operator.RightShift:
2109 opcode = OpCodes.Shr_Un;
2111 opcode = OpCodes.Shr;
2114 case Operator.LeftShift:
2115 opcode = OpCodes.Shl;
2118 case Operator.Equality:
2119 opcode = OpCodes.Ceq;
2122 case Operator.Inequality:
2123 ig.Emit (OpCodes.Ceq);
2124 ig.Emit (OpCodes.Ldc_I4_0);
2126 opcode = OpCodes.Ceq;
2129 case Operator.LessThan:
2131 opcode = OpCodes.Clt_Un;
2133 opcode = OpCodes.Clt;
2136 case Operator.GreaterThan:
2138 opcode = OpCodes.Cgt_Un;
2140 opcode = OpCodes.Cgt;
2143 case Operator.LessThanOrEqual:
2144 if (IsUnsigned (l) || IsFloat (l))
2145 ig.Emit (OpCodes.Cgt_Un);
2147 ig.Emit (OpCodes.Cgt);
2148 ig.Emit (OpCodes.Ldc_I4_0);
2150 opcode = OpCodes.Ceq;
2153 case Operator.GreaterThanOrEqual:
2154 if (IsUnsigned (l) || IsFloat (l))
2155 ig.Emit (OpCodes.Clt_Un);
2157 ig.Emit (OpCodes.Clt);
2159 ig.Emit (OpCodes.Ldc_I4_0);
2161 opcode = OpCodes.Ceq;
2164 case Operator.BitwiseOr:
2165 opcode = OpCodes.Or;
2168 case Operator.BitwiseAnd:
2169 opcode = OpCodes.And;
2172 case Operator.ExclusiveOr:
2173 opcode = OpCodes.Xor;
2177 throw new InternalErrorException (oper.ToString ());
2183 static bool IsUnsigned (Type t)
2188 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2189 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2192 static bool IsFloat (Type t)
2194 return t == TypeManager.float_type || t == TypeManager.double_type;
2197 Expression ResolveOperator (EmitContext ec)
2200 Type r = right.Type;
2202 bool primitives_only = false;
2204 if (standard_operators == null)
2205 CreateStandardOperatorsTable ();
2208 // Handles predefined primitive types
2210 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2211 if ((oper & Operator.ShiftMask) == 0) {
2212 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2215 primitives_only = true;
2219 if (l.IsPointer || r.IsPointer)
2220 return ResolveOperatorPointer (ec, l, r);
2223 bool lenum = TypeManager.IsEnumType (l);
2224 bool renum = TypeManager.IsEnumType (r);
2225 if (lenum || renum) {
2226 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2228 // TODO: Can this be ambiguous
2234 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2235 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2237 expr = ResolveOperatorDelegate (ec, l, r);
2239 // TODO: Can this be ambiguous
2245 expr = ResolveUserOperator (ec, l, r);
2249 // Predefined reference types equality
2250 if ((oper & Operator.EqualityMask) != 0) {
2251 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2257 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2260 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2261 // if 'left' is not an enumeration constant, create one from the type of 'right'
2262 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2265 case Operator.BitwiseOr:
2266 case Operator.BitwiseAnd:
2267 case Operator.ExclusiveOr:
2268 case Operator.Equality:
2269 case Operator.Inequality:
2270 case Operator.LessThan:
2271 case Operator.LessThanOrEqual:
2272 case Operator.GreaterThan:
2273 case Operator.GreaterThanOrEqual:
2274 if (TypeManager.IsEnumType (left.Type))
2277 if (left.IsZeroInteger)
2278 return left.TryReduce (ec, right.Type, loc);
2282 case Operator.Addition:
2283 case Operator.Subtraction:
2286 case Operator.Multiply:
2287 case Operator.Division:
2288 case Operator.Modulus:
2289 case Operator.LeftShift:
2290 case Operator.RightShift:
2291 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2295 Error_OperatorCannotBeApplied (this.left, this.right);
2300 // The `|' operator used on types which were extended is dangerous
2302 void CheckBitwiseOrOnSignExtended ()
2304 OpcodeCast lcast = left as OpcodeCast;
2305 if (lcast != null) {
2306 if (IsUnsigned (lcast.UnderlyingType))
2310 OpcodeCast rcast = right as OpcodeCast;
2311 if (rcast != null) {
2312 if (IsUnsigned (rcast.UnderlyingType))
2316 if (lcast == null && rcast == null)
2319 // FIXME: consider constants
2321 Report.Warning (675, 3, loc,
2322 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2323 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2326 static void CreatePointerOperatorsTable ()
2328 ArrayList temp = new ArrayList ();
2331 // Pointer arithmetic:
2333 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2334 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2335 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2336 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2338 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2339 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2340 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2341 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2344 // T* operator + (int y, T* x);
2345 // T* operator + (uint y, T *x);
2346 // T* operator + (long y, T *x);
2347 // T* operator + (ulong y, T *x);
2349 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2350 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2351 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2352 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2355 // long operator - (T* x, T *y)
2357 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2359 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2362 static void CreateStandardOperatorsTable ()
2364 ArrayList temp = new ArrayList ();
2365 Type bool_type = TypeManager.bool_type;
2367 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2368 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2369 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2370 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2371 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2372 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2373 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2375 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2377 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2378 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2379 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2380 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2381 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2383 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2385 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2386 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2387 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2389 temp.Add (new PredefinedOperator (bool_type,
2390 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2392 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2393 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2394 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2395 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2397 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2401 // Rules used during binary numeric promotion
2403 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2408 Constant c = prim_expr as Constant;
2410 temp = c.ConvertImplicitly (type);
2417 if (type == TypeManager.uint32_type) {
2418 etype = prim_expr.Type;
2419 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2420 type = TypeManager.int64_type;
2422 if (type != second_expr.Type) {
2423 c = second_expr as Constant;
2425 temp = c.ConvertImplicitly (type);
2427 temp = Convert.ImplicitNumericConversion (second_expr, type);
2433 } else if (type == TypeManager.uint64_type) {
2435 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2437 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2438 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2442 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2451 // 7.2.6.2 Binary numeric promotions
2453 public bool DoBinaryOperatorPromotion (EmitContext ec)
2455 Type ltype = left.Type;
2456 Type rtype = right.Type;
2459 foreach (Type t in ConstantFold.binary_promotions) {
2461 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2464 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2467 Type int32 = TypeManager.int32_type;
2468 if (ltype != int32) {
2469 Constant c = left as Constant;
2471 temp = c.ConvertImplicitly (int32);
2473 temp = Convert.ImplicitNumericConversion (left, int32);
2480 if (rtype != int32) {
2481 Constant c = right as Constant;
2483 temp = c.ConvertImplicitly (int32);
2485 temp = Convert.ImplicitNumericConversion (right, int32);
2495 public override Expression DoResolve (EmitContext ec)
2500 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2501 left = ((ParenthesizedExpression) left).Expr;
2502 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2506 if (left.eclass == ExprClass.Type) {
2507 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2511 left = left.Resolve (ec);
2516 Constant lc = left as Constant;
2518 if (lc != null && lc.Type == TypeManager.bool_type &&
2519 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2520 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2522 // FIXME: resolve right expression as unreachable
2523 // right.Resolve (ec);
2525 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2529 right = right.Resolve (ec);
2533 eclass = ExprClass.Value;
2534 Constant rc = right as Constant;
2536 // The conversion rules are ignored in enum context but why
2537 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2538 left = lc = EnumLiftUp (ec, lc, rc, loc);
2542 right = rc = EnumLiftUp (ec, rc, lc, loc);
2547 if (rc != null && lc != null) {
2548 int prev_e = Report.Errors;
2549 Expression e = ConstantFold.BinaryFold (
2550 ec, oper, lc, rc, loc);
2551 if (e != null || Report.Errors != prev_e)
2554 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2555 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2557 if ((ResolveOperator (ec)) == null) {
2558 Error_OperatorCannotBeApplied (left, right);
2563 // The result is a constant with side-effect
2565 Constant side_effect = rc == null ?
2566 new SideEffectConstant (lc, right, loc) :
2567 new SideEffectConstant (rc, left, loc);
2569 return ReducedExpression.Create (side_effect, this);
2573 // Comparison warnings
2574 if ((oper & Operator.ComparisonMask) != 0) {
2575 if (left.Equals (right)) {
2576 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2578 CheckUselessComparison (lc, right.Type);
2579 CheckUselessComparison (rc, left.Type);
2582 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2583 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2584 (left.Type.IsValueType && right is NullLiteral) ||
2585 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2586 (right.Type.IsValueType && left is NullLiteral)))
2587 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2589 return DoResolveCore (ec, left, right);
2592 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2594 Expression expr = ResolveOperator (ec);
2596 Error_OperatorCannotBeApplied (left_orig, right_orig);
2598 if (left == null || right == null)
2599 throw new InternalErrorException ("Invalid conversion");
2601 if (oper == Operator.BitwiseOr)
2602 CheckBitwiseOrOnSignExtended ();
2607 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2609 left.MutateHoistedGenericType (storey);
2610 right.MutateHoistedGenericType (storey);
2614 // D operator + (D x, D y)
2615 // D operator - (D x, D y)
2616 // bool operator == (D x, D y)
2617 // bool operator != (D x, D y)
2619 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2621 bool is_equality = (oper & Operator.EqualityMask) != 0;
2622 if (!TypeManager.IsEqual (l, r)) {
2624 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2625 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2630 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2631 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2642 // Resolve delegate equality as a user operator
2645 return ResolveUserOperator (ec, l, r);
2648 ArrayList args = new ArrayList (2);
2649 args.Add (new Argument (left, Argument.AType.Expression));
2650 args.Add (new Argument (right, Argument.AType.Expression));
2652 if (oper == Operator.Addition) {
2653 if (TypeManager.delegate_combine_delegate_delegate == null) {
2654 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2655 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2658 method = TypeManager.delegate_combine_delegate_delegate;
2660 if (TypeManager.delegate_remove_delegate_delegate == null) {
2661 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2662 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2665 method = TypeManager.delegate_remove_delegate_delegate;
2668 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2669 mg = mg.OverloadResolve (ec, ref args, false, loc);
2671 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2675 // Enumeration operators
2677 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2680 // bool operator == (E x, E y);
2681 // bool operator != (E x, E y);
2682 // bool operator < (E x, E y);
2683 // bool operator > (E x, E y);
2684 // bool operator <= (E x, E y);
2685 // bool operator >= (E x, E y);
2687 // E operator & (E x, E y);
2688 // E operator | (E x, E y);
2689 // E operator ^ (E x, E y);
2691 // U operator - (E e, E f)
2692 // E operator - (E e, U x)
2694 // E operator + (U x, E e)
2695 // E operator + (E e, U x)
2697 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2698 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2701 Expression ltemp = left;
2702 Expression rtemp = right;
2703 Type underlying_type;
2706 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2708 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2714 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2722 if (TypeManager.IsEqual (ltype, rtype)) {
2723 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2725 if (left is Constant)
2726 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2728 left = EmptyCast.Create (left, underlying_type);
2730 if (right is Constant)
2731 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2733 right = EmptyCast.Create (right, underlying_type);
2735 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2737 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2738 Constant c = right as Constant;
2739 if (c == null || !c.IsDefaultValue)
2742 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2745 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2748 if (left is Constant)
2749 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2751 left = EmptyCast.Create (left, underlying_type);
2754 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2756 if (oper != Operator.Addition) {
2757 Constant c = left as Constant;
2758 if (c == null || !c.IsDefaultValue)
2761 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2764 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2767 if (right is Constant)
2768 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2770 right = EmptyCast.Create (right, underlying_type);
2777 // C# specification uses explicit cast syntax which means binary promotion
2778 // should happen, however it seems that csc does not do that
2780 if (!DoBinaryOperatorPromotion (ec)) {
2786 Type res_type = null;
2787 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2788 Type promoted_type = lenum ? left.Type : right.Type;
2789 enum_conversion = Convert.ExplicitNumericConversion (
2790 new EmptyExpression (promoted_type), underlying_type);
2792 if (oper == Operator.Subtraction && renum && lenum)
2793 res_type = underlying_type;
2794 else if (oper == Operator.Addition && renum)
2800 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2801 if (!is_compound || expr == null)
2805 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2808 if (Convert.ImplicitConversionExists (ec, left, rtype))
2811 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2814 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2819 // 7.9.6 Reference type equality operators
2821 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2824 // operator != (object a, object b)
2825 // operator == (object a, object b)
2828 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2830 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2833 type = TypeManager.bool_type;
2834 GenericConstraints constraints;
2836 bool lgen = TypeManager.IsGenericParameter (l);
2838 if (TypeManager.IsEqual (l, r)) {
2841 // Only allow to compare same reference type parameter
2843 constraints = TypeManager.GetTypeParameterConstraints (l);
2844 if (constraints != null && constraints.IsReferenceType)
2850 if (l == TypeManager.anonymous_method_type)
2853 if (TypeManager.IsValueType (l))
2859 bool rgen = TypeManager.IsGenericParameter (r);
2862 // a, Both operands are reference-type values or the value null
2863 // b, One operand is a value of type T where T is a type-parameter and
2864 // the other operand is the value null. Furthermore T does not have the
2865 // value type constrain
2867 if (left is NullLiteral || right is NullLiteral) {
2869 constraints = TypeManager.GetTypeParameterConstraints (l);
2870 if (constraints != null && constraints.HasValueTypeConstraint)
2873 left = new BoxedCast (left, TypeManager.object_type);
2878 constraints = TypeManager.GetTypeParameterConstraints (r);
2879 if (constraints != null && constraints.HasValueTypeConstraint)
2882 right = new BoxedCast (right, TypeManager.object_type);
2888 // An interface is converted to the object before the
2889 // standard conversion is applied. It's not clear from the
2890 // standard but it looks like it works like that.
2893 constraints = TypeManager.GetTypeParameterConstraints (l);
2894 if (constraints == null || constraints.IsReferenceType)
2896 } else if (l.IsInterface) {
2897 l = TypeManager.object_type;
2898 } else if (l.IsValueType) {
2903 constraints = TypeManager.GetTypeParameterConstraints (r);
2904 if (constraints == null || constraints.IsReferenceType)
2906 } else if (r.IsInterface) {
2907 r = TypeManager.object_type;
2908 } else if (r.IsValueType) {
2913 const string ref_comparison = "Possible unintended reference comparison. " +
2914 "Consider casting the {0} side of the expression to `string' to compare the values";
2917 // A standard implicit conversion exists from the type of either
2918 // operand to the type of the other operand
2920 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2921 if (l == TypeManager.string_type)
2922 Report.Warning (253, 2, loc, ref_comparison, "right");
2927 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2928 if (r == TypeManager.string_type)
2929 Report.Warning (252, 2, loc, ref_comparison, "left");
2938 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2941 // bool operator == (void* x, void* y);
2942 // bool operator != (void* x, void* y);
2943 // bool operator < (void* x, void* y);
2944 // bool operator > (void* x, void* y);
2945 // bool operator <= (void* x, void* y);
2946 // bool operator >= (void* x, void* y);
2948 if ((oper & Operator.ComparisonMask) != 0) {
2951 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2958 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2964 type = TypeManager.bool_type;
2968 if (pointer_operators == null)
2969 CreatePointerOperatorsTable ();
2971 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2975 // Build-in operators method overloading
2977 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2979 PredefinedOperator best_operator = null;
2981 Type r = right.Type;
2982 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2984 foreach (PredefinedOperator po in operators) {
2985 if ((po.OperatorsMask & oper_mask) == 0)
2988 if (primitives_only) {
2989 if (!po.IsPrimitiveApplicable (l, r))
2992 if (!po.IsApplicable (ec, left, right))
2996 if (best_operator == null) {
2998 if (primitives_only)
3004 best_operator = po.ResolveBetterOperator (ec, best_operator);
3006 if (best_operator == null) {
3007 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3008 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3015 if (best_operator == null)
3018 Expression expr = best_operator.ConvertResult (ec, this);
3019 if (enum_type == null)
3023 // HACK: required by enum_conversion
3025 expr.Type = enum_type;
3026 return EmptyCast.Create (expr, enum_type);
3030 // Performs user-operator overloading
3032 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3035 if (oper == Operator.LogicalAnd)
3036 user_oper = Operator.BitwiseAnd;
3037 else if (oper == Operator.LogicalOr)
3038 user_oper = Operator.BitwiseOr;
3042 string op = GetOperatorMetadataName (user_oper);
3044 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3045 MethodGroupExpr right_operators = null;
3047 if (!TypeManager.IsEqual (r, l)) {
3048 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3049 if (right_operators == null && left_operators == null)
3051 } else if (left_operators == null) {
3055 ArrayList args = new ArrayList (2);
3056 Argument larg = new Argument (left);
3058 Argument rarg = new Argument (right);
3061 MethodGroupExpr union;
3064 // User-defined operator implementations always take precedence
3065 // over predefined operator implementations
3067 if (left_operators != null && right_operators != null) {
3068 if (IsPredefinedUserOperator (l, user_oper)) {
3069 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3071 union = left_operators;
3072 } else if (IsPredefinedUserOperator (r, user_oper)) {
3073 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3075 union = right_operators;
3077 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3079 } else if (left_operators != null) {
3080 union = left_operators;
3082 union = right_operators;
3085 union = union.OverloadResolve (ec, ref args, true, loc);
3089 Expression oper_expr;
3091 // TODO: CreateExpressionTree is allocated every time
3092 if (user_oper != oper) {
3093 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3094 oper == Operator.LogicalAnd, loc).Resolve (ec);
3096 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3099 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3100 // and not invoke user operator
3102 if ((oper & Operator.EqualityMask) != 0) {
3103 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3104 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3105 type = TypeManager.bool_type;
3106 if (left is NullLiteral || right is NullLiteral)
3107 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3108 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3110 // Two System.Delegate(s) are never equal
3122 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3127 private void CheckUselessComparison (Constant c, Type type)
3129 if (c == null || !IsTypeIntegral (type)
3130 || c is StringConstant
3131 || c is BoolConstant
3132 || c is FloatConstant
3133 || c is DoubleConstant
3134 || c is DecimalConstant
3140 if (c is ULongConstant) {
3141 ulong uvalue = ((ULongConstant) c).Value;
3142 if (uvalue > long.MaxValue) {
3143 if (type == TypeManager.byte_type ||
3144 type == TypeManager.sbyte_type ||
3145 type == TypeManager.short_type ||
3146 type == TypeManager.ushort_type ||
3147 type == TypeManager.int32_type ||
3148 type == TypeManager.uint32_type ||
3149 type == TypeManager.int64_type ||
3150 type == TypeManager.char_type)
3151 WarnUselessComparison (type);
3154 value = (long) uvalue;
3156 else if (c is ByteConstant)
3157 value = ((ByteConstant) c).Value;
3158 else if (c is SByteConstant)
3159 value = ((SByteConstant) c).Value;
3160 else if (c is ShortConstant)
3161 value = ((ShortConstant) c).Value;
3162 else if (c is UShortConstant)
3163 value = ((UShortConstant) c).Value;
3164 else if (c is IntConstant)
3165 value = ((IntConstant) c).Value;
3166 else if (c is UIntConstant)
3167 value = ((UIntConstant) c).Value;
3168 else if (c is LongConstant)
3169 value = ((LongConstant) c).Value;
3170 else if (c is CharConstant)
3171 value = ((CharConstant)c).Value;
3176 if (IsValueOutOfRange (value, type))
3177 WarnUselessComparison (type);
3180 static bool IsValueOutOfRange (long value, Type type)
3182 if (IsTypeUnsigned (type) && value < 0)
3184 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3185 type == TypeManager.byte_type && value >= 0x100 ||
3186 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3187 type == TypeManager.ushort_type && value >= 0x10000 ||
3188 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3189 type == TypeManager.uint32_type && value >= 0x100000000;
3192 static bool IsBuildInEqualityOperator (Type t)
3194 return t == TypeManager.object_type || t == TypeManager.string_type ||
3195 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3198 static bool IsPredefinedUserOperator (Type t, Operator op)
3201 // Some predefined types have user operators
3203 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3206 private static bool IsTypeIntegral (Type type)
3208 return type == TypeManager.uint64_type ||
3209 type == TypeManager.int64_type ||
3210 type == TypeManager.uint32_type ||
3211 type == TypeManager.int32_type ||
3212 type == TypeManager.ushort_type ||
3213 type == TypeManager.short_type ||
3214 type == TypeManager.sbyte_type ||
3215 type == TypeManager.byte_type ||
3216 type == TypeManager.char_type;
3219 private static bool IsTypeUnsigned (Type type)
3221 return type == TypeManager.uint64_type ||
3222 type == TypeManager.uint32_type ||
3223 type == TypeManager.ushort_type ||
3224 type == TypeManager.byte_type ||
3225 type == TypeManager.char_type;
3228 private void WarnUselessComparison (Type type)
3230 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}'",
3231 TypeManager.CSharpName (type));
3235 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3236 /// context of a conditional bool expression. This function will return
3237 /// false if it is was possible to use EmitBranchable, or true if it was.
3239 /// The expression's code is generated, and we will generate a branch to `target'
3240 /// if the resulting expression value is equal to isTrue
3242 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3244 ILGenerator ig = ec.ig;
3247 // This is more complicated than it looks, but its just to avoid
3248 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3249 // but on top of that we want for == and != to use a special path
3250 // if we are comparing against null
3252 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3253 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3256 // put the constant on the rhs, for simplicity
3258 if (left is Constant) {
3259 Expression swap = right;
3264 if (((Constant) right).IsZeroInteger) {
3265 left.EmitBranchable (ec, target, my_on_true);
3268 if (right.Type == TypeManager.bool_type) {
3269 // right is a boolean, and it's not 'false' => it is 'true'
3270 left.EmitBranchable (ec, target, !my_on_true);
3274 } else if (oper == Operator.LogicalAnd) {
3277 Label tests_end = ig.DefineLabel ();
3279 left.EmitBranchable (ec, tests_end, false);
3280 right.EmitBranchable (ec, target, true);
3281 ig.MarkLabel (tests_end);
3284 // This optimizes code like this
3285 // if (true && i > 4)
3287 if (!(left is Constant))
3288 left.EmitBranchable (ec, target, false);
3290 if (!(right is Constant))
3291 right.EmitBranchable (ec, target, false);
3296 } else if (oper == Operator.LogicalOr){
3298 left.EmitBranchable (ec, target, true);
3299 right.EmitBranchable (ec, target, true);
3302 Label tests_end = ig.DefineLabel ();
3303 left.EmitBranchable (ec, tests_end, true);
3304 right.EmitBranchable (ec, target, false);
3305 ig.MarkLabel (tests_end);
3310 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3311 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3312 oper == Operator.Equality || oper == Operator.Inequality)) {
3313 base.EmitBranchable (ec, target, on_true);
3321 bool is_float = IsFloat (t);
3322 bool is_unsigned = is_float || IsUnsigned (t);
3325 case Operator.Equality:
3327 ig.Emit (OpCodes.Beq, target);
3329 ig.Emit (OpCodes.Bne_Un, target);
3332 case Operator.Inequality:
3334 ig.Emit (OpCodes.Bne_Un, target);
3336 ig.Emit (OpCodes.Beq, target);
3339 case Operator.LessThan:
3341 if (is_unsigned && !is_float)
3342 ig.Emit (OpCodes.Blt_Un, target);
3344 ig.Emit (OpCodes.Blt, target);
3347 ig.Emit (OpCodes.Bge_Un, target);
3349 ig.Emit (OpCodes.Bge, target);
3352 case Operator.GreaterThan:
3354 if (is_unsigned && !is_float)
3355 ig.Emit (OpCodes.Bgt_Un, target);
3357 ig.Emit (OpCodes.Bgt, target);
3360 ig.Emit (OpCodes.Ble_Un, target);
3362 ig.Emit (OpCodes.Ble, target);
3365 case Operator.LessThanOrEqual:
3367 if (is_unsigned && !is_float)
3368 ig.Emit (OpCodes.Ble_Un, target);
3370 ig.Emit (OpCodes.Ble, target);
3373 ig.Emit (OpCodes.Bgt_Un, target);
3375 ig.Emit (OpCodes.Bgt, target);
3379 case Operator.GreaterThanOrEqual:
3381 if (is_unsigned && !is_float)
3382 ig.Emit (OpCodes.Bge_Un, target);
3384 ig.Emit (OpCodes.Bge, target);
3387 ig.Emit (OpCodes.Blt_Un, target);
3389 ig.Emit (OpCodes.Blt, target);
3392 throw new InternalErrorException (oper.ToString ());
3396 public override void Emit (EmitContext ec)
3398 EmitOperator (ec, left.Type);
3401 protected virtual void EmitOperator (EmitContext ec, Type l)
3403 ILGenerator ig = ec.ig;
3406 // Handle short-circuit operators differently
3409 if ((oper & Operator.LogicalMask) != 0) {
3410 Label load_result = ig.DefineLabel ();
3411 Label end = ig.DefineLabel ();
3413 bool is_or = oper == Operator.LogicalOr;
3414 left.EmitBranchable (ec, load_result, is_or);
3416 ig.Emit (OpCodes.Br_S, end);
3418 ig.MarkLabel (load_result);
3419 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3427 // Optimize zero-based operations
3429 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3431 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3432 Constant rc = right as Constant;
3433 if (rc != null && rc.IsDefaultValue) {
3439 EmitOperatorOpcode (ec, oper, l);
3442 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3443 // expression because that would wrap lifted binary operation
3445 if (enum_conversion != null)
3446 enum_conversion.Emit (ec);
3449 public override void EmitSideEffect (EmitContext ec)
3451 if ((oper & Operator.LogicalMask) != 0 ||
3452 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3453 base.EmitSideEffect (ec);
3455 left.EmitSideEffect (ec);
3456 right.EmitSideEffect (ec);
3460 protected override void CloneTo (CloneContext clonectx, Expression t)
3462 Binary target = (Binary) t;
3464 target.left = left.Clone (clonectx);
3465 target.right = right.Clone (clonectx);
3468 public override Expression CreateExpressionTree (EmitContext ec)
3470 return CreateExpressionTree (ec, null);
3473 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3476 bool lift_arg = false;
3479 case Operator.Addition:
3480 if (method == null && ec.CheckState && !IsFloat (type))
3481 method_name = "AddChecked";
3483 method_name = "Add";
3485 case Operator.BitwiseAnd:
3486 method_name = "And";
3488 case Operator.BitwiseOr:
3491 case Operator.Division:
3492 method_name = "Divide";
3494 case Operator.Equality:
3495 method_name = "Equal";
3498 case Operator.ExclusiveOr:
3499 method_name = "ExclusiveOr";
3501 case Operator.GreaterThan:
3502 method_name = "GreaterThan";
3505 case Operator.GreaterThanOrEqual:
3506 method_name = "GreaterThanOrEqual";
3509 case Operator.Inequality:
3510 method_name = "NotEqual";
3513 case Operator.LeftShift:
3514 method_name = "LeftShift";
3516 case Operator.LessThan:
3517 method_name = "LessThan";
3520 case Operator.LessThanOrEqual:
3521 method_name = "LessThanOrEqual";
3524 case Operator.LogicalAnd:
3525 method_name = "AndAlso";
3527 case Operator.LogicalOr:
3528 method_name = "OrElse";
3530 case Operator.Modulus:
3531 method_name = "Modulo";
3533 case Operator.Multiply:
3534 if (method == null && ec.CheckState && !IsFloat (type))
3535 method_name = "MultiplyChecked";
3537 method_name = "Multiply";
3539 case Operator.RightShift:
3540 method_name = "RightShift";
3542 case Operator.Subtraction:
3543 if (method == null && ec.CheckState && !IsFloat (type))
3544 method_name = "SubtractChecked";
3546 method_name = "Subtract";
3550 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3553 ArrayList args = new ArrayList (2);
3554 args.Add (new Argument (left.CreateExpressionTree (ec)));
3555 args.Add (new Argument (right.CreateExpressionTree (ec)));
3556 if (method != null) {
3558 args.Add (new Argument (new BoolConstant (false, loc)));
3560 args.Add (new Argument (method.CreateExpressionTree (ec)));
3563 return CreateExpressionFactoryCall (method_name, args);
3568 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3569 // b, c, d... may be strings or objects.
3571 public class StringConcat : Expression {
3572 ArrayList arguments;
3574 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3577 type = TypeManager.string_type;
3578 eclass = ExprClass.Value;
3580 arguments = new ArrayList (2);
3585 public override Expression CreateExpressionTree (EmitContext ec)
3587 Argument arg = (Argument) arguments [0];
3588 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3592 // Creates nested calls tree from an array of arguments used for IL emit
3594 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3596 ArrayList concat_args = new ArrayList (2);
3597 ArrayList add_args = new ArrayList (3);
3599 concat_args.Add (left);
3600 add_args.Add (new Argument (left_etree));
3602 concat_args.Add (arguments [pos]);
3603 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3605 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3609 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3613 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3615 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3616 if (++pos == arguments.Count)
3619 left = new Argument (new EmptyExpression (method.Type));
3620 return CreateExpressionAddCall (ec, left, expr, pos);
3623 public override Expression DoResolve (EmitContext ec)
3628 public void Append (EmitContext ec, Expression operand)
3633 StringConstant sc = operand as StringConstant;
3635 if (arguments.Count != 0) {
3636 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3637 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3638 if (last_expr_constant != null) {
3639 last_argument.Expr = new StringConstant (
3640 last_expr_constant.Value + sc.Value, sc.Location);
3646 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3648 StringConcat concat_oper = operand as StringConcat;
3649 if (concat_oper != null) {
3650 arguments.AddRange (concat_oper.arguments);
3655 arguments.Add (new Argument (operand));
3658 Expression CreateConcatMemberExpression ()
3660 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3663 public override void Emit (EmitContext ec)
3665 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3666 concat = concat.Resolve (ec);
3671 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3673 foreach (Argument a in arguments)
3674 a.Expr.MutateHoistedGenericType (storey);
3679 // User-defined conditional logical operator
3681 public class ConditionalLogicalOperator : UserOperatorCall {
3682 readonly bool is_and;
3685 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3686 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3687 : base (oper_method, arguments, expr_tree, loc)
3689 this.is_and = is_and;
3692 public override Expression DoResolve (EmitContext ec)
3694 MethodInfo method = (MethodInfo)mg;
3695 type = TypeManager.TypeToCoreType (method.ReturnType);
3696 AParametersCollection pd = TypeManager.GetParameterData (method);
3697 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3698 Report.Error (217, loc,
3699 "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",
3700 TypeManager.CSharpSignature (method));
3704 Expression left_dup = new EmptyExpression (type);
3705 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3706 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3707 if (op_true == null || op_false == null) {
3708 Report.Error (218, loc,
3709 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3710 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3714 oper = is_and ? op_false : op_true;
3715 eclass = ExprClass.Value;
3719 public override void Emit (EmitContext ec)
3721 ILGenerator ig = ec.ig;
3722 Label end_target = ig.DefineLabel ();
3725 // Emit and duplicate left argument
3727 ((Argument)arguments [0]).Expr.Emit (ec);
3728 ig.Emit (OpCodes.Dup);
3729 arguments.RemoveAt (0);
3731 oper.EmitBranchable (ec, end_target, true);
3733 ig.MarkLabel (end_target);
3737 public class PointerArithmetic : Expression {
3738 Expression left, right;
3742 // We assume that `l' is always a pointer
3744 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3753 public override Expression CreateExpressionTree (EmitContext ec)
3755 Error_PointerInsideExpressionTree ();
3759 public override Expression DoResolve (EmitContext ec)
3761 eclass = ExprClass.Variable;
3763 if (left.Type == TypeManager.void_ptr_type) {
3764 Error (242, "The operation in question is undefined on void pointers");
3771 public override void Emit (EmitContext ec)
3773 Type op_type = left.Type;
3774 ILGenerator ig = ec.ig;
3776 // It must be either array or fixed buffer
3778 if (TypeManager.HasElementType (op_type)) {
3779 element = TypeManager.GetElementType (op_type);
3781 FieldExpr fe = left as FieldExpr;
3783 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3788 int size = GetTypeSize (element);
3789 Type rtype = right.Type;
3791 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3793 // handle (pointer - pointer)
3797 ig.Emit (OpCodes.Sub);
3801 ig.Emit (OpCodes.Sizeof, element);
3803 IntLiteral.EmitInt (ig, size);
3804 ig.Emit (OpCodes.Div);
3806 ig.Emit (OpCodes.Conv_I8);
3809 // handle + and - on (pointer op int)
3811 Constant left_const = left as Constant;
3812 if (left_const != null) {
3814 // Optimize ((T*)null) pointer operations
3816 if (left_const.IsDefaultValue) {
3817 left = EmptyExpression.Null;
3825 Constant right_const = right as Constant;
3826 if (right_const != null) {
3828 // Optimize 0-based arithmetic
3830 if (right_const.IsDefaultValue)
3834 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3838 ig.Emit (OpCodes.Sizeof, element);
3839 right = EmptyExpression.Null;
3844 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3845 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3846 ig.Emit (OpCodes.Conv_I);
3847 } else if (rtype == TypeManager.uint32_type) {
3848 ig.Emit (OpCodes.Conv_U);
3851 if (right_const == null && size != 1){
3853 ig.Emit (OpCodes.Sizeof, element);
3855 IntLiteral.EmitInt (ig, size);
3856 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3857 ig.Emit (OpCodes.Conv_I8);
3859 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3862 if (left_const == null) {
3863 if (rtype == TypeManager.int64_type)
3864 ig.Emit (OpCodes.Conv_I);
3865 else if (rtype == TypeManager.uint64_type)
3866 ig.Emit (OpCodes.Conv_U);
3868 Binary.EmitOperatorOpcode (ec, op, op_type);
3875 /// Implements the ternary conditional operator (?:)
3877 public class Conditional : Expression {
3878 Expression expr, true_expr, false_expr;
3880 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3883 this.true_expr = true_expr;
3884 this.false_expr = false_expr;
3885 this.loc = expr.Location;
3888 public Expression Expr {
3894 public Expression TrueExpr {
3900 public Expression FalseExpr {
3906 public override Expression CreateExpressionTree (EmitContext ec)
3908 ArrayList args = new ArrayList (3);
3909 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3910 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3911 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3912 return CreateExpressionFactoryCall ("Condition", args);
3915 public override Expression DoResolve (EmitContext ec)
3917 expr = expr.Resolve (ec);
3922 if (expr.Type != TypeManager.bool_type){
3923 expr = Expression.ResolveBoolean (
3930 Assign ass = expr as Assign;
3931 if (ass != null && ass.Source is Constant) {
3932 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3935 true_expr = true_expr.Resolve (ec);
3936 false_expr = false_expr.Resolve (ec);
3938 if (true_expr == null || false_expr == null)
3941 eclass = ExprClass.Value;
3942 Type true_type = true_expr.Type;
3943 Type false_type = false_expr.Type;
3947 // First, if an implicit conversion exists from true_expr
3948 // to false_expr, then the result type is of type false_expr.Type
3950 if (!TypeManager.IsEqual (true_type, false_type)) {
3951 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3954 // Check if both can convert implicitl to each other's type
3956 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3958 "Can not compute type of conditional expression " +
3959 "as `" + TypeManager.CSharpName (true_expr.Type) +
3960 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3961 "' convert implicitly to each other");
3966 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3969 Report.Error (173, loc,
3970 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3971 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3976 // Dead code optimalization
3977 Constant c = expr as Constant;
3979 bool is_false = c.IsDefaultValue;
3980 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3981 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3987 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3989 expr.MutateHoistedGenericType (storey);
3990 true_expr.MutateHoistedGenericType (storey);
3991 false_expr.MutateHoistedGenericType (storey);
3992 type = storey.MutateType (type);
3995 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
4000 public override void Emit (EmitContext ec)
4002 ILGenerator ig = ec.ig;
4003 Label false_target = ig.DefineLabel ();
4004 Label end_target = ig.DefineLabel ();
4006 expr.EmitBranchable (ec, false_target, false);
4007 true_expr.Emit (ec);
4009 if (type.IsInterface) {
4010 LocalBuilder temp = ec.GetTemporaryLocal (type);
4011 ig.Emit (OpCodes.Stloc, temp);
4012 ig.Emit (OpCodes.Ldloc, temp);
4013 ec.FreeTemporaryLocal (temp, type);
4016 ig.Emit (OpCodes.Br, end_target);
4017 ig.MarkLabel (false_target);
4018 false_expr.Emit (ec);
4019 ig.MarkLabel (end_target);
4022 protected override void CloneTo (CloneContext clonectx, Expression t)
4024 Conditional target = (Conditional) t;
4026 target.expr = expr.Clone (clonectx);
4027 target.true_expr = true_expr.Clone (clonectx);
4028 target.false_expr = false_expr.Clone (clonectx);
4032 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4033 LocalTemporary temp;
4036 public abstract HoistedVariable HoistedVariable { get; }
4037 public abstract bool IsFixed { get; }
4038 public abstract bool IsRef { get; }
4039 public abstract string Name { get; }
4040 public abstract void SetHasAddressTaken ();
4043 // Variable IL data, it has to be protected to encapsulate hoisted variables
4045 protected abstract ILocalVariable Variable { get; }
4048 // Variable flow-analysis data
4050 public abstract VariableInfo VariableInfo { get; }
4053 public void AddressOf (EmitContext ec, AddressOp mode)
4055 if (IsHoistedEmitRequired (ec)) {
4056 HoistedVariable.AddressOf (ec, mode);
4060 Variable.EmitAddressOf (ec);
4063 public override void Emit (EmitContext ec)
4068 public override void EmitSideEffect (EmitContext ec)
4074 // This method is used by parameters that are references, that are
4075 // being passed as references: we only want to pass the pointer (that
4076 // is already stored in the parameter, not the address of the pointer,
4077 // and not the value of the variable).
4079 public void EmitLoad (EmitContext ec)
4084 public void Emit (EmitContext ec, bool leave_copy)
4086 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4088 if (IsHoistedEmitRequired (ec)) {
4089 HoistedVariable.Emit (ec, leave_copy);
4097 // If we are a reference, we loaded on the stack a pointer
4098 // Now lets load the real value
4100 LoadFromPtr (ec.ig, type);
4104 ec.ig.Emit (OpCodes.Dup);
4107 temp = new LocalTemporary (Type);
4113 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4114 bool prepare_for_load)
4116 if (IsHoistedEmitRequired (ec)) {
4117 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4121 New n_source = source as New;
4122 if (n_source != null) {
4123 if (!n_source.Emit (ec, this)) {
4136 ec.ig.Emit (OpCodes.Dup);
4138 temp = new LocalTemporary (Type);
4144 StoreFromPtr (ec.ig, type);
4146 Variable.EmitAssign (ec);
4154 public bool IsHoisted {
4155 get { return HoistedVariable != null; }
4158 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4161 // Default implementation return true when there is a hosted variable
4163 return HoistedVariable != null;
4166 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4168 type = storey.MutateType (type);
4175 public class LocalVariableReference : VariableReference {
4176 readonly string name;
4178 public LocalInfo local_info;
4181 public LocalVariableReference (Block block, string name, Location l)
4186 eclass = ExprClass.Variable;
4190 // Setting `is_readonly' to false will allow you to create a writable
4191 // reference to a read-only variable. This is used by foreach and using.
4193 public LocalVariableReference (Block block, string name, Location l,
4194 LocalInfo local_info, bool is_readonly)
4195 : this (block, name, l)
4197 this.local_info = local_info;
4198 this.is_readonly = is_readonly;
4201 public override VariableInfo VariableInfo {
4202 get { return local_info.VariableInfo; }
4205 public override HoistedVariable HoistedVariable {
4206 get { return local_info.HoistedVariableReference; }
4210 // A local variable is always fixed
4212 public override bool IsFixed {
4213 get { return true; }
4216 public override bool IsRef {
4217 get { return false; }
4220 public bool IsReadOnly {
4221 get { return is_readonly; }
4224 public override string Name {
4225 get { return name; }
4228 public bool VerifyAssigned (EmitContext ec)
4230 VariableInfo variable_info = local_info.VariableInfo;
4231 return variable_info == null || variable_info.IsAssigned (ec, loc);
4234 void ResolveLocalInfo ()
4236 if (local_info == null) {
4237 local_info = Block.GetLocalInfo (Name);
4238 type = local_info.VariableType;
4239 is_readonly = local_info.ReadOnly;
4243 public override void SetHasAddressTaken ()
4245 local_info.AddressTaken = true;
4248 public override Expression CreateExpressionTree (EmitContext ec)
4250 ArrayList arg = new ArrayList (1);
4251 arg.Add (new Argument (this));
4252 return CreateExpressionFactoryCall ("Constant", arg);
4255 Expression DoResolveBase (EmitContext ec)
4257 type = local_info.VariableType;
4259 Expression e = Block.GetConstantExpression (Name);
4261 return e.Resolve (ec);
4263 VerifyAssigned (ec);
4266 // If we are referencing a variable from the external block
4267 // flag it for capturing
4269 if (ec.MustCaptureVariable (local_info)) {
4270 if (local_info.AddressTaken)
4271 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4273 if (ec.IsVariableCapturingRequired) {
4274 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4275 storey.CaptureLocalVariable (ec, local_info);
4282 public override Expression DoResolve (EmitContext ec)
4284 ResolveLocalInfo ();
4285 local_info.Used = true;
4287 if (type == null && local_info.Type is VarExpr) {
4288 local_info.VariableType = TypeManager.object_type;
4289 Error_VariableIsUsedBeforeItIsDeclared (Name);
4293 return DoResolveBase (ec);
4296 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4298 ResolveLocalInfo ();
4301 if (right_side == EmptyExpression.OutAccess)
4302 local_info.Used = true;
4304 // Infer implicitly typed local variable
4306 VarExpr ve = local_info.Type as VarExpr;
4308 if (!ve.InferType (ec, right_side))
4310 type = local_info.VariableType = ve.Type;
4317 if (right_side == EmptyExpression.OutAccess) {
4318 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4319 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4320 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4321 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4322 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4323 } else if (right_side == EmptyExpression.UnaryAddress) {
4324 code = 459; msg = "Cannot take the address of {1} `{0}'";
4326 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4328 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4329 } else if (VariableInfo != null) {
4330 VariableInfo.SetAssigned (ec);
4333 return DoResolveBase (ec);
4336 public override int GetHashCode ()
4338 return Name.GetHashCode ();
4341 public override bool Equals (object obj)
4343 LocalVariableReference lvr = obj as LocalVariableReference;
4347 return Name == lvr.Name && Block == lvr.Block;
4350 protected override ILocalVariable Variable {
4351 get { return local_info; }
4354 public override string ToString ()
4356 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4359 protected override void CloneTo (CloneContext clonectx, Expression t)
4361 LocalVariableReference target = (LocalVariableReference) t;
4363 target.Block = clonectx.LookupBlock (Block);
4364 if (local_info != null)
4365 target.local_info = clonectx.LookupVariable (local_info);
4370 /// This represents a reference to a parameter in the intermediate
4373 public class ParameterReference : VariableReference {
4374 readonly ToplevelParameterInfo pi;
4375 readonly ToplevelBlock referenced;
4377 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4380 this.referenced = referenced;
4384 public override bool IsRef {
4385 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4388 bool HasOutModifier {
4389 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4392 public override HoistedVariable HoistedVariable {
4393 get { return pi.Parameter.HoistedVariableReference; }
4397 // A ref or out parameter is classified as a moveable variable, even
4398 // if the argument given for the parameter is a fixed variable
4400 public override bool IsFixed {
4401 get { return !IsRef; }
4404 public override string Name {
4405 get { return Parameter.Name; }
4408 public Parameter Parameter {
4409 get { return pi.Parameter; }
4412 public override VariableInfo VariableInfo {
4413 get { return pi.VariableInfo; }
4416 protected override ILocalVariable Variable {
4417 get { return Parameter; }
4420 public bool IsAssigned (EmitContext ec, Location loc)
4422 // HACK: Variables are not captured in probing mode
4423 if (ec.IsInProbingMode)
4426 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4429 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4433 public override void SetHasAddressTaken ()
4435 Parameter.HasAddressTaken = true;
4438 void SetAssigned (EmitContext ec)
4440 if (HasOutModifier && ec.DoFlowAnalysis)
4441 ec.CurrentBranching.SetAssigned (VariableInfo);
4444 bool DoResolveBase (EmitContext ec)
4446 type = pi.ParameterType;
4447 eclass = ExprClass.Variable;
4449 AnonymousExpression am = ec.CurrentAnonymousMethod;
4453 ToplevelBlock declared = pi.Block;
4454 if (declared != referenced) {
4456 Report.Error (1628, loc,
4457 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4458 Name, am.ContainerType);
4466 if (ec.IsVariableCapturingRequired) {
4467 if (pi.Parameter.HasAddressTaken)
4468 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4470 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4471 storey.CaptureParameter (ec, this);
4477 public override int GetHashCode ()
4479 return Name.GetHashCode ();
4482 public override bool Equals (object obj)
4484 ParameterReference pr = obj as ParameterReference;
4488 return Name == pr.Name && referenced == pr.referenced;
4491 protected override void CloneTo (CloneContext clonectx, Expression target)
4496 public override Expression CreateExpressionTree (EmitContext ec)
4498 if (IsHoistedEmitRequired (ec))
4499 return HoistedVariable.CreateExpressionTree (ec);
4501 return Parameter.ExpressionTreeVariableReference ();
4505 // Notice that for ref/out parameters, the type exposed is not the
4506 // same type exposed externally.
4509 // externally we expose "int&"
4510 // here we expose "int".
4512 // We record this in "is_ref". This means that the type system can treat
4513 // the type as it is expected, but when we generate the code, we generate
4514 // the alternate kind of code.
4516 public override Expression DoResolve (EmitContext ec)
4518 if (!DoResolveBase (ec))
4521 if (HasOutModifier && ec.DoFlowAnalysis &&
4522 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4528 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4530 if (!DoResolveBase (ec))
4533 // HACK: parameters are not captured when probing is on
4534 if (!ec.IsInProbingMode)
4540 static public void EmitLdArg (ILGenerator ig, int x)
4544 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4545 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4546 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4547 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4548 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4551 ig.Emit (OpCodes.Ldarg, x);
4556 /// Used for arguments to New(), Invocation()
4558 public class Argument {
4559 public enum AType : byte {
4566 public static readonly Argument[] Empty = new Argument [0];
4568 public readonly AType ArgType;
4569 public Expression Expr;
4571 public Argument (Expression expr, AType type)
4574 this.ArgType = type;
4577 public Argument (Expression expr)
4580 this.ArgType = AType.Expression;
4584 get { return Expr.Type; }
4587 public Parameter.Modifier Modifier
4592 return Parameter.Modifier.OUT;
4595 return Parameter.Modifier.REF;
4598 return Parameter.Modifier.NONE;
4603 public string GetSignatureForError ()
4605 if (Expr.eclass == ExprClass.MethodGroup)
4606 return Expr.ExprClassName;
4608 return TypeManager.CSharpName (Expr.Type);
4611 public bool ResolveMethodGroup (EmitContext ec)
4613 SimpleName sn = Expr as SimpleName;
4615 Expr = sn.GetMethodGroup ();
4617 // FIXME: csc doesn't report any error if you try to use `ref' or
4618 // `out' in a delegate creation expression.
4619 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4626 public bool Resolve (EmitContext ec, Location loc)
4631 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4632 // Verify that the argument is readable
4633 if (ArgType != AType.Out)
4634 Expr = Expr.Resolve (ec);
4636 // Verify that the argument is writeable
4637 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4638 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4640 return Expr != null;
4644 public void Emit (EmitContext ec)
4646 if (ArgType != AType.Ref && ArgType != AType.Out) {
4651 AddressOp mode = AddressOp.Store;
4652 if (ArgType == AType.Ref)
4653 mode |= AddressOp.Load;
4655 IMemoryLocation ml = (IMemoryLocation) Expr;
4656 ParameterReference pr = ml as ParameterReference;
4659 // ParameterReferences might already be references, so we want
4660 // to pass just the value
4662 if (pr != null && pr.IsRef)
4665 ml.AddressOf (ec, mode);
4668 public Argument Clone (CloneContext clonectx)
4670 return new Argument (Expr.Clone (clonectx), ArgType);
4675 /// Invocation of methods or delegates.
4677 public class Invocation : ExpressionStatement {
4678 protected ArrayList Arguments;
4679 protected Expression expr;
4680 protected MethodGroupExpr mg;
4681 bool arguments_resolved;
4684 // arguments is an ArrayList, but we do not want to typecast,
4685 // as it might be null.
4687 public Invocation (Expression expr, ArrayList arguments)
4689 SimpleName sn = expr as SimpleName;
4691 this.expr = sn.GetMethodGroup ();
4695 Arguments = arguments;
4697 loc = expr.Location;
4700 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4701 : this (expr, arguments)
4703 this.arguments_resolved = arguments_resolved;
4706 public override Expression CreateExpressionTree (EmitContext ec)
4711 // Special conversion for nested expression trees
4713 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4714 args = new ArrayList (1);
4715 args.Add (new Argument (this));
4716 return CreateExpressionFactoryCall ("Quote", args);
4719 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4721 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4724 args = new ArrayList (arg_count);
4727 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4729 args.Add (new Argument (new NullLiteral (loc)));
4731 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4734 // Use extension argument when exists
4737 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4739 args.Add (new Argument (e));
4742 if (Arguments != null) {
4743 foreach (Argument a in Arguments) {
4744 Expression e = a.Expr.CreateExpressionTree (ec);
4746 args.Add (new Argument (e));
4751 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4753 return CreateExpressionFactoryCall ("Call", args);
4756 public override Expression DoResolve (EmitContext ec)
4758 // Don't resolve already resolved expression
4759 if (eclass != ExprClass.Invalid)
4762 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4763 if (expr_resolved == null)
4766 mg = expr_resolved as MethodGroupExpr;
4768 Type expr_type = expr_resolved.Type;
4770 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4771 return (new DelegateInvocation (
4772 expr_resolved, Arguments, loc)).Resolve (ec);
4775 MemberExpr me = expr_resolved as MemberExpr;
4777 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4781 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4783 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4784 expr_resolved.GetSignatureForError ());
4788 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4792 // Next, evaluate all the expressions in the argument list
4794 if (Arguments != null && !arguments_resolved) {
4795 for (int i = 0; i < Arguments.Count; ++i)
4797 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4802 mg = DoResolveOverload (ec);
4806 MethodInfo method = (MethodInfo)mg;
4807 if (method != null) {
4808 type = TypeManager.TypeToCoreType (method.ReturnType);
4810 // TODO: this is a copy of mg.ResolveMemberAccess method
4811 Expression iexpr = mg.InstanceExpression;
4812 if (method.IsStatic) {
4813 if (iexpr == null ||
4814 iexpr is This || iexpr is EmptyExpression ||
4815 mg.IdenticalTypeName) {
4816 mg.InstanceExpression = null;
4818 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4822 if (iexpr == null) {
4823 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4828 if (type.IsPointer){
4836 // Only base will allow this invocation to happen.
4838 if (mg.IsBase && method.IsAbstract){
4839 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4843 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4845 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4847 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4851 IsSpecialMethodInvocation (method, loc);
4853 if (mg.InstanceExpression != null)
4854 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4856 eclass = ExprClass.Value;
4860 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4862 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4865 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4867 if (!TypeManager.IsSpecialMethod (method))
4870 Report.SymbolRelatedToPreviousError (method);
4871 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4872 TypeManager.CSharpSignature (method, true));
4878 /// Emits a list of resolved Arguments that are in the arguments
4881 /// The MethodBase argument might be null if the
4882 /// emission of the arguments is known not to contain
4883 /// a `params' field (for example in constructors or other routines
4884 /// that keep their arguments in this structure)
4886 /// if `dup_args' is true, a copy of the arguments will be left
4887 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4888 /// which will be duplicated before any other args. Only EmitCall
4889 /// should be using this interface.
4891 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4893 if (arguments == null)
4896 int top = arguments.Count;
4897 LocalTemporary [] temps = null;
4899 if (dup_args && top != 0)
4900 temps = new LocalTemporary [top];
4902 int argument_index = 0;
4904 for (int i = 0; i < top; i++) {
4905 a = (Argument) arguments [argument_index++];
4908 ec.ig.Emit (OpCodes.Dup);
4909 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4914 if (this_arg != null)
4917 for (int i = 0; i < top; i ++) {
4918 temps [i].Emit (ec);
4919 temps [i].Release (ec);
4924 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4926 AParametersCollection pd = TypeManager.GetParameterData (mb);
4928 Argument a = (Argument) arguments [pd.Count - 1];
4929 Arglist list = (Arglist) a.Expr;
4931 return list.ArgumentTypes;
4935 /// This checks the ConditionalAttribute on the method
4937 public static bool IsMethodExcluded (MethodBase method, Location loc)
4939 if (method.IsConstructor)
4942 method = TypeManager.DropGenericMethodArguments (method);
4943 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4944 IMethodData md = TypeManager.GetMethod (method);
4946 return md.IsExcluded ();
4948 // For some methods (generated by delegate class) GetMethod returns null
4949 // because they are not included in builder_to_method table
4953 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4957 /// is_base tells whether we want to force the use of the `call'
4958 /// opcode instead of using callvirt. Call is required to call
4959 /// a specific method, while callvirt will always use the most
4960 /// recent method in the vtable.
4962 /// is_static tells whether this is an invocation on a static method
4964 /// instance_expr is an expression that represents the instance
4965 /// it must be non-null if is_static is false.
4967 /// method is the method to invoke.
4969 /// Arguments is the list of arguments to pass to the method or constructor.
4971 public static void EmitCall (EmitContext ec, bool is_base,
4972 Expression instance_expr,
4973 MethodBase method, ArrayList Arguments, Location loc)
4975 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4978 // `dup_args' leaves an extra copy of the arguments on the stack
4979 // `omit_args' does not leave any arguments at all.
4980 // So, basically, you could make one call with `dup_args' set to true,
4981 // and then another with `omit_args' set to true, and the two calls
4982 // would have the same set of arguments. However, each argument would
4983 // only have been evaluated once.
4984 public static void EmitCall (EmitContext ec, bool is_base,
4985 Expression instance_expr,
4986 MethodBase method, ArrayList Arguments, Location loc,
4987 bool dup_args, bool omit_args)
4989 ILGenerator ig = ec.ig;
4990 bool struct_call = false;
4991 bool this_call = false;
4992 LocalTemporary this_arg = null;
4994 Type decl_type = method.DeclaringType;
4996 if (IsMethodExcluded (method, loc))
4999 bool is_static = method.IsStatic;
5001 this_call = instance_expr is This;
5002 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5006 // If this is ourselves, push "this"
5010 Type iexpr_type = instance_expr.Type;
5013 // Push the instance expression
5015 if (TypeManager.IsValueType (iexpr_type)) {
5017 // Special case: calls to a function declared in a
5018 // reference-type with a value-type argument need
5019 // to have their value boxed.
5020 if (decl_type.IsValueType ||
5021 TypeManager.IsGenericParameter (iexpr_type)) {
5023 // If the expression implements IMemoryLocation, then
5024 // we can optimize and use AddressOf on the
5027 // If not we have to use some temporary storage for
5029 if (instance_expr is IMemoryLocation) {
5030 ((IMemoryLocation)instance_expr).
5031 AddressOf (ec, AddressOp.LoadStore);
5033 LocalTemporary temp = new LocalTemporary (iexpr_type);
5034 instance_expr.Emit (ec);
5036 temp.AddressOf (ec, AddressOp.Load);
5039 // avoid the overhead of doing this all the time.
5041 t = TypeManager.GetReferenceType (iexpr_type);
5043 instance_expr.Emit (ec);
5044 ig.Emit (OpCodes.Box, instance_expr.Type);
5045 t = TypeManager.object_type;
5048 instance_expr.Emit (ec);
5049 t = instance_expr.Type;
5053 ig.Emit (OpCodes.Dup);
5054 if (Arguments != null && Arguments.Count != 0) {
5055 this_arg = new LocalTemporary (t);
5056 this_arg.Store (ec);
5063 EmitArguments (ec, Arguments, dup_args, this_arg);
5066 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5067 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5071 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5072 call_op = OpCodes.Call;
5074 call_op = OpCodes.Callvirt;
5076 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5077 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5078 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5085 // and DoFoo is not virtual, you can omit the callvirt,
5086 // because you don't need the null checking behavior.
5088 if (method is MethodInfo)
5089 ig.Emit (call_op, (MethodInfo) method);
5091 ig.Emit (call_op, (ConstructorInfo) method);
5094 public override void Emit (EmitContext ec)
5096 mg.EmitCall (ec, Arguments);
5099 public override void EmitStatement (EmitContext ec)
5104 // Pop the return value if there is one
5106 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5107 ec.ig.Emit (OpCodes.Pop);
5110 protected override void CloneTo (CloneContext clonectx, Expression t)
5112 Invocation target = (Invocation) t;
5114 if (Arguments != null) {
5115 target.Arguments = new ArrayList (Arguments.Count);
5116 foreach (Argument a in Arguments)
5117 target.Arguments.Add (a.Clone (clonectx));
5120 target.expr = expr.Clone (clonectx);
5123 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5125 mg.MutateHoistedGenericType (storey);
5126 if (Arguments != null) {
5127 foreach (Argument a in Arguments)
5128 a.Expr.MutateHoistedGenericType (storey);
5134 // It's either a cast or delegate invocation
5136 public class InvocationOrCast : ExpressionStatement
5139 Expression argument;
5141 public InvocationOrCast (Expression expr, Expression argument)
5144 this.argument = argument;
5145 this.loc = expr.Location;
5148 public override Expression CreateExpressionTree (EmitContext ec)
5150 throw new NotSupportedException ("ET");
5153 public override Expression DoResolve (EmitContext ec)
5155 Expression e = ResolveCore (ec);
5159 return e.Resolve (ec);
5162 Expression ResolveCore (EmitContext ec)
5165 // First try to resolve it as a cast.
5167 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5169 return new Cast (te, argument, loc);
5173 // This can either be a type or a delegate invocation.
5174 // Let's just resolve it and see what we'll get.
5176 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5181 // Ok, so it's a Cast.
5183 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5184 return new Cast (expr, argument, loc);
5187 if (expr.eclass == ExprClass.Namespace) {
5188 expr.Error_UnexpectedKind (null, "type", loc);
5193 // It's a delegate invocation.
5195 if (!TypeManager.IsDelegateType (expr.Type)) {
5196 Error (149, "Method name expected");
5200 ArrayList args = new ArrayList (1);
5201 args.Add (new Argument (argument, Argument.AType.Expression));
5202 return new DelegateInvocation (expr, args, loc);
5205 public override ExpressionStatement ResolveStatement (EmitContext ec)
5207 Expression e = ResolveCore (ec);
5211 ExpressionStatement s = e as ExpressionStatement;
5213 Error_InvalidExpressionStatement ();
5217 return s.ResolveStatement (ec);
5220 public override void Emit (EmitContext ec)
5222 throw new Exception ("Cannot happen");
5225 public override void EmitStatement (EmitContext ec)
5227 throw new Exception ("Cannot happen");
5230 protected override void CloneTo (CloneContext clonectx, Expression t)
5232 InvocationOrCast target = (InvocationOrCast) t;
5234 target.expr = expr.Clone (clonectx);
5235 target.argument = argument.Clone (clonectx);
5241 /// Implements the new expression
5243 public class New : ExpressionStatement, IMemoryLocation {
5244 ArrayList Arguments;
5247 // During bootstrap, it contains the RequestedType,
5248 // but if `type' is not null, it *might* contain a NewDelegate
5249 // (because of field multi-initialization)
5251 Expression RequestedType;
5253 MethodGroupExpr method;
5255 bool is_type_parameter;
5257 public New (Expression requested_type, ArrayList arguments, Location l)
5259 RequestedType = requested_type;
5260 Arguments = arguments;
5265 /// Converts complex core type syntax like 'new int ()' to simple constant
5267 public static Constant Constantify (Type t)
5269 if (t == TypeManager.int32_type)
5270 return new IntConstant (0, Location.Null);
5271 if (t == TypeManager.uint32_type)
5272 return new UIntConstant (0, Location.Null);
5273 if (t == TypeManager.int64_type)
5274 return new LongConstant (0, Location.Null);
5275 if (t == TypeManager.uint64_type)
5276 return new ULongConstant (0, Location.Null);
5277 if (t == TypeManager.float_type)
5278 return new FloatConstant (0, Location.Null);
5279 if (t == TypeManager.double_type)
5280 return new DoubleConstant (0, Location.Null);
5281 if (t == TypeManager.short_type)
5282 return new ShortConstant (0, Location.Null);
5283 if (t == TypeManager.ushort_type)
5284 return new UShortConstant (0, Location.Null);
5285 if (t == TypeManager.sbyte_type)
5286 return new SByteConstant (0, Location.Null);
5287 if (t == TypeManager.byte_type)
5288 return new ByteConstant (0, Location.Null);
5289 if (t == TypeManager.char_type)
5290 return new CharConstant ('\0', Location.Null);
5291 if (t == TypeManager.bool_type)
5292 return new BoolConstant (false, Location.Null);
5293 if (t == TypeManager.decimal_type)
5294 return new DecimalConstant (0, Location.Null);
5295 if (TypeManager.IsEnumType (t))
5296 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5302 // Checks whether the type is an interface that has the
5303 // [ComImport, CoClass] attributes and must be treated
5306 public Expression CheckComImport (EmitContext ec)
5308 if (!type.IsInterface)
5312 // Turn the call into:
5313 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5315 Type real_class = AttributeTester.GetCoClassAttribute (type);
5316 if (real_class == null)
5319 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5320 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5321 return cast.Resolve (ec);
5324 public override Expression CreateExpressionTree (EmitContext ec)
5326 ArrayList args = Arguments == null ?
5327 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5329 if (method == null) {
5330 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5332 args.Add (new Argument (method.CreateExpressionTree (ec)));
5333 if (Arguments != null) {
5335 foreach (Argument a in Arguments) {
5336 expr = a.Expr.CreateExpressionTree (ec);
5338 args.Add (new Argument (expr));
5343 return CreateExpressionFactoryCall ("New", args);
5346 public override Expression DoResolve (EmitContext ec)
5349 // The New DoResolve might be called twice when initializing field
5350 // expressions (see EmitFieldInitializers, the call to
5351 // GetInitializerExpression will perform a resolve on the expression,
5352 // and later the assign will trigger another resolution
5354 // This leads to bugs (#37014)
5357 if (RequestedType is NewDelegate)
5358 return RequestedType;
5362 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5368 if (type.IsPointer) {
5369 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5370 TypeManager.CSharpName (type));
5374 if (Arguments == null) {
5375 Constant c = Constantify (type);
5377 return ReducedExpression.Create (c, this);
5380 if (TypeManager.IsDelegateType (type)) {
5381 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5385 if (type.IsGenericParameter) {
5386 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5388 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5389 Error (304, String.Format (
5390 "Cannot create an instance of the " +
5391 "variable type '{0}' because it " +
5392 "doesn't have the new() constraint",
5397 if ((Arguments != null) && (Arguments.Count != 0)) {
5398 Error (417, String.Format (
5399 "`{0}': cannot provide arguments " +
5400 "when creating an instance of a " +
5401 "variable type.", type));
5405 if (TypeManager.activator_create_instance == null) {
5406 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5407 if (activator_type != null) {
5408 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5409 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5413 is_type_parameter = true;
5414 eclass = ExprClass.Value;
5419 if (type.IsAbstract && type.IsSealed) {
5420 Report.SymbolRelatedToPreviousError (type);
5421 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5425 if (type.IsInterface || type.IsAbstract){
5426 if (!TypeManager.IsGenericType (type)) {
5427 RequestedType = CheckComImport (ec);
5428 if (RequestedType != null)
5429 return RequestedType;
5432 Report.SymbolRelatedToPreviousError (type);
5433 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5437 bool is_struct = type.IsValueType;
5438 eclass = ExprClass.Value;
5441 // SRE returns a match for .ctor () on structs (the object constructor),
5442 // so we have to manually ignore it.
5444 if (is_struct && Arguments == null)
5447 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5448 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5449 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5451 if (Arguments != null){
5452 foreach (Argument a in Arguments){
5453 if (!a.Resolve (ec, loc))
5461 method = ml as MethodGroupExpr;
5462 if (method == null) {
5463 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5467 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5474 bool DoEmitTypeParameter (EmitContext ec)
5477 ILGenerator ig = ec.ig;
5478 // IMemoryLocation ml;
5480 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5481 new Type [] { type });
5483 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5484 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5485 ig.Emit (OpCodes.Call, ci);
5489 // Allow DoEmit() to be called multiple times.
5490 // We need to create a new LocalTemporary each time since
5491 // you can't share LocalBuilders among ILGeneators.
5492 LocalTemporary temp = new LocalTemporary (type);
5494 Label label_activator = ig.DefineLabel ();
5495 Label label_end = ig.DefineLabel ();
5497 temp.AddressOf (ec, AddressOp.Store);
5498 ig.Emit (OpCodes.Initobj, type);
5501 ig.Emit (OpCodes.Box, type);
5502 ig.Emit (OpCodes.Brfalse, label_activator);
5504 temp.AddressOf (ec, AddressOp.Store);
5505 ig.Emit (OpCodes.Initobj, type);
5507 ig.Emit (OpCodes.Br, label_end);
5509 ig.MarkLabel (label_activator);
5511 ig.Emit (OpCodes.Call, ci);
5512 ig.MarkLabel (label_end);
5515 throw new InternalErrorException ();
5520 // This Emit can be invoked in two contexts:
5521 // * As a mechanism that will leave a value on the stack (new object)
5522 // * As one that wont (init struct)
5524 // If we are dealing with a ValueType, we have a few
5525 // situations to deal with:
5527 // * The target is a ValueType, and we have been provided
5528 // the instance (this is easy, we are being assigned).
5530 // * The target of New is being passed as an argument,
5531 // to a boxing operation or a function that takes a
5534 // In this case, we need to create a temporary variable
5535 // that is the argument of New.
5537 // Returns whether a value is left on the stack
5539 // *** Implementation note ***
5541 // To benefit from this optimization, each assignable expression
5542 // has to manually cast to New and call this Emit.
5544 // TODO: It's worth to implement it for arrays and fields
5546 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5548 if (is_type_parameter)
5549 return DoEmitTypeParameter (ec);
5551 bool is_value_type = TypeManager.IsValueType (type);
5552 ILGenerator ig = ec.ig;
5553 VariableReference vr = target as VariableReference;
5555 if (target != null && is_value_type && (vr != null || method == null)) {
5556 target.AddressOf (ec, AddressOp.Store);
5557 } else if (vr != null && vr.IsRef) {
5562 method.EmitArguments (ec, Arguments);
5564 if (is_value_type) {
5565 if (method == null) {
5566 ig.Emit (OpCodes.Initobj, type);
5571 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5576 ConstructorInfo ci = (ConstructorInfo) method;
5578 if (TypeManager.IsGenericType (type))
5579 ci = TypeBuilder.GetConstructor (type, ci);
5582 ig.Emit (OpCodes.Newobj, ci);
5586 public override void Emit (EmitContext ec)
5588 LocalTemporary v = null;
5589 if (method == null && TypeManager.IsValueType (type)) {
5590 // TODO: Use temporary variable from pool
5591 v = new LocalTemporary (type);
5598 public override void EmitStatement (EmitContext ec)
5600 LocalTemporary v = null;
5601 if (method == null && TypeManager.IsValueType (type)) {
5602 // TODO: Use temporary variable from pool
5603 v = new LocalTemporary (type);
5607 ec.ig.Emit (OpCodes.Pop);
5610 public virtual bool HasInitializer {
5616 public void AddressOf (EmitContext ec, AddressOp Mode)
5618 if (is_type_parameter) {
5619 LocalTemporary temp = new LocalTemporary (type);
5620 DoEmitTypeParameter (ec);
5622 temp.AddressOf (ec, Mode);
5626 if (!type.IsValueType){
5628 // We throw an exception. So far, I believe we only need to support
5630 // foreach (int j in new StructType ())
5633 throw new Exception ("AddressOf should not be used for classes");
5636 LocalTemporary value_target = new LocalTemporary (type);
5637 IMemoryLocation ml = (IMemoryLocation) value_target;
5639 ml.AddressOf (ec, AddressOp.Store);
5640 if (method == null) {
5641 ec.ig.Emit (OpCodes.Initobj, type);
5643 method.EmitArguments (ec, Arguments);
5644 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5647 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5650 protected override void CloneTo (CloneContext clonectx, Expression t)
5652 New target = (New) t;
5654 target.RequestedType = RequestedType.Clone (clonectx);
5655 if (Arguments != null){
5656 target.Arguments = new ArrayList ();
5657 foreach (Argument a in Arguments){
5658 target.Arguments.Add (a.Clone (clonectx));
5663 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5665 if (method != null) {
5666 method.MutateHoistedGenericType (storey);
5667 if (Arguments != null) {
5668 foreach (Argument a in Arguments)
5669 a.Expr.MutateHoistedGenericType (storey);
5673 type = storey.MutateType (type);
5678 /// 14.5.10.2: Represents an array creation expression.
5682 /// There are two possible scenarios here: one is an array creation
5683 /// expression that specifies the dimensions and optionally the
5684 /// initialization data and the other which does not need dimensions
5685 /// specified but where initialization data is mandatory.
5687 public class ArrayCreation : Expression {
5688 FullNamedExpression requested_base_type;
5689 ArrayList initializers;
5692 // The list of Argument types.
5693 // This is used to construct the `newarray' or constructor signature
5695 protected ArrayList arguments;
5697 protected Type array_element_type;
5698 bool expect_initializers = false;
5699 int num_arguments = 0;
5700 protected int dimensions;
5701 protected readonly string rank;
5703 protected ArrayList array_data;
5707 // The number of constants in array initializers
5708 int const_initializers_count;
5709 bool only_constant_initializers;
5711 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5713 this.requested_base_type = requested_base_type;
5714 this.initializers = initializers;
5718 arguments = new ArrayList (exprs.Count);
5720 foreach (Expression e in exprs) {
5721 arguments.Add (new Argument (e, Argument.AType.Expression));
5726 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5728 this.requested_base_type = requested_base_type;
5729 this.initializers = initializers;
5733 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5735 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5737 //dimensions = tmp.Length - 1;
5738 expect_initializers = true;
5741 public static void Error_IncorrectArrayInitializer (Location loc)
5743 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5746 protected override void Error_NegativeArrayIndex (Location loc)
5748 Report.Error (248, loc, "Cannot create an array with a negative size");
5751 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5753 if (specified_dims) {
5754 Argument a = (Argument) arguments [idx];
5756 if (!a.Resolve (ec, loc))
5759 Constant c = a.Expr as Constant;
5761 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5765 Report.Error (150, a.Expr.Location, "A constant value is expected");
5769 int value = (int) c.GetValue ();
5771 if (value != probe.Count) {
5772 Error_IncorrectArrayInitializer (loc);
5776 bounds [idx] = value;
5779 int child_bounds = -1;
5780 only_constant_initializers = true;
5781 for (int i = 0; i < probe.Count; ++i) {
5782 object o = probe [i];
5783 if (o is ArrayList) {
5784 ArrayList sub_probe = o as ArrayList;
5785 int current_bounds = sub_probe.Count;
5787 if (child_bounds == -1)
5788 child_bounds = current_bounds;
5790 else if (child_bounds != current_bounds){
5791 Error_IncorrectArrayInitializer (loc);
5794 if (idx + 1 >= dimensions){
5795 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5799 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5803 if (child_bounds != -1){
5804 Error_IncorrectArrayInitializer (loc);
5808 Expression element = ResolveArrayElement (ec, (Expression) o);
5809 if (element == null)
5812 // Initializers with the default values can be ignored
5813 Constant c = element as Constant;
5815 if (c.IsDefaultInitializer (array_element_type)) {
5819 ++const_initializers_count;
5822 only_constant_initializers = false;
5825 array_data.Add (element);
5832 public override Expression CreateExpressionTree (EmitContext ec)
5836 if (array_data == null) {
5837 args = new ArrayList (arguments.Count + 1);
5838 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5839 foreach (Argument a in arguments) {
5840 if (arguments.Count == 1) {
5841 Constant c = a.Expr as Constant;
5842 if (c.IsDefaultValue)
5843 return CreateExpressionFactoryCall ("NewArrayInit", args);
5845 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5848 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5851 if (dimensions > 1) {
5852 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5856 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5857 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5858 if (array_data != null) {
5859 for (int i = 0; i < array_data.Count; ++i) {
5860 Expression e = (Expression) array_data [i];
5862 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5864 args.Add (new Argument (e.CreateExpressionTree (ec)));
5868 return CreateExpressionFactoryCall ("NewArrayInit", args);
5871 public void UpdateIndices ()
5874 for (ArrayList probe = initializers; probe != null;) {
5875 if (probe.Count > 0 && probe [0] is ArrayList) {
5876 Expression e = new IntConstant (probe.Count, Location.Null);
5877 arguments.Add (new Argument (e, Argument.AType.Expression));
5879 bounds [i++] = probe.Count;
5881 probe = (ArrayList) probe [0];
5884 Expression e = new IntConstant (probe.Count, Location.Null);
5885 arguments.Add (new Argument (e, Argument.AType.Expression));
5887 bounds [i++] = probe.Count;
5894 Expression first_emit;
5895 LocalTemporary first_emit_temp;
5897 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5899 element = element.Resolve (ec);
5900 if (element == null)
5903 if (element is CompoundAssign.TargetExpression) {
5904 if (first_emit != null)
5905 throw new InternalErrorException ("Can only handle one mutator at a time");
5906 first_emit = element;
5907 element = first_emit_temp = new LocalTemporary (element.Type);
5910 return Convert.ImplicitConversionRequired (
5911 ec, element, array_element_type, loc);
5914 protected bool ResolveInitializers (EmitContext ec)
5916 if (initializers == null) {
5917 return !expect_initializers;
5921 // We use this to store all the date values in the order in which we
5922 // will need to store them in the byte blob later
5924 array_data = new ArrayList ();
5925 bounds = new System.Collections.Specialized.HybridDictionary ();
5927 if (arguments != null)
5928 return CheckIndices (ec, initializers, 0, true);
5930 arguments = new ArrayList ();
5932 if (!CheckIndices (ec, initializers, 0, false))
5941 // Resolved the type of the array
5943 bool ResolveArrayType (EmitContext ec)
5945 if (requested_base_type == null) {
5946 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5950 if (requested_base_type is VarExpr) {
5951 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5955 StringBuilder array_qualifier = new StringBuilder (rank);
5958 // `In the first form allocates an array instace of the type that results
5959 // from deleting each of the individual expression from the expression list'
5961 if (num_arguments > 0) {
5962 array_qualifier.Append ("[");
5963 for (int i = num_arguments-1; i > 0; i--)
5964 array_qualifier.Append (",");
5965 array_qualifier.Append ("]");
5971 TypeExpr array_type_expr;
5972 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5973 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5974 if (array_type_expr == null)
5977 type = array_type_expr.Type;
5978 array_element_type = TypeManager.GetElementType (type);
5979 dimensions = type.GetArrayRank ();
5984 public override Expression DoResolve (EmitContext ec)
5989 if (!ResolveArrayType (ec))
5993 // First step is to validate the initializers and fill
5994 // in any missing bits
5996 if (!ResolveInitializers (ec))
5999 if (arguments.Count != dimensions) {
6000 Error_IncorrectArrayInitializer (loc);
6003 foreach (Argument a in arguments){
6004 if (!a.Resolve (ec, loc))
6007 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6010 eclass = ExprClass.Value;
6014 MethodInfo GetArrayMethod (int arguments)
6016 ModuleBuilder mb = CodeGen.Module.Builder;
6018 Type[] arg_types = new Type[arguments];
6019 for (int i = 0; i < arguments; i++)
6020 arg_types[i] = TypeManager.int32_type;
6022 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6026 Report.Error (-6, "New invocation: Can not find a constructor for " +
6027 "this argument list");
6034 byte [] MakeByteBlob ()
6039 int count = array_data.Count;
6041 if (TypeManager.IsEnumType (array_element_type))
6042 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6044 factor = GetTypeSize (array_element_type);
6046 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6048 data = new byte [(count * factor + 3) & ~3];
6051 for (int i = 0; i < count; ++i) {
6052 object v = array_data [i];
6054 if (v is EnumConstant)
6055 v = ((EnumConstant) v).Child;
6057 if (v is Constant && !(v is StringConstant))
6058 v = ((Constant) v).GetValue ();
6064 if (array_element_type == TypeManager.int64_type){
6065 if (!(v is Expression)){
6066 long val = (long) v;
6068 for (int j = 0; j < factor; ++j) {
6069 data [idx + j] = (byte) (val & 0xFF);
6073 } else if (array_element_type == TypeManager.uint64_type){
6074 if (!(v is Expression)){
6075 ulong val = (ulong) v;
6077 for (int j = 0; j < factor; ++j) {
6078 data [idx + j] = (byte) (val & 0xFF);
6082 } else if (array_element_type == TypeManager.float_type) {
6083 if (!(v is Expression)){
6084 element = BitConverter.GetBytes ((float) v);
6086 for (int j = 0; j < factor; ++j)
6087 data [idx + j] = element [j];
6088 if (!BitConverter.IsLittleEndian)
6089 System.Array.Reverse (data, idx, 4);
6091 } else if (array_element_type == TypeManager.double_type) {
6092 if (!(v is Expression)){
6093 element = BitConverter.GetBytes ((double) v);
6095 for (int j = 0; j < factor; ++j)
6096 data [idx + j] = element [j];
6098 // FIXME: Handle the ARM float format.
6099 if (!BitConverter.IsLittleEndian)
6100 System.Array.Reverse (data, idx, 8);
6102 } else if (array_element_type == TypeManager.char_type){
6103 if (!(v is Expression)){
6104 int val = (int) ((char) v);
6106 data [idx] = (byte) (val & 0xff);
6107 data [idx+1] = (byte) (val >> 8);
6109 } else if (array_element_type == TypeManager.short_type){
6110 if (!(v is Expression)){
6111 int val = (int) ((short) v);
6113 data [idx] = (byte) (val & 0xff);
6114 data [idx+1] = (byte) (val >> 8);
6116 } else if (array_element_type == TypeManager.ushort_type){
6117 if (!(v is Expression)){
6118 int val = (int) ((ushort) v);
6120 data [idx] = (byte) (val & 0xff);
6121 data [idx+1] = (byte) (val >> 8);
6123 } else if (array_element_type == TypeManager.int32_type) {
6124 if (!(v is Expression)){
6127 data [idx] = (byte) (val & 0xff);
6128 data [idx+1] = (byte) ((val >> 8) & 0xff);
6129 data [idx+2] = (byte) ((val >> 16) & 0xff);
6130 data [idx+3] = (byte) (val >> 24);
6132 } else if (array_element_type == TypeManager.uint32_type) {
6133 if (!(v is Expression)){
6134 uint val = (uint) v;
6136 data [idx] = (byte) (val & 0xff);
6137 data [idx+1] = (byte) ((val >> 8) & 0xff);
6138 data [idx+2] = (byte) ((val >> 16) & 0xff);
6139 data [idx+3] = (byte) (val >> 24);
6141 } else if (array_element_type == TypeManager.sbyte_type) {
6142 if (!(v is Expression)){
6143 sbyte val = (sbyte) v;
6144 data [idx] = (byte) val;
6146 } else if (array_element_type == TypeManager.byte_type) {
6147 if (!(v is Expression)){
6148 byte val = (byte) v;
6149 data [idx] = (byte) val;
6151 } else if (array_element_type == TypeManager.bool_type) {
6152 if (!(v is Expression)){
6153 bool val = (bool) v;
6154 data [idx] = (byte) (val ? 1 : 0);
6156 } else if (array_element_type == TypeManager.decimal_type){
6157 if (!(v is Expression)){
6158 int [] bits = Decimal.GetBits ((decimal) v);
6161 // FIXME: For some reason, this doesn't work on the MS runtime.
6162 int [] nbits = new int [4];
6163 nbits [0] = bits [3];
6164 nbits [1] = bits [2];
6165 nbits [2] = bits [0];
6166 nbits [3] = bits [1];
6168 for (int j = 0; j < 4; j++){
6169 data [p++] = (byte) (nbits [j] & 0xff);
6170 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6171 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6172 data [p++] = (byte) (nbits [j] >> 24);
6176 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6184 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6186 array_element_type = storey.MutateType (array_element_type);
6187 type = storey.MutateType (type);
6188 if (arguments != null) {
6189 foreach (Argument a in arguments)
6190 a.Expr.MutateHoistedGenericType (storey);
6193 if (array_data != null) {
6194 foreach (Expression e in array_data)
6195 e.MutateHoistedGenericType (storey);
6200 // Emits the initializers for the array
6202 void EmitStaticInitializers (EmitContext ec)
6204 // FIXME: This should go to Resolve !
6205 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6206 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6207 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6208 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6209 if (TypeManager.void_initializearray_array_fieldhandle == null)
6214 // First, the static data
6217 ILGenerator ig = ec.ig;
6219 byte [] data = MakeByteBlob ();
6221 fb = RootContext.MakeStaticData (data);
6223 ig.Emit (OpCodes.Dup);
6224 ig.Emit (OpCodes.Ldtoken, fb);
6225 ig.Emit (OpCodes.Call,
6226 TypeManager.void_initializearray_array_fieldhandle);
6230 // Emits pieces of the array that can not be computed at compile
6231 // time (variables and string locations).
6233 // This always expect the top value on the stack to be the array
6235 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6237 ILGenerator ig = ec.ig;
6238 int dims = bounds.Count;
6239 int [] current_pos = new int [dims];
6241 MethodInfo set = null;
6244 Type [] args = new Type [dims + 1];
6246 for (int j = 0; j < dims; j++)
6247 args [j] = TypeManager.int32_type;
6248 args [dims] = array_element_type;
6250 set = CodeGen.Module.Builder.GetArrayMethod (
6252 CallingConventions.HasThis | CallingConventions.Standard,
6253 TypeManager.void_type, args);
6256 for (int i = 0; i < array_data.Count; i++){
6258 Expression e = (Expression)array_data [i];
6260 // Constant can be initialized via StaticInitializer
6261 if (e != null && !(!emitConstants && e is Constant)) {
6262 Type etype = e.Type;
6264 ig.Emit (OpCodes.Dup);
6266 for (int idx = 0; idx < dims; idx++)
6267 IntConstant.EmitInt (ig, current_pos [idx]);
6270 // If we are dealing with a struct, get the
6271 // address of it, so we can store it.
6273 if ((dims == 1) && etype.IsValueType &&
6274 (!TypeManager.IsBuiltinOrEnum (etype) ||
6275 etype == TypeManager.decimal_type)) {
6277 ig.Emit (OpCodes.Ldelema, etype);
6283 bool is_stobj, has_type_arg;
6284 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6286 ig.Emit (OpCodes.Stobj, etype);
6287 else if (has_type_arg)
6288 ig.Emit (op, etype);
6292 ig.Emit (OpCodes.Call, set);
6299 for (int j = dims - 1; j >= 0; j--){
6301 if (current_pos [j] < (int) bounds [j])
6303 current_pos [j] = 0;
6308 public override void Emit (EmitContext ec)
6310 ILGenerator ig = ec.ig;
6312 if (first_emit != null) {
6313 first_emit.Emit (ec);
6314 first_emit_temp.Store (ec);
6317 foreach (Argument a in arguments)
6320 if (arguments.Count == 1)
6321 ig.Emit (OpCodes.Newarr, array_element_type);
6323 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6326 if (initializers == null)
6329 // Emit static initializer for arrays which have contain more than 4 items and
6330 // the static initializer will initialize at least 25% of array values.
6331 // NOTE: const_initializers_count does not contain default constant values.
6332 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6333 TypeManager.IsPrimitiveType (array_element_type)) {
6334 EmitStaticInitializers (ec);
6336 if (!only_constant_initializers)
6337 EmitDynamicInitializers (ec, false);
6339 EmitDynamicInitializers (ec, true);
6342 if (first_emit_temp != null)
6343 first_emit_temp.Release (ec);
6346 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6348 if (arguments.Count != 1) {
6349 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6350 return base.GetAttributableValue (ec, null, out value);
6353 if (array_data == null) {
6354 Constant c = (Constant)((Argument)arguments [0]).Expr;
6355 if (c.IsDefaultValue) {
6356 value = Array.CreateInstance (array_element_type, 0);
6359 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6360 return base.GetAttributableValue (ec, null, out value);
6363 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6364 object element_value;
6365 for (int i = 0; i < ret.Length; ++i)
6367 Expression e = (Expression)array_data [i];
6369 // Is null when an initializer is optimized (value == predefined value)
6373 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6377 ret.SetValue (element_value, i);
6383 protected override void CloneTo (CloneContext clonectx, Expression t)
6385 ArrayCreation target = (ArrayCreation) t;
6387 if (requested_base_type != null)
6388 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6390 if (arguments != null){
6391 target.arguments = new ArrayList (arguments.Count);
6392 foreach (Argument a in arguments)
6393 target.arguments.Add (a.Clone (clonectx));
6396 if (initializers != null){
6397 target.initializers = new ArrayList (initializers.Count);
6398 foreach (object initializer in initializers)
6399 if (initializer is ArrayList) {
6400 ArrayList this_al = (ArrayList)initializer;
6401 ArrayList al = new ArrayList (this_al.Count);
6402 target.initializers.Add (al);
6403 foreach (Expression e in this_al)
6404 al.Add (e.Clone (clonectx));
6406 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6413 // Represents an implicitly typed array epxression
6415 public class ImplicitlyTypedArrayCreation : ArrayCreation
6417 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6418 : base (null, rank, initializers, loc)
6420 if (RootContext.Version <= LanguageVersion.ISO_2)
6421 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6423 if (rank.Length > 2) {
6424 while (rank [++dimensions] == ',');
6430 public override Expression DoResolve (EmitContext ec)
6435 if (!ResolveInitializers (ec))
6438 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6439 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6440 arguments.Count != dimensions) {
6441 Error_NoBestType ();
6446 // At this point we found common base type for all initializer elements
6447 // but we have to be sure that all static initializer elements are of
6450 UnifyInitializerElement (ec);
6452 type = TypeManager.GetConstructedType (array_element_type, rank);
6453 eclass = ExprClass.Value;
6457 void Error_NoBestType ()
6459 Report.Error (826, loc,
6460 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6464 // Converts static initializer only
6466 void UnifyInitializerElement (EmitContext ec)
6468 for (int i = 0; i < array_data.Count; ++i) {
6469 Expression e = (Expression)array_data[i];
6471 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6475 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6477 element = element.Resolve (ec);
6478 if (element == null)
6481 if (array_element_type == null) {
6482 array_element_type = element.Type;
6486 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6490 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6491 array_element_type = element.Type;
6495 Error_NoBestType ();
6500 public sealed class CompilerGeneratedThis : This
6502 public static This Instance = new CompilerGeneratedThis ();
6504 private CompilerGeneratedThis ()
6505 : base (Location.Null)
6509 public CompilerGeneratedThis (Type type, Location loc)
6515 public override Expression DoResolve (EmitContext ec)
6517 eclass = ExprClass.Variable;
6519 type = ec.ContainerType;
6523 public override HoistedVariable HoistedVariable {
6524 get { return null; }
6529 /// Represents the `this' construct
6532 public class This : VariableReference
6534 sealed class ThisVariable : ILocalVariable
6536 public static readonly ILocalVariable Instance = new ThisVariable ();
6538 public void Emit (EmitContext ec)
6540 ec.ig.Emit (OpCodes.Ldarg_0);
6543 public void EmitAssign (EmitContext ec)
6545 throw new InvalidOperationException ();
6548 public void EmitAddressOf (EmitContext ec)
6550 ec.ig.Emit (OpCodes.Ldarg_0);
6555 VariableInfo variable_info;
6558 public This (Block block, Location loc)
6564 public This (Location loc)
6569 public override VariableInfo VariableInfo {
6570 get { return variable_info; }
6573 public override bool IsFixed {
6574 get { return false; }
6577 protected override bool IsHoistedEmitRequired (EmitContext ec)
6580 // Handle 'this' differently, it cannot be assigned hence
6581 // when we are not inside anonymous method we can emit direct access
6583 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6586 public override HoistedVariable HoistedVariable {
6587 get { return TopToplevelBlock.HoistedThisVariable; }
6590 public override bool IsRef {
6591 get { return is_struct; }
6594 protected override ILocalVariable Variable {
6595 get { return ThisVariable.Instance; }
6598 // TODO: Move to ToplevelBlock
6599 ToplevelBlock TopToplevelBlock {
6601 ToplevelBlock tl = block.Toplevel;
6602 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6607 public static bool IsThisAvailable (EmitContext ec)
6609 if (ec.IsStatic || ec.IsInFieldInitializer)
6612 if (ec.CurrentAnonymousMethod == null)
6615 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6621 public bool ResolveBase (EmitContext ec)
6623 if (eclass != ExprClass.Invalid)
6626 eclass = ExprClass.Variable;
6628 if (ec.TypeContainer.CurrentType != null)
6629 type = ec.TypeContainer.CurrentType;
6631 type = ec.ContainerType;
6633 if (!IsThisAvailable (ec)) {
6635 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6637 Report.Error (1673, loc,
6638 "Anonymous methods inside structs cannot access instance members of `this'. " +
6639 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6643 is_struct = ec.TypeContainer is Struct;
6645 if (block != null) {
6646 if (block.Toplevel.ThisVariable != null)
6647 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6649 AnonymousExpression am = ec.CurrentAnonymousMethod;
6652 // this is hoisted to very top level block
6654 if (ec.IsVariableCapturingRequired) {
6656 // TODO: it should be optimized, see test-anon-75.cs
6658 // `this' variable has its own scope which is mostly empty
6659 // and causes creation of extraneous storey references.
6660 // Also it's hard to remove `this' dependencies when we Undo
6663 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6664 if (HoistedVariable == null) {
6665 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6675 // Called from Invocation to check if the invocation is correct
6677 public override void CheckMarshalByRefAccess (EmitContext ec)
6679 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6680 !variable_info.IsAssigned (ec)) {
6681 Error (188, "The `this' object cannot be used before all of its " +
6682 "fields are assigned to");
6683 variable_info.SetAssigned (ec);
6687 public override Expression CreateExpressionTree (EmitContext ec)
6689 ArrayList args = new ArrayList (1);
6690 args.Add (new Argument (this));
6692 // Use typeless constant for ldarg.0 to save some
6693 // space and avoid problems with anonymous stories
6694 return CreateExpressionFactoryCall ("Constant", args);
6697 public override Expression DoResolve (EmitContext ec)
6699 if (!ResolveBase (ec))
6703 if (ec.IsInFieldInitializer) {
6704 Error (27, "Keyword `this' is not available in the current context");
6711 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6713 if (!ResolveBase (ec))
6716 if (variable_info != null)
6717 variable_info.SetAssigned (ec);
6719 if (ec.TypeContainer is Class){
6720 if (right_side == EmptyExpression.UnaryAddress)
6721 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6722 else if (right_side == EmptyExpression.OutAccess)
6723 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6725 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6731 public override int GetHashCode()
6733 return block.GetHashCode ();
6736 public override string Name {
6737 get { return "this"; }
6740 public override bool Equals (object obj)
6742 This t = obj as This;
6746 return block == t.block;
6749 protected override void CloneTo (CloneContext clonectx, Expression t)
6751 This target = (This) t;
6753 target.block = clonectx.LookupBlock (block);
6756 public void RemoveHoisting ()
6758 TopToplevelBlock.HoistedThisVariable = null;
6761 public override void SetHasAddressTaken ()
6768 /// Represents the `__arglist' construct
6770 public class ArglistAccess : Expression
6772 public ArglistAccess (Location loc)
6777 public override Expression CreateExpressionTree (EmitContext ec)
6779 throw new NotSupportedException ("ET");
6782 public override Expression DoResolve (EmitContext ec)
6784 eclass = ExprClass.Variable;
6785 type = TypeManager.runtime_argument_handle_type;
6787 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6789 Error (190, "The __arglist construct is valid only within " +
6790 "a variable argument method");
6797 public override void Emit (EmitContext ec)
6799 ec.ig.Emit (OpCodes.Arglist);
6802 protected override void CloneTo (CloneContext clonectx, Expression target)
6809 /// Represents the `__arglist (....)' construct
6811 public class Arglist : Expression
6813 Argument[] Arguments;
6815 public Arglist (Location loc)
6816 : this (Argument.Empty, loc)
6820 public Arglist (Argument[] args, Location l)
6826 public Type[] ArgumentTypes {
6828 Type[] retval = new Type [Arguments.Length];
6829 for (int i = 0; i < Arguments.Length; i++)
6830 retval [i] = Arguments [i].Type;
6835 public override Expression CreateExpressionTree (EmitContext ec)
6837 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6841 public override Expression DoResolve (EmitContext ec)
6843 eclass = ExprClass.Variable;
6844 type = TypeManager.runtime_argument_handle_type;
6846 foreach (Argument arg in Arguments) {
6847 if (!arg.Resolve (ec, loc))
6854 public override void Emit (EmitContext ec)
6856 foreach (Argument arg in Arguments)
6860 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6862 foreach (Argument arg in Arguments)
6863 arg.Expr.MutateHoistedGenericType (storey);
6866 protected override void CloneTo (CloneContext clonectx, Expression t)
6868 Arglist target = (Arglist) t;
6870 target.Arguments = new Argument [Arguments.Length];
6871 for (int i = 0; i < Arguments.Length; i++)
6872 target.Arguments [i] = Arguments [i].Clone (clonectx);
6877 /// Implements the typeof operator
6879 public class TypeOf : Expression {
6880 Expression QueriedType;
6881 protected Type typearg;
6883 public TypeOf (Expression queried_type, Location l)
6885 QueriedType = queried_type;
6889 public override Expression CreateExpressionTree (EmitContext ec)
6891 ArrayList args = new ArrayList (2);
6892 args.Add (new Argument (this));
6893 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6894 return CreateExpressionFactoryCall ("Constant", args);
6897 public override Expression DoResolve (EmitContext ec)
6899 if (eclass != ExprClass.Invalid)
6902 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6906 typearg = texpr.Type;
6908 if (typearg == TypeManager.void_type) {
6909 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6913 if (typearg.IsPointer && !ec.InUnsafe){
6918 type = TypeManager.type_type;
6920 return DoResolveBase ();
6923 protected Expression DoResolveBase ()
6925 if (TypeManager.system_type_get_type_from_handle == null) {
6926 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6927 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6930 // Even though what is returned is a type object, it's treated as a value by the compiler.
6931 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6932 eclass = ExprClass.Value;
6936 public override void Emit (EmitContext ec)
6938 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6939 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6942 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6944 if (TypeManager.ContainsGenericParameters (typearg) &&
6945 !TypeManager.IsGenericTypeDefinition (typearg)) {
6946 Report.SymbolRelatedToPreviousError (typearg);
6947 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6948 TypeManager.CSharpName (typearg));
6953 if (value_type == TypeManager.object_type) {
6954 value = (object)typearg;
6961 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6963 typearg = storey.MutateType (typearg);
6966 public Type TypeArgument {
6972 protected override void CloneTo (CloneContext clonectx, Expression t)
6974 TypeOf target = (TypeOf) t;
6975 if (QueriedType != null)
6976 target.QueriedType = QueriedType.Clone (clonectx);
6981 /// Implements the `typeof (void)' operator
6983 public class TypeOfVoid : TypeOf {
6984 public TypeOfVoid (Location l) : base (null, l)
6989 public override Expression DoResolve (EmitContext ec)
6991 type = TypeManager.type_type;
6992 typearg = TypeManager.void_type;
6994 return DoResolveBase ();
6998 class TypeOfMethodInfo : TypeOfMethod
7000 public TypeOfMethodInfo (MethodBase method, Location loc)
7001 : base (method, loc)
7005 public override Expression DoResolve (EmitContext ec)
7007 type = typeof (MethodInfo);
7008 return base.DoResolve (ec);
7011 public override void Emit (EmitContext ec)
7013 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7015 ec.ig.Emit (OpCodes.Castclass, type);
7019 class TypeOfConstructorInfo : TypeOfMethod
7021 public TypeOfConstructorInfo (MethodBase method, Location loc)
7022 : base (method, loc)
7026 public override Expression DoResolve (EmitContext ec)
7028 type = typeof (ConstructorInfo);
7029 return base.DoResolve (ec);
7032 public override void Emit (EmitContext ec)
7034 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7036 ec.ig.Emit (OpCodes.Castclass, type);
7040 abstract class TypeOfMethod : Expression
7042 protected readonly MethodBase method;
7044 protected TypeOfMethod (MethodBase method, Location loc)
7046 this.method = method;
7050 public override Expression CreateExpressionTree (EmitContext ec)
7052 ArrayList args = new ArrayList (2);
7053 args.Add (new Argument (this));
7054 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7055 return CreateExpressionFactoryCall ("Constant", args);
7058 public override Expression DoResolve (EmitContext ec)
7060 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7061 MethodInfo mi = is_generic ?
7062 TypeManager.methodbase_get_type_from_handle_generic :
7063 TypeManager.methodbase_get_type_from_handle;
7066 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7067 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7069 if (t == null || handle_type == null)
7072 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7074 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7075 new Type[] { handle_type } );
7078 TypeManager.methodbase_get_type_from_handle_generic = mi;
7080 TypeManager.methodbase_get_type_from_handle = mi;
7083 eclass = ExprClass.Value;
7087 public override void Emit (EmitContext ec)
7089 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7092 mi = TypeManager.methodbase_get_type_from_handle_generic;
7093 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7095 mi = TypeManager.methodbase_get_type_from_handle;
7098 ec.ig.Emit (OpCodes.Call, mi);
7102 internal class TypeOfField : Expression
7104 readonly FieldInfo field;
7106 public TypeOfField (FieldInfo field, Location loc)
7112 public override Expression CreateExpressionTree (EmitContext ec)
7114 throw new NotSupportedException ("ET");
7117 public override Expression DoResolve (EmitContext ec)
7119 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7120 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7121 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7123 if (t != null && handle_type != null)
7124 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7125 "GetFieldFromHandle", loc, handle_type);
7128 type = typeof (FieldInfo);
7129 eclass = ExprClass.Value;
7133 public override void Emit (EmitContext ec)
7135 ec.ig.Emit (OpCodes.Ldtoken, field);
7136 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7141 /// Implements the sizeof expression
7143 public class SizeOf : Expression {
7144 readonly Expression QueriedType;
7147 public SizeOf (Expression queried_type, Location l)
7149 this.QueriedType = queried_type;
7153 public override Expression CreateExpressionTree (EmitContext ec)
7155 Error_PointerInsideExpressionTree ();
7159 public override Expression DoResolve (EmitContext ec)
7161 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7165 type_queried = texpr.Type;
7166 if (TypeManager.IsEnumType (type_queried))
7167 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7169 int size_of = GetTypeSize (type_queried);
7171 return new IntConstant (size_of, loc);
7174 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7179 Report.Error (233, loc,
7180 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7181 TypeManager.CSharpName (type_queried));
7184 type = TypeManager.int32_type;
7185 eclass = ExprClass.Value;
7189 public override void Emit (EmitContext ec)
7191 int size = GetTypeSize (type_queried);
7194 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7196 IntConstant.EmitInt (ec.ig, size);
7199 protected override void CloneTo (CloneContext clonectx, Expression t)
7205 /// Implements the qualified-alias-member (::) expression.
7207 public class QualifiedAliasMember : MemberAccess
7209 readonly string alias;
7210 public static readonly string GlobalAlias = "global";
7212 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7213 : base (null, identifier, targs, l)
7218 public QualifiedAliasMember (string alias, string identifier, Location l)
7219 : base (null, identifier, l)
7224 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7226 if (alias == GlobalAlias) {
7227 expr = RootNamespace.Global;
7228 return base.ResolveAsTypeStep (ec, silent);
7231 int errors = Report.Errors;
7232 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7234 if (errors == Report.Errors)
7235 Report.Error (432, loc, "Alias `{0}' not found", alias);
7239 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7243 if (expr.eclass == ExprClass.Type) {
7245 Report.Error (431, loc,
7246 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7254 public override Expression DoResolve (EmitContext ec)
7256 return ResolveAsTypeStep (ec, false);
7259 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7261 Report.Error (687, loc,
7262 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7263 GetSignatureForError ());
7266 public override string GetSignatureForError ()
7269 if (targs != null) {
7270 name = TypeManager.RemoveGenericArity (Name) + "<" +
7271 targs.GetSignatureForError () + ">";
7274 return alias + "::" + name;
7277 protected override void CloneTo (CloneContext clonectx, Expression t)
7284 /// Implements the member access expression
7286 public class MemberAccess : ATypeNameExpression {
7287 protected Expression expr;
7289 public MemberAccess (Expression expr, string id)
7290 : base (id, expr.Location)
7295 public MemberAccess (Expression expr, string identifier, Location loc)
7296 : base (identifier, loc)
7301 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7302 : base (identifier, args, loc)
7307 // TODO: this method has very poor performace for Enum fields and
7308 // probably for other constants as well
7309 Expression DoResolve (EmitContext ec, Expression right_side)
7312 throw new Exception ();
7315 // Resolve the expression with flow analysis turned off, we'll do the definite
7316 // assignment checks later. This is because we don't know yet what the expression
7317 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7318 // definite assignment check on the actual field and not on the whole struct.
7321 SimpleName original = expr as SimpleName;
7322 Expression expr_resolved = expr.Resolve (ec,
7323 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7324 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7326 if (expr_resolved == null)
7329 string LookupIdentifier = MemberName.MakeName (Name, targs);
7331 if (expr_resolved is Namespace) {
7332 Namespace ns = (Namespace) expr_resolved;
7333 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7335 if ((retval != null) && (targs != null))
7336 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7340 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7344 Type expr_type = expr_resolved.Type;
7345 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7346 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7347 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7351 Constant c = expr_resolved as Constant;
7352 if (c != null && c.GetValue () == null) {
7353 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7354 "System.NullReferenceException");
7357 if (targs != null) {
7358 if (!targs.Resolve (ec))
7362 Expression member_lookup;
7363 member_lookup = MemberLookup (
7364 ec.ContainerType, expr_type, expr_type, Name, loc);
7366 if ((member_lookup == null) && (targs != null)) {
7367 member_lookup = MemberLookup (
7368 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7371 if (member_lookup == null) {
7372 ExprClass expr_eclass = expr_resolved.eclass;
7375 // Extension methods are not allowed on all expression types
7377 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7378 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7379 expr_eclass == ExprClass.EventAccess) {
7380 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7381 if (ex_method_lookup != null) {
7382 ex_method_lookup.ExtensionExpression = expr_resolved;
7384 if (targs != null) {
7385 ex_method_lookup.SetTypeArguments (targs);
7388 return ex_method_lookup.DoResolve (ec);
7392 expr = expr_resolved;
7393 member_lookup = Error_MemberLookupFailed (
7394 ec.ContainerType, expr_type, expr_type, Name, null,
7395 AllMemberTypes, AllBindingFlags);
7396 if (member_lookup == null)
7400 TypeExpr texpr = member_lookup as TypeExpr;
7401 if (texpr != null) {
7402 if (!(expr_resolved is TypeExpr) &&
7403 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7404 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7405 Name, member_lookup.GetSignatureForError ());
7409 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7410 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7411 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7416 ConstructedType ct = expr_resolved as ConstructedType;
7419 // When looking up a nested type in a generic instance
7420 // via reflection, we always get a generic type definition
7421 // and not a generic instance - so we have to do this here.
7423 // See gtest-172-lib.cs and gtest-172.cs for an example.
7425 ct = new ConstructedType (
7426 member_lookup.Type, ct.TypeArguments, loc);
7428 return ct.ResolveAsTypeStep (ec, false);
7431 return member_lookup;
7434 MemberExpr me = (MemberExpr) member_lookup;
7435 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7439 if (targs != null) {
7440 me.SetTypeArguments (targs);
7443 if (original != null && !TypeManager.IsValueType (expr_type)) {
7444 if (me.IsInstance) {
7445 LocalVariableReference var = expr_resolved as LocalVariableReference;
7446 if (var != null && !var.VerifyAssigned (ec))
7451 // The following DoResolve/DoResolveLValue will do the definite assignment
7454 if (right_side != null)
7455 return me.DoResolveLValue (ec, right_side);
7457 return me.DoResolve (ec);
7460 public override Expression DoResolve (EmitContext ec)
7462 return DoResolve (ec, null);
7465 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7467 return DoResolve (ec, right_side);
7470 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7472 return ResolveNamespaceOrType (ec, silent);
7475 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7477 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7479 if (new_expr == null)
7482 string LookupIdentifier = MemberName.MakeName (Name, targs);
7484 if (new_expr is Namespace) {
7485 Namespace ns = (Namespace) new_expr;
7486 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7488 if ((retval != null) && (targs != null))
7489 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7491 if (!silent && retval == null)
7492 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7496 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7497 if (tnew_expr == null)
7500 if (tnew_expr is TypeParameterExpr) {
7501 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7502 tnew_expr.GetSignatureForError ());
7506 Type expr_type = tnew_expr.Type;
7507 Expression member_lookup = MemberLookup (
7508 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7509 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7510 if (member_lookup == null) {
7514 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7518 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7523 TypeArguments the_args = targs;
7524 Type declaring_type = texpr.Type.DeclaringType;
7525 if (TypeManager.HasGenericArguments (declaring_type)) {
7526 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7527 expr_type = expr_type.BaseType;
7530 TypeArguments new_args = new TypeArguments (loc);
7531 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7532 new_args.Add (new TypeExpression (decl, loc));
7535 new_args.Add (targs);
7537 the_args = new_args;
7540 if (the_args != null) {
7541 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7542 return ctype.ResolveAsTypeStep (rc, false);
7549 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7551 Expression member_lookup = MemberLookup (
7552 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7553 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7555 if (member_lookup != null) {
7556 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7557 if (expr_type == null)
7560 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7564 member_lookup = MemberLookup (
7565 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7566 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7568 if (member_lookup == null) {
7569 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7570 Name, expr_type.GetSignatureForError ());
7572 // TODO: Report.SymbolRelatedToPreviousError
7573 member_lookup.Error_UnexpectedKind (null, "type", loc);
7577 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7579 if (RootContext.Version > LanguageVersion.ISO_2 &&
7580 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7581 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7582 "extension method `{1}' of type `{0}' could be found " +
7583 "(are you missing a using directive or an assembly reference?)",
7584 TypeManager.CSharpName (type), name);
7588 base.Error_TypeDoesNotContainDefinition (type, name);
7591 public override string GetSignatureForError ()
7593 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7596 protected override void CloneTo (CloneContext clonectx, Expression t)
7598 MemberAccess target = (MemberAccess) t;
7600 target.expr = expr.Clone (clonectx);
7605 /// Implements checked expressions
7607 public class CheckedExpr : Expression {
7609 public Expression Expr;
7611 public CheckedExpr (Expression e, Location l)
7617 public override Expression CreateExpressionTree (EmitContext ec)
7619 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7620 return Expr.CreateExpressionTree (ec);
7623 public override Expression DoResolve (EmitContext ec)
7625 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7626 Expr = Expr.Resolve (ec);
7631 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7634 eclass = Expr.eclass;
7639 public override void Emit (EmitContext ec)
7641 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7645 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7647 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7648 Expr.EmitBranchable (ec, target, on_true);
7651 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7653 Expr.MutateHoistedGenericType (storey);
7656 protected override void CloneTo (CloneContext clonectx, Expression t)
7658 CheckedExpr target = (CheckedExpr) t;
7660 target.Expr = Expr.Clone (clonectx);
7665 /// Implements the unchecked expression
7667 public class UnCheckedExpr : Expression {
7669 public Expression Expr;
7671 public UnCheckedExpr (Expression e, Location l)
7677 public override Expression CreateExpressionTree (EmitContext ec)
7679 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7680 return Expr.CreateExpressionTree (ec);
7683 public override Expression DoResolve (EmitContext ec)
7685 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7686 Expr = Expr.Resolve (ec);
7691 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7694 eclass = Expr.eclass;
7699 public override void Emit (EmitContext ec)
7701 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7705 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7707 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7708 Expr.EmitBranchable (ec, target, on_true);
7711 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7713 Expr.MutateHoistedGenericType (storey);
7716 protected override void CloneTo (CloneContext clonectx, Expression t)
7718 UnCheckedExpr target = (UnCheckedExpr) t;
7720 target.Expr = Expr.Clone (clonectx);
7725 /// An Element Access expression.
7727 /// During semantic analysis these are transformed into
7728 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7730 public class ElementAccess : Expression {
7731 public ArrayList Arguments;
7732 public Expression Expr;
7734 public ElementAccess (Expression e, ArrayList e_list)
7742 Arguments = new ArrayList (e_list.Count);
7743 foreach (Expression tmp in e_list)
7744 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7747 bool CommonResolve (EmitContext ec)
7749 Expr = Expr.Resolve (ec);
7751 if (Arguments == null)
7754 foreach (Argument a in Arguments){
7755 if (!a.Resolve (ec, loc))
7759 return Expr != null;
7762 public override Expression CreateExpressionTree (EmitContext ec)
7764 ArrayList args = new ArrayList (Arguments.Count + 1);
7765 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7766 foreach (Argument a in Arguments)
7767 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7769 return CreateExpressionFactoryCall ("ArrayIndex", args);
7772 Expression MakePointerAccess (EmitContext ec, Type t)
7774 if (Arguments.Count != 1){
7775 Error (196, "A pointer must be indexed by only one value");
7779 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7782 return new Indirection (p, loc).Resolve (ec);
7785 public override Expression DoResolve (EmitContext ec)
7787 if (!CommonResolve (ec))
7791 // We perform some simple tests, and then to "split" the emit and store
7792 // code we create an instance of a different class, and return that.
7794 // I am experimenting with this pattern.
7798 if (t == TypeManager.array_type){
7799 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7804 return (new ArrayAccess (this, loc)).Resolve (ec);
7806 return MakePointerAccess (ec, t);
7808 FieldExpr fe = Expr as FieldExpr;
7810 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7812 return MakePointerAccess (ec, ff.ElementType);
7815 return (new IndexerAccess (this, loc)).Resolve (ec);
7818 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7820 if (!CommonResolve (ec))
7825 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7828 return MakePointerAccess (ec, type);
7830 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7831 Error_CannotModifyIntermediateExpressionValue (ec);
7833 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7836 public override void Emit (EmitContext ec)
7838 throw new Exception ("Should never be reached");
7841 public override string GetSignatureForError ()
7843 return Expr.GetSignatureForError ();
7846 protected override void CloneTo (CloneContext clonectx, Expression t)
7848 ElementAccess target = (ElementAccess) t;
7850 target.Expr = Expr.Clone (clonectx);
7851 target.Arguments = new ArrayList (Arguments.Count);
7852 foreach (Argument a in Arguments)
7853 target.Arguments.Add (a.Clone (clonectx));
7858 /// Implements array access
7860 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7862 // Points to our "data" repository
7866 LocalTemporary temp;
7870 public ArrayAccess (ElementAccess ea_data, Location l)
7876 public override Expression CreateExpressionTree (EmitContext ec)
7878 return ea.CreateExpressionTree (ec);
7881 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7883 return DoResolve (ec);
7886 public override Expression DoResolve (EmitContext ec)
7889 ExprClass eclass = ea.Expr.eclass;
7891 // As long as the type is valid
7892 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7893 eclass == ExprClass.Value)) {
7894 ea.Expr.Error_UnexpectedKind ("variable or value");
7899 if (eclass != ExprClass.Invalid)
7902 Type t = ea.Expr.Type;
7903 int rank = ea.Arguments.Count;
7904 if (t.GetArrayRank () != rank) {
7905 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7906 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7910 type = TypeManager.GetElementType (t);
7911 if (type.IsPointer && !ec.InUnsafe) {
7912 UnsafeError (ea.Location);
7916 foreach (Argument a in ea.Arguments) {
7917 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7920 eclass = ExprClass.Variable;
7926 /// Emits the right opcode to load an object of Type `t'
7927 /// from an array of T
7929 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7932 MethodInfo get = FetchGetMethod ();
7933 ig.Emit (OpCodes.Call, get);
7937 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7938 ig.Emit (OpCodes.Ldelem_U1);
7939 else if (type == TypeManager.sbyte_type)
7940 ig.Emit (OpCodes.Ldelem_I1);
7941 else if (type == TypeManager.short_type)
7942 ig.Emit (OpCodes.Ldelem_I2);
7943 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7944 ig.Emit (OpCodes.Ldelem_U2);
7945 else if (type == TypeManager.int32_type)
7946 ig.Emit (OpCodes.Ldelem_I4);
7947 else if (type == TypeManager.uint32_type)
7948 ig.Emit (OpCodes.Ldelem_U4);
7949 else if (type == TypeManager.uint64_type)
7950 ig.Emit (OpCodes.Ldelem_I8);
7951 else if (type == TypeManager.int64_type)
7952 ig.Emit (OpCodes.Ldelem_I8);
7953 else if (type == TypeManager.float_type)
7954 ig.Emit (OpCodes.Ldelem_R4);
7955 else if (type == TypeManager.double_type)
7956 ig.Emit (OpCodes.Ldelem_R8);
7957 else if (type == TypeManager.intptr_type)
7958 ig.Emit (OpCodes.Ldelem_I);
7959 else if (TypeManager.IsEnumType (type)){
7960 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7961 } else if (type.IsValueType){
7962 ig.Emit (OpCodes.Ldelema, type);
7963 ig.Emit (OpCodes.Ldobj, type);
7965 } else if (type.IsGenericParameter) {
7966 ig.Emit (OpCodes.Ldelem, type);
7968 } else if (type.IsPointer)
7969 ig.Emit (OpCodes.Ldelem_I);
7971 ig.Emit (OpCodes.Ldelem_Ref);
7974 protected override void Error_NegativeArrayIndex (Location loc)
7976 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7980 /// Returns the right opcode to store an object of Type `t'
7981 /// from an array of T.
7983 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7985 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7986 has_type_arg = false; is_stobj = false;
7987 t = TypeManager.TypeToCoreType (t);
7988 if (TypeManager.IsEnumType (t))
7989 t = TypeManager.GetEnumUnderlyingType (t);
7990 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7991 t == TypeManager.bool_type)
7992 return OpCodes.Stelem_I1;
7993 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7994 t == TypeManager.char_type)
7995 return OpCodes.Stelem_I2;
7996 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7997 return OpCodes.Stelem_I4;
7998 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7999 return OpCodes.Stelem_I8;
8000 else if (t == TypeManager.float_type)
8001 return OpCodes.Stelem_R4;
8002 else if (t == TypeManager.double_type)
8003 return OpCodes.Stelem_R8;
8004 else if (t == TypeManager.intptr_type) {
8005 has_type_arg = true;
8007 return OpCodes.Stobj;
8008 } else if (t.IsValueType) {
8009 has_type_arg = true;
8011 return OpCodes.Stobj;
8013 } else if (t.IsGenericParameter) {
8014 has_type_arg = true;
8015 return OpCodes.Stelem;
8018 } else if (t.IsPointer)
8019 return OpCodes.Stelem_I;
8021 return OpCodes.Stelem_Ref;
8024 MethodInfo FetchGetMethod ()
8026 ModuleBuilder mb = CodeGen.Module.Builder;
8027 int arg_count = ea.Arguments.Count;
8028 Type [] args = new Type [arg_count];
8031 for (int i = 0; i < arg_count; i++){
8032 //args [i++] = a.Type;
8033 args [i] = TypeManager.int32_type;
8036 get = mb.GetArrayMethod (
8037 ea.Expr.Type, "Get",
8038 CallingConventions.HasThis |
8039 CallingConventions.Standard,
8045 MethodInfo FetchAddressMethod ()
8047 ModuleBuilder mb = CodeGen.Module.Builder;
8048 int arg_count = ea.Arguments.Count;
8049 Type [] args = new Type [arg_count];
8053 ret_type = TypeManager.GetReferenceType (type);
8055 for (int i = 0; i < arg_count; i++){
8056 //args [i++] = a.Type;
8057 args [i] = TypeManager.int32_type;
8060 address = mb.GetArrayMethod (
8061 ea.Expr.Type, "Address",
8062 CallingConventions.HasThis |
8063 CallingConventions.Standard,
8070 // Load the array arguments into the stack.
8072 void LoadArrayAndArguments (EmitContext ec)
8076 for (int i = 0; i < ea.Arguments.Count; ++i) {
8077 ((Argument)ea.Arguments [i]).Emit (ec);
8081 public void Emit (EmitContext ec, bool leave_copy)
8083 int rank = ea.Expr.Type.GetArrayRank ();
8084 ILGenerator ig = ec.ig;
8087 LoadFromPtr (ig, this.type);
8089 LoadArrayAndArguments (ec);
8090 EmitLoadOpcode (ig, type, rank);
8094 ig.Emit (OpCodes.Dup);
8095 temp = new LocalTemporary (this.type);
8100 public override void Emit (EmitContext ec)
8105 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8107 int rank = ea.Expr.Type.GetArrayRank ();
8108 ILGenerator ig = ec.ig;
8109 Type t = source.Type;
8110 prepared = prepare_for_load;
8113 AddressOf (ec, AddressOp.LoadStore);
8114 ec.ig.Emit (OpCodes.Dup);
8116 LoadArrayAndArguments (ec);
8120 bool is_stobj, has_type_arg;
8121 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8125 // The stobj opcode used by value types will need
8126 // an address on the stack, not really an array/array
8130 ig.Emit (OpCodes.Ldelema, t);
8135 ec.ig.Emit (OpCodes.Dup);
8136 temp = new LocalTemporary (this.type);
8141 StoreFromPtr (ig, t);
8143 ig.Emit (OpCodes.Stobj, t);
8144 else if (has_type_arg)
8151 ec.ig.Emit (OpCodes.Dup);
8152 temp = new LocalTemporary (this.type);
8157 StoreFromPtr (ig, t);
8159 int arg_count = ea.Arguments.Count;
8160 Type [] args = new Type [arg_count + 1];
8161 for (int i = 0; i < arg_count; i++) {
8162 //args [i++] = a.Type;
8163 args [i] = TypeManager.int32_type;
8165 args [arg_count] = type;
8167 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8168 ea.Expr.Type, "Set",
8169 CallingConventions.HasThis |
8170 CallingConventions.Standard,
8171 TypeManager.void_type, args);
8173 ig.Emit (OpCodes.Call, set);
8183 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8185 if (!source.Emit (ec, this)) {
8187 throw new NotImplementedException ();
8192 throw new NotImplementedException ();
8195 public void AddressOf (EmitContext ec, AddressOp mode)
8197 int rank = ea.Expr.Type.GetArrayRank ();
8198 ILGenerator ig = ec.ig;
8200 LoadArrayAndArguments (ec);
8203 ig.Emit (OpCodes.Ldelema, type);
8205 MethodInfo address = FetchAddressMethod ();
8206 ig.Emit (OpCodes.Call, address);
8210 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8212 type = storey.MutateType (type);
8213 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8218 /// Expressions that represent an indexer call.
8220 public class IndexerAccess : Expression, IAssignMethod
8222 class IndexerMethodGroupExpr : MethodGroupExpr
8224 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8227 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8230 public override string Name {
8236 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8239 // Here is the trick, decrease number of arguments by 1 when only
8240 // available property method is setter. This makes overload resolution
8241 // work correctly for indexers.
8244 if (method.Name [0] == 'g')
8245 return parameters.Count;
8247 return parameters.Count - 1;
8253 // Contains either property getter or setter
8254 public ArrayList Methods;
8255 public ArrayList Properties;
8261 void Append (Type caller_type, MemberInfo [] mi)
8266 foreach (PropertyInfo property in mi) {
8267 MethodInfo accessor = property.GetGetMethod (true);
8268 if (accessor == null)
8269 accessor = property.GetSetMethod (true);
8271 if (Methods == null) {
8272 Methods = new ArrayList ();
8273 Properties = new ArrayList ();
8276 Methods.Add (accessor);
8277 Properties.Add (property);
8281 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8283 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8285 return TypeManager.MemberLookup (
8286 caller_type, caller_type, lookup_type, MemberTypes.Property,
8287 BindingFlags.Public | BindingFlags.Instance |
8288 BindingFlags.DeclaredOnly, p_name, null);
8291 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8293 Indexers ix = new Indexers ();
8296 if (lookup_type.IsGenericParameter) {
8297 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8301 if (gc.HasClassConstraint)
8302 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8304 Type[] ifaces = gc.InterfaceConstraints;
8305 foreach (Type itype in ifaces)
8306 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8312 Type copy = lookup_type;
8313 while (copy != TypeManager.object_type && copy != null){
8314 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8315 copy = copy.BaseType;
8318 if (lookup_type.IsInterface) {
8319 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8320 if (ifaces != null) {
8321 foreach (Type itype in ifaces)
8322 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8337 // Points to our "data" repository
8339 MethodInfo get, set;
8340 bool is_base_indexer;
8342 LocalTemporary temp;
8343 LocalTemporary prepared_value;
8344 Expression set_expr;
8346 protected Type indexer_type;
8347 protected Type current_type;
8348 protected Expression instance_expr;
8349 protected ArrayList arguments;
8351 public IndexerAccess (ElementAccess ea, Location loc)
8352 : this (ea.Expr, false, loc)
8354 this.arguments = ea.Arguments;
8357 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8360 this.instance_expr = instance_expr;
8361 this.is_base_indexer = is_base_indexer;
8362 this.eclass = ExprClass.Value;
8366 static string GetAccessorName (AccessorType at)
8368 if (at == AccessorType.Set)
8371 if (at == AccessorType.Get)
8374 throw new NotImplementedException (at.ToString ());
8377 public override Expression CreateExpressionTree (EmitContext ec)
8379 ArrayList args = new ArrayList (arguments.Count + 2);
8380 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8381 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8382 foreach (Argument a in arguments)
8383 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8385 return CreateExpressionFactoryCall ("Call", args);
8388 protected virtual bool CommonResolve (EmitContext ec)
8390 indexer_type = instance_expr.Type;
8391 current_type = ec.ContainerType;
8396 public override Expression DoResolve (EmitContext ec)
8398 return ResolveAccessor (ec, AccessorType.Get);
8401 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8403 if (right_side == EmptyExpression.OutAccess) {
8404 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8405 GetSignatureForError ());
8409 // if the indexer returns a value type, and we try to set a field in it
8410 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8411 Error_CannotModifyIntermediateExpressionValue (ec);
8414 Expression e = ResolveAccessor (ec, AccessorType.Set);
8418 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8422 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8424 if (!CommonResolve (ec))
8427 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8428 if (ilist.Methods == null) {
8429 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8430 TypeManager.CSharpName (indexer_type));
8434 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8435 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8439 MethodInfo mi = (MethodInfo) mg;
8440 PropertyInfo pi = null;
8441 for (int i = 0; i < ilist.Methods.Count; ++i) {
8442 if (ilist.Methods [i] == mi) {
8443 pi = (PropertyInfo) ilist.Properties [i];
8448 type = TypeManager.TypeToCoreType (pi.PropertyType);
8449 if (type.IsPointer && !ec.InUnsafe)
8452 MethodInfo accessor;
8453 if (accessorType == AccessorType.Get) {
8454 accessor = get = pi.GetGetMethod (true);
8456 accessor = set = pi.GetSetMethod (true);
8457 if (accessor == null && pi.GetGetMethod (true) != null) {
8458 Report.SymbolRelatedToPreviousError (pi);
8459 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8460 TypeManager.GetFullNameSignature (pi));
8465 if (accessor == null) {
8466 Report.SymbolRelatedToPreviousError (pi);
8467 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8468 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8473 // Only base will allow this invocation to happen.
8475 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8476 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8479 bool must_do_cs1540_check;
8480 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8482 set = pi.GetSetMethod (true);
8484 get = pi.GetGetMethod (true);
8486 if (set != null && get != null &&
8487 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8488 Report.SymbolRelatedToPreviousError (accessor);
8489 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8490 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8492 Report.SymbolRelatedToPreviousError (pi);
8493 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8497 instance_expr.CheckMarshalByRefAccess (ec);
8498 eclass = ExprClass.IndexerAccess;
8502 public void Emit (EmitContext ec, bool leave_copy)
8505 prepared_value.Emit (ec);
8507 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8508 arguments, loc, false, false);
8512 ec.ig.Emit (OpCodes.Dup);
8513 temp = new LocalTemporary (Type);
8519 // source is ignored, because we already have a copy of it from the
8520 // LValue resolution and we have already constructed a pre-cached
8521 // version of the arguments (ea.set_arguments);
8523 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8525 prepared = prepare_for_load;
8526 Expression value = set_expr;
8529 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8530 arguments, loc, true, false);
8532 prepared_value = new LocalTemporary (type);
8533 prepared_value.Store (ec);
8535 prepared_value.Release (ec);
8538 ec.ig.Emit (OpCodes.Dup);
8539 temp = new LocalTemporary (Type);
8542 } else if (leave_copy) {
8543 temp = new LocalTemporary (Type);
8549 arguments.Add (new Argument (value, Argument.AType.Expression));
8550 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8558 public override void Emit (EmitContext ec)
8563 public override string GetSignatureForError ()
8565 return TypeManager.CSharpSignature (get != null ? get : set, false);
8568 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8571 get = storey.MutateGenericMethod (get);
8573 set = storey.MutateGenericMethod (set);
8575 instance_expr.MutateHoistedGenericType (storey);
8576 foreach (Argument a in arguments)
8577 a.Expr.MutateHoistedGenericType (storey);
8579 type = storey.MutateType (type);
8582 protected override void CloneTo (CloneContext clonectx, Expression t)
8584 IndexerAccess target = (IndexerAccess) t;
8586 if (arguments != null){
8587 target.arguments = new ArrayList ();
8588 foreach (Argument a in arguments)
8589 target.arguments.Add (a.Clone (clonectx));
8591 if (instance_expr != null)
8592 target.instance_expr = instance_expr.Clone (clonectx);
8597 /// The base operator for method names
8599 public class BaseAccess : Expression {
8600 public readonly string Identifier;
8603 public BaseAccess (string member, Location l)
8605 this.Identifier = member;
8609 public BaseAccess (string member, TypeArguments args, Location l)
8615 public override Expression CreateExpressionTree (EmitContext ec)
8617 throw new NotSupportedException ("ET");
8620 public override Expression DoResolve (EmitContext ec)
8622 Expression c = CommonResolve (ec);
8628 // MethodGroups use this opportunity to flag an error on lacking ()
8630 if (!(c is MethodGroupExpr))
8631 return c.Resolve (ec);
8635 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8637 Expression c = CommonResolve (ec);
8643 // MethodGroups use this opportunity to flag an error on lacking ()
8645 if (! (c is MethodGroupExpr))
8646 return c.DoResolveLValue (ec, right_side);
8651 Expression CommonResolve (EmitContext ec)
8653 Expression member_lookup;
8654 Type current_type = ec.ContainerType;
8655 Type base_type = current_type.BaseType;
8657 if (!This.IsThisAvailable (ec)) {
8659 Error (1511, "Keyword `base' is not available in a static method");
8661 Error (1512, "Keyword `base' is not available in the current context");
8666 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8667 AllMemberTypes, AllBindingFlags, loc);
8668 if (member_lookup == null) {
8669 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8670 null, AllMemberTypes, AllBindingFlags);
8677 left = new TypeExpression (base_type, loc);
8679 left = ec.GetThis (loc);
8681 MemberExpr me = (MemberExpr) member_lookup;
8682 me = me.ResolveMemberAccess (ec, left, loc, null);
8689 me.SetTypeArguments (args);
8695 public override void Emit (EmitContext ec)
8697 throw new Exception ("Should never be called");
8700 protected override void CloneTo (CloneContext clonectx, Expression t)
8702 BaseAccess target = (BaseAccess) t;
8705 target.args = args.Clone ();
8710 /// The base indexer operator
8712 public class BaseIndexerAccess : IndexerAccess {
8713 public BaseIndexerAccess (ArrayList args, Location loc)
8714 : base (null, true, loc)
8716 arguments = new ArrayList ();
8717 foreach (Expression tmp in args)
8718 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8721 protected override bool CommonResolve (EmitContext ec)
8723 instance_expr = ec.GetThis (loc);
8725 current_type = ec.ContainerType.BaseType;
8726 indexer_type = current_type;
8728 foreach (Argument a in arguments){
8729 if (!a.Resolve (ec, loc))
8736 public override Expression CreateExpressionTree (EmitContext ec)
8738 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8739 return base.CreateExpressionTree (ec);
8744 /// This class exists solely to pass the Type around and to be a dummy
8745 /// that can be passed to the conversion functions (this is used by
8746 /// foreach implementation to typecast the object return value from
8747 /// get_Current into the proper type. All code has been generated and
8748 /// we only care about the side effect conversions to be performed
8750 /// This is also now used as a placeholder where a no-action expression
8751 /// is needed (the `New' class).
8753 public class EmptyExpression : Expression {
8754 public static readonly Expression Null = new EmptyExpression ();
8756 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8757 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8758 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8759 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8761 static EmptyExpression temp = new EmptyExpression ();
8762 public static EmptyExpression Grab ()
8764 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8769 public static void Release (EmptyExpression e)
8774 // TODO: should be protected
8775 public EmptyExpression ()
8777 type = TypeManager.object_type;
8778 eclass = ExprClass.Value;
8779 loc = Location.Null;
8782 public EmptyExpression (Type t)
8785 eclass = ExprClass.Value;
8786 loc = Location.Null;
8789 public override Expression CreateExpressionTree (EmitContext ec)
8791 throw new NotSupportedException ("ET");
8794 public override Expression DoResolve (EmitContext ec)
8799 public override void Emit (EmitContext ec)
8801 // nothing, as we only exist to not do anything.
8804 public override void EmitSideEffect (EmitContext ec)
8809 // This is just because we might want to reuse this bad boy
8810 // instead of creating gazillions of EmptyExpressions.
8811 // (CanImplicitConversion uses it)
8813 public void SetType (Type t)
8820 // Empty statement expression
8822 public sealed class EmptyExpressionStatement : ExpressionStatement
8824 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8826 private EmptyExpressionStatement ()
8828 type = TypeManager.object_type;
8829 eclass = ExprClass.Value;
8830 loc = Location.Null;
8833 public override Expression CreateExpressionTree (EmitContext ec)
8838 public override void EmitStatement (EmitContext ec)
8843 public override Expression DoResolve (EmitContext ec)
8848 public override void Emit (EmitContext ec)
8854 public class UserCast : Expression {
8858 public UserCast (MethodInfo method, Expression source, Location l)
8860 this.method = method;
8861 this.source = source;
8862 type = TypeManager.TypeToCoreType (method.ReturnType);
8866 public Expression Source {
8872 public override Expression CreateExpressionTree (EmitContext ec)
8874 ArrayList args = new ArrayList (3);
8875 args.Add (new Argument (source.CreateExpressionTree (ec)));
8876 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8877 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8878 return CreateExpressionFactoryCall ("Convert", args);
8881 public override Expression DoResolve (EmitContext ec)
8883 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8885 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8887 eclass = ExprClass.Value;
8891 public override void Emit (EmitContext ec)
8894 ec.ig.Emit (OpCodes.Call, method);
8897 public override string GetSignatureForError ()
8899 return TypeManager.CSharpSignature (method);
8902 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8904 source.MutateHoistedGenericType (storey);
8905 method = storey.MutateGenericMethod (method);
8910 // This class is used to "construct" the type during a typecast
8911 // operation. Since the Type.GetType class in .NET can parse
8912 // the type specification, we just use this to construct the type
8913 // one bit at a time.
8915 public class ComposedCast : TypeExpr {
8916 FullNamedExpression left;
8919 public ComposedCast (FullNamedExpression left, string dim)
8920 : this (left, dim, left.Location)
8924 public ComposedCast (FullNamedExpression left, string dim, Location l)
8931 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8933 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8937 Type ltype = lexpr.Type;
8939 if ((dim.Length > 0) && (dim [0] == '?')) {
8940 TypeExpr nullable = new Nullable.NullableType (left, loc);
8942 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8943 return nullable.ResolveAsTypeTerminal (ec, false);
8947 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8950 if (dim.Length != 0 && dim [0] == '[') {
8951 if (TypeManager.IsSpecialType (ltype)) {
8952 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8956 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8957 Report.SymbolRelatedToPreviousError (ltype);
8958 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8959 TypeManager.CSharpName (ltype));
8964 type = TypeManager.GetConstructedType (ltype, dim);
8969 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8971 if (type.IsPointer && !ec.IsInUnsafeScope){
8975 eclass = ExprClass.Type;
8979 public override string GetSignatureForError ()
8981 return left.GetSignatureForError () + dim;
8984 protected override void CloneTo (CloneContext clonectx, Expression t)
8986 ComposedCast target = (ComposedCast) t;
8988 target.left = (FullNamedExpression)left.Clone (clonectx);
8991 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8993 return ResolveAsBaseTerminal (ec, silent);
8997 public class FixedBufferPtr : Expression {
9000 public FixedBufferPtr (Expression array, Type array_type, Location l)
9005 type = TypeManager.GetPointerType (array_type);
9006 eclass = ExprClass.Value;
9009 public override Expression CreateExpressionTree (EmitContext ec)
9011 Error_PointerInsideExpressionTree ();
9015 public override void Emit(EmitContext ec)
9020 public override Expression DoResolve (EmitContext ec)
9023 // We are born fully resolved
9031 // This class is used to represent the address of an array, used
9032 // only by the Fixed statement, this generates "&a [0]" construct
9033 // for fixed (char *pa = a)
9035 public class ArrayPtr : FixedBufferPtr {
9038 public ArrayPtr (Expression array, Type array_type, Location l):
9039 base (array, array_type, l)
9041 this.array_type = array_type;
9044 public override void Emit (EmitContext ec)
9048 ILGenerator ig = ec.ig;
9049 IntLiteral.EmitInt (ig, 0);
9050 ig.Emit (OpCodes.Ldelema, array_type);
9055 // Encapsulates a conversion rules required for array indexes
9057 public class ArrayIndexCast : TypeCast
9059 public ArrayIndexCast (Expression expr)
9060 : base (expr, expr.Type)
9064 public override Expression CreateExpressionTree (EmitContext ec)
9066 ArrayList args = new ArrayList (2);
9067 args.Add (new Argument (child.CreateExpressionTree (ec)));
9068 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9069 return CreateExpressionFactoryCall ("ConvertChecked", args);
9072 public override void Emit (EmitContext ec)
9076 if (type == TypeManager.int32_type)
9079 if (type == TypeManager.uint32_type)
9080 ec.ig.Emit (OpCodes.Conv_U);
9081 else if (type == TypeManager.int64_type)
9082 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9083 else if (type == TypeManager.uint64_type)
9084 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9086 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9091 // Implements the `stackalloc' keyword
9093 public class StackAlloc : Expression {
9098 public StackAlloc (Expression type, Expression count, Location l)
9105 public override Expression CreateExpressionTree (EmitContext ec)
9107 throw new NotSupportedException ("ET");
9110 public override Expression DoResolve (EmitContext ec)
9112 count = count.Resolve (ec);
9116 if (count.Type != TypeManager.uint32_type){
9117 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9122 Constant c = count as Constant;
9123 if (c != null && c.IsNegative) {
9124 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9128 if (ec.InCatch || ec.InFinally) {
9129 Error (255, "Cannot use stackalloc in finally or catch");
9133 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9139 if (!TypeManager.VerifyUnManaged (otype, loc))
9142 type = TypeManager.GetPointerType (otype);
9143 eclass = ExprClass.Value;
9148 public override void Emit (EmitContext ec)
9150 int size = GetTypeSize (otype);
9151 ILGenerator ig = ec.ig;
9156 ig.Emit (OpCodes.Sizeof, otype);
9158 IntConstant.EmitInt (ig, size);
9160 ig.Emit (OpCodes.Mul_Ovf_Un);
9161 ig.Emit (OpCodes.Localloc);
9164 protected override void CloneTo (CloneContext clonectx, Expression t)
9166 StackAlloc target = (StackAlloc) t;
9167 target.count = count.Clone (clonectx);
9168 target.t = t.Clone (clonectx);
9173 // An object initializer expression
9175 public class ElementInitializer : Assign
9177 public readonly string Name;
9179 public ElementInitializer (string name, Expression initializer, Location loc)
9180 : base (null, initializer, loc)
9185 protected override void CloneTo (CloneContext clonectx, Expression t)
9187 ElementInitializer target = (ElementInitializer) t;
9188 target.source = source.Clone (clonectx);
9191 public override Expression CreateExpressionTree (EmitContext ec)
9193 ArrayList args = new ArrayList (2);
9194 FieldExpr fe = target as FieldExpr;
9196 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9198 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9200 args.Add (new Argument (source.CreateExpressionTree (ec)));
9201 return CreateExpressionFactoryCall (
9202 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9206 public override Expression DoResolve (EmitContext ec)
9209 return EmptyExpressionStatement.Instance;
9211 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9212 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9218 me.InstanceExpression = ec.CurrentInitializerVariable;
9220 if (source is CollectionOrObjectInitializers) {
9221 Expression previous = ec.CurrentInitializerVariable;
9222 ec.CurrentInitializerVariable = target;
9223 source = source.Resolve (ec);
9224 ec.CurrentInitializerVariable = previous;
9228 eclass = source.eclass;
9233 Expression expr = base.DoResolve (ec);
9238 // Ignore field initializers with default value
9240 Constant c = source as Constant;
9241 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9242 return EmptyExpressionStatement.Instance;
9247 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9249 MemberInfo member = members [0];
9250 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9251 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9252 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9254 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9255 TypeManager.GetFullNameSignature (member));
9260 public override void EmitStatement (EmitContext ec)
9262 if (source is CollectionOrObjectInitializers)
9265 base.EmitStatement (ec);
9270 // A collection initializer expression
9272 public class CollectionElementInitializer : Invocation
9274 public class ElementInitializerArgument : Argument
9276 public ElementInitializerArgument (Expression e)
9282 sealed class AddMemberAccess : MemberAccess
9284 public AddMemberAccess (Expression expr, Location loc)
9285 : base (expr, "Add", loc)
9289 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9291 if (TypeManager.HasElementType (type))
9294 base.Error_TypeDoesNotContainDefinition (type, name);
9298 public CollectionElementInitializer (Expression argument)
9299 : base (null, new ArrayList (1), true)
9301 Arguments.Add (argument);
9302 this.loc = argument.Location;
9305 public CollectionElementInitializer (ArrayList arguments, Location loc)
9306 : base (null, arguments, true)
9311 public override Expression CreateExpressionTree (EmitContext ec)
9313 ArrayList args = new ArrayList (2);
9314 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9316 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9317 foreach (Argument a in Arguments)
9318 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9320 args.Add (new Argument (new ArrayCreation (
9321 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9322 return CreateExpressionFactoryCall ("ElementInit", args);
9325 protected override void CloneTo (CloneContext clonectx, Expression t)
9327 CollectionElementInitializer target = (CollectionElementInitializer) t;
9329 target.Arguments = new ArrayList (Arguments.Count);
9330 foreach (Expression e in Arguments)
9331 target.Arguments.Add (e.Clone (clonectx));
9334 public override Expression DoResolve (EmitContext ec)
9336 if (eclass != ExprClass.Invalid)
9339 // TODO: We could call a constructor which takes element count argument,
9340 // for known types like List<T>, Dictionary<T, U>
9342 for (int i = 0; i < Arguments.Count; ++i) {
9343 Expression expr = Arguments [i] as Expression;
9347 expr = expr.Resolve (ec);
9351 Arguments [i] = new ElementInitializerArgument (expr);
9354 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9356 return base.DoResolve (ec);
9361 // A block of object or collection initializers
9363 public class CollectionOrObjectInitializers : ExpressionStatement
9365 ArrayList initializers;
9367 public static readonly CollectionOrObjectInitializers Empty =
9368 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9370 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9372 this.initializers = initializers;
9376 public bool IsEmpty {
9378 return initializers.Count == 0;
9382 public bool IsCollectionInitializer {
9384 return type == typeof (CollectionOrObjectInitializers);
9388 protected override void CloneTo (CloneContext clonectx, Expression target)
9390 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9392 t.initializers = new ArrayList (initializers.Count);
9393 foreach (Expression e in initializers)
9394 t.initializers.Add (e.Clone (clonectx));
9397 public override Expression CreateExpressionTree (EmitContext ec)
9399 ArrayList expr_initializers = new ArrayList (initializers.Count);
9400 foreach (Expression e in initializers) {
9401 Expression expr = e.CreateExpressionTree (ec);
9403 expr_initializers.Add (expr);
9406 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9409 public override Expression DoResolve (EmitContext ec)
9411 if (eclass != ExprClass.Invalid)
9414 bool is_collection_initialization = false;
9415 ArrayList element_names = null;
9416 for (int i = 0; i < initializers.Count; ++i) {
9417 Expression initializer = (Expression) initializers [i];
9418 ElementInitializer element_initializer = initializer as ElementInitializer;
9421 if (element_initializer != null) {
9422 element_names = new ArrayList (initializers.Count);
9423 element_names.Add (element_initializer.Name);
9425 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9426 TypeManager.ienumerable_type)) {
9427 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9428 "object initializer because type `{1}' does not implement `{2}' interface",
9429 ec.CurrentInitializerVariable.GetSignatureForError (),
9430 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9431 TypeManager.CSharpName (TypeManager.ienumerable_type));
9434 is_collection_initialization = true;
9437 if (is_collection_initialization != (element_initializer == null)) {
9438 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9439 is_collection_initialization ? "collection initializer" : "object initializer");
9443 if (!is_collection_initialization) {
9444 if (element_names.Contains (element_initializer.Name)) {
9445 Report.Error (1912, element_initializer.Location,
9446 "An object initializer includes more than one member `{0}' initialization",
9447 element_initializer.Name);
9449 element_names.Add (element_initializer.Name);
9454 Expression e = initializer.Resolve (ec);
9455 if (e == EmptyExpressionStatement.Instance)
9456 initializers.RemoveAt (i--);
9458 initializers [i] = e;
9461 if (is_collection_initialization) {
9462 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9463 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9464 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9467 type = typeof (CollectionOrObjectInitializers);
9469 type = typeof (ElementInitializer);
9472 eclass = ExprClass.Variable;
9476 public override void Emit (EmitContext ec)
9481 public override void EmitStatement (EmitContext ec)
9483 foreach (ExpressionStatement e in initializers)
9484 e.EmitStatement (ec);
9487 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9489 foreach (Expression e in initializers)
9490 e.MutateHoistedGenericType (storey);
9495 // New expression with element/object initializers
9497 public class NewInitialize : New
9500 // This class serves as a proxy for variable initializer target instances.
9501 // A real variable is assigned later when we resolve left side of an
9504 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9506 NewInitialize new_instance;
9508 public InitializerTargetExpression (NewInitialize newInstance)
9510 this.type = newInstance.type;
9511 this.loc = newInstance.loc;
9512 this.eclass = newInstance.eclass;
9513 this.new_instance = newInstance;
9516 public override Expression CreateExpressionTree (EmitContext ec)
9518 // Should not be reached
9519 throw new NotSupportedException ("ET");
9522 public override Expression DoResolve (EmitContext ec)
9527 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9532 public override void Emit (EmitContext ec)
9534 Expression e = (Expression) new_instance.instance;
9538 #region IMemoryLocation Members
9540 public void AddressOf (EmitContext ec, AddressOp mode)
9542 new_instance.instance.AddressOf (ec, mode);
9548 CollectionOrObjectInitializers initializers;
9549 IMemoryLocation instance;
9551 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9552 : base (requested_type, arguments, l)
9554 this.initializers = initializers;
9557 protected override void CloneTo (CloneContext clonectx, Expression t)
9559 base.CloneTo (clonectx, t);
9561 NewInitialize target = (NewInitialize) t;
9562 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9565 public override Expression CreateExpressionTree (EmitContext ec)
9567 ArrayList args = new ArrayList (2);
9568 args.Add (new Argument (base.CreateExpressionTree (ec)));
9569 if (!initializers.IsEmpty)
9570 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9572 return CreateExpressionFactoryCall (
9573 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9577 public override Expression DoResolve (EmitContext ec)
9579 if (eclass != ExprClass.Invalid)
9582 Expression e = base.DoResolve (ec);
9586 // Empty initializer can be optimized to simple new
9587 if (initializers.IsEmpty) {
9588 initializers.Resolve (ec);
9589 return ReducedExpression.Create (e, this).Resolve (ec);
9592 Expression previous = ec.CurrentInitializerVariable;
9593 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9594 initializers.Resolve (ec);
9595 ec.CurrentInitializerVariable = previous;
9599 public override bool Emit (EmitContext ec, IMemoryLocation target)
9601 bool left_on_stack = base.Emit (ec, target);
9603 if (initializers.IsEmpty)
9604 return left_on_stack;
9606 LocalTemporary temp = null;
9609 // If target is non-hoisted variable, let's use it
9611 VariableReference variable = target as VariableReference;
9612 if (variable != null) {
9615 if (left_on_stack) {
9617 StoreFromPtr (ec.ig, type);
9619 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9621 left_on_stack = false;
9624 temp = target as LocalTemporary;
9627 throw new NotImplementedException ();
9629 temp = new LocalTemporary (type);
9637 initializers.Emit (ec);
9639 if (left_on_stack) {
9644 return left_on_stack;
9647 public override bool HasInitializer {
9649 return !initializers.IsEmpty;
9653 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9655 base.MutateHoistedGenericType (storey);
9656 initializers.MutateHoistedGenericType (storey);
9660 public class AnonymousTypeDeclaration : Expression
9662 ArrayList parameters;
9663 readonly TypeContainer parent;
9664 static readonly ArrayList EmptyParameters = new ArrayList (0);
9666 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9668 this.parameters = parameters;
9669 this.parent = parent;
9673 protected override void CloneTo (CloneContext clonectx, Expression target)
9675 if (parameters == null)
9678 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9679 t.parameters = new ArrayList (parameters.Count);
9680 foreach (AnonymousTypeParameter atp in parameters)
9681 t.parameters.Add (atp.Clone (clonectx));
9684 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9686 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9690 type = AnonymousTypeClass.Create (parent, parameters, loc);
9697 if (Report.Errors == 0)
9700 RootContext.ToplevelTypes.AddAnonymousType (type);
9704 public override Expression CreateExpressionTree (EmitContext ec)
9706 throw new NotSupportedException ("ET");
9709 public override Expression DoResolve (EmitContext ec)
9711 AnonymousTypeClass anonymous_type;
9713 if (!ec.IsAnonymousMethodAllowed) {
9714 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9718 if (parameters == null) {
9719 anonymous_type = CreateAnonymousType (EmptyParameters);
9720 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9721 null, loc).Resolve (ec);
9725 ArrayList arguments = new ArrayList (parameters.Count);
9726 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9727 for (int i = 0; i < parameters.Count; ++i) {
9728 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9734 arguments.Add (new Argument (e));
9735 t_args [i] = new TypeExpression (e.Type, e.Location);
9741 anonymous_type = CreateAnonymousType (parameters);
9742 if (anonymous_type == null)
9745 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9746 new TypeArguments (loc, t_args), loc);
9748 return new New (te, arguments, loc).Resolve (ec);
9751 public override void Emit (EmitContext ec)
9753 throw new InternalErrorException ("Should not be reached");
9757 public class AnonymousTypeParameter : Expression
9759 public readonly string Name;
9760 Expression initializer;
9762 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9766 this.initializer = initializer;
9769 public AnonymousTypeParameter (Parameter parameter)
9771 this.Name = parameter.Name;
9772 this.loc = parameter.Location;
9773 this.initializer = new SimpleName (Name, loc);
9776 protected override void CloneTo (CloneContext clonectx, Expression target)
9778 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9779 t.initializer = initializer.Clone (clonectx);
9782 public override Expression CreateExpressionTree (EmitContext ec)
9784 throw new NotSupportedException ("ET");
9787 public override bool Equals (object o)
9789 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9790 return other != null && Name == other.Name;
9793 public override int GetHashCode ()
9795 return Name.GetHashCode ();
9798 public override Expression DoResolve (EmitContext ec)
9800 Expression e = initializer.Resolve (ec);
9804 if (e.eclass == ExprClass.MethodGroup) {
9805 Error_InvalidInitializer (e.ExprClassName);
9810 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9811 type == TypeManager.anonymous_method_type || type.IsPointer) {
9812 Error_InvalidInitializer (e.GetSignatureForError ());
9819 protected virtual void Error_InvalidInitializer (string initializer)
9821 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9825 public override void Emit (EmitContext ec)
9827 throw new InternalErrorException ("Should not be reached");