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 return new FloatLiteral (-fl.Value, e.Location);
249 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
251 if (expr_type == TypeManager.double_type) {
252 DoubleLiteral dl = e as DoubleLiteral;
253 // For better error reporting
255 return new DoubleLiteral (-dl.Value, e.Location);
257 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
259 if (expr_type == TypeManager.decimal_type)
260 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
264 case Operator.LogicalNot:
265 if (expr_type != TypeManager.bool_type)
268 bool b = (bool)e.GetValue ();
269 return new BoolConstant (!b, e.Location);
271 case Operator.OnesComplement:
272 // Unary numeric promotions
273 if (expr_type == TypeManager.byte_type)
274 return new IntConstant (~((ByteConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.sbyte_type)
276 return new IntConstant (~((SByteConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.short_type)
278 return new IntConstant (~((ShortConstant)e).Value, e.Location);
279 if (expr_type == TypeManager.ushort_type)
280 return new IntConstant (~((UShortConstant)e).Value, e.Location);
281 if (expr_type == TypeManager.char_type)
282 return new IntConstant (~((CharConstant)e).Value, e.Location);
284 // Predefined operators
285 if (expr_type == TypeManager.int32_type)
286 return new IntConstant (~((IntConstant)e).Value, e.Location);
287 if (expr_type == TypeManager.uint32_type)
288 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
289 if (expr_type == TypeManager.int64_type)
290 return new LongConstant (~((LongConstant)e).Value, e.Location);
291 if (expr_type == TypeManager.uint64_type){
292 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
294 if (e is EnumConstant) {
295 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
297 e = new EnumConstant (e, expr_type);
302 throw new Exception ("Can not constant fold: " + Oper.ToString());
305 protected Expression ResolveOperator (EmitContext ec, Expression expr)
307 eclass = ExprClass.Value;
309 if (predefined_operators == null)
310 CreatePredefinedOperatorsTable ();
312 Type expr_type = expr.Type;
313 Expression best_expr;
316 // Primitive types first
318 if (TypeManager.IsPrimitiveType (expr_type)) {
319 best_expr = ResolvePrimitivePredefinedType (expr);
320 if (best_expr == null)
323 type = best_expr.Type;
329 // E operator ~(E x);
331 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
332 return ResolveEnumOperator (ec, expr);
334 return ResolveUserType (ec, expr);
337 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
339 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
340 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
341 if (best_expr == null)
345 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
347 return EmptyCast.Create (this, type);
350 public override Expression CreateExpressionTree (EmitContext ec)
352 return CreateExpressionTree (ec, null);
355 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
359 case Operator.AddressOf:
360 Error_PointerInsideExpressionTree ();
362 case Operator.UnaryNegation:
363 if (ec.CheckState && user_op == null && !IsFloat (type))
364 method_name = "NegateChecked";
366 method_name = "Negate";
368 case Operator.OnesComplement:
369 case Operator.LogicalNot:
372 case Operator.UnaryPlus:
373 method_name = "UnaryPlus";
376 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
379 ArrayList args = new ArrayList (2);
380 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
382 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
383 return CreateExpressionFactoryCall (method_name, args);
386 static void CreatePredefinedOperatorsTable ()
388 predefined_operators = new Type [(int) Operator.TOP] [];
391 // 7.6.1 Unary plus operator
393 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
394 TypeManager.int32_type, TypeManager.uint32_type,
395 TypeManager.int64_type, TypeManager.uint64_type,
396 TypeManager.float_type, TypeManager.double_type,
397 TypeManager.decimal_type
401 // 7.6.2 Unary minus operator
403 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
404 TypeManager.int32_type,
405 TypeManager.int64_type,
406 TypeManager.float_type, TypeManager.double_type,
407 TypeManager.decimal_type
411 // 7.6.3 Logical negation operator
413 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
414 TypeManager.bool_type
418 // 7.6.4 Bitwise complement operator
420 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
421 TypeManager.int32_type, TypeManager.uint32_type,
422 TypeManager.int64_type, TypeManager.uint64_type
427 // Unary numeric promotions
429 static Expression DoNumericPromotion (Operator op, Expression expr)
431 Type expr_type = expr.Type;
432 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
433 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
434 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
435 expr_type == TypeManager.char_type)
436 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
438 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
439 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
444 public override Expression DoResolve (EmitContext ec)
446 if (Oper == Operator.AddressOf) {
447 return ResolveAddressOf (ec);
450 Expr = Expr.Resolve (ec);
454 if (TypeManager.IsNullableValueType (Expr.Type))
455 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
458 // Attempt to use a constant folding operation.
460 Constant cexpr = Expr as Constant;
462 cexpr = TryReduceConstant (ec, cexpr);
467 Expression expr = ResolveOperator (ec, Expr);
469 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
472 // Reduce unary operator on predefined types
474 if (expr == this && Oper == Operator.UnaryPlus)
480 public override Expression DoResolveLValue (EmitContext ec, Expression right)
485 public override void Emit (EmitContext ec)
487 EmitOperator (ec, type);
490 protected void EmitOperator (EmitContext ec, Type type)
492 ILGenerator ig = ec.ig;
495 case Operator.UnaryPlus:
499 case Operator.UnaryNegation:
500 if (ec.CheckState && !IsFloat (type)) {
501 ig.Emit (OpCodes.Ldc_I4_0);
502 if (type == TypeManager.int64_type)
503 ig.Emit (OpCodes.Conv_U8);
505 ig.Emit (OpCodes.Sub_Ovf);
508 ig.Emit (OpCodes.Neg);
513 case Operator.LogicalNot:
515 ig.Emit (OpCodes.Ldc_I4_0);
516 ig.Emit (OpCodes.Ceq);
519 case Operator.OnesComplement:
521 ig.Emit (OpCodes.Not);
524 case Operator.AddressOf:
525 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
529 throw new Exception ("This should not happen: Operator = "
534 // Same trick as in Binary expression
536 if (enum_conversion != null)
537 enum_conversion.Emit (ec);
540 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
542 if (Oper == Operator.LogicalNot)
543 Expr.EmitBranchable (ec, target, !on_true);
545 base.EmitBranchable (ec, target, on_true);
548 public override void EmitSideEffect (EmitContext ec)
550 Expr.EmitSideEffect (ec);
553 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
555 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
556 oper, TypeManager.CSharpName (t));
559 static bool IsFloat (Type t)
561 return t == TypeManager.float_type || t == TypeManager.double_type;
565 // Returns a stringified representation of the Operator
567 public static string OperName (Operator oper)
570 case Operator.UnaryPlus:
572 case Operator.UnaryNegation:
574 case Operator.LogicalNot:
576 case Operator.OnesComplement:
578 case Operator.AddressOf:
582 throw new NotImplementedException (oper.ToString ());
585 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
587 type = storey.MutateType (type);
588 Expr.MutateHoistedGenericType (storey);
591 Expression ResolveAddressOf (EmitContext ec)
596 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
597 if (Expr == null || Expr.eclass != ExprClass.Variable) {
598 Error (211, "Cannot take the address of the given expression");
602 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
606 IVariableReference vr = Expr as IVariableReference;
609 VariableInfo vi = vr.VariableInfo;
611 if (vi.LocalInfo != null)
612 vi.LocalInfo.Used = true;
615 // A variable is considered definitely assigned if you take its address.
620 is_fixed = vr.IsFixed;
621 vr.SetHasAddressTaken ();
624 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
627 IFixedExpression fe = Expr as IFixedExpression;
628 is_fixed = fe != null && fe.IsFixed;
631 if (!is_fixed && !ec.InFixedInitializer) {
632 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
635 type = TypeManager.GetPointerType (Expr.Type);
636 eclass = ExprClass.Value;
640 Expression ResolvePrimitivePredefinedType (Expression expr)
642 expr = DoNumericPromotion (Oper, expr);
643 Type expr_type = expr.Type;
644 Type[] predefined = predefined_operators [(int) Oper];
645 foreach (Type t in predefined) {
653 // Perform user-operator overload resolution
655 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
657 CSharp.Operator.OpType op_type;
659 case Operator.LogicalNot:
660 op_type = CSharp.Operator.OpType.LogicalNot; break;
661 case Operator.OnesComplement:
662 op_type = CSharp.Operator.OpType.OnesComplement; break;
663 case Operator.UnaryNegation:
664 op_type = CSharp.Operator.OpType.UnaryNegation; break;
665 case Operator.UnaryPlus:
666 op_type = CSharp.Operator.OpType.UnaryPlus; break;
668 throw new InternalErrorException (Oper.ToString ());
671 string op_name = CSharp.Operator.GetMetadataName (op_type);
672 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
676 ArrayList args = new ArrayList (1);
677 args.Add (new Argument (expr));
678 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
683 Expr = ((Argument) args [0]).Expr;
684 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
688 // Unary user type overload resolution
690 Expression ResolveUserType (EmitContext ec, Expression expr)
692 Expression best_expr = ResolveUserOperator (ec, expr);
693 if (best_expr != null)
696 Type[] predefined = predefined_operators [(int) Oper];
697 foreach (Type t in predefined) {
698 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
699 if (oper_expr == null)
703 // decimal type is predefined but has user-operators
705 if (oper_expr.Type == TypeManager.decimal_type)
706 oper_expr = ResolveUserType (ec, oper_expr);
708 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
710 if (oper_expr == null)
713 if (best_expr == null) {
714 best_expr = oper_expr;
718 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
720 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
721 OperName (Oper), TypeManager.CSharpName (expr.Type));
726 best_expr = oper_expr;
729 if (best_expr == null)
733 // HACK: Decimal user-operator is included in standard operators
735 if (best_expr.Type == TypeManager.decimal_type)
739 type = best_expr.Type;
743 protected override void CloneTo (CloneContext clonectx, Expression t)
745 Unary target = (Unary) t;
747 target.Expr = Expr.Clone (clonectx);
752 // Unary operators are turned into Indirection expressions
753 // after semantic analysis (this is so we can take the address
754 // of an indirection).
756 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
758 LocalTemporary temporary;
761 public Indirection (Expression expr, Location l)
767 public override Expression CreateExpressionTree (EmitContext ec)
769 Error_PointerInsideExpressionTree ();
773 protected override void CloneTo (CloneContext clonectx, Expression t)
775 Indirection target = (Indirection) t;
776 target.expr = expr.Clone (clonectx);
779 public override void Emit (EmitContext ec)
784 LoadFromPtr (ec.ig, Type);
787 public void Emit (EmitContext ec, bool leave_copy)
791 ec.ig.Emit (OpCodes.Dup);
792 temporary = new LocalTemporary (expr.Type);
793 temporary.Store (ec);
797 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
799 prepared = prepare_for_load;
803 if (prepare_for_load)
804 ec.ig.Emit (OpCodes.Dup);
808 ec.ig.Emit (OpCodes.Dup);
809 temporary = new LocalTemporary (expr.Type);
810 temporary.Store (ec);
813 StoreFromPtr (ec.ig, type);
815 if (temporary != null) {
817 temporary.Release (ec);
821 public void AddressOf (EmitContext ec, AddressOp Mode)
826 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
828 return DoResolve (ec);
831 public override Expression DoResolve (EmitContext ec)
833 expr = expr.Resolve (ec);
840 if (!expr.Type.IsPointer) {
841 Error (193, "The * or -> operator must be applied to a pointer");
845 if (expr.Type == TypeManager.void_ptr_type) {
846 Error (242, "The operation in question is undefined on void pointers");
850 type = TypeManager.GetElementType (expr.Type);
851 eclass = ExprClass.Variable;
855 public bool IsFixed {
859 public override string ToString ()
861 return "*(" + expr + ")";
866 /// Unary Mutator expressions (pre and post ++ and --)
870 /// UnaryMutator implements ++ and -- expressions. It derives from
871 /// ExpressionStatement becuase the pre/post increment/decrement
872 /// operators can be used in a statement context.
874 /// FIXME: Idea, we could split this up in two classes, one simpler
875 /// for the common case, and one with the extra fields for more complex
876 /// classes (indexers require temporary access; overloaded require method)
879 public class UnaryMutator : ExpressionStatement {
881 public enum Mode : byte {
888 PreDecrement = IsDecrement,
889 PostIncrement = IsPost,
890 PostDecrement = IsPost | IsDecrement
894 bool is_expr = false;
895 bool recurse = false;
900 // This is expensive for the simplest case.
902 UserOperatorCall method;
904 public UnaryMutator (Mode m, Expression e)
911 static string OperName (Mode mode)
913 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
918 /// Returns whether an object of type `t' can be incremented
919 /// or decremented with add/sub (ie, basically whether we can
920 /// use pre-post incr-decr operations on it, but it is not a
921 /// System.Decimal, which we require operator overloading to catch)
923 static bool IsIncrementableNumber (Type t)
925 return (t == TypeManager.sbyte_type) ||
926 (t == TypeManager.byte_type) ||
927 (t == TypeManager.short_type) ||
928 (t == TypeManager.ushort_type) ||
929 (t == TypeManager.int32_type) ||
930 (t == TypeManager.uint32_type) ||
931 (t == TypeManager.int64_type) ||
932 (t == TypeManager.uint64_type) ||
933 (t == TypeManager.char_type) ||
934 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
935 (t == TypeManager.float_type) ||
936 (t == TypeManager.double_type) ||
937 (t.IsPointer && t != TypeManager.void_ptr_type);
940 Expression ResolveOperator (EmitContext ec)
945 // The operand of the prefix/postfix increment decrement operators
946 // should be an expression that is classified as a variable,
947 // a property access or an indexer access
949 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
950 expr = expr.ResolveLValue (ec, expr, Location);
952 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
956 // Step 1: Perform Operator Overload location
961 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
962 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
964 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
966 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
969 ArrayList args = new ArrayList (1);
970 args.Add (new Argument (expr, Argument.AType.Expression));
971 mg = mg.OverloadResolve (ec, ref args, false, loc);
975 method = new UserOperatorCall (mg, args, null, loc);
976 Convert.ImplicitConversionRequired (ec, method, type, loc);
980 if (!IsIncrementableNumber (type)) {
981 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
982 TypeManager.CSharpName (type) + "'");
989 public override Expression CreateExpressionTree (EmitContext ec)
991 return new SimpleAssign (this, this).CreateExpressionTree (ec);
994 public override Expression DoResolve (EmitContext ec)
996 expr = expr.Resolve (ec);
1001 eclass = ExprClass.Value;
1004 if (TypeManager.IsNullableValueType (expr.Type))
1005 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1008 return ResolveOperator (ec);
1012 // Loads the proper "1" into the stack based on the type, then it emits the
1013 // opcode for the operation requested
1015 void LoadOneAndEmitOp (EmitContext ec, Type t)
1018 // Measure if getting the typecode and using that is more/less efficient
1019 // that comparing types. t.GetTypeCode() is an internal call.
1021 ILGenerator ig = ec.ig;
1023 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1024 LongConstant.EmitLong (ig, 1);
1025 else if (t == TypeManager.double_type)
1026 ig.Emit (OpCodes.Ldc_R8, 1.0);
1027 else if (t == TypeManager.float_type)
1028 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1029 else if (t.IsPointer){
1030 Type et = TypeManager.GetElementType (t);
1031 int n = GetTypeSize (et);
1034 ig.Emit (OpCodes.Sizeof, et);
1036 IntConstant.EmitInt (ig, n);
1037 ig.Emit (OpCodes.Conv_I);
1040 ig.Emit (OpCodes.Ldc_I4_1);
1043 // Now emit the operation
1046 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1047 Binary.EmitOperatorOpcode (ec, op, t);
1049 if (t == TypeManager.sbyte_type){
1051 ig.Emit (OpCodes.Conv_Ovf_I1);
1053 ig.Emit (OpCodes.Conv_I1);
1054 } else if (t == TypeManager.byte_type){
1056 ig.Emit (OpCodes.Conv_Ovf_U1);
1058 ig.Emit (OpCodes.Conv_U1);
1059 } else if (t == TypeManager.short_type){
1061 ig.Emit (OpCodes.Conv_Ovf_I2);
1063 ig.Emit (OpCodes.Conv_I2);
1064 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1066 ig.Emit (OpCodes.Conv_Ovf_U2);
1068 ig.Emit (OpCodes.Conv_U2);
1073 void EmitCode (EmitContext ec, bool is_expr)
1076 this.is_expr = is_expr;
1077 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1080 public override void Emit (EmitContext ec)
1083 // We use recurse to allow ourselfs to be the source
1084 // of an assignment. This little hack prevents us from
1085 // having to allocate another expression
1088 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1090 LoadOneAndEmitOp (ec, expr.Type);
1092 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1097 EmitCode (ec, true);
1100 public override void EmitStatement (EmitContext ec)
1102 EmitCode (ec, false);
1105 protected override void CloneTo (CloneContext clonectx, Expression t)
1107 UnaryMutator target = (UnaryMutator) t;
1109 target.expr = expr.Clone (clonectx);
1114 /// Base class for the `Is' and `As' classes.
1118 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1121 public abstract class Probe : Expression {
1122 public Expression ProbeType;
1123 protected Expression expr;
1124 protected TypeExpr probe_type_expr;
1126 public Probe (Expression expr, Expression probe_type, Location l)
1128 ProbeType = probe_type;
1133 public Expression Expr {
1139 public override Expression DoResolve (EmitContext ec)
1141 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1142 if (probe_type_expr == null)
1145 expr = expr.Resolve (ec);
1149 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1150 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1154 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1155 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1160 if (expr.Type == TypeManager.anonymous_method_type) {
1161 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1169 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1171 expr.MutateHoistedGenericType (storey);
1172 probe_type_expr.MutateHoistedGenericType (storey);
1175 protected abstract string OperatorName { get; }
1177 protected override void CloneTo (CloneContext clonectx, Expression t)
1179 Probe target = (Probe) t;
1181 target.expr = expr.Clone (clonectx);
1182 target.ProbeType = ProbeType.Clone (clonectx);
1188 /// Implementation of the `is' operator.
1190 public class Is : Probe {
1191 Nullable.Unwrap expr_unwrap;
1193 public Is (Expression expr, Expression probe_type, Location l)
1194 : base (expr, probe_type, l)
1198 public override Expression CreateExpressionTree (EmitContext ec)
1200 ArrayList args = new ArrayList (2);
1201 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1202 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1203 return CreateExpressionFactoryCall ("TypeIs", args);
1206 public override void Emit (EmitContext ec)
1208 ILGenerator ig = ec.ig;
1209 if (expr_unwrap != null) {
1210 expr_unwrap.EmitCheck (ec);
1215 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1216 ig.Emit (OpCodes.Ldnull);
1217 ig.Emit (OpCodes.Cgt_Un);
1220 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1222 ILGenerator ig = ec.ig;
1223 if (expr_unwrap != null) {
1224 expr_unwrap.EmitCheck (ec);
1227 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1229 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1232 Expression CreateConstantResult (bool result)
1235 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1236 TypeManager.CSharpName (probe_type_expr.Type));
1238 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1244 public override Expression DoResolve (EmitContext ec)
1246 if (base.DoResolve (ec) == null)
1250 bool d_is_nullable = false;
1253 // If E is a method group or the null literal, or if the type of E is a reference
1254 // type or a nullable type and the value of E is null, the result is false
1256 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1257 return CreateConstantResult (false);
1259 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1260 d = TypeManager.GetTypeArguments (d) [0];
1261 d_is_nullable = true;
1264 type = TypeManager.bool_type;
1265 eclass = ExprClass.Value;
1266 Type t = probe_type_expr.Type;
1267 bool t_is_nullable = false;
1268 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1269 t = TypeManager.GetTypeArguments (t) [0];
1270 t_is_nullable = true;
1273 if (t.IsValueType) {
1276 // D and T are the same value types but D can be null
1278 if (d_is_nullable && !t_is_nullable) {
1279 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1284 // The result is true if D and T are the same value types
1286 return CreateConstantResult (true);
1289 if (TypeManager.IsGenericParameter (d))
1290 return ResolveGenericParameter (t, d);
1293 // An unboxing conversion exists
1295 if (Convert.ExplicitReferenceConversionExists (d, t))
1298 if (TypeManager.IsGenericParameter (t))
1299 return ResolveGenericParameter (d, t);
1301 if (d.IsValueType) {
1303 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1304 return CreateConstantResult (true);
1306 if (TypeManager.IsGenericParameter (d))
1307 return ResolveGenericParameter (t, d);
1309 if (TypeManager.ContainsGenericParameters (d))
1312 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1313 Convert.ExplicitReferenceConversionExists (d, t)) {
1319 return CreateConstantResult (false);
1322 Expression ResolveGenericParameter (Type d, Type t)
1325 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1326 if (constraints != null) {
1327 if (constraints.IsReferenceType && d.IsValueType)
1328 return CreateConstantResult (false);
1330 if (constraints.IsValueType && !d.IsValueType)
1331 return CreateConstantResult (TypeManager.IsEqual (d, t));
1334 if (!TypeManager.IsReferenceType (expr.Type))
1335 expr = new BoxedCast (expr, d);
1343 protected override string OperatorName {
1344 get { return "is"; }
1349 /// Implementation of the `as' operator.
1351 public class As : Probe {
1353 Expression resolved_type;
1355 public As (Expression expr, Expression probe_type, Location l)
1356 : base (expr, probe_type, l)
1360 public override Expression CreateExpressionTree (EmitContext ec)
1362 ArrayList args = new ArrayList (2);
1363 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1364 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1365 return CreateExpressionFactoryCall ("TypeAs", args);
1368 public override void Emit (EmitContext ec)
1370 ILGenerator ig = ec.ig;
1375 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1378 if (TypeManager.IsNullableType (type))
1379 ig.Emit (OpCodes.Unbox_Any, type);
1383 public override Expression DoResolve (EmitContext ec)
1385 // Because expr is modified
1386 if (eclass != ExprClass.Invalid)
1389 if (resolved_type == null) {
1390 resolved_type = base.DoResolve (ec);
1392 if (resolved_type == null)
1396 type = probe_type_expr.Type;
1397 eclass = ExprClass.Value;
1398 Type etype = expr.Type;
1400 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1401 if (probe_type_expr is TypeParameterExpr) {
1402 Report.Error (413, loc,
1403 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1404 probe_type_expr.GetSignatureForError ());
1406 Report.Error (77, loc,
1407 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1408 TypeManager.CSharpName (type));
1413 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1414 return Nullable.LiftedNull.CreateFromExpression (this);
1417 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1424 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1425 if (TypeManager.IsGenericParameter (etype))
1426 expr = new BoxedCast (expr, etype);
1432 if (TypeManager.ContainsGenericParameters (etype) ||
1433 TypeManager.ContainsGenericParameters (type)) {
1434 expr = new BoxedCast (expr, etype);
1439 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1440 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1445 protected override string OperatorName {
1446 get { return "as"; }
1449 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1451 return expr.GetAttributableValue (ec, value_type, out value);
1456 /// This represents a typecast in the source language.
1458 /// FIXME: Cast expressions have an unusual set of parsing
1459 /// rules, we need to figure those out.
1461 public class Cast : Expression {
1462 Expression target_type;
1465 public Cast (Expression cast_type, Expression expr)
1466 : this (cast_type, expr, cast_type.Location)
1470 public Cast (Expression cast_type, Expression expr, Location loc)
1472 this.target_type = cast_type;
1477 public Expression TargetType {
1478 get { return target_type; }
1481 public Expression Expr {
1482 get { return expr; }
1485 public override Expression CreateExpressionTree (EmitContext ec)
1487 throw new NotSupportedException ("ET");
1490 public override Expression DoResolve (EmitContext ec)
1492 expr = expr.Resolve (ec);
1496 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1502 if (type.IsAbstract && type.IsSealed) {
1503 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1507 eclass = ExprClass.Value;
1509 Constant c = expr as Constant;
1511 c = c.TryReduce (ec, type, loc);
1516 if (type.IsPointer && !ec.InUnsafe) {
1520 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1524 public override void Emit (EmitContext ec)
1526 throw new Exception ("Should not happen");
1529 protected override void CloneTo (CloneContext clonectx, Expression t)
1531 Cast target = (Cast) t;
1533 target.target_type = target_type.Clone (clonectx);
1534 target.expr = expr.Clone (clonectx);
1539 // C# 2.0 Default value expression
1541 public class DefaultValueExpression : Expression
1545 public DefaultValueExpression (Expression expr, Location loc)
1551 public override Expression CreateExpressionTree (EmitContext ec)
1553 ArrayList args = new ArrayList (2);
1554 args.Add (new Argument (this));
1555 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1556 return CreateExpressionFactoryCall ("Constant", args);
1559 public override Expression DoResolve (EmitContext ec)
1561 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1567 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1568 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1572 return new NullLiteral (Location).ConvertImplicitly (type);
1574 if (TypeManager.IsReferenceType (type)) {
1575 return new EmptyConstantCast (new NullLiteral (Location), type);
1578 // return ReducedExpression.Create (new NullLiteral (Location), this);
1581 Constant c = New.Constantify (type);
1585 eclass = ExprClass.Variable;
1589 public override void Emit (EmitContext ec)
1591 LocalTemporary temp_storage = new LocalTemporary(type);
1593 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1594 ec.ig.Emit(OpCodes.Initobj, type);
1595 temp_storage.Emit(ec);
1598 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1600 type = storey.MutateType (type);
1603 protected override void CloneTo (CloneContext clonectx, Expression t)
1605 DefaultValueExpression target = (DefaultValueExpression) t;
1607 target.expr = expr.Clone (clonectx);
1612 /// Binary operators
1614 public class Binary : Expression {
1616 protected class PredefinedOperator {
1617 protected readonly Type left;
1618 protected readonly Type right;
1619 public readonly Operator OperatorsMask;
1620 public Type ReturnType;
1622 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1623 : this (ltype, rtype, op_mask, ltype)
1627 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1628 : this (type, type, op_mask, return_type)
1632 public PredefinedOperator (Type type, Operator op_mask)
1633 : this (type, type, op_mask, type)
1637 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1639 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1640 throw new InternalErrorException ("Only masked values can be used");
1644 this.OperatorsMask = op_mask;
1645 this.ReturnType = return_type;
1648 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1650 b.type = ReturnType;
1652 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1653 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1656 // A user operators does not support multiple user conversions, but decimal type
1657 // is considered to be predefined type therefore we apply predefined operators rules
1658 // and then look for decimal user-operator implementation
1660 if (left == TypeManager.decimal_type)
1661 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1666 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1669 // We are dealing with primitive types only
1671 return left == ltype && ltype == rtype;
1674 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1676 if (TypeManager.IsEqual (left, lexpr.Type) &&
1677 TypeManager.IsEqual (right, rexpr.Type))
1680 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1681 Convert.ImplicitConversionExists (ec, rexpr, right);
1684 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1687 if (left != null && best_operator.left != null) {
1688 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1692 // When second arguments are same as the first one, the result is same
1694 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1695 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1698 if (result == 0 || result > 2)
1701 return result == 1 ? best_operator : this;
1705 class PredefinedStringOperator : PredefinedOperator {
1706 public PredefinedStringOperator (Type type, Operator op_mask)
1707 : base (type, op_mask, type)
1709 ReturnType = TypeManager.string_type;
1712 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1713 : base (ltype, rtype, op_mask)
1715 ReturnType = TypeManager.string_type;
1718 public override Expression ConvertResult (EmitContext ec, Binary b)
1721 // Use original expression for nullable arguments
1723 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1725 b.left = unwrap.Original;
1727 unwrap = b.right as Nullable.Unwrap;
1729 b.right = unwrap.Original;
1731 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1732 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1735 // Start a new concat expression using converted expression
1737 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1741 class PredefinedShiftOperator : PredefinedOperator {
1742 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1743 base (ltype, TypeManager.int32_type, op_mask)
1747 public override Expression ConvertResult (EmitContext ec, Binary b)
1749 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1751 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1753 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1756 // b = b.left >> b.right & (0x1f|0x3f)
1758 b.right = new Binary (Operator.BitwiseAnd,
1759 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1762 // Expression tree representation does not use & mask
1764 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1765 b.type = ReturnType;
1770 class PredefinedPointerOperator : PredefinedOperator {
1771 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1772 : base (ltype, rtype, op_mask)
1776 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1777 : base (ltype, rtype, op_mask, retType)
1781 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1782 : base (type, op_mask, return_type)
1786 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1789 if (!lexpr.Type.IsPointer)
1792 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1796 if (right == null) {
1797 if (!rexpr.Type.IsPointer)
1800 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1807 public override Expression ConvertResult (EmitContext ec, Binary b)
1810 b.left = EmptyCast.Create (b.left, left);
1811 } else if (right != null) {
1812 b.right = EmptyCast.Create (b.right, right);
1815 Type r_type = ReturnType;
1816 Expression left_arg, right_arg;
1817 if (r_type == null) {
1820 right_arg = b.right;
1821 r_type = b.left.Type;
1825 r_type = b.right.Type;
1829 right_arg = b.right;
1832 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1837 public enum Operator {
1838 Multiply = 0 | ArithmeticMask,
1839 Division = 1 | ArithmeticMask,
1840 Modulus = 2 | ArithmeticMask,
1841 Addition = 3 | ArithmeticMask | AdditionMask,
1842 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1844 LeftShift = 5 | ShiftMask,
1845 RightShift = 6 | ShiftMask,
1847 LessThan = 7 | ComparisonMask | RelationalMask,
1848 GreaterThan = 8 | ComparisonMask | RelationalMask,
1849 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1850 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1851 Equality = 11 | ComparisonMask | EqualityMask,
1852 Inequality = 12 | ComparisonMask | EqualityMask,
1854 BitwiseAnd = 13 | BitwiseMask,
1855 ExclusiveOr = 14 | BitwiseMask,
1856 BitwiseOr = 15 | BitwiseMask,
1858 LogicalAnd = 16 | LogicalMask,
1859 LogicalOr = 17 | LogicalMask,
1864 ValuesOnlyMask = ArithmeticMask - 1,
1865 ArithmeticMask = 1 << 5,
1867 ComparisonMask = 1 << 7,
1868 EqualityMask = 1 << 8,
1869 BitwiseMask = 1 << 9,
1870 LogicalMask = 1 << 10,
1871 AdditionMask = 1 << 11,
1872 SubtractionMask = 1 << 12,
1873 RelationalMask = 1 << 13
1876 readonly Operator oper;
1877 protected Expression left, right;
1878 readonly bool is_compound;
1879 Expression enum_conversion;
1881 static PredefinedOperator [] standard_operators;
1882 static PredefinedOperator [] pointer_operators;
1884 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1885 : this (oper, left, right)
1887 this.is_compound = isCompound;
1890 public Binary (Operator oper, Expression left, Expression right)
1895 this.loc = left.Location;
1898 public Operator Oper {
1905 /// Returns a stringified representation of the Operator
1907 string OperName (Operator oper)
1911 case Operator.Multiply:
1914 case Operator.Division:
1917 case Operator.Modulus:
1920 case Operator.Addition:
1923 case Operator.Subtraction:
1926 case Operator.LeftShift:
1929 case Operator.RightShift:
1932 case Operator.LessThan:
1935 case Operator.GreaterThan:
1938 case Operator.LessThanOrEqual:
1941 case Operator.GreaterThanOrEqual:
1944 case Operator.Equality:
1947 case Operator.Inequality:
1950 case Operator.BitwiseAnd:
1953 case Operator.BitwiseOr:
1956 case Operator.ExclusiveOr:
1959 case Operator.LogicalOr:
1962 case Operator.LogicalAnd:
1966 s = oper.ToString ();
1976 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1978 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1981 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1984 // TODO: This should be handled as Type of method group in CSharpName
1985 if (left.eclass == ExprClass.MethodGroup)
1986 l = left.ExprClassName;
1988 l = TypeManager.CSharpName (left.Type);
1990 if (right.eclass == ExprClass.MethodGroup)
1991 r = right.ExprClassName;
1993 r = TypeManager.CSharpName (right.Type);
1995 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1999 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2001 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2004 static string GetOperatorMetadataName (Operator op)
2006 CSharp.Operator.OpType op_type;
2008 case Operator.Addition:
2009 op_type = CSharp.Operator.OpType.Addition; break;
2010 case Operator.BitwiseAnd:
2011 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2012 case Operator.BitwiseOr:
2013 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2014 case Operator.Division:
2015 op_type = CSharp.Operator.OpType.Division; break;
2016 case Operator.Equality:
2017 op_type = CSharp.Operator.OpType.Equality; break;
2018 case Operator.ExclusiveOr:
2019 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2020 case Operator.GreaterThan:
2021 op_type = CSharp.Operator.OpType.GreaterThan; break;
2022 case Operator.GreaterThanOrEqual:
2023 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2024 case Operator.Inequality:
2025 op_type = CSharp.Operator.OpType.Inequality; break;
2026 case Operator.LeftShift:
2027 op_type = CSharp.Operator.OpType.LeftShift; break;
2028 case Operator.LessThan:
2029 op_type = CSharp.Operator.OpType.LessThan; break;
2030 case Operator.LessThanOrEqual:
2031 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2032 case Operator.Modulus:
2033 op_type = CSharp.Operator.OpType.Modulus; break;
2034 case Operator.Multiply:
2035 op_type = CSharp.Operator.OpType.Multiply; break;
2036 case Operator.RightShift:
2037 op_type = CSharp.Operator.OpType.RightShift; break;
2038 case Operator.Subtraction:
2039 op_type = CSharp.Operator.OpType.Subtraction; break;
2041 throw new InternalErrorException (op.ToString ());
2044 return CSharp.Operator.GetMetadataName (op_type);
2047 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2050 ILGenerator ig = ec.ig;
2053 case Operator.Multiply:
2055 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2056 opcode = OpCodes.Mul_Ovf;
2057 else if (!IsFloat (l))
2058 opcode = OpCodes.Mul_Ovf_Un;
2060 opcode = OpCodes.Mul;
2062 opcode = OpCodes.Mul;
2066 case Operator.Division:
2068 opcode = OpCodes.Div_Un;
2070 opcode = OpCodes.Div;
2073 case Operator.Modulus:
2075 opcode = OpCodes.Rem_Un;
2077 opcode = OpCodes.Rem;
2080 case Operator.Addition:
2082 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2083 opcode = OpCodes.Add_Ovf;
2084 else if (!IsFloat (l))
2085 opcode = OpCodes.Add_Ovf_Un;
2087 opcode = OpCodes.Add;
2089 opcode = OpCodes.Add;
2092 case Operator.Subtraction:
2094 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2095 opcode = OpCodes.Sub_Ovf;
2096 else if (!IsFloat (l))
2097 opcode = OpCodes.Sub_Ovf_Un;
2099 opcode = OpCodes.Sub;
2101 opcode = OpCodes.Sub;
2104 case Operator.RightShift:
2106 opcode = OpCodes.Shr_Un;
2108 opcode = OpCodes.Shr;
2111 case Operator.LeftShift:
2112 opcode = OpCodes.Shl;
2115 case Operator.Equality:
2116 opcode = OpCodes.Ceq;
2119 case Operator.Inequality:
2120 ig.Emit (OpCodes.Ceq);
2121 ig.Emit (OpCodes.Ldc_I4_0);
2123 opcode = OpCodes.Ceq;
2126 case Operator.LessThan:
2128 opcode = OpCodes.Clt_Un;
2130 opcode = OpCodes.Clt;
2133 case Operator.GreaterThan:
2135 opcode = OpCodes.Cgt_Un;
2137 opcode = OpCodes.Cgt;
2140 case Operator.LessThanOrEqual:
2141 if (IsUnsigned (l) || IsFloat (l))
2142 ig.Emit (OpCodes.Cgt_Un);
2144 ig.Emit (OpCodes.Cgt);
2145 ig.Emit (OpCodes.Ldc_I4_0);
2147 opcode = OpCodes.Ceq;
2150 case Operator.GreaterThanOrEqual:
2151 if (IsUnsigned (l) || IsFloat (l))
2152 ig.Emit (OpCodes.Clt_Un);
2154 ig.Emit (OpCodes.Clt);
2156 ig.Emit (OpCodes.Ldc_I4_0);
2158 opcode = OpCodes.Ceq;
2161 case Operator.BitwiseOr:
2162 opcode = OpCodes.Or;
2165 case Operator.BitwiseAnd:
2166 opcode = OpCodes.And;
2169 case Operator.ExclusiveOr:
2170 opcode = OpCodes.Xor;
2174 throw new InternalErrorException (oper.ToString ());
2180 static bool IsUnsigned (Type t)
2185 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2186 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2189 static bool IsFloat (Type t)
2191 return t == TypeManager.float_type || t == TypeManager.double_type;
2194 Expression ResolveOperator (EmitContext ec)
2197 Type r = right.Type;
2199 bool primitives_only = false;
2201 if (standard_operators == null)
2202 CreateStandardOperatorsTable ();
2205 // Handles predefined primitive types
2207 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2208 if ((oper & Operator.ShiftMask) == 0) {
2209 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2212 primitives_only = true;
2216 if (l.IsPointer || r.IsPointer)
2217 return ResolveOperatorPointer (ec, l, r);
2220 bool lenum = TypeManager.IsEnumType (l);
2221 bool renum = TypeManager.IsEnumType (r);
2222 if (lenum || renum) {
2223 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2225 // TODO: Can this be ambiguous
2231 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2232 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2234 expr = ResolveOperatorDelegate (ec, l, r);
2236 // TODO: Can this be ambiguous
2242 expr = ResolveUserOperator (ec, l, r);
2246 // Predefined reference types equality
2247 if ((oper & Operator.EqualityMask) != 0) {
2248 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2254 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2257 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2258 // if 'left' is not an enumeration constant, create one from the type of 'right'
2259 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2262 case Operator.BitwiseOr:
2263 case Operator.BitwiseAnd:
2264 case Operator.ExclusiveOr:
2265 case Operator.Equality:
2266 case Operator.Inequality:
2267 case Operator.LessThan:
2268 case Operator.LessThanOrEqual:
2269 case Operator.GreaterThan:
2270 case Operator.GreaterThanOrEqual:
2271 if (TypeManager.IsEnumType (left.Type))
2274 if (left.IsZeroInteger)
2275 return left.TryReduce (ec, right.Type, loc);
2279 case Operator.Addition:
2280 case Operator.Subtraction:
2283 case Operator.Multiply:
2284 case Operator.Division:
2285 case Operator.Modulus:
2286 case Operator.LeftShift:
2287 case Operator.RightShift:
2288 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2292 Error_OperatorCannotBeApplied (this.left, this.right);
2297 // The `|' operator used on types which were extended is dangerous
2299 void CheckBitwiseOrOnSignExtended ()
2301 OpcodeCast lcast = left as OpcodeCast;
2302 if (lcast != null) {
2303 if (IsUnsigned (lcast.UnderlyingType))
2307 OpcodeCast rcast = right as OpcodeCast;
2308 if (rcast != null) {
2309 if (IsUnsigned (rcast.UnderlyingType))
2313 if (lcast == null && rcast == null)
2316 // FIXME: consider constants
2318 Report.Warning (675, 3, loc,
2319 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2320 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2323 static void CreatePointerOperatorsTable ()
2325 ArrayList temp = new ArrayList ();
2328 // Pointer arithmetic:
2330 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2331 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2332 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2333 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2335 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2336 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2337 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2338 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2341 // T* operator + (int y, T* x);
2342 // T* operator + (uint y, T *x);
2343 // T* operator + (long y, T *x);
2344 // T* operator + (ulong y, T *x);
2346 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2347 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2348 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2349 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2352 // long operator - (T* x, T *y)
2354 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2356 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2359 static void CreateStandardOperatorsTable ()
2361 ArrayList temp = new ArrayList ();
2362 Type bool_type = TypeManager.bool_type;
2364 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2365 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2366 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2367 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2368 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2369 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2370 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2372 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2373 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2374 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2375 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2377 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2378 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2380 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2382 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2383 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2384 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2386 temp.Add (new PredefinedOperator (bool_type,
2387 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2389 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2390 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2391 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2392 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2394 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2398 // Rules used during binary numeric promotion
2400 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2405 Constant c = prim_expr as Constant;
2407 temp = c.ConvertImplicitly (type);
2414 if (type == TypeManager.uint32_type) {
2415 etype = prim_expr.Type;
2416 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2417 type = TypeManager.int64_type;
2419 if (type != second_expr.Type) {
2420 c = second_expr as Constant;
2422 temp = c.ConvertImplicitly (type);
2424 temp = Convert.ImplicitNumericConversion (second_expr, type);
2430 } else if (type == TypeManager.uint64_type) {
2432 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2434 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2435 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2439 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2448 // 7.2.6.2 Binary numeric promotions
2450 public bool DoBinaryOperatorPromotion (EmitContext ec)
2452 Type ltype = left.Type;
2453 Type rtype = right.Type;
2456 foreach (Type t in ConstantFold.binary_promotions) {
2458 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2461 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2464 Type int32 = TypeManager.int32_type;
2465 if (ltype != int32) {
2466 Constant c = left as Constant;
2468 temp = c.ConvertImplicitly (int32);
2470 temp = Convert.ImplicitNumericConversion (left, int32);
2477 if (rtype != int32) {
2478 Constant c = right as Constant;
2480 temp = c.ConvertImplicitly (int32);
2482 temp = Convert.ImplicitNumericConversion (right, int32);
2492 public override Expression DoResolve (EmitContext ec)
2497 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2498 left = ((ParenthesizedExpression) left).Expr;
2499 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2503 if (left.eclass == ExprClass.Type) {
2504 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2508 left = left.Resolve (ec);
2513 Constant lc = left as Constant;
2515 if (lc != null && lc.Type == TypeManager.bool_type &&
2516 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2517 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2519 // FIXME: resolve right expression as unreachable
2520 // right.Resolve (ec);
2522 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2526 right = right.Resolve (ec);
2530 eclass = ExprClass.Value;
2531 Constant rc = right as Constant;
2533 // The conversion rules are ignored in enum context but why
2534 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2535 left = lc = EnumLiftUp (ec, lc, rc, loc);
2539 right = rc = EnumLiftUp (ec, rc, lc, loc);
2544 if (rc != null && lc != null) {
2545 int prev_e = Report.Errors;
2546 Expression e = ConstantFold.BinaryFold (
2547 ec, oper, lc, rc, loc);
2548 if (e != null || Report.Errors != prev_e)
2551 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2552 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2554 if ((ResolveOperator (ec)) == null) {
2555 Error_OperatorCannotBeApplied (left, right);
2560 // The result is a constant with side-effect
2562 Constant side_effect = rc == null ?
2563 new SideEffectConstant (lc, right, loc) :
2564 new SideEffectConstant (rc, left, loc);
2566 return ReducedExpression.Create (side_effect, this);
2570 // Comparison warnings
2571 if ((oper & Operator.ComparisonMask) != 0) {
2572 if (left.Equals (right)) {
2573 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2575 CheckUselessComparison (lc, right.Type);
2576 CheckUselessComparison (rc, left.Type);
2579 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2580 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2581 (left.Type.IsValueType && right is NullLiteral) ||
2582 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2583 (right.Type.IsValueType && left is NullLiteral)))
2584 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2586 return DoResolveCore (ec, left, right);
2589 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2591 Expression expr = ResolveOperator (ec);
2593 Error_OperatorCannotBeApplied (left_orig, right_orig);
2595 if (left == null || right == null)
2596 throw new InternalErrorException ("Invalid conversion");
2598 if (oper == Operator.BitwiseOr)
2599 CheckBitwiseOrOnSignExtended ();
2604 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2606 left.MutateHoistedGenericType (storey);
2607 right.MutateHoistedGenericType (storey);
2611 // D operator + (D x, D y)
2612 // D operator - (D x, D y)
2613 // bool operator == (D x, D y)
2614 // bool operator != (D x, D y)
2616 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2618 bool is_equality = (oper & Operator.EqualityMask) != 0;
2619 if (!TypeManager.IsEqual (l, r)) {
2621 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2622 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2627 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2628 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2639 // Resolve delegate equality as a user operator
2642 return ResolveUserOperator (ec, l, r);
2645 ArrayList args = new ArrayList (2);
2646 args.Add (new Argument (left, Argument.AType.Expression));
2647 args.Add (new Argument (right, Argument.AType.Expression));
2649 if (oper == Operator.Addition) {
2650 if (TypeManager.delegate_combine_delegate_delegate == null) {
2651 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2652 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2655 method = TypeManager.delegate_combine_delegate_delegate;
2657 if (TypeManager.delegate_remove_delegate_delegate == null) {
2658 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2659 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2662 method = TypeManager.delegate_remove_delegate_delegate;
2665 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2666 mg = mg.OverloadResolve (ec, ref args, false, loc);
2668 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2672 // Enumeration operators
2674 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2677 // bool operator == (E x, E y);
2678 // bool operator != (E x, E y);
2679 // bool operator < (E x, E y);
2680 // bool operator > (E x, E y);
2681 // bool operator <= (E x, E y);
2682 // bool operator >= (E x, E y);
2684 // E operator & (E x, E y);
2685 // E operator | (E x, E y);
2686 // E operator ^ (E x, E y);
2688 // U operator - (E e, E f)
2689 // E operator - (E e, U x)
2691 // E operator + (U x, E e)
2692 // E operator + (E e, U x)
2694 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2695 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2698 Expression ltemp = left;
2699 Expression rtemp = right;
2700 Type underlying_type;
2703 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2705 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2711 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2719 if (TypeManager.IsEqual (ltype, rtype)) {
2720 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2722 if (left is Constant)
2723 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2725 left = EmptyCast.Create (left, underlying_type);
2727 if (right is Constant)
2728 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2730 right = EmptyCast.Create (right, underlying_type);
2732 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2734 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2735 Constant c = right as Constant;
2736 if (c == null || !c.IsDefaultValue)
2739 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2742 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2745 if (left is Constant)
2746 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2748 left = EmptyCast.Create (left, underlying_type);
2751 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2753 if (oper != Operator.Addition) {
2754 Constant c = left as Constant;
2755 if (c == null || !c.IsDefaultValue)
2758 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2761 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2764 if (right is Constant)
2765 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2767 right = EmptyCast.Create (right, underlying_type);
2774 // C# specification uses explicit cast syntax which means binary promotion
2775 // should happen, however it seems that csc does not do that
2777 if (!DoBinaryOperatorPromotion (ec)) {
2783 Type res_type = null;
2784 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2785 Type promoted_type = lenum ? left.Type : right.Type;
2786 enum_conversion = Convert.ExplicitNumericConversion (
2787 new EmptyExpression (promoted_type), underlying_type);
2789 if (oper == Operator.Subtraction && renum && lenum)
2790 res_type = underlying_type;
2791 else if (oper == Operator.Addition && renum)
2797 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2798 if (!is_compound || expr == null)
2802 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2805 if (Convert.ImplicitConversionExists (ec, left, rtype))
2808 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2811 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2816 // 7.9.6 Reference type equality operators
2818 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2821 // operator != (object a, object b)
2822 // operator == (object a, object b)
2825 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2827 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2830 type = TypeManager.bool_type;
2831 GenericConstraints constraints;
2833 bool lgen = TypeManager.IsGenericParameter (l);
2835 if (TypeManager.IsEqual (l, r)) {
2838 // Only allow to compare same reference type parameter
2840 constraints = TypeManager.GetTypeParameterConstraints (l);
2841 if (constraints != null && constraints.IsReferenceType)
2847 if (l == TypeManager.anonymous_method_type)
2850 if (TypeManager.IsValueType (l))
2856 bool rgen = TypeManager.IsGenericParameter (r);
2859 // a, Both operands are reference-type values or the value null
2860 // b, One operand is a value of type T where T is a type-parameter and
2861 // the other operand is the value null. Furthermore T does not have the
2862 // value type constrain
2864 if (left is NullLiteral || right is NullLiteral) {
2866 constraints = TypeManager.GetTypeParameterConstraints (l);
2867 if (constraints != null && constraints.HasValueTypeConstraint)
2870 left = new BoxedCast (left, TypeManager.object_type);
2875 constraints = TypeManager.GetTypeParameterConstraints (r);
2876 if (constraints != null && constraints.HasValueTypeConstraint)
2879 right = new BoxedCast (right, TypeManager.object_type);
2885 // An interface is converted to the object before the
2886 // standard conversion is applied. It's not clear from the
2887 // standard but it looks like it works like that.
2890 constraints = TypeManager.GetTypeParameterConstraints (l);
2891 if (constraints == null || constraints.IsReferenceType)
2893 } else if (l.IsInterface) {
2894 l = TypeManager.object_type;
2895 } else if (l.IsValueType) {
2900 constraints = TypeManager.GetTypeParameterConstraints (r);
2901 if (constraints == null || constraints.IsReferenceType)
2903 } else if (r.IsInterface) {
2904 r = TypeManager.object_type;
2905 } else if (r.IsValueType) {
2910 const string ref_comparison = "Possible unintended reference comparison. " +
2911 "Consider casting the {0} side of the expression to `string' to compare the values";
2914 // A standard implicit conversion exists from the type of either
2915 // operand to the type of the other operand
2917 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2918 if (l == TypeManager.string_type)
2919 Report.Warning (253, 2, loc, ref_comparison, "right");
2924 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2925 if (r == TypeManager.string_type)
2926 Report.Warning (252, 2, loc, ref_comparison, "left");
2935 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2938 // bool operator == (void* x, void* y);
2939 // bool operator != (void* x, void* y);
2940 // bool operator < (void* x, void* y);
2941 // bool operator > (void* x, void* y);
2942 // bool operator <= (void* x, void* y);
2943 // bool operator >= (void* x, void* y);
2945 if ((oper & Operator.ComparisonMask) != 0) {
2948 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2955 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2961 type = TypeManager.bool_type;
2965 if (pointer_operators == null)
2966 CreatePointerOperatorsTable ();
2968 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2972 // Build-in operators method overloading
2974 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2976 PredefinedOperator best_operator = null;
2978 Type r = right.Type;
2979 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2981 foreach (PredefinedOperator po in operators) {
2982 if ((po.OperatorsMask & oper_mask) == 0)
2985 if (primitives_only) {
2986 if (!po.IsPrimitiveApplicable (l, r))
2989 if (!po.IsApplicable (ec, left, right))
2993 if (best_operator == null) {
2995 if (primitives_only)
3001 best_operator = po.ResolveBetterOperator (ec, best_operator);
3003 if (best_operator == null) {
3004 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3005 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3012 if (best_operator == null)
3015 Expression expr = best_operator.ConvertResult (ec, this);
3016 if (enum_type == null)
3020 // HACK: required by enum_conversion
3022 expr.Type = enum_type;
3023 return EmptyCast.Create (expr, enum_type);
3027 // Performs user-operator overloading
3029 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3032 if (oper == Operator.LogicalAnd)
3033 user_oper = Operator.BitwiseAnd;
3034 else if (oper == Operator.LogicalOr)
3035 user_oper = Operator.BitwiseOr;
3039 string op = GetOperatorMetadataName (user_oper);
3041 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3042 MethodGroupExpr right_operators = null;
3044 if (!TypeManager.IsEqual (r, l)) {
3045 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3046 if (right_operators == null && left_operators == null)
3048 } else if (left_operators == null) {
3052 ArrayList args = new ArrayList (2);
3053 Argument larg = new Argument (left);
3055 Argument rarg = new Argument (right);
3058 MethodGroupExpr union;
3061 // User-defined operator implementations always take precedence
3062 // over predefined operator implementations
3064 if (left_operators != null && right_operators != null) {
3065 if (IsPredefinedUserOperator (l, user_oper)) {
3066 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3068 union = left_operators;
3069 } else if (IsPredefinedUserOperator (r, user_oper)) {
3070 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3072 union = right_operators;
3074 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3076 } else if (left_operators != null) {
3077 union = left_operators;
3079 union = right_operators;
3082 union = union.OverloadResolve (ec, ref args, true, loc);
3086 Expression oper_expr;
3088 // TODO: CreateExpressionTree is allocated every time
3089 if (user_oper != oper) {
3090 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3091 oper == Operator.LogicalAnd, loc).Resolve (ec);
3093 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3096 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3097 // and not invoke user operator
3099 if ((oper & Operator.EqualityMask) != 0) {
3100 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3101 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3102 type = TypeManager.bool_type;
3103 if (left is NullLiteral || right is NullLiteral)
3104 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3105 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3107 // Two System.Delegate(s) are never equal
3119 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3124 private void CheckUselessComparison (Constant c, Type type)
3126 if (c == null || !IsTypeIntegral (type)
3127 || c is StringConstant
3128 || c is BoolConstant
3129 || c is FloatConstant
3130 || c is DoubleConstant
3131 || c is DecimalConstant
3137 if (c is ULongConstant) {
3138 ulong uvalue = ((ULongConstant) c).Value;
3139 if (uvalue > long.MaxValue) {
3140 if (type == TypeManager.byte_type ||
3141 type == TypeManager.sbyte_type ||
3142 type == TypeManager.short_type ||
3143 type == TypeManager.ushort_type ||
3144 type == TypeManager.int32_type ||
3145 type == TypeManager.uint32_type ||
3146 type == TypeManager.int64_type ||
3147 type == TypeManager.char_type)
3148 WarnUselessComparison (type);
3151 value = (long) uvalue;
3153 else if (c is ByteConstant)
3154 value = ((ByteConstant) c).Value;
3155 else if (c is SByteConstant)
3156 value = ((SByteConstant) c).Value;
3157 else if (c is ShortConstant)
3158 value = ((ShortConstant) c).Value;
3159 else if (c is UShortConstant)
3160 value = ((UShortConstant) c).Value;
3161 else if (c is IntConstant)
3162 value = ((IntConstant) c).Value;
3163 else if (c is UIntConstant)
3164 value = ((UIntConstant) c).Value;
3165 else if (c is LongConstant)
3166 value = ((LongConstant) c).Value;
3167 else if (c is CharConstant)
3168 value = ((CharConstant)c).Value;
3173 if (IsValueOutOfRange (value, type))
3174 WarnUselessComparison (type);
3177 static bool IsValueOutOfRange (long value, Type type)
3179 if (IsTypeUnsigned (type) && value < 0)
3181 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3182 type == TypeManager.byte_type && value >= 0x100 ||
3183 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3184 type == TypeManager.ushort_type && value >= 0x10000 ||
3185 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3186 type == TypeManager.uint32_type && value >= 0x100000000;
3189 static bool IsBuildInEqualityOperator (Type t)
3191 return t == TypeManager.object_type || t == TypeManager.string_type ||
3192 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3195 static bool IsPredefinedUserOperator (Type t, Operator op)
3198 // Some predefined types have user operators
3200 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3203 private static bool IsTypeIntegral (Type type)
3205 return type == TypeManager.uint64_type ||
3206 type == TypeManager.int64_type ||
3207 type == TypeManager.uint32_type ||
3208 type == TypeManager.int32_type ||
3209 type == TypeManager.ushort_type ||
3210 type == TypeManager.short_type ||
3211 type == TypeManager.sbyte_type ||
3212 type == TypeManager.byte_type ||
3213 type == TypeManager.char_type;
3216 private static bool IsTypeUnsigned (Type type)
3218 return type == TypeManager.uint64_type ||
3219 type == TypeManager.uint32_type ||
3220 type == TypeManager.ushort_type ||
3221 type == TypeManager.byte_type ||
3222 type == TypeManager.char_type;
3225 private void WarnUselessComparison (Type type)
3227 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}'",
3228 TypeManager.CSharpName (type));
3232 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3233 /// context of a conditional bool expression. This function will return
3234 /// false if it is was possible to use EmitBranchable, or true if it was.
3236 /// The expression's code is generated, and we will generate a branch to `target'
3237 /// if the resulting expression value is equal to isTrue
3239 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3241 ILGenerator ig = ec.ig;
3244 // This is more complicated than it looks, but its just to avoid
3245 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3246 // but on top of that we want for == and != to use a special path
3247 // if we are comparing against null
3249 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3250 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3253 // put the constant on the rhs, for simplicity
3255 if (left is Constant) {
3256 Expression swap = right;
3261 if (((Constant) right).IsZeroInteger) {
3262 left.EmitBranchable (ec, target, my_on_true);
3265 if (right.Type == TypeManager.bool_type) {
3266 // right is a boolean, and it's not 'false' => it is 'true'
3267 left.EmitBranchable (ec, target, !my_on_true);
3271 } else if (oper == Operator.LogicalAnd) {
3274 Label tests_end = ig.DefineLabel ();
3276 left.EmitBranchable (ec, tests_end, false);
3277 right.EmitBranchable (ec, target, true);
3278 ig.MarkLabel (tests_end);
3281 // This optimizes code like this
3282 // if (true && i > 4)
3284 if (!(left is Constant))
3285 left.EmitBranchable (ec, target, false);
3287 if (!(right is Constant))
3288 right.EmitBranchable (ec, target, false);
3293 } else if (oper == Operator.LogicalOr){
3295 left.EmitBranchable (ec, target, true);
3296 right.EmitBranchable (ec, target, true);
3299 Label tests_end = ig.DefineLabel ();
3300 left.EmitBranchable (ec, tests_end, true);
3301 right.EmitBranchable (ec, target, false);
3302 ig.MarkLabel (tests_end);
3307 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3308 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3309 oper == Operator.Equality || oper == Operator.Inequality)) {
3310 base.EmitBranchable (ec, target, on_true);
3318 bool is_float = IsFloat (t);
3319 bool is_unsigned = is_float || IsUnsigned (t);
3322 case Operator.Equality:
3324 ig.Emit (OpCodes.Beq, target);
3326 ig.Emit (OpCodes.Bne_Un, target);
3329 case Operator.Inequality:
3331 ig.Emit (OpCodes.Bne_Un, target);
3333 ig.Emit (OpCodes.Beq, target);
3336 case Operator.LessThan:
3338 if (is_unsigned && !is_float)
3339 ig.Emit (OpCodes.Blt_Un, target);
3341 ig.Emit (OpCodes.Blt, target);
3344 ig.Emit (OpCodes.Bge_Un, target);
3346 ig.Emit (OpCodes.Bge, target);
3349 case Operator.GreaterThan:
3351 if (is_unsigned && !is_float)
3352 ig.Emit (OpCodes.Bgt_Un, target);
3354 ig.Emit (OpCodes.Bgt, target);
3357 ig.Emit (OpCodes.Ble_Un, target);
3359 ig.Emit (OpCodes.Ble, target);
3362 case Operator.LessThanOrEqual:
3364 if (is_unsigned && !is_float)
3365 ig.Emit (OpCodes.Ble_Un, target);
3367 ig.Emit (OpCodes.Ble, target);
3370 ig.Emit (OpCodes.Bgt_Un, target);
3372 ig.Emit (OpCodes.Bgt, target);
3376 case Operator.GreaterThanOrEqual:
3378 if (is_unsigned && !is_float)
3379 ig.Emit (OpCodes.Bge_Un, target);
3381 ig.Emit (OpCodes.Bge, target);
3384 ig.Emit (OpCodes.Blt_Un, target);
3386 ig.Emit (OpCodes.Blt, target);
3389 throw new InternalErrorException (oper.ToString ());
3393 public override void Emit (EmitContext ec)
3395 EmitOperator (ec, left.Type);
3398 protected virtual void EmitOperator (EmitContext ec, Type l)
3400 ILGenerator ig = ec.ig;
3403 // Handle short-circuit operators differently
3406 if ((oper & Operator.LogicalMask) != 0) {
3407 Label load_result = ig.DefineLabel ();
3408 Label end = ig.DefineLabel ();
3410 bool is_or = oper == Operator.LogicalOr;
3411 left.EmitBranchable (ec, load_result, is_or);
3413 ig.Emit (OpCodes.Br_S, end);
3415 ig.MarkLabel (load_result);
3416 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3424 // Optimize zero-based operations
3426 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3428 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3429 Constant rc = right as Constant;
3430 if (rc != null && rc.IsDefaultValue) {
3436 EmitOperatorOpcode (ec, oper, l);
3439 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3440 // expression because that would wrap lifted binary operation
3442 if (enum_conversion != null)
3443 enum_conversion.Emit (ec);
3446 public override void EmitSideEffect (EmitContext ec)
3448 if ((oper & Operator.LogicalMask) != 0 ||
3449 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3450 base.EmitSideEffect (ec);
3452 left.EmitSideEffect (ec);
3453 right.EmitSideEffect (ec);
3457 protected override void CloneTo (CloneContext clonectx, Expression t)
3459 Binary target = (Binary) t;
3461 target.left = left.Clone (clonectx);
3462 target.right = right.Clone (clonectx);
3465 public override Expression CreateExpressionTree (EmitContext ec)
3467 return CreateExpressionTree (ec, null);
3470 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3473 bool lift_arg = false;
3476 case Operator.Addition:
3477 if (method == null && ec.CheckState && !IsFloat (type))
3478 method_name = "AddChecked";
3480 method_name = "Add";
3482 case Operator.BitwiseAnd:
3483 method_name = "And";
3485 case Operator.BitwiseOr:
3488 case Operator.Division:
3489 method_name = "Divide";
3491 case Operator.Equality:
3492 method_name = "Equal";
3495 case Operator.ExclusiveOr:
3496 method_name = "ExclusiveOr";
3498 case Operator.GreaterThan:
3499 method_name = "GreaterThan";
3502 case Operator.GreaterThanOrEqual:
3503 method_name = "GreaterThanOrEqual";
3506 case Operator.Inequality:
3507 method_name = "NotEqual";
3510 case Operator.LeftShift:
3511 method_name = "LeftShift";
3513 case Operator.LessThan:
3514 method_name = "LessThan";
3517 case Operator.LessThanOrEqual:
3518 method_name = "LessThanOrEqual";
3521 case Operator.LogicalAnd:
3522 method_name = "AndAlso";
3524 case Operator.LogicalOr:
3525 method_name = "OrElse";
3527 case Operator.Modulus:
3528 method_name = "Modulo";
3530 case Operator.Multiply:
3531 if (method == null && ec.CheckState && !IsFloat (type))
3532 method_name = "MultiplyChecked";
3534 method_name = "Multiply";
3536 case Operator.RightShift:
3537 method_name = "RightShift";
3539 case Operator.Subtraction:
3540 if (method == null && ec.CheckState && !IsFloat (type))
3541 method_name = "SubtractChecked";
3543 method_name = "Subtract";
3547 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3550 ArrayList args = new ArrayList (2);
3551 args.Add (new Argument (left.CreateExpressionTree (ec)));
3552 args.Add (new Argument (right.CreateExpressionTree (ec)));
3553 if (method != null) {
3555 args.Add (new Argument (new BoolConstant (false, loc)));
3557 args.Add (new Argument (method.CreateExpressionTree (ec)));
3560 return CreateExpressionFactoryCall (method_name, args);
3565 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3566 // b, c, d... may be strings or objects.
3568 public class StringConcat : Expression {
3569 ArrayList arguments;
3571 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3574 type = TypeManager.string_type;
3575 eclass = ExprClass.Value;
3577 arguments = new ArrayList (2);
3582 public override Expression CreateExpressionTree (EmitContext ec)
3584 Argument arg = (Argument) arguments [0];
3585 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3589 // Creates nested calls tree from an array of arguments used for IL emit
3591 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3593 ArrayList concat_args = new ArrayList (2);
3594 ArrayList add_args = new ArrayList (3);
3596 concat_args.Add (left);
3597 add_args.Add (new Argument (left_etree));
3599 concat_args.Add (arguments [pos]);
3600 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3602 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3606 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3610 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3612 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3613 if (++pos == arguments.Count)
3616 left = new Argument (new EmptyExpression (method.Type));
3617 return CreateExpressionAddCall (ec, left, expr, pos);
3620 public override Expression DoResolve (EmitContext ec)
3625 public void Append (EmitContext ec, Expression operand)
3630 StringConstant sc = operand as StringConstant;
3632 if (arguments.Count != 0) {
3633 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3634 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3635 if (last_expr_constant != null) {
3636 last_argument.Expr = new StringConstant (
3637 last_expr_constant.Value + sc.Value, sc.Location);
3643 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3645 StringConcat concat_oper = operand as StringConcat;
3646 if (concat_oper != null) {
3647 arguments.AddRange (concat_oper.arguments);
3652 arguments.Add (new Argument (operand));
3655 Expression CreateConcatMemberExpression ()
3657 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3660 public override void Emit (EmitContext ec)
3662 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3663 concat = concat.Resolve (ec);
3668 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3670 foreach (Argument a in arguments)
3671 a.Expr.MutateHoistedGenericType (storey);
3676 // User-defined conditional logical operator
3678 public class ConditionalLogicalOperator : UserOperatorCall {
3679 readonly bool is_and;
3682 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3683 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3684 : base (oper_method, arguments, expr_tree, loc)
3686 this.is_and = is_and;
3689 public override Expression DoResolve (EmitContext ec)
3691 MethodInfo method = (MethodInfo)mg;
3692 type = TypeManager.TypeToCoreType (method.ReturnType);
3693 AParametersCollection pd = TypeManager.GetParameterData (method);
3694 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3695 Report.Error (217, loc,
3696 "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",
3697 TypeManager.CSharpSignature (method));
3701 Expression left_dup = new EmptyExpression (type);
3702 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3703 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3704 if (op_true == null || op_false == null) {
3705 Report.Error (218, loc,
3706 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3707 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3711 oper = is_and ? op_false : op_true;
3712 eclass = ExprClass.Value;
3716 public override void Emit (EmitContext ec)
3718 ILGenerator ig = ec.ig;
3719 Label end_target = ig.DefineLabel ();
3722 // Emit and duplicate left argument
3724 ((Argument)arguments [0]).Expr.Emit (ec);
3725 ig.Emit (OpCodes.Dup);
3726 arguments.RemoveAt (0);
3728 oper.EmitBranchable (ec, end_target, true);
3730 ig.MarkLabel (end_target);
3734 public class PointerArithmetic : Expression {
3735 Expression left, right;
3739 // We assume that `l' is always a pointer
3741 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3750 public override Expression CreateExpressionTree (EmitContext ec)
3752 Error_PointerInsideExpressionTree ();
3756 public override Expression DoResolve (EmitContext ec)
3758 eclass = ExprClass.Variable;
3760 if (left.Type == TypeManager.void_ptr_type) {
3761 Error (242, "The operation in question is undefined on void pointers");
3768 public override void Emit (EmitContext ec)
3770 Type op_type = left.Type;
3771 ILGenerator ig = ec.ig;
3773 // It must be either array or fixed buffer
3775 if (TypeManager.HasElementType (op_type)) {
3776 element = TypeManager.GetElementType (op_type);
3778 FieldExpr fe = left as FieldExpr;
3780 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3785 int size = GetTypeSize (element);
3786 Type rtype = right.Type;
3788 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3790 // handle (pointer - pointer)
3794 ig.Emit (OpCodes.Sub);
3798 ig.Emit (OpCodes.Sizeof, element);
3800 IntLiteral.EmitInt (ig, size);
3801 ig.Emit (OpCodes.Div);
3803 ig.Emit (OpCodes.Conv_I8);
3806 // handle + and - on (pointer op int)
3808 Constant left_const = left as Constant;
3809 if (left_const != null) {
3811 // Optimize ((T*)null) pointer operations
3813 if (left_const.IsDefaultValue) {
3814 left = EmptyExpression.Null;
3822 Constant right_const = right as Constant;
3823 if (right_const != null) {
3825 // Optimize 0-based arithmetic
3827 if (right_const.IsDefaultValue)
3831 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3835 ig.Emit (OpCodes.Sizeof, element);
3836 right = EmptyExpression.Null;
3841 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3842 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3843 ig.Emit (OpCodes.Conv_I);
3844 } else if (rtype == TypeManager.uint32_type) {
3845 ig.Emit (OpCodes.Conv_U);
3848 if (right_const == null && size != 1){
3850 ig.Emit (OpCodes.Sizeof, element);
3852 IntLiteral.EmitInt (ig, size);
3853 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3854 ig.Emit (OpCodes.Conv_I8);
3856 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3859 if (left_const == null) {
3860 if (rtype == TypeManager.int64_type)
3861 ig.Emit (OpCodes.Conv_I);
3862 else if (rtype == TypeManager.uint64_type)
3863 ig.Emit (OpCodes.Conv_U);
3865 Binary.EmitOperatorOpcode (ec, op, op_type);
3872 /// Implements the ternary conditional operator (?:)
3874 public class Conditional : Expression {
3875 Expression expr, true_expr, false_expr;
3877 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3880 this.true_expr = true_expr;
3881 this.false_expr = false_expr;
3882 this.loc = expr.Location;
3885 public Expression Expr {
3891 public Expression TrueExpr {
3897 public Expression FalseExpr {
3903 public override Expression CreateExpressionTree (EmitContext ec)
3905 ArrayList args = new ArrayList (3);
3906 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3907 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3908 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3909 return CreateExpressionFactoryCall ("Condition", args);
3912 public override Expression DoResolve (EmitContext ec)
3914 expr = expr.Resolve (ec);
3919 if (expr.Type != TypeManager.bool_type){
3920 expr = Expression.ResolveBoolean (
3927 Assign ass = expr as Assign;
3928 if (ass != null && ass.Source is Constant) {
3929 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3932 true_expr = true_expr.Resolve (ec);
3933 false_expr = false_expr.Resolve (ec);
3935 if (true_expr == null || false_expr == null)
3938 eclass = ExprClass.Value;
3939 Type true_type = true_expr.Type;
3940 Type false_type = false_expr.Type;
3944 // First, if an implicit conversion exists from true_expr
3945 // to false_expr, then the result type is of type false_expr.Type
3947 if (!TypeManager.IsEqual (true_type, false_type)) {
3948 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3951 // Check if both can convert implicitl to each other's type
3953 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3955 "Can not compute type of conditional expression " +
3956 "as `" + TypeManager.CSharpName (true_expr.Type) +
3957 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3958 "' convert implicitly to each other");
3963 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3966 Report.Error (173, loc,
3967 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3968 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3973 // Dead code optimalization
3974 Constant c = expr as Constant;
3976 bool is_false = c.IsDefaultValue;
3977 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3978 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3984 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3986 expr.MutateHoistedGenericType (storey);
3987 true_expr.MutateHoistedGenericType (storey);
3988 false_expr.MutateHoistedGenericType (storey);
3989 type = storey.MutateType (type);
3992 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3997 public override void Emit (EmitContext ec)
3999 ILGenerator ig = ec.ig;
4000 Label false_target = ig.DefineLabel ();
4001 Label end_target = ig.DefineLabel ();
4003 expr.EmitBranchable (ec, false_target, false);
4004 true_expr.Emit (ec);
4006 if (type.IsInterface) {
4007 LocalBuilder temp = ec.GetTemporaryLocal (type);
4008 ig.Emit (OpCodes.Stloc, temp);
4009 ig.Emit (OpCodes.Ldloc, temp);
4010 ec.FreeTemporaryLocal (temp, type);
4013 ig.Emit (OpCodes.Br, end_target);
4014 ig.MarkLabel (false_target);
4015 false_expr.Emit (ec);
4016 ig.MarkLabel (end_target);
4019 protected override void CloneTo (CloneContext clonectx, Expression t)
4021 Conditional target = (Conditional) t;
4023 target.expr = expr.Clone (clonectx);
4024 target.true_expr = true_expr.Clone (clonectx);
4025 target.false_expr = false_expr.Clone (clonectx);
4029 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4030 LocalTemporary temp;
4033 public abstract HoistedVariable HoistedVariable { get; }
4034 public abstract bool IsFixed { get; }
4035 public abstract bool IsRef { get; }
4036 public abstract string Name { get; }
4037 public abstract void SetHasAddressTaken ();
4040 // Variable IL data, it has to be protected to encapsulate hoisted variables
4042 protected abstract ILocalVariable Variable { get; }
4045 // Variable flow-analysis data
4047 public abstract VariableInfo VariableInfo { get; }
4050 public void AddressOf (EmitContext ec, AddressOp mode)
4052 if (IsHoistedEmitRequired (ec)) {
4053 HoistedVariable.AddressOf (ec, mode);
4057 Variable.EmitAddressOf (ec);
4060 public override void Emit (EmitContext ec)
4065 public override void EmitSideEffect (EmitContext ec)
4071 // This method is used by parameters that are references, that are
4072 // being passed as references: we only want to pass the pointer (that
4073 // is already stored in the parameter, not the address of the pointer,
4074 // and not the value of the variable).
4076 public void EmitLoad (EmitContext ec)
4081 public void Emit (EmitContext ec, bool leave_copy)
4083 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4085 if (IsHoistedEmitRequired (ec)) {
4086 HoistedVariable.Emit (ec, leave_copy);
4094 // If we are a reference, we loaded on the stack a pointer
4095 // Now lets load the real value
4097 LoadFromPtr (ec.ig, type);
4101 ec.ig.Emit (OpCodes.Dup);
4104 temp = new LocalTemporary (Type);
4110 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4111 bool prepare_for_load)
4113 if (IsHoistedEmitRequired (ec)) {
4114 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4118 New n_source = source as New;
4119 if (n_source != null) {
4120 if (!n_source.Emit (ec, this)) {
4133 ec.ig.Emit (OpCodes.Dup);
4135 temp = new LocalTemporary (Type);
4141 StoreFromPtr (ec.ig, type);
4143 Variable.EmitAssign (ec);
4151 public bool IsHoisted {
4152 get { return HoistedVariable != null; }
4155 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4158 // Default implementation return true when there is a hosted variable
4160 return HoistedVariable != null;
4163 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4165 type = storey.MutateType (type);
4172 public class LocalVariableReference : VariableReference {
4173 readonly string name;
4175 public LocalInfo local_info;
4178 public LocalVariableReference (Block block, string name, Location l)
4183 eclass = ExprClass.Variable;
4187 // Setting `is_readonly' to false will allow you to create a writable
4188 // reference to a read-only variable. This is used by foreach and using.
4190 public LocalVariableReference (Block block, string name, Location l,
4191 LocalInfo local_info, bool is_readonly)
4192 : this (block, name, l)
4194 this.local_info = local_info;
4195 this.is_readonly = is_readonly;
4198 public override VariableInfo VariableInfo {
4199 get { return local_info.VariableInfo; }
4202 public override HoistedVariable HoistedVariable {
4203 get { return local_info.HoistedVariableReference; }
4207 // A local variable is always fixed
4209 public override bool IsFixed {
4210 get { return true; }
4213 public override bool IsRef {
4214 get { return false; }
4217 public bool IsReadOnly {
4218 get { return is_readonly; }
4221 public override string Name {
4222 get { return name; }
4225 public bool VerifyAssigned (EmitContext ec)
4227 VariableInfo variable_info = local_info.VariableInfo;
4228 return variable_info == null || variable_info.IsAssigned (ec, loc);
4231 void ResolveLocalInfo ()
4233 if (local_info == null) {
4234 local_info = Block.GetLocalInfo (Name);
4235 type = local_info.VariableType;
4236 is_readonly = local_info.ReadOnly;
4240 public override void SetHasAddressTaken ()
4242 local_info.AddressTaken = true;
4245 public override Expression CreateExpressionTree (EmitContext ec)
4247 ArrayList arg = new ArrayList (1);
4248 arg.Add (new Argument (this));
4249 return CreateExpressionFactoryCall ("Constant", arg);
4252 Expression DoResolveBase (EmitContext ec)
4254 type = local_info.VariableType;
4256 Expression e = Block.GetConstantExpression (Name);
4258 return e.Resolve (ec);
4260 VerifyAssigned (ec);
4263 // If we are referencing a variable from the external block
4264 // flag it for capturing
4266 if (ec.MustCaptureVariable (local_info)) {
4267 if (local_info.AddressTaken)
4268 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4270 if (ec.IsVariableCapturingRequired) {
4271 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4272 storey.CaptureLocalVariable (ec, local_info);
4279 public override Expression DoResolve (EmitContext ec)
4281 ResolveLocalInfo ();
4282 local_info.Used = true;
4284 if (type == null && local_info.Type is VarExpr) {
4285 local_info.VariableType = TypeManager.object_type;
4286 Error_VariableIsUsedBeforeItIsDeclared (Name);
4290 return DoResolveBase (ec);
4293 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4295 ResolveLocalInfo ();
4298 if (right_side == EmptyExpression.OutAccess)
4299 local_info.Used = true;
4301 // Infer implicitly typed local variable
4303 VarExpr ve = local_info.Type as VarExpr;
4305 if (!ve.InferType (ec, right_side))
4307 type = local_info.VariableType = ve.Type;
4314 if (right_side == EmptyExpression.OutAccess) {
4315 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4316 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4317 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4318 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4319 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4320 } else if (right_side == EmptyExpression.UnaryAddress) {
4321 code = 459; msg = "Cannot take the address of {1} `{0}'";
4323 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4325 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4326 } else if (VariableInfo != null) {
4327 VariableInfo.SetAssigned (ec);
4330 return DoResolveBase (ec);
4333 public override int GetHashCode ()
4335 return Name.GetHashCode ();
4338 public override bool Equals (object obj)
4340 LocalVariableReference lvr = obj as LocalVariableReference;
4344 return Name == lvr.Name && Block == lvr.Block;
4347 protected override ILocalVariable Variable {
4348 get { return local_info; }
4351 public override string ToString ()
4353 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4356 protected override void CloneTo (CloneContext clonectx, Expression t)
4358 LocalVariableReference target = (LocalVariableReference) t;
4360 target.Block = clonectx.LookupBlock (Block);
4361 if (local_info != null)
4362 target.local_info = clonectx.LookupVariable (local_info);
4367 /// This represents a reference to a parameter in the intermediate
4370 public class ParameterReference : VariableReference {
4371 readonly ToplevelParameterInfo pi;
4372 readonly ToplevelBlock referenced;
4374 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4377 this.referenced = referenced;
4381 public override bool IsRef {
4382 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4385 bool HasOutModifier {
4386 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4389 public override HoistedVariable HoistedVariable {
4390 get { return pi.Parameter.HoistedVariableReference; }
4394 // A ref or out parameter is classified as a moveable variable, even
4395 // if the argument given for the parameter is a fixed variable
4397 public override bool IsFixed {
4398 get { return !IsRef; }
4401 public override string Name {
4402 get { return Parameter.Name; }
4405 public Parameter Parameter {
4406 get { return pi.Parameter; }
4409 public override VariableInfo VariableInfo {
4410 get { return pi.VariableInfo; }
4413 protected override ILocalVariable Variable {
4414 get { return Parameter; }
4417 public bool IsAssigned (EmitContext ec, Location loc)
4419 // HACK: Variables are not captured in probing mode
4420 if (ec.IsInProbingMode)
4423 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4426 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4430 public override void SetHasAddressTaken ()
4432 Parameter.HasAddressTaken = true;
4435 void SetAssigned (EmitContext ec)
4437 if (HasOutModifier && ec.DoFlowAnalysis)
4438 ec.CurrentBranching.SetAssigned (VariableInfo);
4441 bool DoResolveBase (EmitContext ec)
4443 type = pi.ParameterType;
4444 eclass = ExprClass.Variable;
4446 AnonymousExpression am = ec.CurrentAnonymousMethod;
4450 ToplevelBlock declared = pi.Block;
4451 if (declared != referenced) {
4453 Report.Error (1628, loc,
4454 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4455 Name, am.ContainerType);
4463 if (ec.IsVariableCapturingRequired) {
4464 if (pi.Parameter.HasAddressTaken)
4465 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4467 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4468 storey.CaptureParameter (ec, this);
4474 public override int GetHashCode ()
4476 return Name.GetHashCode ();
4479 public override bool Equals (object obj)
4481 ParameterReference pr = obj as ParameterReference;
4485 return Name == pr.Name && referenced == pr.referenced;
4488 protected override void CloneTo (CloneContext clonectx, Expression target)
4493 public override Expression CreateExpressionTree (EmitContext ec)
4495 if (IsHoistedEmitRequired (ec))
4496 return HoistedVariable.CreateExpressionTree (ec);
4498 return Parameter.ExpressionTreeVariableReference ();
4502 // Notice that for ref/out parameters, the type exposed is not the
4503 // same type exposed externally.
4506 // externally we expose "int&"
4507 // here we expose "int".
4509 // We record this in "is_ref". This means that the type system can treat
4510 // the type as it is expected, but when we generate the code, we generate
4511 // the alternate kind of code.
4513 public override Expression DoResolve (EmitContext ec)
4515 if (!DoResolveBase (ec))
4518 if (HasOutModifier && ec.DoFlowAnalysis &&
4519 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4525 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4527 if (!DoResolveBase (ec))
4530 // HACK: parameters are not captured when probing is on
4531 if (!ec.IsInProbingMode)
4537 static public void EmitLdArg (ILGenerator ig, int x)
4541 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4542 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4543 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4544 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4545 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4548 ig.Emit (OpCodes.Ldarg, x);
4553 /// Used for arguments to New(), Invocation()
4555 public class Argument {
4556 public enum AType : byte {
4563 public static readonly Argument[] Empty = new Argument [0];
4565 public readonly AType ArgType;
4566 public Expression Expr;
4568 public Argument (Expression expr, AType type)
4571 this.ArgType = type;
4574 public Argument (Expression expr)
4577 this.ArgType = AType.Expression;
4581 get { return Expr.Type; }
4584 public Parameter.Modifier Modifier
4589 return Parameter.Modifier.OUT;
4592 return Parameter.Modifier.REF;
4595 return Parameter.Modifier.NONE;
4600 public string GetSignatureForError ()
4602 if (Expr.eclass == ExprClass.MethodGroup)
4603 return Expr.ExprClassName;
4605 return TypeManager.CSharpName (Expr.Type);
4608 public bool ResolveMethodGroup (EmitContext ec)
4610 SimpleName sn = Expr as SimpleName;
4612 Expr = sn.GetMethodGroup ();
4614 // FIXME: csc doesn't report any error if you try to use `ref' or
4615 // `out' in a delegate creation expression.
4616 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4623 public bool Resolve (EmitContext ec, Location loc)
4628 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4629 // Verify that the argument is readable
4630 if (ArgType != AType.Out)
4631 Expr = Expr.Resolve (ec);
4633 // Verify that the argument is writeable
4634 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4635 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4637 return Expr != null;
4641 public void Emit (EmitContext ec)
4643 if (ArgType != AType.Ref && ArgType != AType.Out) {
4648 AddressOp mode = AddressOp.Store;
4649 if (ArgType == AType.Ref)
4650 mode |= AddressOp.Load;
4652 IMemoryLocation ml = (IMemoryLocation) Expr;
4653 ParameterReference pr = ml as ParameterReference;
4656 // ParameterReferences might already be references, so we want
4657 // to pass just the value
4659 if (pr != null && pr.IsRef)
4662 ml.AddressOf (ec, mode);
4665 public Argument Clone (CloneContext clonectx)
4667 return new Argument (Expr.Clone (clonectx), ArgType);
4672 /// Invocation of methods or delegates.
4674 public class Invocation : ExpressionStatement {
4675 protected ArrayList Arguments;
4676 protected Expression expr;
4677 protected MethodGroupExpr mg;
4678 bool arguments_resolved;
4681 // arguments is an ArrayList, but we do not want to typecast,
4682 // as it might be null.
4684 public Invocation (Expression expr, ArrayList arguments)
4686 SimpleName sn = expr as SimpleName;
4688 this.expr = sn.GetMethodGroup ();
4692 Arguments = arguments;
4694 loc = expr.Location;
4697 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4698 : this (expr, arguments)
4700 this.arguments_resolved = arguments_resolved;
4703 public override Expression CreateExpressionTree (EmitContext ec)
4708 // Special conversion for nested expression trees
4710 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4711 args = new ArrayList (1);
4712 args.Add (new Argument (this));
4713 return CreateExpressionFactoryCall ("Quote", args);
4716 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4718 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4721 args = new ArrayList (arg_count);
4724 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4726 args.Add (new Argument (new NullLiteral (loc)));
4728 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4731 // Use extension argument when exists
4734 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4736 args.Add (new Argument (e));
4739 if (Arguments != null) {
4740 foreach (Argument a in Arguments) {
4741 Expression e = a.Expr.CreateExpressionTree (ec);
4743 args.Add (new Argument (e));
4748 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4750 return CreateExpressionFactoryCall ("Call", args);
4753 public override Expression DoResolve (EmitContext ec)
4755 // Don't resolve already resolved expression
4756 if (eclass != ExprClass.Invalid)
4759 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4760 if (expr_resolved == null)
4763 mg = expr_resolved as MethodGroupExpr;
4765 Type expr_type = expr_resolved.Type;
4767 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4768 return (new DelegateInvocation (
4769 expr_resolved, Arguments, loc)).Resolve (ec);
4772 MemberExpr me = expr_resolved as MemberExpr;
4774 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4778 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4780 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4781 expr_resolved.GetSignatureForError ());
4785 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4789 // Next, evaluate all the expressions in the argument list
4791 if (Arguments != null && !arguments_resolved) {
4792 for (int i = 0; i < Arguments.Count; ++i)
4794 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4799 mg = DoResolveOverload (ec);
4803 MethodInfo method = (MethodInfo)mg;
4804 if (method != null) {
4805 type = TypeManager.TypeToCoreType (method.ReturnType);
4807 // TODO: this is a copy of mg.ResolveMemberAccess method
4808 Expression iexpr = mg.InstanceExpression;
4809 if (method.IsStatic) {
4810 if (iexpr == null ||
4811 iexpr is This || iexpr is EmptyExpression ||
4812 mg.IdenticalTypeName) {
4813 mg.InstanceExpression = null;
4815 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4819 if (iexpr == null) {
4820 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4825 if (type.IsPointer){
4833 // Only base will allow this invocation to happen.
4835 if (mg.IsBase && method.IsAbstract){
4836 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4840 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4842 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4844 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4848 IsSpecialMethodInvocation (method, loc);
4850 if (mg.InstanceExpression != null)
4851 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4853 eclass = ExprClass.Value;
4857 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4859 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4862 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4864 if (!TypeManager.IsSpecialMethod (method))
4867 Report.SymbolRelatedToPreviousError (method);
4868 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4869 TypeManager.CSharpSignature (method, true));
4875 /// Emits a list of resolved Arguments that are in the arguments
4878 /// The MethodBase argument might be null if the
4879 /// emission of the arguments is known not to contain
4880 /// a `params' field (for example in constructors or other routines
4881 /// that keep their arguments in this structure)
4883 /// if `dup_args' is true, a copy of the arguments will be left
4884 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4885 /// which will be duplicated before any other args. Only EmitCall
4886 /// should be using this interface.
4888 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4890 if (arguments == null)
4893 int top = arguments.Count;
4894 LocalTemporary [] temps = null;
4896 if (dup_args && top != 0)
4897 temps = new LocalTemporary [top];
4899 int argument_index = 0;
4901 for (int i = 0; i < top; i++) {
4902 a = (Argument) arguments [argument_index++];
4905 ec.ig.Emit (OpCodes.Dup);
4906 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4911 if (this_arg != null)
4914 for (int i = 0; i < top; i ++) {
4915 temps [i].Emit (ec);
4916 temps [i].Release (ec);
4921 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4923 AParametersCollection pd = TypeManager.GetParameterData (mb);
4925 Argument a = (Argument) arguments [pd.Count - 1];
4926 Arglist list = (Arglist) a.Expr;
4928 return list.ArgumentTypes;
4932 /// This checks the ConditionalAttribute on the method
4934 public static bool IsMethodExcluded (MethodBase method, Location loc)
4936 if (method.IsConstructor)
4939 method = TypeManager.DropGenericMethodArguments (method);
4940 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4941 IMethodData md = TypeManager.GetMethod (method);
4943 return md.IsExcluded ();
4945 // For some methods (generated by delegate class) GetMethod returns null
4946 // because they are not included in builder_to_method table
4950 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4954 /// is_base tells whether we want to force the use of the `call'
4955 /// opcode instead of using callvirt. Call is required to call
4956 /// a specific method, while callvirt will always use the most
4957 /// recent method in the vtable.
4959 /// is_static tells whether this is an invocation on a static method
4961 /// instance_expr is an expression that represents the instance
4962 /// it must be non-null if is_static is false.
4964 /// method is the method to invoke.
4966 /// Arguments is the list of arguments to pass to the method or constructor.
4968 public static void EmitCall (EmitContext ec, bool is_base,
4969 Expression instance_expr,
4970 MethodBase method, ArrayList Arguments, Location loc)
4972 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4975 // `dup_args' leaves an extra copy of the arguments on the stack
4976 // `omit_args' does not leave any arguments at all.
4977 // So, basically, you could make one call with `dup_args' set to true,
4978 // and then another with `omit_args' set to true, and the two calls
4979 // would have the same set of arguments. However, each argument would
4980 // only have been evaluated once.
4981 public static void EmitCall (EmitContext ec, bool is_base,
4982 Expression instance_expr,
4983 MethodBase method, ArrayList Arguments, Location loc,
4984 bool dup_args, bool omit_args)
4986 ILGenerator ig = ec.ig;
4987 bool struct_call = false;
4988 bool this_call = false;
4989 LocalTemporary this_arg = null;
4991 Type decl_type = method.DeclaringType;
4993 if (IsMethodExcluded (method, loc))
4996 bool is_static = method.IsStatic;
4998 this_call = instance_expr is This;
4999 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5003 // If this is ourselves, push "this"
5007 Type iexpr_type = instance_expr.Type;
5010 // Push the instance expression
5012 if (TypeManager.IsValueType (iexpr_type)) {
5014 // Special case: calls to a function declared in a
5015 // reference-type with a value-type argument need
5016 // to have their value boxed.
5017 if (decl_type.IsValueType ||
5018 TypeManager.IsGenericParameter (iexpr_type)) {
5020 // If the expression implements IMemoryLocation, then
5021 // we can optimize and use AddressOf on the
5024 // If not we have to use some temporary storage for
5026 if (instance_expr is IMemoryLocation) {
5027 ((IMemoryLocation)instance_expr).
5028 AddressOf (ec, AddressOp.LoadStore);
5030 LocalTemporary temp = new LocalTemporary (iexpr_type);
5031 instance_expr.Emit (ec);
5033 temp.AddressOf (ec, AddressOp.Load);
5036 // avoid the overhead of doing this all the time.
5038 t = TypeManager.GetReferenceType (iexpr_type);
5040 instance_expr.Emit (ec);
5041 ig.Emit (OpCodes.Box, instance_expr.Type);
5042 t = TypeManager.object_type;
5045 instance_expr.Emit (ec);
5046 t = instance_expr.Type;
5050 ig.Emit (OpCodes.Dup);
5051 if (Arguments != null && Arguments.Count != 0) {
5052 this_arg = new LocalTemporary (t);
5053 this_arg.Store (ec);
5060 EmitArguments (ec, Arguments, dup_args, this_arg);
5063 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5064 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5068 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5069 call_op = OpCodes.Call;
5071 call_op = OpCodes.Callvirt;
5073 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5074 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5075 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5082 // and DoFoo is not virtual, you can omit the callvirt,
5083 // because you don't need the null checking behavior.
5085 if (method is MethodInfo)
5086 ig.Emit (call_op, (MethodInfo) method);
5088 ig.Emit (call_op, (ConstructorInfo) method);
5091 public override void Emit (EmitContext ec)
5093 mg.EmitCall (ec, Arguments);
5096 public override void EmitStatement (EmitContext ec)
5101 // Pop the return value if there is one
5103 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5104 ec.ig.Emit (OpCodes.Pop);
5107 protected override void CloneTo (CloneContext clonectx, Expression t)
5109 Invocation target = (Invocation) t;
5111 if (Arguments != null) {
5112 target.Arguments = new ArrayList (Arguments.Count);
5113 foreach (Argument a in Arguments)
5114 target.Arguments.Add (a.Clone (clonectx));
5117 target.expr = expr.Clone (clonectx);
5120 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5122 mg.MutateHoistedGenericType (storey);
5123 if (Arguments != null) {
5124 foreach (Argument a in Arguments)
5125 a.Expr.MutateHoistedGenericType (storey);
5131 // It's either a cast or delegate invocation
5133 public class InvocationOrCast : ExpressionStatement
5136 Expression argument;
5138 public InvocationOrCast (Expression expr, Expression argument)
5141 this.argument = argument;
5142 this.loc = expr.Location;
5145 public override Expression CreateExpressionTree (EmitContext ec)
5147 throw new NotSupportedException ("ET");
5150 public override Expression DoResolve (EmitContext ec)
5152 Expression e = ResolveCore (ec);
5156 return e.Resolve (ec);
5159 Expression ResolveCore (EmitContext ec)
5162 // First try to resolve it as a cast.
5164 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5166 return new Cast (te, argument, loc);
5170 // This can either be a type or a delegate invocation.
5171 // Let's just resolve it and see what we'll get.
5173 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5178 // Ok, so it's a Cast.
5180 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5181 return new Cast (expr, argument, loc);
5184 if (expr.eclass == ExprClass.Namespace) {
5185 expr.Error_UnexpectedKind (null, "type", loc);
5190 // It's a delegate invocation.
5192 if (!TypeManager.IsDelegateType (expr.Type)) {
5193 Error (149, "Method name expected");
5197 ArrayList args = new ArrayList (1);
5198 args.Add (new Argument (argument, Argument.AType.Expression));
5199 return new DelegateInvocation (expr, args, loc);
5202 public override ExpressionStatement ResolveStatement (EmitContext ec)
5204 Expression e = ResolveCore (ec);
5208 ExpressionStatement s = e as ExpressionStatement;
5210 Error_InvalidExpressionStatement ();
5214 return s.ResolveStatement (ec);
5217 public override void Emit (EmitContext ec)
5219 throw new Exception ("Cannot happen");
5222 public override void EmitStatement (EmitContext ec)
5224 throw new Exception ("Cannot happen");
5227 protected override void CloneTo (CloneContext clonectx, Expression t)
5229 InvocationOrCast target = (InvocationOrCast) t;
5231 target.expr = expr.Clone (clonectx);
5232 target.argument = argument.Clone (clonectx);
5238 /// Implements the new expression
5240 public class New : ExpressionStatement, IMemoryLocation {
5241 ArrayList Arguments;
5244 // During bootstrap, it contains the RequestedType,
5245 // but if `type' is not null, it *might* contain a NewDelegate
5246 // (because of field multi-initialization)
5248 Expression RequestedType;
5250 MethodGroupExpr method;
5252 bool is_type_parameter;
5254 public New (Expression requested_type, ArrayList arguments, Location l)
5256 RequestedType = requested_type;
5257 Arguments = arguments;
5262 /// Converts complex core type syntax like 'new int ()' to simple constant
5264 public static Constant Constantify (Type t)
5266 if (t == TypeManager.int32_type)
5267 return new IntConstant (0, Location.Null);
5268 if (t == TypeManager.uint32_type)
5269 return new UIntConstant (0, Location.Null);
5270 if (t == TypeManager.int64_type)
5271 return new LongConstant (0, Location.Null);
5272 if (t == TypeManager.uint64_type)
5273 return new ULongConstant (0, Location.Null);
5274 if (t == TypeManager.float_type)
5275 return new FloatConstant (0, Location.Null);
5276 if (t == TypeManager.double_type)
5277 return new DoubleConstant (0, Location.Null);
5278 if (t == TypeManager.short_type)
5279 return new ShortConstant (0, Location.Null);
5280 if (t == TypeManager.ushort_type)
5281 return new UShortConstant (0, Location.Null);
5282 if (t == TypeManager.sbyte_type)
5283 return new SByteConstant (0, Location.Null);
5284 if (t == TypeManager.byte_type)
5285 return new ByteConstant (0, Location.Null);
5286 if (t == TypeManager.char_type)
5287 return new CharConstant ('\0', Location.Null);
5288 if (t == TypeManager.bool_type)
5289 return new BoolConstant (false, Location.Null);
5290 if (t == TypeManager.decimal_type)
5291 return new DecimalConstant (0, Location.Null);
5292 if (TypeManager.IsEnumType (t))
5293 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5299 // Checks whether the type is an interface that has the
5300 // [ComImport, CoClass] attributes and must be treated
5303 public Expression CheckComImport (EmitContext ec)
5305 if (!type.IsInterface)
5309 // Turn the call into:
5310 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5312 Type real_class = AttributeTester.GetCoClassAttribute (type);
5313 if (real_class == null)
5316 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5317 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5318 return cast.Resolve (ec);
5321 public override Expression CreateExpressionTree (EmitContext ec)
5323 ArrayList args = Arguments == null ?
5324 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5326 if (method == null) {
5327 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5329 args.Add (new Argument (method.CreateExpressionTree (ec)));
5330 if (Arguments != null) {
5332 foreach (Argument a in Arguments) {
5333 expr = a.Expr.CreateExpressionTree (ec);
5335 args.Add (new Argument (expr));
5340 return CreateExpressionFactoryCall ("New", args);
5343 public override Expression DoResolve (EmitContext ec)
5346 // The New DoResolve might be called twice when initializing field
5347 // expressions (see EmitFieldInitializers, the call to
5348 // GetInitializerExpression will perform a resolve on the expression,
5349 // and later the assign will trigger another resolution
5351 // This leads to bugs (#37014)
5354 if (RequestedType is NewDelegate)
5355 return RequestedType;
5359 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5365 if (type.IsPointer) {
5366 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5367 TypeManager.CSharpName (type));
5371 if (Arguments == null) {
5372 Constant c = Constantify (type);
5374 return ReducedExpression.Create (c, this);
5377 if (TypeManager.IsDelegateType (type)) {
5378 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5382 if (type.IsGenericParameter) {
5383 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5385 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5386 Error (304, String.Format (
5387 "Cannot create an instance of the " +
5388 "variable type '{0}' because it " +
5389 "doesn't have the new() constraint",
5394 if ((Arguments != null) && (Arguments.Count != 0)) {
5395 Error (417, String.Format (
5396 "`{0}': cannot provide arguments " +
5397 "when creating an instance of a " +
5398 "variable type.", type));
5402 if (TypeManager.activator_create_instance == null) {
5403 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5404 if (activator_type != null) {
5405 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5406 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5410 is_type_parameter = true;
5411 eclass = ExprClass.Value;
5416 if (type.IsAbstract && type.IsSealed) {
5417 Report.SymbolRelatedToPreviousError (type);
5418 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5422 if (type.IsInterface || type.IsAbstract){
5423 if (!TypeManager.IsGenericType (type)) {
5424 RequestedType = CheckComImport (ec);
5425 if (RequestedType != null)
5426 return RequestedType;
5429 Report.SymbolRelatedToPreviousError (type);
5430 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5434 bool is_struct = type.IsValueType;
5435 eclass = ExprClass.Value;
5438 // SRE returns a match for .ctor () on structs (the object constructor),
5439 // so we have to manually ignore it.
5441 if (is_struct && Arguments == null)
5444 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5445 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5446 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5448 if (Arguments != null){
5449 foreach (Argument a in Arguments){
5450 if (!a.Resolve (ec, loc))
5458 method = ml as MethodGroupExpr;
5459 if (method == null) {
5460 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5464 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5471 bool DoEmitTypeParameter (EmitContext ec)
5474 ILGenerator ig = ec.ig;
5475 // IMemoryLocation ml;
5477 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5478 new Type [] { type });
5480 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5481 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5482 ig.Emit (OpCodes.Call, ci);
5486 // Allow DoEmit() to be called multiple times.
5487 // We need to create a new LocalTemporary each time since
5488 // you can't share LocalBuilders among ILGeneators.
5489 LocalTemporary temp = new LocalTemporary (type);
5491 Label label_activator = ig.DefineLabel ();
5492 Label label_end = ig.DefineLabel ();
5494 temp.AddressOf (ec, AddressOp.Store);
5495 ig.Emit (OpCodes.Initobj, type);
5498 ig.Emit (OpCodes.Box, type);
5499 ig.Emit (OpCodes.Brfalse, label_activator);
5501 temp.AddressOf (ec, AddressOp.Store);
5502 ig.Emit (OpCodes.Initobj, type);
5504 ig.Emit (OpCodes.Br, label_end);
5506 ig.MarkLabel (label_activator);
5508 ig.Emit (OpCodes.Call, ci);
5509 ig.MarkLabel (label_end);
5512 throw new InternalErrorException ();
5517 // This Emit can be invoked in two contexts:
5518 // * As a mechanism that will leave a value on the stack (new object)
5519 // * As one that wont (init struct)
5521 // If we are dealing with a ValueType, we have a few
5522 // situations to deal with:
5524 // * The target is a ValueType, and we have been provided
5525 // the instance (this is easy, we are being assigned).
5527 // * The target of New is being passed as an argument,
5528 // to a boxing operation or a function that takes a
5531 // In this case, we need to create a temporary variable
5532 // that is the argument of New.
5534 // Returns whether a value is left on the stack
5536 // *** Implementation note ***
5538 // To benefit from this optimization, each assignable expression
5539 // has to manually cast to New and call this Emit.
5541 // TODO: It's worth to implement it for arrays and fields
5543 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5545 if (is_type_parameter)
5546 return DoEmitTypeParameter (ec);
5548 bool is_value_type = TypeManager.IsValueType (type);
5549 ILGenerator ig = ec.ig;
5550 VariableReference vr = target as VariableReference;
5552 if (target != null && is_value_type && (vr != null || method == null)) {
5553 target.AddressOf (ec, AddressOp.Store);
5554 } else if (vr != null && vr.IsRef) {
5559 method.EmitArguments (ec, Arguments);
5561 if (is_value_type) {
5562 if (method == null) {
5563 ig.Emit (OpCodes.Initobj, type);
5568 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5573 ConstructorInfo ci = (ConstructorInfo) method;
5575 if (TypeManager.IsGenericType (type))
5576 ci = TypeBuilder.GetConstructor (type, ci);
5579 ig.Emit (OpCodes.Newobj, ci);
5583 public override void Emit (EmitContext ec)
5585 LocalTemporary v = null;
5586 if (method == null && TypeManager.IsValueType (type)) {
5587 // TODO: Use temporary variable from pool
5588 v = new LocalTemporary (type);
5595 public override void EmitStatement (EmitContext ec)
5597 LocalTemporary v = null;
5598 if (method == null && TypeManager.IsValueType (type)) {
5599 // TODO: Use temporary variable from pool
5600 v = new LocalTemporary (type);
5604 ec.ig.Emit (OpCodes.Pop);
5607 public virtual bool HasInitializer {
5613 public void AddressOf (EmitContext ec, AddressOp Mode)
5615 if (is_type_parameter) {
5616 LocalTemporary temp = new LocalTemporary (type);
5617 DoEmitTypeParameter (ec);
5619 temp.AddressOf (ec, Mode);
5623 if (!type.IsValueType){
5625 // We throw an exception. So far, I believe we only need to support
5627 // foreach (int j in new StructType ())
5630 throw new Exception ("AddressOf should not be used for classes");
5633 LocalTemporary value_target = new LocalTemporary (type);
5634 IMemoryLocation ml = (IMemoryLocation) value_target;
5636 ml.AddressOf (ec, AddressOp.Store);
5637 if (method == null) {
5638 ec.ig.Emit (OpCodes.Initobj, type);
5640 method.EmitArguments (ec, Arguments);
5641 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5644 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5647 protected override void CloneTo (CloneContext clonectx, Expression t)
5649 New target = (New) t;
5651 target.RequestedType = RequestedType.Clone (clonectx);
5652 if (Arguments != null){
5653 target.Arguments = new ArrayList ();
5654 foreach (Argument a in Arguments){
5655 target.Arguments.Add (a.Clone (clonectx));
5660 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5662 if (method != null) {
5663 method.MutateHoistedGenericType (storey);
5664 if (Arguments != null) {
5665 foreach (Argument a in Arguments)
5666 a.Expr.MutateHoistedGenericType (storey);
5670 type = storey.MutateType (type);
5675 /// 14.5.10.2: Represents an array creation expression.
5679 /// There are two possible scenarios here: one is an array creation
5680 /// expression that specifies the dimensions and optionally the
5681 /// initialization data and the other which does not need dimensions
5682 /// specified but where initialization data is mandatory.
5684 public class ArrayCreation : Expression {
5685 FullNamedExpression requested_base_type;
5686 ArrayList initializers;
5689 // The list of Argument types.
5690 // This is used to construct the `newarray' or constructor signature
5692 protected ArrayList arguments;
5694 protected Type array_element_type;
5695 bool expect_initializers = false;
5696 int num_arguments = 0;
5697 protected int dimensions;
5698 protected readonly string rank;
5700 protected ArrayList array_data;
5704 // The number of constants in array initializers
5705 int const_initializers_count;
5706 bool only_constant_initializers;
5708 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5710 this.requested_base_type = requested_base_type;
5711 this.initializers = initializers;
5715 arguments = new ArrayList (exprs.Count);
5717 foreach (Expression e in exprs) {
5718 arguments.Add (new Argument (e, Argument.AType.Expression));
5723 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5725 this.requested_base_type = requested_base_type;
5726 this.initializers = initializers;
5730 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5732 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5734 //dimensions = tmp.Length - 1;
5735 expect_initializers = true;
5738 public static void Error_IncorrectArrayInitializer (Location loc)
5740 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5743 protected override void Error_NegativeArrayIndex (Location loc)
5745 Report.Error (248, loc, "Cannot create an array with a negative size");
5748 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5750 if (specified_dims) {
5751 Argument a = (Argument) arguments [idx];
5753 if (!a.Resolve (ec, loc))
5756 Constant c = a.Expr as Constant;
5758 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5762 Report.Error (150, a.Expr.Location, "A constant value is expected");
5766 int value = (int) c.GetValue ();
5768 if (value != probe.Count) {
5769 Error_IncorrectArrayInitializer (loc);
5773 bounds [idx] = value;
5776 int child_bounds = -1;
5777 only_constant_initializers = true;
5778 for (int i = 0; i < probe.Count; ++i) {
5779 object o = probe [i];
5780 if (o is ArrayList) {
5781 ArrayList sub_probe = o as ArrayList;
5782 int current_bounds = sub_probe.Count;
5784 if (child_bounds == -1)
5785 child_bounds = current_bounds;
5787 else if (child_bounds != current_bounds){
5788 Error_IncorrectArrayInitializer (loc);
5791 if (idx + 1 >= dimensions){
5792 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5796 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5800 if (child_bounds != -1){
5801 Error_IncorrectArrayInitializer (loc);
5805 Expression element = ResolveArrayElement (ec, (Expression) o);
5806 if (element == null)
5809 // Initializers with the default values can be ignored
5810 Constant c = element as Constant;
5812 if (c.IsDefaultInitializer (array_element_type)) {
5816 ++const_initializers_count;
5819 only_constant_initializers = false;
5822 array_data.Add (element);
5829 public override Expression CreateExpressionTree (EmitContext ec)
5833 if (array_data == null) {
5834 args = new ArrayList (arguments.Count + 1);
5835 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5836 foreach (Argument a in arguments) {
5837 if (arguments.Count == 1) {
5838 Constant c = a.Expr as Constant;
5839 if (c.IsDefaultValue)
5840 return CreateExpressionFactoryCall ("NewArrayInit", args);
5842 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5845 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5848 if (dimensions > 1) {
5849 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5853 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5854 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5855 if (array_data != null) {
5856 for (int i = 0; i < array_data.Count; ++i) {
5857 Expression e = (Expression) array_data [i];
5859 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5861 args.Add (new Argument (e.CreateExpressionTree (ec)));
5865 return CreateExpressionFactoryCall ("NewArrayInit", args);
5868 public void UpdateIndices ()
5871 for (ArrayList probe = initializers; probe != null;) {
5872 if (probe.Count > 0 && probe [0] is ArrayList) {
5873 Expression e = new IntConstant (probe.Count, Location.Null);
5874 arguments.Add (new Argument (e, Argument.AType.Expression));
5876 bounds [i++] = probe.Count;
5878 probe = (ArrayList) probe [0];
5881 Expression e = new IntConstant (probe.Count, Location.Null);
5882 arguments.Add (new Argument (e, Argument.AType.Expression));
5884 bounds [i++] = probe.Count;
5891 Expression first_emit;
5892 LocalTemporary first_emit_temp;
5894 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5896 element = element.Resolve (ec);
5897 if (element == null)
5900 if (element is CompoundAssign.TargetExpression) {
5901 if (first_emit != null)
5902 throw new InternalErrorException ("Can only handle one mutator at a time");
5903 first_emit = element;
5904 element = first_emit_temp = new LocalTemporary (element.Type);
5907 return Convert.ImplicitConversionRequired (
5908 ec, element, array_element_type, loc);
5911 protected bool ResolveInitializers (EmitContext ec)
5913 if (initializers == null) {
5914 return !expect_initializers;
5918 // We use this to store all the date values in the order in which we
5919 // will need to store them in the byte blob later
5921 array_data = new ArrayList ();
5922 bounds = new System.Collections.Specialized.HybridDictionary ();
5924 if (arguments != null)
5925 return CheckIndices (ec, initializers, 0, true);
5927 arguments = new ArrayList ();
5929 if (!CheckIndices (ec, initializers, 0, false))
5938 // Resolved the type of the array
5940 bool ResolveArrayType (EmitContext ec)
5942 if (requested_base_type == null) {
5943 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5947 if (requested_base_type is VarExpr) {
5948 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5952 StringBuilder array_qualifier = new StringBuilder (rank);
5955 // `In the first form allocates an array instace of the type that results
5956 // from deleting each of the individual expression from the expression list'
5958 if (num_arguments > 0) {
5959 array_qualifier.Append ("[");
5960 for (int i = num_arguments-1; i > 0; i--)
5961 array_qualifier.Append (",");
5962 array_qualifier.Append ("]");
5968 TypeExpr array_type_expr;
5969 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5970 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5971 if (array_type_expr == null)
5974 type = array_type_expr.Type;
5975 array_element_type = TypeManager.GetElementType (type);
5976 dimensions = type.GetArrayRank ();
5981 public override Expression DoResolve (EmitContext ec)
5986 if (!ResolveArrayType (ec))
5990 // First step is to validate the initializers and fill
5991 // in any missing bits
5993 if (!ResolveInitializers (ec))
5996 if (arguments.Count != dimensions) {
5997 Error_IncorrectArrayInitializer (loc);
6000 foreach (Argument a in arguments){
6001 if (!a.Resolve (ec, loc))
6004 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6007 eclass = ExprClass.Value;
6011 MethodInfo GetArrayMethod (int arguments)
6013 ModuleBuilder mb = CodeGen.Module.Builder;
6015 Type[] arg_types = new Type[arguments];
6016 for (int i = 0; i < arguments; i++)
6017 arg_types[i] = TypeManager.int32_type;
6019 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6023 Report.Error (-6, "New invocation: Can not find a constructor for " +
6024 "this argument list");
6031 byte [] MakeByteBlob ()
6036 int count = array_data.Count;
6038 if (TypeManager.IsEnumType (array_element_type))
6039 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6041 factor = GetTypeSize (array_element_type);
6043 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6045 data = new byte [(count * factor + 3) & ~3];
6048 for (int i = 0; i < count; ++i) {
6049 object v = array_data [i];
6051 if (v is EnumConstant)
6052 v = ((EnumConstant) v).Child;
6054 if (v is Constant && !(v is StringConstant))
6055 v = ((Constant) v).GetValue ();
6061 if (array_element_type == TypeManager.int64_type){
6062 if (!(v is Expression)){
6063 long val = (long) v;
6065 for (int j = 0; j < factor; ++j) {
6066 data [idx + j] = (byte) (val & 0xFF);
6070 } else if (array_element_type == TypeManager.uint64_type){
6071 if (!(v is Expression)){
6072 ulong val = (ulong) v;
6074 for (int j = 0; j < factor; ++j) {
6075 data [idx + j] = (byte) (val & 0xFF);
6079 } else if (array_element_type == TypeManager.float_type) {
6080 if (!(v is Expression)){
6081 element = BitConverter.GetBytes ((float) v);
6083 for (int j = 0; j < factor; ++j)
6084 data [idx + j] = element [j];
6085 if (!BitConverter.IsLittleEndian)
6086 System.Array.Reverse (data, idx, 4);
6088 } else if (array_element_type == TypeManager.double_type) {
6089 if (!(v is Expression)){
6090 element = BitConverter.GetBytes ((double) v);
6092 for (int j = 0; j < factor; ++j)
6093 data [idx + j] = element [j];
6095 // FIXME: Handle the ARM float format.
6096 if (!BitConverter.IsLittleEndian)
6097 System.Array.Reverse (data, idx, 8);
6099 } else if (array_element_type == TypeManager.char_type){
6100 if (!(v is Expression)){
6101 int val = (int) ((char) v);
6103 data [idx] = (byte) (val & 0xff);
6104 data [idx+1] = (byte) (val >> 8);
6106 } else if (array_element_type == TypeManager.short_type){
6107 if (!(v is Expression)){
6108 int val = (int) ((short) v);
6110 data [idx] = (byte) (val & 0xff);
6111 data [idx+1] = (byte) (val >> 8);
6113 } else if (array_element_type == TypeManager.ushort_type){
6114 if (!(v is Expression)){
6115 int val = (int) ((ushort) v);
6117 data [idx] = (byte) (val & 0xff);
6118 data [idx+1] = (byte) (val >> 8);
6120 } else if (array_element_type == TypeManager.int32_type) {
6121 if (!(v is Expression)){
6124 data [idx] = (byte) (val & 0xff);
6125 data [idx+1] = (byte) ((val >> 8) & 0xff);
6126 data [idx+2] = (byte) ((val >> 16) & 0xff);
6127 data [idx+3] = (byte) (val >> 24);
6129 } else if (array_element_type == TypeManager.uint32_type) {
6130 if (!(v is Expression)){
6131 uint val = (uint) v;
6133 data [idx] = (byte) (val & 0xff);
6134 data [idx+1] = (byte) ((val >> 8) & 0xff);
6135 data [idx+2] = (byte) ((val >> 16) & 0xff);
6136 data [idx+3] = (byte) (val >> 24);
6138 } else if (array_element_type == TypeManager.sbyte_type) {
6139 if (!(v is Expression)){
6140 sbyte val = (sbyte) v;
6141 data [idx] = (byte) val;
6143 } else if (array_element_type == TypeManager.byte_type) {
6144 if (!(v is Expression)){
6145 byte val = (byte) v;
6146 data [idx] = (byte) val;
6148 } else if (array_element_type == TypeManager.bool_type) {
6149 if (!(v is Expression)){
6150 bool val = (bool) v;
6151 data [idx] = (byte) (val ? 1 : 0);
6153 } else if (array_element_type == TypeManager.decimal_type){
6154 if (!(v is Expression)){
6155 int [] bits = Decimal.GetBits ((decimal) v);
6158 // FIXME: For some reason, this doesn't work on the MS runtime.
6159 int [] nbits = new int [4];
6160 nbits [0] = bits [3];
6161 nbits [1] = bits [2];
6162 nbits [2] = bits [0];
6163 nbits [3] = bits [1];
6165 for (int j = 0; j < 4; j++){
6166 data [p++] = (byte) (nbits [j] & 0xff);
6167 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6168 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6169 data [p++] = (byte) (nbits [j] >> 24);
6173 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6181 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6183 array_element_type = storey.MutateType (array_element_type);
6184 type = storey.MutateType (type);
6185 if (arguments != null) {
6186 foreach (Argument a in arguments)
6187 a.Expr.MutateHoistedGenericType (storey);
6190 if (array_data != null) {
6191 foreach (Expression e in array_data)
6192 e.MutateHoistedGenericType (storey);
6197 // Emits the initializers for the array
6199 void EmitStaticInitializers (EmitContext ec)
6201 // FIXME: This should go to Resolve !
6202 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6203 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6204 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6205 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6206 if (TypeManager.void_initializearray_array_fieldhandle == null)
6211 // First, the static data
6214 ILGenerator ig = ec.ig;
6216 byte [] data = MakeByteBlob ();
6218 fb = RootContext.MakeStaticData (data);
6220 ig.Emit (OpCodes.Dup);
6221 ig.Emit (OpCodes.Ldtoken, fb);
6222 ig.Emit (OpCodes.Call,
6223 TypeManager.void_initializearray_array_fieldhandle);
6227 // Emits pieces of the array that can not be computed at compile
6228 // time (variables and string locations).
6230 // This always expect the top value on the stack to be the array
6232 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6234 ILGenerator ig = ec.ig;
6235 int dims = bounds.Count;
6236 int [] current_pos = new int [dims];
6238 MethodInfo set = null;
6241 Type [] args = new Type [dims + 1];
6243 for (int j = 0; j < dims; j++)
6244 args [j] = TypeManager.int32_type;
6245 args [dims] = array_element_type;
6247 set = CodeGen.Module.Builder.GetArrayMethod (
6249 CallingConventions.HasThis | CallingConventions.Standard,
6250 TypeManager.void_type, args);
6253 for (int i = 0; i < array_data.Count; i++){
6255 Expression e = (Expression)array_data [i];
6257 // Constant can be initialized via StaticInitializer
6258 if (e != null && !(!emitConstants && e is Constant)) {
6259 Type etype = e.Type;
6261 ig.Emit (OpCodes.Dup);
6263 for (int idx = 0; idx < dims; idx++)
6264 IntConstant.EmitInt (ig, current_pos [idx]);
6267 // If we are dealing with a struct, get the
6268 // address of it, so we can store it.
6270 if ((dims == 1) && etype.IsValueType &&
6271 (!TypeManager.IsBuiltinOrEnum (etype) ||
6272 etype == TypeManager.decimal_type)) {
6274 ig.Emit (OpCodes.Ldelema, etype);
6280 bool is_stobj, has_type_arg;
6281 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6283 ig.Emit (OpCodes.Stobj, etype);
6284 else if (has_type_arg)
6285 ig.Emit (op, etype);
6289 ig.Emit (OpCodes.Call, set);
6296 for (int j = dims - 1; j >= 0; j--){
6298 if (current_pos [j] < (int) bounds [j])
6300 current_pos [j] = 0;
6305 public override void Emit (EmitContext ec)
6307 ILGenerator ig = ec.ig;
6309 if (first_emit != null) {
6310 first_emit.Emit (ec);
6311 first_emit_temp.Store (ec);
6314 foreach (Argument a in arguments)
6317 if (arguments.Count == 1)
6318 ig.Emit (OpCodes.Newarr, array_element_type);
6320 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6323 if (initializers == null)
6326 // Emit static initializer for arrays which have contain more than 4 items and
6327 // the static initializer will initialize at least 25% of array values.
6328 // NOTE: const_initializers_count does not contain default constant values.
6329 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6330 TypeManager.IsPrimitiveType (array_element_type)) {
6331 EmitStaticInitializers (ec);
6333 if (!only_constant_initializers)
6334 EmitDynamicInitializers (ec, false);
6336 EmitDynamicInitializers (ec, true);
6339 if (first_emit_temp != null)
6340 first_emit_temp.Release (ec);
6343 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6345 if (arguments.Count != 1) {
6346 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6347 return base.GetAttributableValue (ec, null, out value);
6350 if (array_data == null) {
6351 Constant c = (Constant)((Argument)arguments [0]).Expr;
6352 if (c.IsDefaultValue) {
6353 value = Array.CreateInstance (array_element_type, 0);
6356 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6357 return base.GetAttributableValue (ec, null, out value);
6360 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6361 object element_value;
6362 for (int i = 0; i < ret.Length; ++i)
6364 Expression e = (Expression)array_data [i];
6366 // Is null when an initializer is optimized (value == predefined value)
6370 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6374 ret.SetValue (element_value, i);
6380 protected override void CloneTo (CloneContext clonectx, Expression t)
6382 ArrayCreation target = (ArrayCreation) t;
6384 if (requested_base_type != null)
6385 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6387 if (arguments != null){
6388 target.arguments = new ArrayList (arguments.Count);
6389 foreach (Argument a in arguments)
6390 target.arguments.Add (a.Clone (clonectx));
6393 if (initializers != null){
6394 target.initializers = new ArrayList (initializers.Count);
6395 foreach (object initializer in initializers)
6396 if (initializer is ArrayList) {
6397 ArrayList this_al = (ArrayList)initializer;
6398 ArrayList al = new ArrayList (this_al.Count);
6399 target.initializers.Add (al);
6400 foreach (Expression e in this_al)
6401 al.Add (e.Clone (clonectx));
6403 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6410 // Represents an implicitly typed array epxression
6412 public class ImplicitlyTypedArrayCreation : ArrayCreation
6414 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6415 : base (null, rank, initializers, loc)
6417 if (RootContext.Version <= LanguageVersion.ISO_2)
6418 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6420 if (rank.Length > 2) {
6421 while (rank [++dimensions] == ',');
6427 public override Expression DoResolve (EmitContext ec)
6432 if (!ResolveInitializers (ec))
6435 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6436 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6437 arguments.Count != dimensions) {
6438 Error_NoBestType ();
6443 // At this point we found common base type for all initializer elements
6444 // but we have to be sure that all static initializer elements are of
6447 UnifyInitializerElement (ec);
6449 type = TypeManager.GetConstructedType (array_element_type, rank);
6450 eclass = ExprClass.Value;
6454 void Error_NoBestType ()
6456 Report.Error (826, loc,
6457 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6461 // Converts static initializer only
6463 void UnifyInitializerElement (EmitContext ec)
6465 for (int i = 0; i < array_data.Count; ++i) {
6466 Expression e = (Expression)array_data[i];
6468 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6472 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6474 element = element.Resolve (ec);
6475 if (element == null)
6478 if (array_element_type == null) {
6479 array_element_type = element.Type;
6483 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6487 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6488 array_element_type = element.Type;
6492 Error_NoBestType ();
6497 public sealed class CompilerGeneratedThis : This
6499 public static This Instance = new CompilerGeneratedThis ();
6501 private CompilerGeneratedThis ()
6502 : base (Location.Null)
6506 public CompilerGeneratedThis (Type type, Location loc)
6512 public override Expression DoResolve (EmitContext ec)
6514 eclass = ExprClass.Variable;
6516 type = ec.ContainerType;
6520 public override HoistedVariable HoistedVariable {
6521 get { return null; }
6526 /// Represents the `this' construct
6529 public class This : VariableReference
6531 sealed class ThisVariable : ILocalVariable
6533 public static readonly ILocalVariable Instance = new ThisVariable ();
6535 public void Emit (EmitContext ec)
6537 ec.ig.Emit (OpCodes.Ldarg_0);
6540 public void EmitAssign (EmitContext ec)
6542 throw new InvalidOperationException ();
6545 public void EmitAddressOf (EmitContext ec)
6547 ec.ig.Emit (OpCodes.Ldarg_0);
6552 VariableInfo variable_info;
6555 public This (Block block, Location loc)
6561 public This (Location loc)
6566 public override VariableInfo VariableInfo {
6567 get { return variable_info; }
6570 public override bool IsFixed {
6571 get { return false; }
6574 protected override bool IsHoistedEmitRequired (EmitContext ec)
6577 // Handle 'this' differently, it cannot be assigned hence
6578 // when we are not inside anonymous method we can emit direct access
6580 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6583 public override HoistedVariable HoistedVariable {
6584 get { return TopToplevelBlock.HoistedThisVariable; }
6587 public override bool IsRef {
6588 get { return is_struct; }
6591 protected override ILocalVariable Variable {
6592 get { return ThisVariable.Instance; }
6595 // TODO: Move to ToplevelBlock
6596 ToplevelBlock TopToplevelBlock {
6598 ToplevelBlock tl = block.Toplevel;
6599 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6604 public static bool IsThisAvailable (EmitContext ec)
6606 if (ec.IsStatic || ec.IsInFieldInitializer)
6609 if (ec.CurrentAnonymousMethod == null)
6612 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6618 public bool ResolveBase (EmitContext ec)
6620 if (eclass != ExprClass.Invalid)
6623 eclass = ExprClass.Variable;
6625 if (ec.TypeContainer.CurrentType != null)
6626 type = ec.TypeContainer.CurrentType;
6628 type = ec.ContainerType;
6630 if (!IsThisAvailable (ec)) {
6632 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6634 Report.Error (1673, loc,
6635 "Anonymous methods inside structs cannot access instance members of `this'. " +
6636 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6640 is_struct = ec.TypeContainer is Struct;
6642 if (block != null) {
6643 if (block.Toplevel.ThisVariable != null)
6644 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6646 AnonymousExpression am = ec.CurrentAnonymousMethod;
6649 // this is hoisted to very top level block
6651 if (ec.IsVariableCapturingRequired) {
6653 // TODO: it should be optimized, see test-anon-75.cs
6655 // `this' variable has its own scope which is mostly empty
6656 // and causes creation of extraneous storey references.
6657 // Also it's hard to remove `this' dependencies when we Undo
6660 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6661 if (HoistedVariable == null) {
6662 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6672 // Called from Invocation to check if the invocation is correct
6674 public override void CheckMarshalByRefAccess (EmitContext ec)
6676 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6677 !variable_info.IsAssigned (ec)) {
6678 Error (188, "The `this' object cannot be used before all of its " +
6679 "fields are assigned to");
6680 variable_info.SetAssigned (ec);
6684 public override Expression CreateExpressionTree (EmitContext ec)
6686 ArrayList args = new ArrayList (1);
6687 args.Add (new Argument (this));
6689 // Use typeless constant for ldarg.0 to save some
6690 // space and avoid problems with anonymous stories
6691 return CreateExpressionFactoryCall ("Constant", args);
6694 public override Expression DoResolve (EmitContext ec)
6696 if (!ResolveBase (ec))
6700 if (ec.IsInFieldInitializer) {
6701 Error (27, "Keyword `this' is not available in the current context");
6708 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6710 if (!ResolveBase (ec))
6713 if (variable_info != null)
6714 variable_info.SetAssigned (ec);
6716 if (ec.TypeContainer is Class){
6717 if (right_side == EmptyExpression.UnaryAddress)
6718 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6719 else if (right_side == EmptyExpression.OutAccess)
6720 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6722 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6728 public override int GetHashCode()
6730 return block.GetHashCode ();
6733 public override string Name {
6734 get { return "this"; }
6737 public override bool Equals (object obj)
6739 This t = obj as This;
6743 return block == t.block;
6746 protected override void CloneTo (CloneContext clonectx, Expression t)
6748 This target = (This) t;
6750 target.block = clonectx.LookupBlock (block);
6753 public void RemoveHoisting ()
6755 TopToplevelBlock.HoistedThisVariable = null;
6758 public override void SetHasAddressTaken ()
6765 /// Represents the `__arglist' construct
6767 public class ArglistAccess : Expression
6769 public ArglistAccess (Location loc)
6774 public override Expression CreateExpressionTree (EmitContext ec)
6776 throw new NotSupportedException ("ET");
6779 public override Expression DoResolve (EmitContext ec)
6781 eclass = ExprClass.Variable;
6782 type = TypeManager.runtime_argument_handle_type;
6784 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6786 Error (190, "The __arglist construct is valid only within " +
6787 "a variable argument method");
6794 public override void Emit (EmitContext ec)
6796 ec.ig.Emit (OpCodes.Arglist);
6799 protected override void CloneTo (CloneContext clonectx, Expression target)
6806 /// Represents the `__arglist (....)' construct
6808 public class Arglist : Expression
6810 Argument[] Arguments;
6812 public Arglist (Location loc)
6813 : this (Argument.Empty, loc)
6817 public Arglist (Argument[] args, Location l)
6823 public Type[] ArgumentTypes {
6825 Type[] retval = new Type [Arguments.Length];
6826 for (int i = 0; i < Arguments.Length; i++)
6827 retval [i] = Arguments [i].Type;
6832 public override Expression CreateExpressionTree (EmitContext ec)
6834 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6838 public override Expression DoResolve (EmitContext ec)
6840 eclass = ExprClass.Variable;
6841 type = TypeManager.runtime_argument_handle_type;
6843 foreach (Argument arg in Arguments) {
6844 if (!arg.Resolve (ec, loc))
6851 public override void Emit (EmitContext ec)
6853 foreach (Argument arg in Arguments)
6857 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6859 foreach (Argument arg in Arguments)
6860 arg.Expr.MutateHoistedGenericType (storey);
6863 protected override void CloneTo (CloneContext clonectx, Expression t)
6865 Arglist target = (Arglist) t;
6867 target.Arguments = new Argument [Arguments.Length];
6868 for (int i = 0; i < Arguments.Length; i++)
6869 target.Arguments [i] = Arguments [i].Clone (clonectx);
6874 /// Implements the typeof operator
6876 public class TypeOf : Expression {
6877 Expression QueriedType;
6878 protected Type typearg;
6880 public TypeOf (Expression queried_type, Location l)
6882 QueriedType = queried_type;
6886 public override Expression CreateExpressionTree (EmitContext ec)
6888 ArrayList args = new ArrayList (2);
6889 args.Add (new Argument (this));
6890 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6891 return CreateExpressionFactoryCall ("Constant", args);
6894 public override Expression DoResolve (EmitContext ec)
6896 if (eclass != ExprClass.Invalid)
6899 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6903 typearg = texpr.Type;
6905 if (typearg == TypeManager.void_type) {
6906 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6910 if (typearg.IsPointer && !ec.InUnsafe){
6915 type = TypeManager.type_type;
6917 return DoResolveBase ();
6920 protected Expression DoResolveBase ()
6922 if (TypeManager.system_type_get_type_from_handle == null) {
6923 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6924 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6927 // Even though what is returned is a type object, it's treated as a value by the compiler.
6928 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6929 eclass = ExprClass.Value;
6933 public override void Emit (EmitContext ec)
6935 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6936 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6939 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6941 if (TypeManager.ContainsGenericParameters (typearg) &&
6942 !TypeManager.IsGenericTypeDefinition (typearg)) {
6943 Report.SymbolRelatedToPreviousError (typearg);
6944 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6945 TypeManager.CSharpName (typearg));
6950 if (value_type == TypeManager.object_type) {
6951 value = (object)typearg;
6958 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6960 typearg = storey.MutateType (typearg);
6963 public Type TypeArgument {
6969 protected override void CloneTo (CloneContext clonectx, Expression t)
6971 TypeOf target = (TypeOf) t;
6972 if (QueriedType != null)
6973 target.QueriedType = QueriedType.Clone (clonectx);
6978 /// Implements the `typeof (void)' operator
6980 public class TypeOfVoid : TypeOf {
6981 public TypeOfVoid (Location l) : base (null, l)
6986 public override Expression DoResolve (EmitContext ec)
6988 type = TypeManager.type_type;
6989 typearg = TypeManager.void_type;
6991 return DoResolveBase ();
6995 class TypeOfMethodInfo : TypeOfMethod
6997 public TypeOfMethodInfo (MethodBase method, Location loc)
6998 : base (method, loc)
7002 public override Expression DoResolve (EmitContext ec)
7004 type = typeof (MethodInfo);
7005 return base.DoResolve (ec);
7008 public override void Emit (EmitContext ec)
7010 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7012 ec.ig.Emit (OpCodes.Castclass, type);
7016 class TypeOfConstructorInfo : TypeOfMethod
7018 public TypeOfConstructorInfo (MethodBase method, Location loc)
7019 : base (method, loc)
7023 public override Expression DoResolve (EmitContext ec)
7025 type = typeof (ConstructorInfo);
7026 return base.DoResolve (ec);
7029 public override void Emit (EmitContext ec)
7031 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7033 ec.ig.Emit (OpCodes.Castclass, type);
7037 abstract class TypeOfMethod : Expression
7039 protected readonly MethodBase method;
7041 protected TypeOfMethod (MethodBase method, Location loc)
7043 this.method = method;
7047 public override Expression CreateExpressionTree (EmitContext ec)
7049 ArrayList args = new ArrayList (2);
7050 args.Add (new Argument (this));
7051 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7052 return CreateExpressionFactoryCall ("Constant", args);
7055 public override Expression DoResolve (EmitContext ec)
7057 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7058 MethodInfo mi = is_generic ?
7059 TypeManager.methodbase_get_type_from_handle_generic :
7060 TypeManager.methodbase_get_type_from_handle;
7063 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7064 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7066 if (t == null || handle_type == null)
7069 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7071 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7072 new Type[] { handle_type } );
7075 TypeManager.methodbase_get_type_from_handle_generic = mi;
7077 TypeManager.methodbase_get_type_from_handle = mi;
7080 eclass = ExprClass.Value;
7084 public override void Emit (EmitContext ec)
7086 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7089 mi = TypeManager.methodbase_get_type_from_handle_generic;
7090 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7092 mi = TypeManager.methodbase_get_type_from_handle;
7095 ec.ig.Emit (OpCodes.Call, mi);
7099 internal class TypeOfField : Expression
7101 readonly FieldInfo field;
7103 public TypeOfField (FieldInfo field, Location loc)
7109 public override Expression CreateExpressionTree (EmitContext ec)
7111 throw new NotSupportedException ("ET");
7114 public override Expression DoResolve (EmitContext ec)
7116 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7117 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7118 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7120 if (t != null && handle_type != null)
7121 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7122 "GetFieldFromHandle", loc, handle_type);
7125 type = typeof (FieldInfo);
7126 eclass = ExprClass.Value;
7130 public override void Emit (EmitContext ec)
7132 ec.ig.Emit (OpCodes.Ldtoken, field);
7133 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7138 /// Implements the sizeof expression
7140 public class SizeOf : Expression {
7141 readonly Expression QueriedType;
7144 public SizeOf (Expression queried_type, Location l)
7146 this.QueriedType = queried_type;
7150 public override Expression CreateExpressionTree (EmitContext ec)
7152 Error_PointerInsideExpressionTree ();
7156 public override Expression DoResolve (EmitContext ec)
7158 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7162 type_queried = texpr.Type;
7163 if (TypeManager.IsEnumType (type_queried))
7164 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7166 int size_of = GetTypeSize (type_queried);
7168 return new IntConstant (size_of, loc);
7171 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7176 Report.Error (233, loc,
7177 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7178 TypeManager.CSharpName (type_queried));
7181 type = TypeManager.int32_type;
7182 eclass = ExprClass.Value;
7186 public override void Emit (EmitContext ec)
7188 int size = GetTypeSize (type_queried);
7191 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7193 IntConstant.EmitInt (ec.ig, size);
7196 protected override void CloneTo (CloneContext clonectx, Expression t)
7202 /// Implements the qualified-alias-member (::) expression.
7204 public class QualifiedAliasMember : MemberAccess
7206 readonly string alias;
7207 public static readonly string GlobalAlias = "global";
7209 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7210 : base (null, identifier, targs, l)
7215 public QualifiedAliasMember (string alias, string identifier, Location l)
7216 : base (null, identifier, l)
7221 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7223 if (alias == GlobalAlias) {
7224 expr = RootNamespace.Global;
7225 return base.ResolveAsTypeStep (ec, silent);
7228 int errors = Report.Errors;
7229 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7231 if (errors == Report.Errors)
7232 Report.Error (432, loc, "Alias `{0}' not found", alias);
7236 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7240 if (expr.eclass == ExprClass.Type) {
7242 Report.Error (431, loc,
7243 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7251 public override Expression DoResolve (EmitContext ec)
7253 return ResolveAsTypeStep (ec, false);
7256 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7258 Report.Error (687, loc,
7259 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7260 GetSignatureForError ());
7263 public override string GetSignatureForError ()
7266 if (targs != null) {
7267 name = TypeManager.RemoveGenericArity (Name) + "<" +
7268 targs.GetSignatureForError () + ">";
7271 return alias + "::" + name;
7274 protected override void CloneTo (CloneContext clonectx, Expression t)
7281 /// Implements the member access expression
7283 public class MemberAccess : ATypeNameExpression {
7284 protected Expression expr;
7286 public MemberAccess (Expression expr, string id)
7287 : base (id, expr.Location)
7292 public MemberAccess (Expression expr, string identifier, Location loc)
7293 : base (identifier, loc)
7298 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7299 : base (identifier, args, loc)
7304 Expression DoResolve (EmitContext ec, Expression right_side)
7307 throw new Exception ();
7310 // Resolve the expression with flow analysis turned off, we'll do the definite
7311 // assignment checks later. This is because we don't know yet what the expression
7312 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7313 // definite assignment check on the actual field and not on the whole struct.
7316 SimpleName original = expr as SimpleName;
7317 Expression expr_resolved = expr.Resolve (ec,
7318 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7319 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7321 if (expr_resolved == null)
7324 string LookupIdentifier = MemberName.MakeName (Name, targs);
7326 Namespace ns = expr_resolved as Namespace;
7328 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7331 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, LookupIdentifier);
7332 else if (targs != null)
7333 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7338 Type expr_type = expr_resolved.Type;
7339 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7340 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7341 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7345 Constant c = expr_resolved as Constant;
7346 if (c != null && c.GetValue () == null) {
7347 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7348 "System.NullReferenceException");
7351 if (targs != null) {
7352 if (!targs.Resolve (ec))
7356 Expression member_lookup;
7357 member_lookup = MemberLookup (
7358 ec.ContainerType, expr_type, expr_type, Name, loc);
7360 if ((member_lookup == null) && (targs != null)) {
7361 member_lookup = MemberLookup (
7362 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7365 if (member_lookup == null) {
7366 ExprClass expr_eclass = expr_resolved.eclass;
7369 // Extension methods are not allowed on all expression types
7371 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7372 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7373 expr_eclass == ExprClass.EventAccess) {
7374 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7375 if (ex_method_lookup != null) {
7376 ex_method_lookup.ExtensionExpression = expr_resolved;
7378 if (targs != null) {
7379 ex_method_lookup.SetTypeArguments (targs);
7382 return ex_method_lookup.DoResolve (ec);
7386 expr = expr_resolved;
7387 member_lookup = Error_MemberLookupFailed (
7388 ec.ContainerType, expr_type, expr_type, Name, null,
7389 AllMemberTypes, AllBindingFlags);
7390 if (member_lookup == null)
7394 TypeExpr texpr = member_lookup as TypeExpr;
7395 if (texpr != null) {
7396 if (!(expr_resolved is TypeExpr) &&
7397 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7398 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7399 Name, member_lookup.GetSignatureForError ());
7403 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7404 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7405 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7410 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7413 // When looking up a nested type in a generic instance
7414 // via reflection, we always get a generic type definition
7415 // and not a generic instance - so we have to do this here.
7417 // See gtest-172-lib.cs and gtest-172.cs for an example.
7419 ct = new GenericTypeExpr (
7420 member_lookup.Type, ct.TypeArguments, loc);
7422 return ct.ResolveAsTypeStep (ec, false);
7425 return member_lookup;
7428 MemberExpr me = (MemberExpr) member_lookup;
7429 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7433 if (targs != null) {
7434 me.SetTypeArguments (targs);
7437 if (original != null && !TypeManager.IsValueType (expr_type)) {
7438 if (me.IsInstance) {
7439 LocalVariableReference var = expr_resolved as LocalVariableReference;
7440 if (var != null && !var.VerifyAssigned (ec))
7445 // The following DoResolve/DoResolveLValue will do the definite assignment
7448 if (right_side != null)
7449 return me.DoResolveLValue (ec, right_side);
7451 return me.DoResolve (ec);
7454 public override Expression DoResolve (EmitContext ec)
7456 return DoResolve (ec, null);
7459 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7461 return DoResolve (ec, right_side);
7464 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7466 return ResolveNamespaceOrType (ec, silent);
7469 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7471 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7473 if (expr_resolved == null)
7476 string LookupIdentifier = MemberName.MakeName (Name, targs);
7478 Namespace ns = expr_resolved as Namespace;
7480 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7482 if (retval == null && !silent)
7483 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7484 else if (targs != null)
7485 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7490 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7491 if (tnew_expr == null)
7494 if (tnew_expr is TypeParameterExpr) {
7495 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7496 tnew_expr.GetSignatureForError ());
7500 Type expr_type = tnew_expr.Type;
7501 Expression member_lookup = MemberLookup (
7502 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7503 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7504 if (member_lookup == null) {
7508 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7512 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7517 TypeArguments the_args = targs;
7518 Type declaring_type = texpr.Type.DeclaringType;
7519 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7520 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7521 expr_type = expr_type.BaseType;
7524 TypeArguments new_args = new TypeArguments ();
7525 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7526 new_args.Add (new TypeExpression (decl, loc));
7529 new_args.Add (targs);
7531 the_args = new_args;
7534 if (the_args != null) {
7535 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7536 return ctype.ResolveAsTypeStep (rc, false);
7543 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7545 Expression member_lookup = MemberLookup (
7546 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7547 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7549 if (member_lookup != null) {
7550 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7551 if (expr_type == null)
7554 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7558 member_lookup = MemberLookup (
7559 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7560 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7562 if (member_lookup == null) {
7563 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7564 Name, expr_type.GetSignatureForError ());
7566 // TODO: Report.SymbolRelatedToPreviousError
7567 member_lookup.Error_UnexpectedKind (null, "type", loc);
7571 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7573 if (RootContext.Version > LanguageVersion.ISO_2 &&
7574 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7575 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7576 "extension method `{1}' of type `{0}' could be found " +
7577 "(are you missing a using directive or an assembly reference?)",
7578 TypeManager.CSharpName (type), name);
7582 base.Error_TypeDoesNotContainDefinition (type, name);
7585 public override string GetSignatureForError ()
7587 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7590 protected override void CloneTo (CloneContext clonectx, Expression t)
7592 MemberAccess target = (MemberAccess) t;
7594 target.expr = expr.Clone (clonectx);
7599 /// Implements checked expressions
7601 public class CheckedExpr : Expression {
7603 public Expression Expr;
7605 public CheckedExpr (Expression e, Location l)
7611 public override Expression CreateExpressionTree (EmitContext ec)
7613 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7614 return Expr.CreateExpressionTree (ec);
7617 public override Expression DoResolve (EmitContext ec)
7619 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7620 Expr = Expr.Resolve (ec);
7625 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7628 eclass = Expr.eclass;
7633 public override void Emit (EmitContext ec)
7635 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7639 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7641 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7642 Expr.EmitBranchable (ec, target, on_true);
7645 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7647 Expr.MutateHoistedGenericType (storey);
7650 protected override void CloneTo (CloneContext clonectx, Expression t)
7652 CheckedExpr target = (CheckedExpr) t;
7654 target.Expr = Expr.Clone (clonectx);
7659 /// Implements the unchecked expression
7661 public class UnCheckedExpr : Expression {
7663 public Expression Expr;
7665 public UnCheckedExpr (Expression e, Location l)
7671 public override Expression CreateExpressionTree (EmitContext ec)
7673 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7674 return Expr.CreateExpressionTree (ec);
7677 public override Expression DoResolve (EmitContext ec)
7679 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7680 Expr = Expr.Resolve (ec);
7685 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7688 eclass = Expr.eclass;
7693 public override void Emit (EmitContext ec)
7695 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7699 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7701 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7702 Expr.EmitBranchable (ec, target, on_true);
7705 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7707 Expr.MutateHoistedGenericType (storey);
7710 protected override void CloneTo (CloneContext clonectx, Expression t)
7712 UnCheckedExpr target = (UnCheckedExpr) t;
7714 target.Expr = Expr.Clone (clonectx);
7719 /// An Element Access expression.
7721 /// During semantic analysis these are transformed into
7722 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7724 public class ElementAccess : Expression {
7725 public ArrayList Arguments;
7726 public Expression Expr;
7728 public ElementAccess (Expression e, ArrayList e_list)
7736 Arguments = new ArrayList (e_list.Count);
7737 foreach (Expression tmp in e_list)
7738 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7741 bool CommonResolve (EmitContext ec)
7743 Expr = Expr.Resolve (ec);
7745 if (Arguments == null)
7748 foreach (Argument a in Arguments){
7749 if (!a.Resolve (ec, loc))
7753 return Expr != null;
7756 public override Expression CreateExpressionTree (EmitContext ec)
7758 ArrayList args = new ArrayList (Arguments.Count + 1);
7759 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7760 foreach (Argument a in Arguments)
7761 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7763 return CreateExpressionFactoryCall ("ArrayIndex", args);
7766 Expression MakePointerAccess (EmitContext ec, Type t)
7768 if (Arguments.Count != 1){
7769 Error (196, "A pointer must be indexed by only one value");
7773 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7776 return new Indirection (p, loc).Resolve (ec);
7779 public override Expression DoResolve (EmitContext ec)
7781 if (!CommonResolve (ec))
7785 // We perform some simple tests, and then to "split" the emit and store
7786 // code we create an instance of a different class, and return that.
7788 // I am experimenting with this pattern.
7792 if (t == TypeManager.array_type){
7793 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7798 return (new ArrayAccess (this, loc)).Resolve (ec);
7800 return MakePointerAccess (ec, t);
7802 FieldExpr fe = Expr as FieldExpr;
7804 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7806 return MakePointerAccess (ec, ff.ElementType);
7809 return (new IndexerAccess (this, loc)).Resolve (ec);
7812 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7814 if (!CommonResolve (ec))
7819 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7822 return MakePointerAccess (ec, type);
7824 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7825 Error_CannotModifyIntermediateExpressionValue (ec);
7827 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7830 public override void Emit (EmitContext ec)
7832 throw new Exception ("Should never be reached");
7835 public override string GetSignatureForError ()
7837 return Expr.GetSignatureForError ();
7840 protected override void CloneTo (CloneContext clonectx, Expression t)
7842 ElementAccess target = (ElementAccess) t;
7844 target.Expr = Expr.Clone (clonectx);
7845 target.Arguments = new ArrayList (Arguments.Count);
7846 foreach (Argument a in Arguments)
7847 target.Arguments.Add (a.Clone (clonectx));
7852 /// Implements array access
7854 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7856 // Points to our "data" repository
7860 LocalTemporary temp;
7864 public ArrayAccess (ElementAccess ea_data, Location l)
7870 public override Expression CreateExpressionTree (EmitContext ec)
7872 return ea.CreateExpressionTree (ec);
7875 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7877 return DoResolve (ec);
7880 public override Expression DoResolve (EmitContext ec)
7883 ExprClass eclass = ea.Expr.eclass;
7885 // As long as the type is valid
7886 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7887 eclass == ExprClass.Value)) {
7888 ea.Expr.Error_UnexpectedKind ("variable or value");
7893 if (eclass != ExprClass.Invalid)
7896 Type t = ea.Expr.Type;
7897 int rank = ea.Arguments.Count;
7898 if (t.GetArrayRank () != rank) {
7899 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7900 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7904 type = TypeManager.GetElementType (t);
7905 if (type.IsPointer && !ec.InUnsafe) {
7906 UnsafeError (ea.Location);
7910 foreach (Argument a in ea.Arguments) {
7911 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7914 eclass = ExprClass.Variable;
7920 /// Emits the right opcode to load an object of Type `t'
7921 /// from an array of T
7923 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7926 MethodInfo get = FetchGetMethod ();
7927 ig.Emit (OpCodes.Call, get);
7931 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7932 ig.Emit (OpCodes.Ldelem_U1);
7933 else if (type == TypeManager.sbyte_type)
7934 ig.Emit (OpCodes.Ldelem_I1);
7935 else if (type == TypeManager.short_type)
7936 ig.Emit (OpCodes.Ldelem_I2);
7937 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7938 ig.Emit (OpCodes.Ldelem_U2);
7939 else if (type == TypeManager.int32_type)
7940 ig.Emit (OpCodes.Ldelem_I4);
7941 else if (type == TypeManager.uint32_type)
7942 ig.Emit (OpCodes.Ldelem_U4);
7943 else if (type == TypeManager.uint64_type)
7944 ig.Emit (OpCodes.Ldelem_I8);
7945 else if (type == TypeManager.int64_type)
7946 ig.Emit (OpCodes.Ldelem_I8);
7947 else if (type == TypeManager.float_type)
7948 ig.Emit (OpCodes.Ldelem_R4);
7949 else if (type == TypeManager.double_type)
7950 ig.Emit (OpCodes.Ldelem_R8);
7951 else if (type == TypeManager.intptr_type)
7952 ig.Emit (OpCodes.Ldelem_I);
7953 else if (TypeManager.IsEnumType (type)){
7954 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7955 } else if (type.IsValueType){
7956 ig.Emit (OpCodes.Ldelema, type);
7957 ig.Emit (OpCodes.Ldobj, type);
7959 } else if (type.IsGenericParameter) {
7960 ig.Emit (OpCodes.Ldelem, type);
7962 } else if (type.IsPointer)
7963 ig.Emit (OpCodes.Ldelem_I);
7965 ig.Emit (OpCodes.Ldelem_Ref);
7968 protected override void Error_NegativeArrayIndex (Location loc)
7970 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7974 /// Returns the right opcode to store an object of Type `t'
7975 /// from an array of T.
7977 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7979 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7980 has_type_arg = false; is_stobj = false;
7981 t = TypeManager.TypeToCoreType (t);
7982 if (TypeManager.IsEnumType (t))
7983 t = TypeManager.GetEnumUnderlyingType (t);
7984 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7985 t == TypeManager.bool_type)
7986 return OpCodes.Stelem_I1;
7987 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7988 t == TypeManager.char_type)
7989 return OpCodes.Stelem_I2;
7990 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7991 return OpCodes.Stelem_I4;
7992 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7993 return OpCodes.Stelem_I8;
7994 else if (t == TypeManager.float_type)
7995 return OpCodes.Stelem_R4;
7996 else if (t == TypeManager.double_type)
7997 return OpCodes.Stelem_R8;
7998 else if (t == TypeManager.intptr_type) {
7999 has_type_arg = true;
8001 return OpCodes.Stobj;
8002 } else if (t.IsValueType) {
8003 has_type_arg = true;
8005 return OpCodes.Stobj;
8007 } else if (t.IsGenericParameter) {
8008 has_type_arg = true;
8009 return OpCodes.Stelem;
8012 } else if (t.IsPointer)
8013 return OpCodes.Stelem_I;
8015 return OpCodes.Stelem_Ref;
8018 MethodInfo FetchGetMethod ()
8020 ModuleBuilder mb = CodeGen.Module.Builder;
8021 int arg_count = ea.Arguments.Count;
8022 Type [] args = new Type [arg_count];
8025 for (int i = 0; i < arg_count; i++){
8026 //args [i++] = a.Type;
8027 args [i] = TypeManager.int32_type;
8030 get = mb.GetArrayMethod (
8031 ea.Expr.Type, "Get",
8032 CallingConventions.HasThis |
8033 CallingConventions.Standard,
8039 MethodInfo FetchAddressMethod ()
8041 ModuleBuilder mb = CodeGen.Module.Builder;
8042 int arg_count = ea.Arguments.Count;
8043 Type [] args = new Type [arg_count];
8047 ret_type = TypeManager.GetReferenceType (type);
8049 for (int i = 0; i < arg_count; i++){
8050 //args [i++] = a.Type;
8051 args [i] = TypeManager.int32_type;
8054 address = mb.GetArrayMethod (
8055 ea.Expr.Type, "Address",
8056 CallingConventions.HasThis |
8057 CallingConventions.Standard,
8064 // Load the array arguments into the stack.
8066 void LoadArrayAndArguments (EmitContext ec)
8070 for (int i = 0; i < ea.Arguments.Count; ++i) {
8071 ((Argument)ea.Arguments [i]).Emit (ec);
8075 public void Emit (EmitContext ec, bool leave_copy)
8077 int rank = ea.Expr.Type.GetArrayRank ();
8078 ILGenerator ig = ec.ig;
8081 LoadFromPtr (ig, this.type);
8083 LoadArrayAndArguments (ec);
8084 EmitLoadOpcode (ig, type, rank);
8088 ig.Emit (OpCodes.Dup);
8089 temp = new LocalTemporary (this.type);
8094 public override void Emit (EmitContext ec)
8099 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8101 int rank = ea.Expr.Type.GetArrayRank ();
8102 ILGenerator ig = ec.ig;
8103 Type t = source.Type;
8104 prepared = prepare_for_load;
8107 AddressOf (ec, AddressOp.LoadStore);
8108 ec.ig.Emit (OpCodes.Dup);
8110 LoadArrayAndArguments (ec);
8114 bool is_stobj, has_type_arg;
8115 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8119 // The stobj opcode used by value types will need
8120 // an address on the stack, not really an array/array
8124 ig.Emit (OpCodes.Ldelema, t);
8129 ec.ig.Emit (OpCodes.Dup);
8130 temp = new LocalTemporary (this.type);
8135 StoreFromPtr (ig, t);
8137 ig.Emit (OpCodes.Stobj, t);
8138 else if (has_type_arg)
8145 ec.ig.Emit (OpCodes.Dup);
8146 temp = new LocalTemporary (this.type);
8151 StoreFromPtr (ig, t);
8153 int arg_count = ea.Arguments.Count;
8154 Type [] args = new Type [arg_count + 1];
8155 for (int i = 0; i < arg_count; i++) {
8156 //args [i++] = a.Type;
8157 args [i] = TypeManager.int32_type;
8159 args [arg_count] = type;
8161 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8162 ea.Expr.Type, "Set",
8163 CallingConventions.HasThis |
8164 CallingConventions.Standard,
8165 TypeManager.void_type, args);
8167 ig.Emit (OpCodes.Call, set);
8177 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8179 if (!source.Emit (ec, this)) {
8181 throw new NotImplementedException ();
8186 throw new NotImplementedException ();
8189 public void AddressOf (EmitContext ec, AddressOp mode)
8191 int rank = ea.Expr.Type.GetArrayRank ();
8192 ILGenerator ig = ec.ig;
8194 LoadArrayAndArguments (ec);
8197 ig.Emit (OpCodes.Ldelema, type);
8199 MethodInfo address = FetchAddressMethod ();
8200 ig.Emit (OpCodes.Call, address);
8204 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8206 type = storey.MutateType (type);
8207 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8212 /// Expressions that represent an indexer call.
8214 public class IndexerAccess : Expression, IAssignMethod
8216 class IndexerMethodGroupExpr : MethodGroupExpr
8218 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8221 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8224 public override string Name {
8230 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8233 // Here is the trick, decrease number of arguments by 1 when only
8234 // available property method is setter. This makes overload resolution
8235 // work correctly for indexers.
8238 if (method.Name [0] == 'g')
8239 return parameters.Count;
8241 return parameters.Count - 1;
8247 // Contains either property getter or setter
8248 public ArrayList Methods;
8249 public ArrayList Properties;
8255 void Append (Type caller_type, MemberInfo [] mi)
8260 foreach (PropertyInfo property in mi) {
8261 MethodInfo accessor = property.GetGetMethod (true);
8262 if (accessor == null)
8263 accessor = property.GetSetMethod (true);
8265 if (Methods == null) {
8266 Methods = new ArrayList ();
8267 Properties = new ArrayList ();
8270 Methods.Add (accessor);
8271 Properties.Add (property);
8275 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8277 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8279 return TypeManager.MemberLookup (
8280 caller_type, caller_type, lookup_type, MemberTypes.Property,
8281 BindingFlags.Public | BindingFlags.Instance |
8282 BindingFlags.DeclaredOnly, p_name, null);
8285 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8287 Indexers ix = new Indexers ();
8290 if (lookup_type.IsGenericParameter) {
8291 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8295 if (gc.HasClassConstraint)
8296 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8298 Type[] ifaces = gc.InterfaceConstraints;
8299 foreach (Type itype in ifaces)
8300 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8306 Type copy = lookup_type;
8307 while (copy != TypeManager.object_type && copy != null){
8308 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8309 copy = copy.BaseType;
8312 if (lookup_type.IsInterface) {
8313 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8314 if (ifaces != null) {
8315 foreach (Type itype in ifaces)
8316 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8331 // Points to our "data" repository
8333 MethodInfo get, set;
8334 bool is_base_indexer;
8336 LocalTemporary temp;
8337 LocalTemporary prepared_value;
8338 Expression set_expr;
8340 protected Type indexer_type;
8341 protected Type current_type;
8342 protected Expression instance_expr;
8343 protected ArrayList arguments;
8345 public IndexerAccess (ElementAccess ea, Location loc)
8346 : this (ea.Expr, false, loc)
8348 this.arguments = ea.Arguments;
8351 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8354 this.instance_expr = instance_expr;
8355 this.is_base_indexer = is_base_indexer;
8356 this.eclass = ExprClass.Value;
8360 static string GetAccessorName (AccessorType at)
8362 if (at == AccessorType.Set)
8365 if (at == AccessorType.Get)
8368 throw new NotImplementedException (at.ToString ());
8371 public override Expression CreateExpressionTree (EmitContext ec)
8373 ArrayList args = new ArrayList (arguments.Count + 2);
8374 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8375 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8376 foreach (Argument a in arguments)
8377 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8379 return CreateExpressionFactoryCall ("Call", args);
8382 protected virtual bool CommonResolve (EmitContext ec)
8384 indexer_type = instance_expr.Type;
8385 current_type = ec.ContainerType;
8390 public override Expression DoResolve (EmitContext ec)
8392 return ResolveAccessor (ec, AccessorType.Get);
8395 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8397 if (right_side == EmptyExpression.OutAccess) {
8398 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8399 GetSignatureForError ());
8403 // if the indexer returns a value type, and we try to set a field in it
8404 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8405 Error_CannotModifyIntermediateExpressionValue (ec);
8408 Expression e = ResolveAccessor (ec, AccessorType.Set);
8412 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8416 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8418 if (!CommonResolve (ec))
8421 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8422 if (ilist.Methods == null) {
8423 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8424 TypeManager.CSharpName (indexer_type));
8428 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8429 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8433 MethodInfo mi = (MethodInfo) mg;
8434 PropertyInfo pi = null;
8435 for (int i = 0; i < ilist.Methods.Count; ++i) {
8436 if (ilist.Methods [i] == mi) {
8437 pi = (PropertyInfo) ilist.Properties [i];
8442 type = TypeManager.TypeToCoreType (pi.PropertyType);
8443 if (type.IsPointer && !ec.InUnsafe)
8446 MethodInfo accessor;
8447 if (accessorType == AccessorType.Get) {
8448 accessor = get = pi.GetGetMethod (true);
8450 accessor = set = pi.GetSetMethod (true);
8451 if (accessor == null && pi.GetGetMethod (true) != null) {
8452 Report.SymbolRelatedToPreviousError (pi);
8453 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8454 TypeManager.GetFullNameSignature (pi));
8459 if (accessor == null) {
8460 Report.SymbolRelatedToPreviousError (pi);
8461 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8462 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8467 // Only base will allow this invocation to happen.
8469 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8470 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8473 bool must_do_cs1540_check;
8474 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8476 set = pi.GetSetMethod (true);
8478 get = pi.GetGetMethod (true);
8480 if (set != null && get != null &&
8481 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8482 Report.SymbolRelatedToPreviousError (accessor);
8483 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8484 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8486 Report.SymbolRelatedToPreviousError (pi);
8487 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8491 instance_expr.CheckMarshalByRefAccess (ec);
8492 eclass = ExprClass.IndexerAccess;
8496 public void Emit (EmitContext ec, bool leave_copy)
8499 prepared_value.Emit (ec);
8501 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8502 arguments, loc, false, false);
8506 ec.ig.Emit (OpCodes.Dup);
8507 temp = new LocalTemporary (Type);
8513 // source is ignored, because we already have a copy of it from the
8514 // LValue resolution and we have already constructed a pre-cached
8515 // version of the arguments (ea.set_arguments);
8517 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8519 prepared = prepare_for_load;
8520 Expression value = set_expr;
8523 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8524 arguments, loc, true, false);
8526 prepared_value = new LocalTemporary (type);
8527 prepared_value.Store (ec);
8529 prepared_value.Release (ec);
8532 ec.ig.Emit (OpCodes.Dup);
8533 temp = new LocalTemporary (Type);
8536 } else if (leave_copy) {
8537 temp = new LocalTemporary (Type);
8543 arguments.Add (new Argument (value, Argument.AType.Expression));
8544 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8552 public override void Emit (EmitContext ec)
8557 public override string GetSignatureForError ()
8559 return TypeManager.CSharpSignature (get != null ? get : set, false);
8562 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8565 get = storey.MutateGenericMethod (get);
8567 set = storey.MutateGenericMethod (set);
8569 instance_expr.MutateHoistedGenericType (storey);
8570 foreach (Argument a in arguments)
8571 a.Expr.MutateHoistedGenericType (storey);
8573 type = storey.MutateType (type);
8576 protected override void CloneTo (CloneContext clonectx, Expression t)
8578 IndexerAccess target = (IndexerAccess) t;
8580 if (arguments != null){
8581 target.arguments = new ArrayList ();
8582 foreach (Argument a in arguments)
8583 target.arguments.Add (a.Clone (clonectx));
8585 if (instance_expr != null)
8586 target.instance_expr = instance_expr.Clone (clonectx);
8591 /// The base operator for method names
8593 public class BaseAccess : Expression {
8594 public readonly string Identifier;
8597 public BaseAccess (string member, Location l)
8599 this.Identifier = member;
8603 public BaseAccess (string member, TypeArguments args, Location l)
8609 public override Expression CreateExpressionTree (EmitContext ec)
8611 throw new NotSupportedException ("ET");
8614 public override Expression DoResolve (EmitContext ec)
8616 Expression c = CommonResolve (ec);
8622 // MethodGroups use this opportunity to flag an error on lacking ()
8624 if (!(c is MethodGroupExpr))
8625 return c.Resolve (ec);
8629 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8631 Expression c = CommonResolve (ec);
8637 // MethodGroups use this opportunity to flag an error on lacking ()
8639 if (! (c is MethodGroupExpr))
8640 return c.DoResolveLValue (ec, right_side);
8645 Expression CommonResolve (EmitContext ec)
8647 Expression member_lookup;
8648 Type current_type = ec.ContainerType;
8649 Type base_type = current_type.BaseType;
8651 if (!This.IsThisAvailable (ec)) {
8653 Error (1511, "Keyword `base' is not available in a static method");
8655 Error (1512, "Keyword `base' is not available in the current context");
8660 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8661 AllMemberTypes, AllBindingFlags, loc);
8662 if (member_lookup == null) {
8663 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8664 null, AllMemberTypes, AllBindingFlags);
8671 left = new TypeExpression (base_type, loc);
8673 left = ec.GetThis (loc);
8675 MemberExpr me = (MemberExpr) member_lookup;
8676 me = me.ResolveMemberAccess (ec, left, loc, null);
8683 me.SetTypeArguments (args);
8689 public override void Emit (EmitContext ec)
8691 throw new Exception ("Should never be called");
8694 protected override void CloneTo (CloneContext clonectx, Expression t)
8696 BaseAccess target = (BaseAccess) t;
8699 target.args = args.Clone ();
8704 /// The base indexer operator
8706 public class BaseIndexerAccess : IndexerAccess {
8707 public BaseIndexerAccess (ArrayList args, Location loc)
8708 : base (null, true, loc)
8710 arguments = new ArrayList ();
8711 foreach (Expression tmp in args)
8712 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8715 protected override bool CommonResolve (EmitContext ec)
8717 instance_expr = ec.GetThis (loc);
8719 current_type = ec.ContainerType.BaseType;
8720 indexer_type = current_type;
8722 foreach (Argument a in arguments){
8723 if (!a.Resolve (ec, loc))
8730 public override Expression CreateExpressionTree (EmitContext ec)
8732 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8733 return base.CreateExpressionTree (ec);
8738 /// This class exists solely to pass the Type around and to be a dummy
8739 /// that can be passed to the conversion functions (this is used by
8740 /// foreach implementation to typecast the object return value from
8741 /// get_Current into the proper type. All code has been generated and
8742 /// we only care about the side effect conversions to be performed
8744 /// This is also now used as a placeholder where a no-action expression
8745 /// is needed (the `New' class).
8747 public class EmptyExpression : Expression {
8748 public static readonly Expression Null = new EmptyExpression ();
8750 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8751 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8752 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8753 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8755 static EmptyExpression temp = new EmptyExpression ();
8756 public static EmptyExpression Grab ()
8758 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8763 public static void Release (EmptyExpression e)
8768 // TODO: should be protected
8769 public EmptyExpression ()
8771 type = TypeManager.object_type;
8772 eclass = ExprClass.Value;
8773 loc = Location.Null;
8776 public EmptyExpression (Type t)
8779 eclass = ExprClass.Value;
8780 loc = Location.Null;
8783 public override Expression CreateExpressionTree (EmitContext ec)
8785 throw new NotSupportedException ("ET");
8788 public override Expression DoResolve (EmitContext ec)
8793 public override void Emit (EmitContext ec)
8795 // nothing, as we only exist to not do anything.
8798 public override void EmitSideEffect (EmitContext ec)
8803 // This is just because we might want to reuse this bad boy
8804 // instead of creating gazillions of EmptyExpressions.
8805 // (CanImplicitConversion uses it)
8807 public void SetType (Type t)
8814 // Empty statement expression
8816 public sealed class EmptyExpressionStatement : ExpressionStatement
8818 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8820 private EmptyExpressionStatement ()
8822 eclass = ExprClass.Value;
8823 loc = Location.Null;
8826 public override Expression CreateExpressionTree (EmitContext ec)
8831 public override void EmitStatement (EmitContext ec)
8836 public override Expression DoResolve (EmitContext ec)
8838 type = TypeManager.object_type;
8842 public override void Emit (EmitContext ec)
8848 public class UserCast : Expression {
8852 public UserCast (MethodInfo method, Expression source, Location l)
8854 this.method = method;
8855 this.source = source;
8856 type = TypeManager.TypeToCoreType (method.ReturnType);
8860 public Expression Source {
8866 public override Expression CreateExpressionTree (EmitContext ec)
8868 ArrayList args = new ArrayList (3);
8869 args.Add (new Argument (source.CreateExpressionTree (ec)));
8870 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8871 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8872 return CreateExpressionFactoryCall ("Convert", args);
8875 public override Expression DoResolve (EmitContext ec)
8877 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8879 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8881 eclass = ExprClass.Value;
8885 public override void Emit (EmitContext ec)
8888 ec.ig.Emit (OpCodes.Call, method);
8891 public override string GetSignatureForError ()
8893 return TypeManager.CSharpSignature (method);
8896 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8898 source.MutateHoistedGenericType (storey);
8899 method = storey.MutateGenericMethod (method);
8904 // This class is used to "construct" the type during a typecast
8905 // operation. Since the Type.GetType class in .NET can parse
8906 // the type specification, we just use this to construct the type
8907 // one bit at a time.
8909 public class ComposedCast : TypeExpr {
8910 FullNamedExpression left;
8913 public ComposedCast (FullNamedExpression left, string dim)
8914 : this (left, dim, left.Location)
8918 public ComposedCast (FullNamedExpression left, string dim, Location l)
8925 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8927 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8931 Type ltype = lexpr.Type;
8933 if ((dim.Length > 0) && (dim [0] == '?')) {
8934 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8936 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8937 return nullable.ResolveAsTypeTerminal (ec, false);
8941 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8944 if (dim.Length != 0 && dim [0] == '[') {
8945 if (TypeManager.IsSpecialType (ltype)) {
8946 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8950 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8951 Report.SymbolRelatedToPreviousError (ltype);
8952 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8953 TypeManager.CSharpName (ltype));
8958 type = TypeManager.GetConstructedType (ltype, dim);
8963 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8965 if (type.IsPointer && !ec.IsInUnsafeScope){
8969 eclass = ExprClass.Type;
8973 public override string GetSignatureForError ()
8975 return left.GetSignatureForError () + dim;
8978 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8980 return ResolveAsBaseTerminal (ec, silent);
8984 public class FixedBufferPtr : Expression {
8987 public FixedBufferPtr (Expression array, Type array_type, Location l)
8992 type = TypeManager.GetPointerType (array_type);
8993 eclass = ExprClass.Value;
8996 public override Expression CreateExpressionTree (EmitContext ec)
8998 Error_PointerInsideExpressionTree ();
9002 public override void Emit(EmitContext ec)
9007 public override Expression DoResolve (EmitContext ec)
9010 // We are born fully resolved
9018 // This class is used to represent the address of an array, used
9019 // only by the Fixed statement, this generates "&a [0]" construct
9020 // for fixed (char *pa = a)
9022 public class ArrayPtr : FixedBufferPtr {
9025 public ArrayPtr (Expression array, Type array_type, Location l):
9026 base (array, array_type, l)
9028 this.array_type = array_type;
9031 public override void Emit (EmitContext ec)
9035 ILGenerator ig = ec.ig;
9036 IntLiteral.EmitInt (ig, 0);
9037 ig.Emit (OpCodes.Ldelema, array_type);
9042 // Encapsulates a conversion rules required for array indexes
9044 public class ArrayIndexCast : TypeCast
9046 public ArrayIndexCast (Expression expr)
9047 : base (expr, expr.Type)
9051 public override Expression CreateExpressionTree (EmitContext ec)
9053 ArrayList args = new ArrayList (2);
9054 args.Add (new Argument (child.CreateExpressionTree (ec)));
9055 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9056 return CreateExpressionFactoryCall ("ConvertChecked", args);
9059 public override void Emit (EmitContext ec)
9063 if (type == TypeManager.int32_type)
9066 if (type == TypeManager.uint32_type)
9067 ec.ig.Emit (OpCodes.Conv_U);
9068 else if (type == TypeManager.int64_type)
9069 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9070 else if (type == TypeManager.uint64_type)
9071 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9073 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9078 // Implements the `stackalloc' keyword
9080 public class StackAlloc : Expression {
9085 public StackAlloc (Expression type, Expression count, Location l)
9092 public override Expression CreateExpressionTree (EmitContext ec)
9094 throw new NotSupportedException ("ET");
9097 public override Expression DoResolve (EmitContext ec)
9099 count = count.Resolve (ec);
9103 if (count.Type != TypeManager.uint32_type){
9104 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9109 Constant c = count as Constant;
9110 if (c != null && c.IsNegative) {
9111 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9115 if (ec.InCatch || ec.InFinally) {
9116 Error (255, "Cannot use stackalloc in finally or catch");
9120 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9126 if (!TypeManager.VerifyUnManaged (otype, loc))
9129 type = TypeManager.GetPointerType (otype);
9130 eclass = ExprClass.Value;
9135 public override void Emit (EmitContext ec)
9137 int size = GetTypeSize (otype);
9138 ILGenerator ig = ec.ig;
9143 ig.Emit (OpCodes.Sizeof, otype);
9145 IntConstant.EmitInt (ig, size);
9147 ig.Emit (OpCodes.Mul_Ovf_Un);
9148 ig.Emit (OpCodes.Localloc);
9151 protected override void CloneTo (CloneContext clonectx, Expression t)
9153 StackAlloc target = (StackAlloc) t;
9154 target.count = count.Clone (clonectx);
9155 target.t = t.Clone (clonectx);
9160 // An object initializer expression
9162 public class ElementInitializer : Assign
9164 public readonly string Name;
9166 public ElementInitializer (string name, Expression initializer, Location loc)
9167 : base (null, initializer, loc)
9172 protected override void CloneTo (CloneContext clonectx, Expression t)
9174 ElementInitializer target = (ElementInitializer) t;
9175 target.source = source.Clone (clonectx);
9178 public override Expression CreateExpressionTree (EmitContext ec)
9180 ArrayList args = new ArrayList (2);
9181 FieldExpr fe = target as FieldExpr;
9183 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9185 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9187 args.Add (new Argument (source.CreateExpressionTree (ec)));
9188 return CreateExpressionFactoryCall (
9189 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9193 public override Expression DoResolve (EmitContext ec)
9196 return EmptyExpressionStatement.Instance;
9198 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9199 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9205 me.InstanceExpression = ec.CurrentInitializerVariable;
9207 if (source is CollectionOrObjectInitializers) {
9208 Expression previous = ec.CurrentInitializerVariable;
9209 ec.CurrentInitializerVariable = target;
9210 source = source.Resolve (ec);
9211 ec.CurrentInitializerVariable = previous;
9215 eclass = source.eclass;
9220 Expression expr = base.DoResolve (ec);
9225 // Ignore field initializers with default value
9227 Constant c = source as Constant;
9228 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9229 return EmptyExpressionStatement.Instance.DoResolve (ec);
9234 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9236 MemberInfo member = members [0];
9237 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9238 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9239 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9241 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9242 TypeManager.GetFullNameSignature (member));
9247 public override void EmitStatement (EmitContext ec)
9249 if (source is CollectionOrObjectInitializers)
9252 base.EmitStatement (ec);
9257 // A collection initializer expression
9259 public class CollectionElementInitializer : Invocation
9261 public class ElementInitializerArgument : Argument
9263 public ElementInitializerArgument (Expression e)
9269 sealed class AddMemberAccess : MemberAccess
9271 public AddMemberAccess (Expression expr, Location loc)
9272 : base (expr, "Add", loc)
9276 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9278 if (TypeManager.HasElementType (type))
9281 base.Error_TypeDoesNotContainDefinition (type, name);
9285 public CollectionElementInitializer (Expression argument)
9286 : base (null, new ArrayList (1), true)
9288 Arguments.Add (argument);
9289 this.loc = argument.Location;
9292 public CollectionElementInitializer (ArrayList arguments, Location loc)
9293 : base (null, arguments, true)
9298 public override Expression CreateExpressionTree (EmitContext ec)
9300 ArrayList args = new ArrayList (2);
9301 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9303 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9304 foreach (Argument a in Arguments)
9305 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9307 args.Add (new Argument (new ArrayCreation (
9308 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9309 return CreateExpressionFactoryCall ("ElementInit", args);
9312 protected override void CloneTo (CloneContext clonectx, Expression t)
9314 CollectionElementInitializer target = (CollectionElementInitializer) t;
9316 target.Arguments = new ArrayList (Arguments.Count);
9317 foreach (Expression e in Arguments)
9318 target.Arguments.Add (e.Clone (clonectx));
9321 public override Expression DoResolve (EmitContext ec)
9323 if (eclass != ExprClass.Invalid)
9326 // TODO: We could call a constructor which takes element count argument,
9327 // for known types like List<T>, Dictionary<T, U>
9329 for (int i = 0; i < Arguments.Count; ++i) {
9330 Expression expr = Arguments [i] as Expression;
9334 expr = expr.Resolve (ec);
9338 Arguments [i] = new ElementInitializerArgument (expr);
9341 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9343 return base.DoResolve (ec);
9348 // A block of object or collection initializers
9350 public class CollectionOrObjectInitializers : ExpressionStatement
9352 ArrayList initializers;
9354 public static readonly CollectionOrObjectInitializers Empty =
9355 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9357 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9359 this.initializers = initializers;
9363 public bool IsEmpty {
9365 return initializers.Count == 0;
9369 public bool IsCollectionInitializer {
9371 return type == typeof (CollectionOrObjectInitializers);
9375 protected override void CloneTo (CloneContext clonectx, Expression target)
9377 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9379 t.initializers = new ArrayList (initializers.Count);
9380 foreach (Expression e in initializers)
9381 t.initializers.Add (e.Clone (clonectx));
9384 public override Expression CreateExpressionTree (EmitContext ec)
9386 ArrayList expr_initializers = new ArrayList (initializers.Count);
9387 foreach (Expression e in initializers) {
9388 Expression expr = e.CreateExpressionTree (ec);
9390 expr_initializers.Add (expr);
9393 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9396 public override Expression DoResolve (EmitContext ec)
9398 if (eclass != ExprClass.Invalid)
9401 bool is_collection_initialization = false;
9402 ArrayList element_names = null;
9403 for (int i = 0; i < initializers.Count; ++i) {
9404 Expression initializer = (Expression) initializers [i];
9405 ElementInitializer element_initializer = initializer as ElementInitializer;
9408 if (element_initializer != null) {
9409 element_names = new ArrayList (initializers.Count);
9410 element_names.Add (element_initializer.Name);
9412 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9413 TypeManager.ienumerable_type)) {
9414 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9415 "object initializer because type `{1}' does not implement `{2}' interface",
9416 ec.CurrentInitializerVariable.GetSignatureForError (),
9417 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9418 TypeManager.CSharpName (TypeManager.ienumerable_type));
9421 is_collection_initialization = true;
9424 if (is_collection_initialization != (element_initializer == null)) {
9425 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9426 is_collection_initialization ? "collection initializer" : "object initializer");
9430 if (!is_collection_initialization) {
9431 if (element_names.Contains (element_initializer.Name)) {
9432 Report.Error (1912, element_initializer.Location,
9433 "An object initializer includes more than one member `{0}' initialization",
9434 element_initializer.Name);
9436 element_names.Add (element_initializer.Name);
9441 Expression e = initializer.Resolve (ec);
9442 if (e == EmptyExpressionStatement.Instance)
9443 initializers.RemoveAt (i--);
9445 initializers [i] = e;
9448 if (is_collection_initialization) {
9449 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9450 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9451 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9454 type = typeof (CollectionOrObjectInitializers);
9456 type = typeof (ElementInitializer);
9459 eclass = ExprClass.Variable;
9463 public override void Emit (EmitContext ec)
9468 public override void EmitStatement (EmitContext ec)
9470 foreach (ExpressionStatement e in initializers)
9471 e.EmitStatement (ec);
9474 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9476 foreach (Expression e in initializers)
9477 e.MutateHoistedGenericType (storey);
9482 // New expression with element/object initializers
9484 public class NewInitialize : New
9487 // This class serves as a proxy for variable initializer target instances.
9488 // A real variable is assigned later when we resolve left side of an
9491 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9493 NewInitialize new_instance;
9495 public InitializerTargetExpression (NewInitialize newInstance)
9497 this.type = newInstance.type;
9498 this.loc = newInstance.loc;
9499 this.eclass = newInstance.eclass;
9500 this.new_instance = newInstance;
9503 public override Expression CreateExpressionTree (EmitContext ec)
9505 // Should not be reached
9506 throw new NotSupportedException ("ET");
9509 public override Expression DoResolve (EmitContext ec)
9514 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9519 public override void Emit (EmitContext ec)
9521 Expression e = (Expression) new_instance.instance;
9525 #region IMemoryLocation Members
9527 public void AddressOf (EmitContext ec, AddressOp mode)
9529 new_instance.instance.AddressOf (ec, mode);
9535 CollectionOrObjectInitializers initializers;
9536 IMemoryLocation instance;
9538 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9539 : base (requested_type, arguments, l)
9541 this.initializers = initializers;
9544 protected override void CloneTo (CloneContext clonectx, Expression t)
9546 base.CloneTo (clonectx, t);
9548 NewInitialize target = (NewInitialize) t;
9549 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9552 public override Expression CreateExpressionTree (EmitContext ec)
9554 ArrayList args = new ArrayList (2);
9555 args.Add (new Argument (base.CreateExpressionTree (ec)));
9556 if (!initializers.IsEmpty)
9557 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9559 return CreateExpressionFactoryCall (
9560 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9564 public override Expression DoResolve (EmitContext ec)
9566 if (eclass != ExprClass.Invalid)
9569 Expression e = base.DoResolve (ec);
9573 // Empty initializer can be optimized to simple new
9574 if (initializers.IsEmpty) {
9575 initializers.Resolve (ec);
9576 return ReducedExpression.Create (e, this).Resolve (ec);
9579 Expression previous = ec.CurrentInitializerVariable;
9580 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9581 initializers.Resolve (ec);
9582 ec.CurrentInitializerVariable = previous;
9586 public override bool Emit (EmitContext ec, IMemoryLocation target)
9588 bool left_on_stack = base.Emit (ec, target);
9590 if (initializers.IsEmpty)
9591 return left_on_stack;
9593 LocalTemporary temp = null;
9596 // If target is non-hoisted variable, let's use it
9598 VariableReference variable = target as VariableReference;
9599 if (variable != null) {
9602 if (left_on_stack) {
9604 StoreFromPtr (ec.ig, type);
9606 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9608 left_on_stack = false;
9611 temp = target as LocalTemporary;
9614 throw new NotImplementedException ();
9616 temp = new LocalTemporary (type);
9624 initializers.Emit (ec);
9626 if (left_on_stack) {
9631 return left_on_stack;
9634 public override bool HasInitializer {
9636 return !initializers.IsEmpty;
9640 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9642 base.MutateHoistedGenericType (storey);
9643 initializers.MutateHoistedGenericType (storey);
9647 public class AnonymousTypeDeclaration : Expression
9649 ArrayList parameters;
9650 readonly TypeContainer parent;
9651 static readonly ArrayList EmptyParameters = new ArrayList (0);
9653 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9655 this.parameters = parameters;
9656 this.parent = parent;
9660 protected override void CloneTo (CloneContext clonectx, Expression target)
9662 if (parameters == null)
9665 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9666 t.parameters = new ArrayList (parameters.Count);
9667 foreach (AnonymousTypeParameter atp in parameters)
9668 t.parameters.Add (atp.Clone (clonectx));
9671 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9673 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9677 type = AnonymousTypeClass.Create (parent, parameters, loc);
9684 if (Report.Errors == 0)
9687 RootContext.ToplevelTypes.AddAnonymousType (type);
9691 public override Expression CreateExpressionTree (EmitContext ec)
9693 throw new NotSupportedException ("ET");
9696 public override Expression DoResolve (EmitContext ec)
9698 AnonymousTypeClass anonymous_type;
9700 if (!ec.IsAnonymousMethodAllowed) {
9701 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9705 if (parameters == null) {
9706 anonymous_type = CreateAnonymousType (EmptyParameters);
9707 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9708 null, loc).Resolve (ec);
9712 ArrayList arguments = new ArrayList (parameters.Count);
9713 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9714 for (int i = 0; i < parameters.Count; ++i) {
9715 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9721 arguments.Add (new Argument (e));
9722 t_args [i] = new TypeExpression (e.Type, e.Location);
9728 anonymous_type = CreateAnonymousType (parameters);
9729 if (anonymous_type == null)
9732 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9733 new TypeArguments (t_args), loc);
9735 return new New (te, arguments, loc).Resolve (ec);
9738 public override void Emit (EmitContext ec)
9740 throw new InternalErrorException ("Should not be reached");
9744 public class AnonymousTypeParameter : Expression
9746 public readonly string Name;
9747 Expression initializer;
9749 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9753 this.initializer = initializer;
9756 public AnonymousTypeParameter (Parameter parameter)
9758 this.Name = parameter.Name;
9759 this.loc = parameter.Location;
9760 this.initializer = new SimpleName (Name, loc);
9763 protected override void CloneTo (CloneContext clonectx, Expression target)
9765 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9766 t.initializer = initializer.Clone (clonectx);
9769 public override Expression CreateExpressionTree (EmitContext ec)
9771 throw new NotSupportedException ("ET");
9774 public override bool Equals (object o)
9776 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9777 return other != null && Name == other.Name;
9780 public override int GetHashCode ()
9782 return Name.GetHashCode ();
9785 public override Expression DoResolve (EmitContext ec)
9787 Expression e = initializer.Resolve (ec);
9791 if (e.eclass == ExprClass.MethodGroup) {
9792 Error_InvalidInitializer (e.ExprClassName);
9797 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9798 type == TypeManager.anonymous_method_type || type.IsPointer) {
9799 Error_InvalidInitializer (e.GetSignatureForError ());
9806 protected virtual void Error_InvalidInitializer (string initializer)
9808 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9812 public override void Emit (EmitContext ec)
9814 throw new InternalErrorException ("Should not be reached");