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 (TypeManager.IsStruct (t)) {
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 (TypeManager.IsStruct (d)) {
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 && TypeManager.IsStruct (d))
1328 return CreateConstantResult (false);
1330 if (constraints.IsValueType && !TypeManager.IsStruct (d))
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, type);
1378 if (TypeManager.IsGenericParameter (type) || 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 void MutateHoistedGenericType (AnonymousMethodStorey storey)
1451 type = storey.MutateType (type);
1452 base.MutateHoistedGenericType (storey);
1455 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1457 return expr.GetAttributableValue (ec, value_type, out value);
1462 /// This represents a typecast in the source language.
1464 /// FIXME: Cast expressions have an unusual set of parsing
1465 /// rules, we need to figure those out.
1467 public class Cast : Expression {
1468 Expression target_type;
1471 public Cast (Expression cast_type, Expression expr)
1472 : this (cast_type, expr, cast_type.Location)
1476 public Cast (Expression cast_type, Expression expr, Location loc)
1478 this.target_type = cast_type;
1483 public Expression TargetType {
1484 get { return target_type; }
1487 public Expression Expr {
1488 get { return expr; }
1491 public override Expression CreateExpressionTree (EmitContext ec)
1493 throw new NotSupportedException ("ET");
1496 public override Expression DoResolve (EmitContext ec)
1498 expr = expr.Resolve (ec);
1502 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1508 if (type.IsAbstract && type.IsSealed) {
1509 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1513 eclass = ExprClass.Value;
1515 Constant c = expr as Constant;
1517 c = c.TryReduce (ec, type, loc);
1522 if (type.IsPointer && !ec.InUnsafe) {
1526 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1530 public override void Emit (EmitContext ec)
1532 throw new Exception ("Should not happen");
1535 protected override void CloneTo (CloneContext clonectx, Expression t)
1537 Cast target = (Cast) t;
1539 target.target_type = target_type.Clone (clonectx);
1540 target.expr = expr.Clone (clonectx);
1545 // C# 2.0 Default value expression
1547 public class DefaultValueExpression : Expression
1551 public DefaultValueExpression (Expression expr, Location loc)
1557 public override Expression CreateExpressionTree (EmitContext ec)
1559 ArrayList args = new ArrayList (2);
1560 args.Add (new Argument (this));
1561 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1562 return CreateExpressionFactoryCall ("Constant", args);
1565 public override Expression DoResolve (EmitContext ec)
1567 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1573 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1574 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1578 return new NullLiteral (Location).ConvertImplicitly (type);
1580 if (TypeManager.IsReferenceType (type)) {
1581 return new EmptyConstantCast (new NullLiteral (Location), type);
1584 // return ReducedExpression.Create (new NullLiteral (Location), this);
1587 Constant c = New.Constantify (type);
1591 eclass = ExprClass.Variable;
1595 public override void Emit (EmitContext ec)
1597 LocalTemporary temp_storage = new LocalTemporary(type);
1599 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1600 ec.ig.Emit(OpCodes.Initobj, type);
1601 temp_storage.Emit(ec);
1604 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1606 type = storey.MutateType (type);
1609 protected override void CloneTo (CloneContext clonectx, Expression t)
1611 DefaultValueExpression target = (DefaultValueExpression) t;
1613 target.expr = expr.Clone (clonectx);
1618 /// Binary operators
1620 public class Binary : Expression {
1622 protected class PredefinedOperator {
1623 protected readonly Type left;
1624 protected readonly Type right;
1625 public readonly Operator OperatorsMask;
1626 public Type ReturnType;
1628 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1629 : this (ltype, rtype, op_mask, ltype)
1633 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1634 : this (type, type, op_mask, return_type)
1638 public PredefinedOperator (Type type, Operator op_mask)
1639 : this (type, type, op_mask, type)
1643 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1645 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1646 throw new InternalErrorException ("Only masked values can be used");
1650 this.OperatorsMask = op_mask;
1651 this.ReturnType = return_type;
1654 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1656 b.type = ReturnType;
1658 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1659 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1662 // A user operators does not support multiple user conversions, but decimal type
1663 // is considered to be predefined type therefore we apply predefined operators rules
1664 // and then look for decimal user-operator implementation
1666 if (left == TypeManager.decimal_type)
1667 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1672 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1675 // We are dealing with primitive types only
1677 return left == ltype && ltype == rtype;
1680 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1682 if (TypeManager.IsEqual (left, lexpr.Type) &&
1683 TypeManager.IsEqual (right, rexpr.Type))
1686 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1687 Convert.ImplicitConversionExists (ec, rexpr, right);
1690 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1693 if (left != null && best_operator.left != null) {
1694 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1698 // When second arguments are same as the first one, the result is same
1700 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1701 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1704 if (result == 0 || result > 2)
1707 return result == 1 ? best_operator : this;
1711 class PredefinedStringOperator : PredefinedOperator {
1712 public PredefinedStringOperator (Type type, Operator op_mask)
1713 : base (type, op_mask, type)
1715 ReturnType = TypeManager.string_type;
1718 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1719 : base (ltype, rtype, op_mask)
1721 ReturnType = TypeManager.string_type;
1724 public override Expression ConvertResult (EmitContext ec, Binary b)
1727 // Use original expression for nullable arguments
1729 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1731 b.left = unwrap.Original;
1733 unwrap = b.right as Nullable.Unwrap;
1735 b.right = unwrap.Original;
1737 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1738 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1741 // Start a new concat expression using converted expression
1743 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1747 class PredefinedShiftOperator : PredefinedOperator {
1748 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1749 base (ltype, TypeManager.int32_type, op_mask)
1753 public override Expression ConvertResult (EmitContext ec, Binary b)
1755 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1757 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1759 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1762 // b = b.left >> b.right & (0x1f|0x3f)
1764 b.right = new Binary (Operator.BitwiseAnd,
1765 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1768 // Expression tree representation does not use & mask
1770 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1771 b.type = ReturnType;
1776 class PredefinedPointerOperator : PredefinedOperator {
1777 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1778 : base (ltype, rtype, op_mask)
1782 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1783 : base (ltype, rtype, op_mask, retType)
1787 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1788 : base (type, op_mask, return_type)
1792 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1795 if (!lexpr.Type.IsPointer)
1798 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1802 if (right == null) {
1803 if (!rexpr.Type.IsPointer)
1806 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1813 public override Expression ConvertResult (EmitContext ec, Binary b)
1816 b.left = EmptyCast.Create (b.left, left);
1817 } else if (right != null) {
1818 b.right = EmptyCast.Create (b.right, right);
1821 Type r_type = ReturnType;
1822 Expression left_arg, right_arg;
1823 if (r_type == null) {
1826 right_arg = b.right;
1827 r_type = b.left.Type;
1831 r_type = b.right.Type;
1835 right_arg = b.right;
1838 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1843 public enum Operator {
1844 Multiply = 0 | ArithmeticMask,
1845 Division = 1 | ArithmeticMask,
1846 Modulus = 2 | ArithmeticMask,
1847 Addition = 3 | ArithmeticMask | AdditionMask,
1848 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1850 LeftShift = 5 | ShiftMask,
1851 RightShift = 6 | ShiftMask,
1853 LessThan = 7 | ComparisonMask | RelationalMask,
1854 GreaterThan = 8 | ComparisonMask | RelationalMask,
1855 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1856 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1857 Equality = 11 | ComparisonMask | EqualityMask,
1858 Inequality = 12 | ComparisonMask | EqualityMask,
1860 BitwiseAnd = 13 | BitwiseMask,
1861 ExclusiveOr = 14 | BitwiseMask,
1862 BitwiseOr = 15 | BitwiseMask,
1864 LogicalAnd = 16 | LogicalMask,
1865 LogicalOr = 17 | LogicalMask,
1870 ValuesOnlyMask = ArithmeticMask - 1,
1871 ArithmeticMask = 1 << 5,
1873 ComparisonMask = 1 << 7,
1874 EqualityMask = 1 << 8,
1875 BitwiseMask = 1 << 9,
1876 LogicalMask = 1 << 10,
1877 AdditionMask = 1 << 11,
1878 SubtractionMask = 1 << 12,
1879 RelationalMask = 1 << 13
1882 readonly Operator oper;
1883 protected Expression left, right;
1884 readonly bool is_compound;
1885 Expression enum_conversion;
1887 static PredefinedOperator [] standard_operators;
1888 static PredefinedOperator [] pointer_operators;
1890 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1891 : this (oper, left, right)
1893 this.is_compound = isCompound;
1896 public Binary (Operator oper, Expression left, Expression right)
1901 this.loc = left.Location;
1904 public Operator Oper {
1911 /// Returns a stringified representation of the Operator
1913 string OperName (Operator oper)
1917 case Operator.Multiply:
1920 case Operator.Division:
1923 case Operator.Modulus:
1926 case Operator.Addition:
1929 case Operator.Subtraction:
1932 case Operator.LeftShift:
1935 case Operator.RightShift:
1938 case Operator.LessThan:
1941 case Operator.GreaterThan:
1944 case Operator.LessThanOrEqual:
1947 case Operator.GreaterThanOrEqual:
1950 case Operator.Equality:
1953 case Operator.Inequality:
1956 case Operator.BitwiseAnd:
1959 case Operator.BitwiseOr:
1962 case Operator.ExclusiveOr:
1965 case Operator.LogicalOr:
1968 case Operator.LogicalAnd:
1972 s = oper.ToString ();
1982 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1984 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1987 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1990 // TODO: This should be handled as Type of method group in CSharpName
1991 if (left.eclass == ExprClass.MethodGroup)
1992 l = left.ExprClassName;
1994 l = TypeManager.CSharpName (left.Type);
1996 if (right.eclass == ExprClass.MethodGroup)
1997 r = right.ExprClassName;
1999 r = TypeManager.CSharpName (right.Type);
2001 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2005 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2007 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2010 static string GetOperatorMetadataName (Operator op)
2012 CSharp.Operator.OpType op_type;
2014 case Operator.Addition:
2015 op_type = CSharp.Operator.OpType.Addition; break;
2016 case Operator.BitwiseAnd:
2017 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2018 case Operator.BitwiseOr:
2019 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2020 case Operator.Division:
2021 op_type = CSharp.Operator.OpType.Division; break;
2022 case Operator.Equality:
2023 op_type = CSharp.Operator.OpType.Equality; break;
2024 case Operator.ExclusiveOr:
2025 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2026 case Operator.GreaterThan:
2027 op_type = CSharp.Operator.OpType.GreaterThan; break;
2028 case Operator.GreaterThanOrEqual:
2029 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2030 case Operator.Inequality:
2031 op_type = CSharp.Operator.OpType.Inequality; break;
2032 case Operator.LeftShift:
2033 op_type = CSharp.Operator.OpType.LeftShift; break;
2034 case Operator.LessThan:
2035 op_type = CSharp.Operator.OpType.LessThan; break;
2036 case Operator.LessThanOrEqual:
2037 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2038 case Operator.Modulus:
2039 op_type = CSharp.Operator.OpType.Modulus; break;
2040 case Operator.Multiply:
2041 op_type = CSharp.Operator.OpType.Multiply; break;
2042 case Operator.RightShift:
2043 op_type = CSharp.Operator.OpType.RightShift; break;
2044 case Operator.Subtraction:
2045 op_type = CSharp.Operator.OpType.Subtraction; break;
2047 throw new InternalErrorException (op.ToString ());
2050 return CSharp.Operator.GetMetadataName (op_type);
2053 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2056 ILGenerator ig = ec.ig;
2059 case Operator.Multiply:
2061 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2062 opcode = OpCodes.Mul_Ovf;
2063 else if (!IsFloat (l))
2064 opcode = OpCodes.Mul_Ovf_Un;
2066 opcode = OpCodes.Mul;
2068 opcode = OpCodes.Mul;
2072 case Operator.Division:
2074 opcode = OpCodes.Div_Un;
2076 opcode = OpCodes.Div;
2079 case Operator.Modulus:
2081 opcode = OpCodes.Rem_Un;
2083 opcode = OpCodes.Rem;
2086 case Operator.Addition:
2088 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2089 opcode = OpCodes.Add_Ovf;
2090 else if (!IsFloat (l))
2091 opcode = OpCodes.Add_Ovf_Un;
2093 opcode = OpCodes.Add;
2095 opcode = OpCodes.Add;
2098 case Operator.Subtraction:
2100 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2101 opcode = OpCodes.Sub_Ovf;
2102 else if (!IsFloat (l))
2103 opcode = OpCodes.Sub_Ovf_Un;
2105 opcode = OpCodes.Sub;
2107 opcode = OpCodes.Sub;
2110 case Operator.RightShift:
2112 opcode = OpCodes.Shr_Un;
2114 opcode = OpCodes.Shr;
2117 case Operator.LeftShift:
2118 opcode = OpCodes.Shl;
2121 case Operator.Equality:
2122 opcode = OpCodes.Ceq;
2125 case Operator.Inequality:
2126 ig.Emit (OpCodes.Ceq);
2127 ig.Emit (OpCodes.Ldc_I4_0);
2129 opcode = OpCodes.Ceq;
2132 case Operator.LessThan:
2134 opcode = OpCodes.Clt_Un;
2136 opcode = OpCodes.Clt;
2139 case Operator.GreaterThan:
2141 opcode = OpCodes.Cgt_Un;
2143 opcode = OpCodes.Cgt;
2146 case Operator.LessThanOrEqual:
2147 if (IsUnsigned (l) || IsFloat (l))
2148 ig.Emit (OpCodes.Cgt_Un);
2150 ig.Emit (OpCodes.Cgt);
2151 ig.Emit (OpCodes.Ldc_I4_0);
2153 opcode = OpCodes.Ceq;
2156 case Operator.GreaterThanOrEqual:
2157 if (IsUnsigned (l) || IsFloat (l))
2158 ig.Emit (OpCodes.Clt_Un);
2160 ig.Emit (OpCodes.Clt);
2162 ig.Emit (OpCodes.Ldc_I4_0);
2164 opcode = OpCodes.Ceq;
2167 case Operator.BitwiseOr:
2168 opcode = OpCodes.Or;
2171 case Operator.BitwiseAnd:
2172 opcode = OpCodes.And;
2175 case Operator.ExclusiveOr:
2176 opcode = OpCodes.Xor;
2180 throw new InternalErrorException (oper.ToString ());
2186 static bool IsUnsigned (Type t)
2191 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2192 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2195 static bool IsFloat (Type t)
2197 return t == TypeManager.float_type || t == TypeManager.double_type;
2200 Expression ResolveOperator (EmitContext ec)
2203 Type r = right.Type;
2205 bool primitives_only = false;
2207 if (standard_operators == null)
2208 CreateStandardOperatorsTable ();
2211 // Handles predefined primitive types
2213 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2214 if ((oper & Operator.ShiftMask) == 0) {
2215 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2218 primitives_only = true;
2222 if (l.IsPointer || r.IsPointer)
2223 return ResolveOperatorPointer (ec, l, r);
2226 bool lenum = TypeManager.IsEnumType (l);
2227 bool renum = TypeManager.IsEnumType (r);
2228 if (lenum || renum) {
2229 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2231 // TODO: Can this be ambiguous
2237 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2238 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2240 expr = ResolveOperatorDelegate (ec, l, r);
2242 // TODO: Can this be ambiguous
2248 expr = ResolveUserOperator (ec, l, r);
2252 // Predefined reference types equality
2253 if ((oper & Operator.EqualityMask) != 0) {
2254 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2260 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2263 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2264 // if 'left' is not an enumeration constant, create one from the type of 'right'
2265 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2268 case Operator.BitwiseOr:
2269 case Operator.BitwiseAnd:
2270 case Operator.ExclusiveOr:
2271 case Operator.Equality:
2272 case Operator.Inequality:
2273 case Operator.LessThan:
2274 case Operator.LessThanOrEqual:
2275 case Operator.GreaterThan:
2276 case Operator.GreaterThanOrEqual:
2277 if (TypeManager.IsEnumType (left.Type))
2280 if (left.IsZeroInteger)
2281 return left.TryReduce (ec, right.Type, loc);
2285 case Operator.Addition:
2286 case Operator.Subtraction:
2289 case Operator.Multiply:
2290 case Operator.Division:
2291 case Operator.Modulus:
2292 case Operator.LeftShift:
2293 case Operator.RightShift:
2294 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2298 Error_OperatorCannotBeApplied (this.left, this.right);
2303 // The `|' operator used on types which were extended is dangerous
2305 void CheckBitwiseOrOnSignExtended ()
2307 OpcodeCast lcast = left as OpcodeCast;
2308 if (lcast != null) {
2309 if (IsUnsigned (lcast.UnderlyingType))
2313 OpcodeCast rcast = right as OpcodeCast;
2314 if (rcast != null) {
2315 if (IsUnsigned (rcast.UnderlyingType))
2319 if (lcast == null && rcast == null)
2322 // FIXME: consider constants
2324 Report.Warning (675, 3, loc,
2325 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2326 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2329 static void CreatePointerOperatorsTable ()
2331 ArrayList temp = new ArrayList ();
2334 // Pointer arithmetic:
2336 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2337 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2338 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2339 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2341 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2342 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2343 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2344 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2347 // T* operator + (int y, T* x);
2348 // T* operator + (uint y, T *x);
2349 // T* operator + (long y, T *x);
2350 // T* operator + (ulong y, T *x);
2352 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2353 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2354 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2355 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2358 // long operator - (T* x, T *y)
2360 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2362 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2365 static void CreateStandardOperatorsTable ()
2367 ArrayList temp = new ArrayList ();
2368 Type bool_type = TypeManager.bool_type;
2370 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2371 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2372 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2373 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2374 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2375 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2376 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2378 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2379 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2380 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2381 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2382 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2383 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2384 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2386 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2388 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2389 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2390 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2392 temp.Add (new PredefinedOperator (bool_type,
2393 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2395 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2396 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2397 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2398 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2400 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2404 // Rules used during binary numeric promotion
2406 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2411 Constant c = prim_expr as Constant;
2413 temp = c.ConvertImplicitly (type);
2420 if (type == TypeManager.uint32_type) {
2421 etype = prim_expr.Type;
2422 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2423 type = TypeManager.int64_type;
2425 if (type != second_expr.Type) {
2426 c = second_expr as Constant;
2428 temp = c.ConvertImplicitly (type);
2430 temp = Convert.ImplicitNumericConversion (second_expr, type);
2436 } else if (type == TypeManager.uint64_type) {
2438 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2440 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2441 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2445 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2454 // 7.2.6.2 Binary numeric promotions
2456 public bool DoBinaryOperatorPromotion (EmitContext ec)
2458 Type ltype = left.Type;
2459 Type rtype = right.Type;
2462 foreach (Type t in ConstantFold.binary_promotions) {
2464 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2467 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2470 Type int32 = TypeManager.int32_type;
2471 if (ltype != int32) {
2472 Constant c = left as Constant;
2474 temp = c.ConvertImplicitly (int32);
2476 temp = Convert.ImplicitNumericConversion (left, int32);
2483 if (rtype != int32) {
2484 Constant c = right as Constant;
2486 temp = c.ConvertImplicitly (int32);
2488 temp = Convert.ImplicitNumericConversion (right, int32);
2498 public override Expression DoResolve (EmitContext ec)
2503 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2504 left = ((ParenthesizedExpression) left).Expr;
2505 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2509 if (left.eclass == ExprClass.Type) {
2510 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2514 left = left.Resolve (ec);
2519 Constant lc = left as Constant;
2521 if (lc != null && lc.Type == TypeManager.bool_type &&
2522 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2523 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2525 // FIXME: resolve right expression as unreachable
2526 // right.Resolve (ec);
2528 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2532 right = right.Resolve (ec);
2536 eclass = ExprClass.Value;
2537 Constant rc = right as Constant;
2539 // The conversion rules are ignored in enum context but why
2540 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2541 lc = EnumLiftUp (ec, lc, rc, loc);
2543 rc = EnumLiftUp (ec, rc, lc, loc);
2546 if (rc != null && lc != null) {
2547 int prev_e = Report.Errors;
2548 Expression e = ConstantFold.BinaryFold (
2549 ec, oper, lc, rc, loc);
2550 if (e != null || Report.Errors != prev_e)
2553 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2554 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2556 if ((ResolveOperator (ec)) == null) {
2557 Error_OperatorCannotBeApplied (left, right);
2562 // The result is a constant with side-effect
2564 Constant side_effect = rc == null ?
2565 new SideEffectConstant (lc, right, loc) :
2566 new SideEffectConstant (rc, left, loc);
2568 return ReducedExpression.Create (side_effect, this);
2572 // Comparison warnings
2573 if ((oper & Operator.ComparisonMask) != 0) {
2574 if (left.Equals (right)) {
2575 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2577 CheckUselessComparison (lc, right.Type);
2578 CheckUselessComparison (rc, left.Type);
2581 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2582 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2583 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2584 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2585 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2586 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2588 return DoResolveCore (ec, left, right);
2591 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2593 Expression expr = ResolveOperator (ec);
2595 Error_OperatorCannotBeApplied (left_orig, right_orig);
2597 if (left == null || right == null)
2598 throw new InternalErrorException ("Invalid conversion");
2600 if (oper == Operator.BitwiseOr)
2601 CheckBitwiseOrOnSignExtended ();
2606 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2608 left.MutateHoistedGenericType (storey);
2609 right.MutateHoistedGenericType (storey);
2613 // D operator + (D x, D y)
2614 // D operator - (D x, D y)
2615 // bool operator == (D x, D y)
2616 // bool operator != (D x, D y)
2618 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2620 bool is_equality = (oper & Operator.EqualityMask) != 0;
2621 if (!TypeManager.IsEqual (l, r)) {
2623 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2624 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2629 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2630 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2641 // Resolve delegate equality as a user operator
2644 return ResolveUserOperator (ec, l, r);
2647 ArrayList args = new ArrayList (2);
2648 args.Add (new Argument (left, Argument.AType.Expression));
2649 args.Add (new Argument (right, Argument.AType.Expression));
2651 if (oper == Operator.Addition) {
2652 if (TypeManager.delegate_combine_delegate_delegate == null) {
2653 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2654 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2657 method = TypeManager.delegate_combine_delegate_delegate;
2659 if (TypeManager.delegate_remove_delegate_delegate == null) {
2660 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2661 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2664 method = TypeManager.delegate_remove_delegate_delegate;
2667 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2668 mg = mg.OverloadResolve (ec, ref args, false, loc);
2670 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2674 // Enumeration operators
2676 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
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);
2683 // bool operator <= (E x, E y);
2684 // bool operator >= (E x, E y);
2686 // E operator & (E x, E y);
2687 // E operator | (E x, E y);
2688 // E operator ^ (E x, E y);
2690 // U operator - (E e, E f)
2691 // E operator - (E e, U x)
2693 // E operator + (U x, E e)
2694 // E operator + (E e, U x)
2696 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2697 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2700 Expression ltemp = left;
2701 Expression rtemp = right;
2702 Type underlying_type;
2705 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2707 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2713 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2721 if (TypeManager.IsEqual (ltype, rtype)) {
2722 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2724 if (left is Constant)
2725 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2727 left = EmptyCast.Create (left, underlying_type);
2729 if (right is Constant)
2730 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2732 right = EmptyCast.Create (right, underlying_type);
2734 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2736 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2737 Constant c = right as Constant;
2738 if (c == null || !c.IsDefaultValue)
2741 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2744 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2747 if (left is Constant)
2748 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2750 left = EmptyCast.Create (left, underlying_type);
2753 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2755 if (oper != Operator.Addition) {
2756 Constant c = left as Constant;
2757 if (c == null || !c.IsDefaultValue)
2760 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2763 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2766 if (right is Constant)
2767 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2769 right = EmptyCast.Create (right, underlying_type);
2776 // C# specification uses explicit cast syntax which means binary promotion
2777 // should happen, however it seems that csc does not do that
2779 if (!DoBinaryOperatorPromotion (ec)) {
2785 Type res_type = null;
2786 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2787 Type promoted_type = lenum ? left.Type : right.Type;
2788 enum_conversion = Convert.ExplicitNumericConversion (
2789 new EmptyExpression (promoted_type), underlying_type);
2791 if (oper == Operator.Subtraction && renum && lenum)
2792 res_type = underlying_type;
2793 else if (oper == Operator.Addition && renum)
2799 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2800 if (!is_compound || expr == null)
2804 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2807 if (Convert.ImplicitConversionExists (ec, left, rtype))
2810 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2813 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2818 // 7.9.6 Reference type equality operators
2820 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2823 // operator != (object a, object b)
2824 // operator == (object a, object b)
2827 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2829 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2832 type = TypeManager.bool_type;
2833 GenericConstraints constraints;
2835 bool lgen = TypeManager.IsGenericParameter (l);
2837 if (TypeManager.IsEqual (l, r)) {
2840 // Only allow to compare same reference type parameter
2842 constraints = TypeManager.GetTypeParameterConstraints (l);
2843 if (constraints != null && constraints.IsReferenceType)
2849 if (l == TypeManager.anonymous_method_type)
2852 if (TypeManager.IsValueType (l))
2858 bool rgen = TypeManager.IsGenericParameter (r);
2861 // a, Both operands are reference-type values or the value null
2862 // b, One operand is a value of type T where T is a type-parameter and
2863 // the other operand is the value null. Furthermore T does not have the
2864 // value type constrain
2866 if (left is NullLiteral || right is NullLiteral) {
2868 constraints = TypeManager.GetTypeParameterConstraints (l);
2869 if (constraints != null && constraints.HasValueTypeConstraint)
2872 left = new BoxedCast (left, TypeManager.object_type);
2877 constraints = TypeManager.GetTypeParameterConstraints (r);
2878 if (constraints != null && constraints.HasValueTypeConstraint)
2881 right = new BoxedCast (right, TypeManager.object_type);
2887 // An interface is converted to the object before the
2888 // standard conversion is applied. It's not clear from the
2889 // standard but it looks like it works like that.
2892 constraints = TypeManager.GetTypeParameterConstraints (l);
2893 if (constraints == null || constraints.IsReferenceType)
2895 } else if (l.IsInterface) {
2896 l = TypeManager.object_type;
2897 } else if (TypeManager.IsStruct (l)) {
2902 constraints = TypeManager.GetTypeParameterConstraints (r);
2903 if (constraints == null || constraints.IsReferenceType)
2905 } else if (r.IsInterface) {
2906 r = TypeManager.object_type;
2907 } else if (TypeManager.IsStruct (r)) {
2912 const string ref_comparison = "Possible unintended reference comparison. " +
2913 "Consider casting the {0} side of the expression to `string' to compare the values";
2916 // A standard implicit conversion exists from the type of either
2917 // operand to the type of the other operand
2919 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2920 if (l == TypeManager.string_type)
2921 Report.Warning (253, 2, loc, ref_comparison, "right");
2926 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2927 if (r == TypeManager.string_type)
2928 Report.Warning (252, 2, loc, ref_comparison, "left");
2937 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
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);
2944 // bool operator <= (void* x, void* y);
2945 // bool operator >= (void* x, void* y);
2947 if ((oper & Operator.ComparisonMask) != 0) {
2950 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2957 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2963 type = TypeManager.bool_type;
2967 if (pointer_operators == null)
2968 CreatePointerOperatorsTable ();
2970 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2974 // Build-in operators method overloading
2976 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2978 PredefinedOperator best_operator = null;
2980 Type r = right.Type;
2981 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2983 foreach (PredefinedOperator po in operators) {
2984 if ((po.OperatorsMask & oper_mask) == 0)
2987 if (primitives_only) {
2988 if (!po.IsPrimitiveApplicable (l, r))
2991 if (!po.IsApplicable (ec, left, right))
2995 if (best_operator == null) {
2997 if (primitives_only)
3003 best_operator = po.ResolveBetterOperator (ec, best_operator);
3005 if (best_operator == null) {
3006 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3007 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3014 if (best_operator == null)
3017 Expression expr = best_operator.ConvertResult (ec, this);
3018 if (enum_type == null)
3022 // HACK: required by enum_conversion
3024 expr.Type = enum_type;
3025 return EmptyCast.Create (expr, enum_type);
3029 // Performs user-operator overloading
3031 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3034 if (oper == Operator.LogicalAnd)
3035 user_oper = Operator.BitwiseAnd;
3036 else if (oper == Operator.LogicalOr)
3037 user_oper = Operator.BitwiseOr;
3041 string op = GetOperatorMetadataName (user_oper);
3043 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3044 MethodGroupExpr right_operators = null;
3046 if (!TypeManager.IsEqual (r, l)) {
3047 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3048 if (right_operators == null && left_operators == null)
3050 } else if (left_operators == null) {
3054 ArrayList args = new ArrayList (2);
3055 Argument larg = new Argument (left);
3057 Argument rarg = new Argument (right);
3060 MethodGroupExpr union;
3063 // User-defined operator implementations always take precedence
3064 // over predefined operator implementations
3066 if (left_operators != null && right_operators != null) {
3067 if (IsPredefinedUserOperator (l, user_oper)) {
3068 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3070 union = left_operators;
3071 } else if (IsPredefinedUserOperator (r, user_oper)) {
3072 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3074 union = right_operators;
3076 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3078 } else if (left_operators != null) {
3079 union = left_operators;
3081 union = right_operators;
3084 union = union.OverloadResolve (ec, ref args, true, loc);
3088 Expression oper_expr;
3090 // TODO: CreateExpressionTree is allocated every time
3091 if (user_oper != oper) {
3092 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3093 oper == Operator.LogicalAnd, loc).Resolve (ec);
3095 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3098 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3099 // and not invoke user operator
3101 if ((oper & Operator.EqualityMask) != 0) {
3102 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3103 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3104 type = TypeManager.bool_type;
3105 if (left is NullLiteral || right is NullLiteral)
3106 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3107 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3109 // Two System.Delegate(s) are never equal
3121 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3126 private void CheckUselessComparison (Constant c, Type type)
3128 if (c == null || !IsTypeIntegral (type)
3129 || c is StringConstant
3130 || c is BoolConstant
3131 || c is FloatConstant
3132 || c is DoubleConstant
3133 || c is DecimalConstant
3139 if (c is ULongConstant) {
3140 ulong uvalue = ((ULongConstant) c).Value;
3141 if (uvalue > long.MaxValue) {
3142 if (type == TypeManager.byte_type ||
3143 type == TypeManager.sbyte_type ||
3144 type == TypeManager.short_type ||
3145 type == TypeManager.ushort_type ||
3146 type == TypeManager.int32_type ||
3147 type == TypeManager.uint32_type ||
3148 type == TypeManager.int64_type ||
3149 type == TypeManager.char_type)
3150 WarnUselessComparison (type);
3153 value = (long) uvalue;
3155 else if (c is ByteConstant)
3156 value = ((ByteConstant) c).Value;
3157 else if (c is SByteConstant)
3158 value = ((SByteConstant) c).Value;
3159 else if (c is ShortConstant)
3160 value = ((ShortConstant) c).Value;
3161 else if (c is UShortConstant)
3162 value = ((UShortConstant) c).Value;
3163 else if (c is IntConstant)
3164 value = ((IntConstant) c).Value;
3165 else if (c is UIntConstant)
3166 value = ((UIntConstant) c).Value;
3167 else if (c is LongConstant)
3168 value = ((LongConstant) c).Value;
3169 else if (c is CharConstant)
3170 value = ((CharConstant)c).Value;
3175 if (IsValueOutOfRange (value, type))
3176 WarnUselessComparison (type);
3179 static bool IsValueOutOfRange (long value, Type type)
3181 if (IsTypeUnsigned (type) && value < 0)
3183 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3184 type == TypeManager.byte_type && value >= 0x100 ||
3185 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3186 type == TypeManager.ushort_type && value >= 0x10000 ||
3187 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3188 type == TypeManager.uint32_type && value >= 0x100000000;
3191 static bool IsBuildInEqualityOperator (Type t)
3193 return t == TypeManager.object_type || t == TypeManager.string_type ||
3194 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3197 static bool IsPredefinedUserOperator (Type t, Operator op)
3200 // Some predefined types have user operators
3202 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3205 private static bool IsTypeIntegral (Type type)
3207 return type == TypeManager.uint64_type ||
3208 type == TypeManager.int64_type ||
3209 type == TypeManager.uint32_type ||
3210 type == TypeManager.int32_type ||
3211 type == TypeManager.ushort_type ||
3212 type == TypeManager.short_type ||
3213 type == TypeManager.sbyte_type ||
3214 type == TypeManager.byte_type ||
3215 type == TypeManager.char_type;
3218 private static bool IsTypeUnsigned (Type type)
3220 return type == TypeManager.uint64_type ||
3221 type == TypeManager.uint32_type ||
3222 type == TypeManager.ushort_type ||
3223 type == TypeManager.byte_type ||
3224 type == TypeManager.char_type;
3227 private void WarnUselessComparison (Type type)
3229 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}'",
3230 TypeManager.CSharpName (type));
3234 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3235 /// context of a conditional bool expression. This function will return
3236 /// false if it is was possible to use EmitBranchable, or true if it was.
3238 /// The expression's code is generated, and we will generate a branch to `target'
3239 /// if the resulting expression value is equal to isTrue
3241 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3243 ILGenerator ig = ec.ig;
3246 // This is more complicated than it looks, but its just to avoid
3247 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3248 // but on top of that we want for == and != to use a special path
3249 // if we are comparing against null
3251 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3252 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3255 // put the constant on the rhs, for simplicity
3257 if (left is Constant) {
3258 Expression swap = right;
3263 if (((Constant) right).IsZeroInteger) {
3264 left.EmitBranchable (ec, target, my_on_true);
3267 if (right.Type == TypeManager.bool_type) {
3268 // right is a boolean, and it's not 'false' => it is 'true'
3269 left.EmitBranchable (ec, target, !my_on_true);
3273 } else if (oper == Operator.LogicalAnd) {
3276 Label tests_end = ig.DefineLabel ();
3278 left.EmitBranchable (ec, tests_end, false);
3279 right.EmitBranchable (ec, target, true);
3280 ig.MarkLabel (tests_end);
3283 // This optimizes code like this
3284 // if (true && i > 4)
3286 if (!(left is Constant))
3287 left.EmitBranchable (ec, target, false);
3289 if (!(right is Constant))
3290 right.EmitBranchable (ec, target, false);
3295 } else if (oper == Operator.LogicalOr){
3297 left.EmitBranchable (ec, target, true);
3298 right.EmitBranchable (ec, target, true);
3301 Label tests_end = ig.DefineLabel ();
3302 left.EmitBranchable (ec, tests_end, true);
3303 right.EmitBranchable (ec, target, false);
3304 ig.MarkLabel (tests_end);
3309 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3310 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3311 oper == Operator.Equality || oper == Operator.Inequality)) {
3312 base.EmitBranchable (ec, target, on_true);
3320 bool is_float = IsFloat (t);
3321 bool is_unsigned = is_float || IsUnsigned (t);
3324 case Operator.Equality:
3326 ig.Emit (OpCodes.Beq, target);
3328 ig.Emit (OpCodes.Bne_Un, target);
3331 case Operator.Inequality:
3333 ig.Emit (OpCodes.Bne_Un, target);
3335 ig.Emit (OpCodes.Beq, target);
3338 case Operator.LessThan:
3340 if (is_unsigned && !is_float)
3341 ig.Emit (OpCodes.Blt_Un, target);
3343 ig.Emit (OpCodes.Blt, target);
3346 ig.Emit (OpCodes.Bge_Un, target);
3348 ig.Emit (OpCodes.Bge, target);
3351 case Operator.GreaterThan:
3353 if (is_unsigned && !is_float)
3354 ig.Emit (OpCodes.Bgt_Un, target);
3356 ig.Emit (OpCodes.Bgt, target);
3359 ig.Emit (OpCodes.Ble_Un, target);
3361 ig.Emit (OpCodes.Ble, target);
3364 case Operator.LessThanOrEqual:
3366 if (is_unsigned && !is_float)
3367 ig.Emit (OpCodes.Ble_Un, target);
3369 ig.Emit (OpCodes.Ble, target);
3372 ig.Emit (OpCodes.Bgt_Un, target);
3374 ig.Emit (OpCodes.Bgt, target);
3378 case Operator.GreaterThanOrEqual:
3380 if (is_unsigned && !is_float)
3381 ig.Emit (OpCodes.Bge_Un, target);
3383 ig.Emit (OpCodes.Bge, target);
3386 ig.Emit (OpCodes.Blt_Un, target);
3388 ig.Emit (OpCodes.Blt, target);
3391 throw new InternalErrorException (oper.ToString ());
3395 public override void Emit (EmitContext ec)
3397 EmitOperator (ec, left.Type);
3400 protected virtual void EmitOperator (EmitContext ec, Type l)
3402 ILGenerator ig = ec.ig;
3405 // Handle short-circuit operators differently
3408 if ((oper & Operator.LogicalMask) != 0) {
3409 Label load_result = ig.DefineLabel ();
3410 Label end = ig.DefineLabel ();
3412 bool is_or = oper == Operator.LogicalOr;
3413 left.EmitBranchable (ec, load_result, is_or);
3415 ig.Emit (OpCodes.Br_S, end);
3417 ig.MarkLabel (load_result);
3418 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3426 // Optimize zero-based operations
3428 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3430 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3431 Constant rc = right as Constant;
3432 if (rc != null && rc.IsDefaultValue) {
3438 EmitOperatorOpcode (ec, oper, l);
3441 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3442 // expression because that would wrap lifted binary operation
3444 if (enum_conversion != null)
3445 enum_conversion.Emit (ec);
3448 public override void EmitSideEffect (EmitContext ec)
3450 if ((oper & Operator.LogicalMask) != 0 ||
3451 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3452 base.EmitSideEffect (ec);
3454 left.EmitSideEffect (ec);
3455 right.EmitSideEffect (ec);
3459 protected override void CloneTo (CloneContext clonectx, Expression t)
3461 Binary target = (Binary) t;
3463 target.left = left.Clone (clonectx);
3464 target.right = right.Clone (clonectx);
3467 public override Expression CreateExpressionTree (EmitContext ec)
3469 return CreateExpressionTree (ec, null);
3472 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3475 bool lift_arg = false;
3478 case Operator.Addition:
3479 if (method == null && ec.CheckState && !IsFloat (type))
3480 method_name = "AddChecked";
3482 method_name = "Add";
3484 case Operator.BitwiseAnd:
3485 method_name = "And";
3487 case Operator.BitwiseOr:
3490 case Operator.Division:
3491 method_name = "Divide";
3493 case Operator.Equality:
3494 method_name = "Equal";
3497 case Operator.ExclusiveOr:
3498 method_name = "ExclusiveOr";
3500 case Operator.GreaterThan:
3501 method_name = "GreaterThan";
3504 case Operator.GreaterThanOrEqual:
3505 method_name = "GreaterThanOrEqual";
3508 case Operator.Inequality:
3509 method_name = "NotEqual";
3512 case Operator.LeftShift:
3513 method_name = "LeftShift";
3515 case Operator.LessThan:
3516 method_name = "LessThan";
3519 case Operator.LessThanOrEqual:
3520 method_name = "LessThanOrEqual";
3523 case Operator.LogicalAnd:
3524 method_name = "AndAlso";
3526 case Operator.LogicalOr:
3527 method_name = "OrElse";
3529 case Operator.Modulus:
3530 method_name = "Modulo";
3532 case Operator.Multiply:
3533 if (method == null && ec.CheckState && !IsFloat (type))
3534 method_name = "MultiplyChecked";
3536 method_name = "Multiply";
3538 case Operator.RightShift:
3539 method_name = "RightShift";
3541 case Operator.Subtraction:
3542 if (method == null && ec.CheckState && !IsFloat (type))
3543 method_name = "SubtractChecked";
3545 method_name = "Subtract";
3549 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3552 ArrayList args = new ArrayList (2);
3553 args.Add (new Argument (left.CreateExpressionTree (ec)));
3554 args.Add (new Argument (right.CreateExpressionTree (ec)));
3555 if (method != null) {
3557 args.Add (new Argument (new BoolConstant (false, loc)));
3559 args.Add (new Argument (method.CreateExpressionTree (ec)));
3562 return CreateExpressionFactoryCall (method_name, args);
3567 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3568 // b, c, d... may be strings or objects.
3570 public class StringConcat : Expression {
3571 ArrayList arguments;
3573 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3576 type = TypeManager.string_type;
3577 eclass = ExprClass.Value;
3579 arguments = new ArrayList (2);
3584 public override Expression CreateExpressionTree (EmitContext ec)
3586 Argument arg = (Argument) arguments [0];
3587 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3591 // Creates nested calls tree from an array of arguments used for IL emit
3593 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3595 ArrayList concat_args = new ArrayList (2);
3596 ArrayList add_args = new ArrayList (3);
3598 concat_args.Add (left);
3599 add_args.Add (new Argument (left_etree));
3601 concat_args.Add (arguments [pos]);
3602 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3604 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3608 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3612 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3614 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3615 if (++pos == arguments.Count)
3618 left = new Argument (new EmptyExpression (method.Type));
3619 return CreateExpressionAddCall (ec, left, expr, pos);
3622 public override Expression DoResolve (EmitContext ec)
3627 public void Append (EmitContext ec, Expression operand)
3632 StringConstant sc = operand as StringConstant;
3634 if (arguments.Count != 0) {
3635 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3636 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3637 if (last_expr_constant != null) {
3638 last_argument.Expr = new StringConstant (
3639 last_expr_constant.Value + sc.Value, sc.Location);
3645 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3647 StringConcat concat_oper = operand as StringConcat;
3648 if (concat_oper != null) {
3649 arguments.AddRange (concat_oper.arguments);
3654 arguments.Add (new Argument (operand));
3657 Expression CreateConcatMemberExpression ()
3659 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3662 public override void Emit (EmitContext ec)
3664 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3665 concat = concat.Resolve (ec);
3670 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3672 foreach (Argument a in arguments)
3673 a.Expr.MutateHoistedGenericType (storey);
3678 // User-defined conditional logical operator
3680 public class ConditionalLogicalOperator : UserOperatorCall {
3681 readonly bool is_and;
3684 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3685 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3686 : base (oper_method, arguments, expr_tree, loc)
3688 this.is_and = is_and;
3691 public override Expression DoResolve (EmitContext ec)
3693 MethodInfo method = (MethodInfo)mg;
3694 type = TypeManager.TypeToCoreType (method.ReturnType);
3695 AParametersCollection pd = TypeManager.GetParameterData (method);
3696 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3697 Report.Error (217, loc,
3698 "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",
3699 TypeManager.CSharpSignature (method));
3703 Expression left_dup = new EmptyExpression (type);
3704 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3705 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3706 if (op_true == null || op_false == null) {
3707 Report.Error (218, loc,
3708 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3709 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3713 oper = is_and ? op_false : op_true;
3714 eclass = ExprClass.Value;
3718 public override void Emit (EmitContext ec)
3720 ILGenerator ig = ec.ig;
3721 Label end_target = ig.DefineLabel ();
3724 // Emit and duplicate left argument
3726 ((Argument)arguments [0]).Expr.Emit (ec);
3727 ig.Emit (OpCodes.Dup);
3728 arguments.RemoveAt (0);
3730 oper.EmitBranchable (ec, end_target, true);
3732 ig.MarkLabel (end_target);
3736 public class PointerArithmetic : Expression {
3737 Expression left, right;
3741 // We assume that `l' is always a pointer
3743 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3752 public override Expression CreateExpressionTree (EmitContext ec)
3754 Error_PointerInsideExpressionTree ();
3758 public override Expression DoResolve (EmitContext ec)
3760 eclass = ExprClass.Variable;
3762 if (left.Type == TypeManager.void_ptr_type) {
3763 Error (242, "The operation in question is undefined on void pointers");
3770 public override void Emit (EmitContext ec)
3772 Type op_type = left.Type;
3773 ILGenerator ig = ec.ig;
3775 // It must be either array or fixed buffer
3777 if (TypeManager.HasElementType (op_type)) {
3778 element = TypeManager.GetElementType (op_type);
3780 FieldExpr fe = left as FieldExpr;
3782 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3787 int size = GetTypeSize (element);
3788 Type rtype = right.Type;
3790 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3792 // handle (pointer - pointer)
3796 ig.Emit (OpCodes.Sub);
3800 ig.Emit (OpCodes.Sizeof, element);
3802 IntLiteral.EmitInt (ig, size);
3803 ig.Emit (OpCodes.Div);
3805 ig.Emit (OpCodes.Conv_I8);
3808 // handle + and - on (pointer op int)
3810 Constant left_const = left as Constant;
3811 if (left_const != null) {
3813 // Optimize ((T*)null) pointer operations
3815 if (left_const.IsDefaultValue) {
3816 left = EmptyExpression.Null;
3824 Constant right_const = right as Constant;
3825 if (right_const != null) {
3827 // Optimize 0-based arithmetic
3829 if (right_const.IsDefaultValue)
3833 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3837 ig.Emit (OpCodes.Sizeof, element);
3838 right = EmptyExpression.Null;
3843 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3844 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3845 ig.Emit (OpCodes.Conv_I);
3846 } else if (rtype == TypeManager.uint32_type) {
3847 ig.Emit (OpCodes.Conv_U);
3850 if (right_const == null && size != 1){
3852 ig.Emit (OpCodes.Sizeof, element);
3854 IntLiteral.EmitInt (ig, size);
3855 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3856 ig.Emit (OpCodes.Conv_I8);
3858 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3861 if (left_const == null) {
3862 if (rtype == TypeManager.int64_type)
3863 ig.Emit (OpCodes.Conv_I);
3864 else if (rtype == TypeManager.uint64_type)
3865 ig.Emit (OpCodes.Conv_U);
3867 Binary.EmitOperatorOpcode (ec, op, op_type);
3874 /// Implements the ternary conditional operator (?:)
3876 public class Conditional : Expression {
3877 Expression expr, true_expr, false_expr;
3879 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3882 this.true_expr = true_expr;
3883 this.false_expr = false_expr;
3884 this.loc = expr.Location;
3887 public Expression Expr {
3893 public Expression TrueExpr {
3899 public Expression FalseExpr {
3905 public override Expression CreateExpressionTree (EmitContext ec)
3907 ArrayList args = new ArrayList (3);
3908 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3909 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3910 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3911 return CreateExpressionFactoryCall ("Condition", args);
3914 public override Expression DoResolve (EmitContext ec)
3916 expr = expr.Resolve (ec);
3921 if (expr.Type != TypeManager.bool_type){
3922 expr = Expression.ResolveBoolean (
3929 Assign ass = expr as Assign;
3930 if (ass != null && ass.Source is Constant) {
3931 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3934 true_expr = true_expr.Resolve (ec);
3935 false_expr = false_expr.Resolve (ec);
3937 if (true_expr == null || false_expr == null)
3940 eclass = ExprClass.Value;
3941 Type true_type = true_expr.Type;
3942 Type false_type = false_expr.Type;
3946 // First, if an implicit conversion exists from true_expr
3947 // to false_expr, then the result type is of type false_expr.Type
3949 if (!TypeManager.IsEqual (true_type, false_type)) {
3950 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3953 // Check if both can convert implicitl to each other's type
3955 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3957 "Can not compute type of conditional expression " +
3958 "as `" + TypeManager.CSharpName (true_expr.Type) +
3959 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3960 "' convert implicitly to each other");
3965 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3968 Report.Error (173, loc,
3969 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3970 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3975 // Dead code optimalization
3976 Constant c = expr as Constant;
3978 bool is_false = c.IsDefaultValue;
3979 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3980 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3986 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3988 expr.MutateHoistedGenericType (storey);
3989 true_expr.MutateHoistedGenericType (storey);
3990 false_expr.MutateHoistedGenericType (storey);
3991 type = storey.MutateType (type);
3994 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3999 public override void Emit (EmitContext ec)
4001 ILGenerator ig = ec.ig;
4002 Label false_target = ig.DefineLabel ();
4003 Label end_target = ig.DefineLabel ();
4005 expr.EmitBranchable (ec, false_target, false);
4006 true_expr.Emit (ec);
4008 if (type.IsInterface) {
4009 LocalBuilder temp = ec.GetTemporaryLocal (type);
4010 ig.Emit (OpCodes.Stloc, temp);
4011 ig.Emit (OpCodes.Ldloc, temp);
4012 ec.FreeTemporaryLocal (temp, type);
4015 ig.Emit (OpCodes.Br, end_target);
4016 ig.MarkLabel (false_target);
4017 false_expr.Emit (ec);
4018 ig.MarkLabel (end_target);
4021 protected override void CloneTo (CloneContext clonectx, Expression t)
4023 Conditional target = (Conditional) t;
4025 target.expr = expr.Clone (clonectx);
4026 target.true_expr = true_expr.Clone (clonectx);
4027 target.false_expr = false_expr.Clone (clonectx);
4031 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4032 LocalTemporary temp;
4035 public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
4036 public abstract bool IsFixed { get; }
4037 public abstract bool IsRef { get; }
4038 public abstract string Name { get; }
4039 public abstract void SetHasAddressTaken ();
4042 // Variable IL data, it has to be protected to encapsulate hoisted variables
4044 protected abstract ILocalVariable Variable { get; }
4047 // Variable flow-analysis data
4049 public abstract VariableInfo VariableInfo { get; }
4052 public void AddressOf (EmitContext ec, AddressOp mode)
4054 HoistedVariable hv = GetHoistedVariable (ec);
4056 hv.AddressOf (ec, mode);
4060 Variable.EmitAddressOf (ec);
4063 public override void Emit (EmitContext ec)
4068 public override void EmitSideEffect (EmitContext ec)
4074 // This method is used by parameters that are references, that are
4075 // being passed as references: we only want to pass the pointer (that
4076 // is already stored in the parameter, not the address of the pointer,
4077 // and not the value of the variable).
4079 public void EmitLoad (EmitContext ec)
4084 public void Emit (EmitContext ec, bool leave_copy)
4086 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4088 HoistedVariable hv = GetHoistedVariable (ec);
4090 hv.Emit (ec, leave_copy);
4098 // If we are a reference, we loaded on the stack a pointer
4099 // Now lets load the real value
4101 LoadFromPtr (ec.ig, type);
4105 ec.ig.Emit (OpCodes.Dup);
4108 temp = new LocalTemporary (Type);
4114 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4115 bool prepare_for_load)
4117 HoistedVariable hv = GetHoistedVariable (ec);
4119 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4123 New n_source = source as New;
4124 if (n_source != null) {
4125 if (!n_source.Emit (ec, this)) {
4138 ec.ig.Emit (OpCodes.Dup);
4140 temp = new LocalTemporary (Type);
4146 StoreFromPtr (ec.ig, type);
4148 Variable.EmitAssign (ec);
4156 public bool IsHoisted {
4157 get { return GetHoistedVariable (null) != null; }
4160 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4162 type = storey.MutateType (type);
4169 public class LocalVariableReference : VariableReference {
4170 readonly string name;
4172 public LocalInfo local_info;
4175 public LocalVariableReference (Block block, string name, Location l)
4180 eclass = ExprClass.Variable;
4184 // Setting `is_readonly' to false will allow you to create a writable
4185 // reference to a read-only variable. This is used by foreach and using.
4187 public LocalVariableReference (Block block, string name, Location l,
4188 LocalInfo local_info, bool is_readonly)
4189 : this (block, name, l)
4191 this.local_info = local_info;
4192 this.is_readonly = is_readonly;
4195 public override VariableInfo VariableInfo {
4196 get { return local_info.VariableInfo; }
4199 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4201 return local_info.HoistedVariableReference;
4205 // A local variable is always fixed
4207 public override bool IsFixed {
4208 get { return true; }
4211 public override bool IsRef {
4212 get { return false; }
4215 public bool IsReadOnly {
4216 get { return is_readonly; }
4219 public override string Name {
4220 get { return name; }
4223 public bool VerifyAssigned (EmitContext ec)
4225 VariableInfo variable_info = local_info.VariableInfo;
4226 return variable_info == null || variable_info.IsAssigned (ec, loc);
4229 void ResolveLocalInfo ()
4231 if (local_info == null) {
4232 local_info = Block.GetLocalInfo (Name);
4233 type = local_info.VariableType;
4234 is_readonly = local_info.ReadOnly;
4238 public override void SetHasAddressTaken ()
4240 local_info.AddressTaken = true;
4243 public override Expression CreateExpressionTree (EmitContext ec)
4245 ArrayList arg = new ArrayList (1);
4246 arg.Add (new Argument (this));
4247 return CreateExpressionFactoryCall ("Constant", arg);
4250 Expression DoResolveBase (EmitContext ec)
4252 type = local_info.VariableType;
4254 Expression e = Block.GetConstantExpression (Name);
4256 return e.Resolve (ec);
4258 VerifyAssigned (ec);
4261 // If we are referencing a variable from the external block
4262 // flag it for capturing
4264 if (ec.MustCaptureVariable (local_info)) {
4265 if (local_info.AddressTaken)
4266 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4268 if (ec.IsVariableCapturingRequired) {
4269 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4270 storey.CaptureLocalVariable (ec, local_info);
4277 public override Expression DoResolve (EmitContext ec)
4279 ResolveLocalInfo ();
4280 local_info.Used = true;
4282 if (type == null && local_info.Type is VarExpr) {
4283 local_info.VariableType = TypeManager.object_type;
4284 Error_VariableIsUsedBeforeItIsDeclared (Name);
4288 return DoResolveBase (ec);
4291 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4293 ResolveLocalInfo ();
4296 if (right_side == EmptyExpression.OutAccess)
4297 local_info.Used = true;
4299 // Infer implicitly typed local variable
4301 VarExpr ve = local_info.Type as VarExpr;
4303 if (!ve.InferType (ec, right_side))
4305 type = local_info.VariableType = ve.Type;
4312 if (right_side == EmptyExpression.OutAccess) {
4313 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4314 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4315 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4316 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4317 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4318 } else if (right_side == EmptyExpression.UnaryAddress) {
4319 code = 459; msg = "Cannot take the address of {1} `{0}'";
4321 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4323 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4324 } else if (VariableInfo != null) {
4325 VariableInfo.SetAssigned (ec);
4328 return DoResolveBase (ec);
4331 public override int GetHashCode ()
4333 return Name.GetHashCode ();
4336 public override bool Equals (object obj)
4338 LocalVariableReference lvr = obj as LocalVariableReference;
4342 return Name == lvr.Name && Block == lvr.Block;
4345 protected override ILocalVariable Variable {
4346 get { return local_info; }
4349 public override string ToString ()
4351 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4354 protected override void CloneTo (CloneContext clonectx, Expression t)
4356 LocalVariableReference target = (LocalVariableReference) t;
4358 target.Block = clonectx.LookupBlock (Block);
4359 if (local_info != null)
4360 target.local_info = clonectx.LookupVariable (local_info);
4365 /// This represents a reference to a parameter in the intermediate
4368 public class ParameterReference : VariableReference {
4369 readonly ToplevelParameterInfo pi;
4371 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4377 public override bool IsRef {
4378 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4381 bool HasOutModifier {
4382 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4385 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4387 return pi.Parameter.HoistedVariableReference;
4391 // A ref or out parameter is classified as a moveable variable, even
4392 // if the argument given for the parameter is a fixed variable
4394 public override bool IsFixed {
4395 get { return !IsRef; }
4398 public override string Name {
4399 get { return Parameter.Name; }
4402 public Parameter Parameter {
4403 get { return pi.Parameter; }
4406 public override VariableInfo VariableInfo {
4407 get { return pi.VariableInfo; }
4410 protected override ILocalVariable Variable {
4411 get { return Parameter; }
4414 public bool IsAssigned (EmitContext ec, Location loc)
4416 // HACK: Variables are not captured in probing mode
4417 if (ec.IsInProbingMode)
4420 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4423 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4427 public override void SetHasAddressTaken ()
4429 Parameter.HasAddressTaken = true;
4432 void SetAssigned (EmitContext ec)
4434 if (HasOutModifier && ec.DoFlowAnalysis)
4435 ec.CurrentBranching.SetAssigned (VariableInfo);
4438 bool DoResolveBase (EmitContext ec)
4440 type = pi.ParameterType;
4441 eclass = ExprClass.Variable;
4443 AnonymousExpression am = ec.CurrentAnonymousMethod;
4447 Block b = ec.CurrentBlock;
4449 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4450 for (int i = 0; i < p.Length; ++i) {
4451 if (p [i] != Parameter)
4455 // Skip closest anonymous method parameters
4457 if (b == ec.CurrentBlock && !am.IsIterator)
4461 Report.Error (1628, loc,
4462 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4463 Name, am.ContainerType);
4471 b = b.Toplevel.Parent;
4474 if (pi.Parameter.HasAddressTaken)
4475 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4477 if (ec.IsVariableCapturingRequired) {
4478 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4479 storey.CaptureParameter (ec, this);
4485 public override int GetHashCode ()
4487 return Name.GetHashCode ();
4490 public override bool Equals (object obj)
4492 ParameterReference pr = obj as ParameterReference;
4496 return Name == pr.Name;
4499 protected override void CloneTo (CloneContext clonectx, Expression target)
4504 public override Expression CreateExpressionTree (EmitContext ec)
4506 HoistedVariable hv = GetHoistedVariable (ec);
4508 return hv.CreateExpressionTree (ec);
4510 return Parameter.ExpressionTreeVariableReference ();
4514 // Notice that for ref/out parameters, the type exposed is not the
4515 // same type exposed externally.
4518 // externally we expose "int&"
4519 // here we expose "int".
4521 // We record this in "is_ref". This means that the type system can treat
4522 // the type as it is expected, but when we generate the code, we generate
4523 // the alternate kind of code.
4525 public override Expression DoResolve (EmitContext ec)
4527 if (!DoResolveBase (ec))
4530 if (HasOutModifier && ec.DoFlowAnalysis &&
4531 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4537 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4539 if (!DoResolveBase (ec))
4542 // HACK: parameters are not captured when probing is on
4543 if (!ec.IsInProbingMode)
4549 static public void EmitLdArg (ILGenerator ig, int x)
4553 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4554 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4555 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4556 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4557 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4560 ig.Emit (OpCodes.Ldarg, x);
4565 /// Used for arguments to New(), Invocation()
4567 public class Argument {
4568 public enum AType : byte {
4575 public static readonly Argument[] Empty = new Argument [0];
4577 public readonly AType ArgType;
4578 public Expression Expr;
4580 public Argument (Expression expr, AType type)
4583 this.ArgType = type;
4586 public Argument (Expression expr)
4589 this.ArgType = AType.Expression;
4593 get { return Expr.Type; }
4596 public Parameter.Modifier Modifier
4601 return Parameter.Modifier.OUT;
4604 return Parameter.Modifier.REF;
4607 return Parameter.Modifier.NONE;
4612 public string GetSignatureForError ()
4614 if (Expr.eclass == ExprClass.MethodGroup)
4615 return Expr.ExprClassName;
4617 return TypeManager.CSharpName (Expr.Type);
4620 public bool ResolveMethodGroup (EmitContext ec)
4622 SimpleName sn = Expr as SimpleName;
4624 Expr = sn.GetMethodGroup ();
4626 // FIXME: csc doesn't report any error if you try to use `ref' or
4627 // `out' in a delegate creation expression.
4628 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4635 public bool Resolve (EmitContext ec, Location loc)
4640 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4641 // Verify that the argument is readable
4642 if (ArgType != AType.Out)
4643 Expr = Expr.Resolve (ec);
4645 // Verify that the argument is writeable
4646 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4647 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4649 return Expr != null;
4653 public void Emit (EmitContext ec)
4655 if (ArgType != AType.Ref && ArgType != AType.Out) {
4660 AddressOp mode = AddressOp.Store;
4661 if (ArgType == AType.Ref)
4662 mode |= AddressOp.Load;
4664 IMemoryLocation ml = (IMemoryLocation) Expr;
4665 ParameterReference pr = ml as ParameterReference;
4668 // ParameterReferences might already be references, so we want
4669 // to pass just the value
4671 if (pr != null && pr.IsRef)
4674 ml.AddressOf (ec, mode);
4677 public Argument Clone (CloneContext clonectx)
4679 return new Argument (Expr.Clone (clonectx), ArgType);
4684 /// Invocation of methods or delegates.
4686 public class Invocation : ExpressionStatement {
4687 protected ArrayList Arguments;
4688 protected Expression expr;
4689 protected MethodGroupExpr mg;
4690 bool arguments_resolved;
4693 // arguments is an ArrayList, but we do not want to typecast,
4694 // as it might be null.
4696 public Invocation (Expression expr, ArrayList arguments)
4698 SimpleName sn = expr as SimpleName;
4700 this.expr = sn.GetMethodGroup ();
4704 Arguments = arguments;
4706 loc = expr.Location;
4709 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4710 : this (expr, arguments)
4712 this.arguments_resolved = arguments_resolved;
4715 public override Expression CreateExpressionTree (EmitContext ec)
4720 // Special conversion for nested expression trees
4722 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4723 args = new ArrayList (1);
4724 args.Add (new Argument (this));
4725 return CreateExpressionFactoryCall ("Quote", args);
4728 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4730 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4733 args = new ArrayList (arg_count);
4736 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4738 args.Add (new Argument (new NullLiteral (loc)));
4740 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4743 // Use extension argument when exists
4746 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4748 args.Add (new Argument (e));
4751 if (Arguments != null) {
4752 foreach (Argument a in Arguments) {
4753 Expression e = a.Expr.CreateExpressionTree (ec);
4755 args.Add (new Argument (e));
4760 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4762 return CreateExpressionFactoryCall ("Call", args);
4765 public override Expression DoResolve (EmitContext ec)
4767 // Don't resolve already resolved expression
4768 if (eclass != ExprClass.Invalid)
4771 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4772 if (expr_resolved == null)
4775 mg = expr_resolved as MethodGroupExpr;
4777 Type expr_type = expr_resolved.Type;
4779 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4780 return (new DelegateInvocation (
4781 expr_resolved, Arguments, loc)).Resolve (ec);
4784 MemberExpr me = expr_resolved as MemberExpr;
4786 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4790 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4792 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4793 expr_resolved.GetSignatureForError ());
4797 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4801 // Next, evaluate all the expressions in the argument list
4803 if (Arguments != null && !arguments_resolved) {
4804 for (int i = 0; i < Arguments.Count; ++i)
4806 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4811 mg = DoResolveOverload (ec);
4815 MethodInfo method = (MethodInfo)mg;
4816 if (method != null) {
4817 type = TypeManager.TypeToCoreType (method.ReturnType);
4819 // TODO: this is a copy of mg.ResolveMemberAccess method
4820 Expression iexpr = mg.InstanceExpression;
4821 if (method.IsStatic) {
4822 if (iexpr == null ||
4823 iexpr is This || iexpr is EmptyExpression ||
4824 mg.IdenticalTypeName) {
4825 mg.InstanceExpression = null;
4827 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4831 if (iexpr == null) {
4832 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4837 if (type.IsPointer){
4845 // Only base will allow this invocation to happen.
4847 if (mg.IsBase && method.IsAbstract){
4848 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4852 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4854 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4856 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4860 IsSpecialMethodInvocation (method, loc);
4862 if (mg.InstanceExpression != null)
4863 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4865 eclass = ExprClass.Value;
4869 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4871 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4874 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4876 if (!TypeManager.IsSpecialMethod (method))
4879 Report.SymbolRelatedToPreviousError (method);
4880 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4881 TypeManager.CSharpSignature (method, true));
4887 /// Emits a list of resolved Arguments that are in the arguments
4890 /// The MethodBase argument might be null if the
4891 /// emission of the arguments is known not to contain
4892 /// a `params' field (for example in constructors or other routines
4893 /// that keep their arguments in this structure)
4895 /// if `dup_args' is true, a copy of the arguments will be left
4896 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4897 /// which will be duplicated before any other args. Only EmitCall
4898 /// should be using this interface.
4900 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4902 if (arguments == null)
4905 int top = arguments.Count;
4906 LocalTemporary [] temps = null;
4908 if (dup_args && top != 0)
4909 temps = new LocalTemporary [top];
4911 int argument_index = 0;
4913 for (int i = 0; i < top; i++) {
4914 a = (Argument) arguments [argument_index++];
4917 ec.ig.Emit (OpCodes.Dup);
4918 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4923 if (this_arg != null)
4926 for (int i = 0; i < top; i ++) {
4927 temps [i].Emit (ec);
4928 temps [i].Release (ec);
4933 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4935 AParametersCollection pd = TypeManager.GetParameterData (mb);
4937 Argument a = (Argument) arguments [pd.Count - 1];
4938 Arglist list = (Arglist) a.Expr;
4940 return list.ArgumentTypes;
4944 /// This checks the ConditionalAttribute on the method
4946 public static bool IsMethodExcluded (MethodBase method, Location loc)
4948 if (method.IsConstructor)
4951 method = TypeManager.DropGenericMethodArguments (method);
4952 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4953 IMethodData md = TypeManager.GetMethod (method);
4955 return md.IsExcluded ();
4957 // For some methods (generated by delegate class) GetMethod returns null
4958 // because they are not included in builder_to_method table
4962 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4966 /// is_base tells whether we want to force the use of the `call'
4967 /// opcode instead of using callvirt. Call is required to call
4968 /// a specific method, while callvirt will always use the most
4969 /// recent method in the vtable.
4971 /// is_static tells whether this is an invocation on a static method
4973 /// instance_expr is an expression that represents the instance
4974 /// it must be non-null if is_static is false.
4976 /// method is the method to invoke.
4978 /// Arguments is the list of arguments to pass to the method or constructor.
4980 public static void EmitCall (EmitContext ec, bool is_base,
4981 Expression instance_expr,
4982 MethodBase method, ArrayList Arguments, Location loc)
4984 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4987 // `dup_args' leaves an extra copy of the arguments on the stack
4988 // `omit_args' does not leave any arguments at all.
4989 // So, basically, you could make one call with `dup_args' set to true,
4990 // and then another with `omit_args' set to true, and the two calls
4991 // would have the same set of arguments. However, each argument would
4992 // only have been evaluated once.
4993 public static void EmitCall (EmitContext ec, bool is_base,
4994 Expression instance_expr,
4995 MethodBase method, ArrayList Arguments, Location loc,
4996 bool dup_args, bool omit_args)
4998 ILGenerator ig = ec.ig;
4999 bool struct_call = false;
5000 bool this_call = false;
5001 LocalTemporary this_arg = null;
5003 Type decl_type = method.DeclaringType;
5005 if (IsMethodExcluded (method, loc))
5008 bool is_static = method.IsStatic;
5010 this_call = instance_expr is This;
5011 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type) || (!this_call && TypeManager.IsStruct (instance_expr.Type)))
5015 // If this is ourselves, push "this"
5019 Type iexpr_type = instance_expr.Type;
5022 // Push the instance expression
5024 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5026 // Special case: calls to a function declared in a
5027 // reference-type with a value-type argument need
5028 // to have their value boxed.
5029 if (TypeManager.IsStruct (decl_type) ||
5030 TypeManager.IsGenericParameter (iexpr_type)) {
5032 // If the expression implements IMemoryLocation, then
5033 // we can optimize and use AddressOf on the
5036 // If not we have to use some temporary storage for
5038 if (instance_expr is IMemoryLocation) {
5039 ((IMemoryLocation)instance_expr).
5040 AddressOf (ec, AddressOp.LoadStore);
5042 LocalTemporary temp = new LocalTemporary (iexpr_type);
5043 instance_expr.Emit (ec);
5045 temp.AddressOf (ec, AddressOp.Load);
5048 // avoid the overhead of doing this all the time.
5050 t = TypeManager.GetReferenceType (iexpr_type);
5052 instance_expr.Emit (ec);
5053 ig.Emit (OpCodes.Box, instance_expr.Type);
5054 t = TypeManager.object_type;
5057 instance_expr.Emit (ec);
5058 t = instance_expr.Type;
5062 ig.Emit (OpCodes.Dup);
5063 if (Arguments != null && Arguments.Count != 0) {
5064 this_arg = new LocalTemporary (t);
5065 this_arg.Store (ec);
5072 EmitArguments (ec, Arguments, dup_args, this_arg);
5075 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5076 call_op = OpCodes.Call;
5078 call_op = OpCodes.Callvirt;
5081 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5082 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5086 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5087 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5088 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5095 // and DoFoo is not virtual, you can omit the callvirt,
5096 // because you don't need the null checking behavior.
5098 if (method is MethodInfo)
5099 ig.Emit (call_op, (MethodInfo) method);
5101 ig.Emit (call_op, (ConstructorInfo) method);
5104 public override void Emit (EmitContext ec)
5106 mg.EmitCall (ec, Arguments);
5109 public override void EmitStatement (EmitContext ec)
5114 // Pop the return value if there is one
5116 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5117 ec.ig.Emit (OpCodes.Pop);
5120 protected override void CloneTo (CloneContext clonectx, Expression t)
5122 Invocation target = (Invocation) t;
5124 if (Arguments != null) {
5125 target.Arguments = new ArrayList (Arguments.Count);
5126 foreach (Argument a in Arguments)
5127 target.Arguments.Add (a.Clone (clonectx));
5130 target.expr = expr.Clone (clonectx);
5133 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5135 mg.MutateHoistedGenericType (storey);
5136 if (Arguments != null) {
5137 foreach (Argument a in Arguments)
5138 a.Expr.MutateHoistedGenericType (storey);
5144 // It's either a cast or delegate invocation
5146 public class InvocationOrCast : ExpressionStatement
5149 Expression argument;
5151 public InvocationOrCast (Expression expr, Expression argument)
5154 this.argument = argument;
5155 this.loc = expr.Location;
5158 public override Expression CreateExpressionTree (EmitContext ec)
5160 throw new NotSupportedException ("ET");
5163 public override Expression DoResolve (EmitContext ec)
5165 Expression e = ResolveCore (ec);
5169 return e.Resolve (ec);
5172 Expression ResolveCore (EmitContext ec)
5175 // First try to resolve it as a cast.
5177 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5179 return new Cast (te, argument, loc);
5183 // This can either be a type or a delegate invocation.
5184 // Let's just resolve it and see what we'll get.
5186 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5191 // Ok, so it's a Cast.
5193 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5194 return new Cast (expr, argument, loc);
5197 if (expr.eclass == ExprClass.Namespace) {
5198 expr.Error_UnexpectedKind (null, "type", loc);
5203 // It's a delegate invocation.
5205 if (!TypeManager.IsDelegateType (expr.Type)) {
5206 Error (149, "Method name expected");
5210 ArrayList args = new ArrayList (1);
5211 args.Add (new Argument (argument, Argument.AType.Expression));
5212 return new DelegateInvocation (expr, args, loc);
5215 public override ExpressionStatement ResolveStatement (EmitContext ec)
5217 Expression e = ResolveCore (ec);
5221 ExpressionStatement s = e as ExpressionStatement;
5223 Error_InvalidExpressionStatement ();
5227 return s.ResolveStatement (ec);
5230 public override void Emit (EmitContext ec)
5232 throw new Exception ("Cannot happen");
5235 public override void EmitStatement (EmitContext ec)
5237 throw new Exception ("Cannot happen");
5240 protected override void CloneTo (CloneContext clonectx, Expression t)
5242 InvocationOrCast target = (InvocationOrCast) t;
5244 target.expr = expr.Clone (clonectx);
5245 target.argument = argument.Clone (clonectx);
5251 /// Implements the new expression
5253 public class New : ExpressionStatement, IMemoryLocation {
5254 ArrayList Arguments;
5257 // During bootstrap, it contains the RequestedType,
5258 // but if `type' is not null, it *might* contain a NewDelegate
5259 // (because of field multi-initialization)
5261 Expression RequestedType;
5263 MethodGroupExpr method;
5265 bool is_type_parameter;
5267 public New (Expression requested_type, ArrayList arguments, Location l)
5269 RequestedType = requested_type;
5270 Arguments = arguments;
5275 /// Converts complex core type syntax like 'new int ()' to simple constant
5277 public static Constant Constantify (Type t)
5279 if (t == TypeManager.int32_type)
5280 return new IntConstant (0, Location.Null);
5281 if (t == TypeManager.uint32_type)
5282 return new UIntConstant (0, Location.Null);
5283 if (t == TypeManager.int64_type)
5284 return new LongConstant (0, Location.Null);
5285 if (t == TypeManager.uint64_type)
5286 return new ULongConstant (0, Location.Null);
5287 if (t == TypeManager.float_type)
5288 return new FloatConstant (0, Location.Null);
5289 if (t == TypeManager.double_type)
5290 return new DoubleConstant (0, Location.Null);
5291 if (t == TypeManager.short_type)
5292 return new ShortConstant (0, Location.Null);
5293 if (t == TypeManager.ushort_type)
5294 return new UShortConstant (0, Location.Null);
5295 if (t == TypeManager.sbyte_type)
5296 return new SByteConstant (0, Location.Null);
5297 if (t == TypeManager.byte_type)
5298 return new ByteConstant (0, Location.Null);
5299 if (t == TypeManager.char_type)
5300 return new CharConstant ('\0', Location.Null);
5301 if (t == TypeManager.bool_type)
5302 return new BoolConstant (false, Location.Null);
5303 if (t == TypeManager.decimal_type)
5304 return new DecimalConstant (0, Location.Null);
5305 if (TypeManager.IsEnumType (t))
5306 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5312 // Checks whether the type is an interface that has the
5313 // [ComImport, CoClass] attributes and must be treated
5316 public Expression CheckComImport (EmitContext ec)
5318 if (!type.IsInterface)
5322 // Turn the call into:
5323 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5325 Type real_class = AttributeTester.GetCoClassAttribute (type);
5326 if (real_class == null)
5329 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5330 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5331 return cast.Resolve (ec);
5334 public override Expression CreateExpressionTree (EmitContext ec)
5336 ArrayList args = Arguments == null ?
5337 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5339 if (method == null) {
5340 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5342 args.Add (new Argument (method.CreateExpressionTree (ec)));
5343 if (Arguments != null) {
5345 foreach (Argument a in Arguments) {
5346 expr = a.Expr.CreateExpressionTree (ec);
5348 args.Add (new Argument (expr));
5353 return CreateExpressionFactoryCall ("New", args);
5356 public override Expression DoResolve (EmitContext ec)
5359 // The New DoResolve might be called twice when initializing field
5360 // expressions (see EmitFieldInitializers, the call to
5361 // GetInitializerExpression will perform a resolve on the expression,
5362 // and later the assign will trigger another resolution
5364 // This leads to bugs (#37014)
5367 if (RequestedType is NewDelegate)
5368 return RequestedType;
5372 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5378 if (type.IsPointer) {
5379 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5380 TypeManager.CSharpName (type));
5384 if (Arguments == null) {
5385 Constant c = Constantify (type);
5387 return ReducedExpression.Create (c, this);
5390 if (TypeManager.IsDelegateType (type)) {
5391 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5395 if (type.IsGenericParameter) {
5396 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5398 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5399 Error (304, String.Format (
5400 "Cannot create an instance of the " +
5401 "variable type '{0}' because it " +
5402 "doesn't have the new() constraint",
5407 if ((Arguments != null) && (Arguments.Count != 0)) {
5408 Error (417, String.Format (
5409 "`{0}': cannot provide arguments " +
5410 "when creating an instance of a " +
5411 "variable type.", type));
5415 if (TypeManager.activator_create_instance == null) {
5416 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5417 if (activator_type != null) {
5418 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5419 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5423 is_type_parameter = true;
5424 eclass = ExprClass.Value;
5429 if (type.IsAbstract && type.IsSealed) {
5430 Report.SymbolRelatedToPreviousError (type);
5431 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5435 if (type.IsInterface || type.IsAbstract){
5436 if (!TypeManager.IsGenericType (type)) {
5437 RequestedType = CheckComImport (ec);
5438 if (RequestedType != null)
5439 return RequestedType;
5442 Report.SymbolRelatedToPreviousError (type);
5443 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5447 bool is_struct = TypeManager.IsStruct (type);
5448 eclass = ExprClass.Value;
5451 // SRE returns a match for .ctor () on structs (the object constructor),
5452 // so we have to manually ignore it.
5454 if (is_struct && Arguments == null)
5457 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5458 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5459 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5461 if (Arguments != null){
5462 foreach (Argument a in Arguments){
5463 if (!a.Resolve (ec, loc))
5471 method = ml as MethodGroupExpr;
5472 if (method == null) {
5473 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5477 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5484 bool DoEmitTypeParameter (EmitContext ec)
5487 ILGenerator ig = ec.ig;
5488 // IMemoryLocation ml;
5490 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5491 new Type [] { type });
5493 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5494 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5495 ig.Emit (OpCodes.Call, ci);
5499 // Allow DoEmit() to be called multiple times.
5500 // We need to create a new LocalTemporary each time since
5501 // you can't share LocalBuilders among ILGeneators.
5502 LocalTemporary temp = new LocalTemporary (type);
5504 Label label_activator = ig.DefineLabel ();
5505 Label label_end = ig.DefineLabel ();
5507 temp.AddressOf (ec, AddressOp.Store);
5508 ig.Emit (OpCodes.Initobj, type);
5511 ig.Emit (OpCodes.Box, type);
5512 ig.Emit (OpCodes.Brfalse, label_activator);
5514 temp.AddressOf (ec, AddressOp.Store);
5515 ig.Emit (OpCodes.Initobj, type);
5517 ig.Emit (OpCodes.Br, label_end);
5519 ig.MarkLabel (label_activator);
5521 ig.Emit (OpCodes.Call, ci);
5522 ig.MarkLabel (label_end);
5525 throw new InternalErrorException ();
5530 // This Emit can be invoked in two contexts:
5531 // * As a mechanism that will leave a value on the stack (new object)
5532 // * As one that wont (init struct)
5534 // If we are dealing with a ValueType, we have a few
5535 // situations to deal with:
5537 // * The target is a ValueType, and we have been provided
5538 // the instance (this is easy, we are being assigned).
5540 // * The target of New is being passed as an argument,
5541 // to a boxing operation or a function that takes a
5544 // In this case, we need to create a temporary variable
5545 // that is the argument of New.
5547 // Returns whether a value is left on the stack
5549 // *** Implementation note ***
5551 // To benefit from this optimization, each assignable expression
5552 // has to manually cast to New and call this Emit.
5554 // TODO: It's worth to implement it for arrays and fields
5556 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5558 if (is_type_parameter)
5559 return DoEmitTypeParameter (ec);
5561 bool is_value_type = TypeManager.IsValueType (type);
5562 ILGenerator ig = ec.ig;
5563 VariableReference vr = target as VariableReference;
5565 if (target != null && is_value_type && (vr != null || method == null)) {
5566 target.AddressOf (ec, AddressOp.Store);
5567 } else if (vr != null && vr.IsRef) {
5572 method.EmitArguments (ec, Arguments);
5574 if (is_value_type) {
5575 if (method == null) {
5576 ig.Emit (OpCodes.Initobj, type);
5581 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5586 ConstructorInfo ci = (ConstructorInfo) method;
5588 if (TypeManager.IsGenericType (type))
5589 ci = TypeBuilder.GetConstructor (type, ci);
5592 ig.Emit (OpCodes.Newobj, ci);
5596 public override void Emit (EmitContext ec)
5598 LocalTemporary v = null;
5599 if (method == null && TypeManager.IsValueType (type)) {
5600 // TODO: Use temporary variable from pool
5601 v = new LocalTemporary (type);
5608 public override void EmitStatement (EmitContext ec)
5610 LocalTemporary v = null;
5611 if (method == null && TypeManager.IsValueType (type)) {
5612 // TODO: Use temporary variable from pool
5613 v = new LocalTemporary (type);
5617 ec.ig.Emit (OpCodes.Pop);
5620 public virtual bool HasInitializer {
5626 public void AddressOf (EmitContext ec, AddressOp Mode)
5628 if (is_type_parameter) {
5629 LocalTemporary temp = new LocalTemporary (type);
5630 DoEmitTypeParameter (ec);
5632 temp.AddressOf (ec, Mode);
5636 if (!TypeManager.IsStruct (type)){
5638 // We throw an exception. So far, I believe we only need to support
5640 // foreach (int j in new StructType ())
5643 throw new Exception ("AddressOf should not be used for classes");
5646 LocalTemporary value_target = new LocalTemporary (type);
5647 IMemoryLocation ml = (IMemoryLocation) value_target;
5649 ml.AddressOf (ec, AddressOp.Store);
5650 if (method == null) {
5651 ec.ig.Emit (OpCodes.Initobj, type);
5653 method.EmitArguments (ec, Arguments);
5654 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5657 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5660 protected override void CloneTo (CloneContext clonectx, Expression t)
5662 New target = (New) t;
5664 target.RequestedType = RequestedType.Clone (clonectx);
5665 if (Arguments != null){
5666 target.Arguments = new ArrayList ();
5667 foreach (Argument a in Arguments){
5668 target.Arguments.Add (a.Clone (clonectx));
5673 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5675 if (method != null) {
5676 method.MutateHoistedGenericType (storey);
5677 if (Arguments != null) {
5678 foreach (Argument a in Arguments)
5679 a.Expr.MutateHoistedGenericType (storey);
5683 type = storey.MutateType (type);
5688 /// 14.5.10.2: Represents an array creation expression.
5692 /// There are two possible scenarios here: one is an array creation
5693 /// expression that specifies the dimensions and optionally the
5694 /// initialization data and the other which does not need dimensions
5695 /// specified but where initialization data is mandatory.
5697 public class ArrayCreation : Expression {
5698 FullNamedExpression requested_base_type;
5699 ArrayList initializers;
5702 // The list of Argument types.
5703 // This is used to construct the `newarray' or constructor signature
5705 protected ArrayList arguments;
5707 protected Type array_element_type;
5708 bool expect_initializers = false;
5709 int num_arguments = 0;
5710 protected int dimensions;
5711 protected readonly string rank;
5713 protected ArrayList array_data;
5717 // The number of constants in array initializers
5718 int const_initializers_count;
5719 bool only_constant_initializers;
5721 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5723 this.requested_base_type = requested_base_type;
5724 this.initializers = initializers;
5728 arguments = new ArrayList (exprs.Count);
5730 foreach (Expression e in exprs) {
5731 arguments.Add (new Argument (e, Argument.AType.Expression));
5736 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5738 this.requested_base_type = requested_base_type;
5739 this.initializers = initializers;
5743 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5745 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5747 //dimensions = tmp.Length - 1;
5748 expect_initializers = true;
5751 public static void Error_IncorrectArrayInitializer (Location loc)
5753 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5756 protected override void Error_NegativeArrayIndex (Location loc)
5758 Report.Error (248, loc, "Cannot create an array with a negative size");
5761 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5763 if (specified_dims) {
5764 Argument a = (Argument) arguments [idx];
5766 if (!a.Resolve (ec, loc))
5769 Constant c = a.Expr as Constant;
5771 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5775 Report.Error (150, a.Expr.Location, "A constant value is expected");
5779 int value = (int) c.GetValue ();
5781 if (value != probe.Count) {
5782 Error_IncorrectArrayInitializer (loc);
5786 bounds [idx] = value;
5789 int child_bounds = -1;
5790 only_constant_initializers = true;
5791 for (int i = 0; i < probe.Count; ++i) {
5792 object o = probe [i];
5793 if (o is ArrayList) {
5794 ArrayList sub_probe = o as ArrayList;
5795 int current_bounds = sub_probe.Count;
5797 if (child_bounds == -1)
5798 child_bounds = current_bounds;
5800 else if (child_bounds != current_bounds){
5801 Error_IncorrectArrayInitializer (loc);
5804 if (idx + 1 >= dimensions){
5805 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5809 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5813 if (child_bounds != -1){
5814 Error_IncorrectArrayInitializer (loc);
5818 Expression element = ResolveArrayElement (ec, (Expression) o);
5819 if (element == null)
5822 // Initializers with the default values can be ignored
5823 Constant c = element as Constant;
5825 if (c.IsDefaultInitializer (array_element_type)) {
5829 ++const_initializers_count;
5832 only_constant_initializers = false;
5835 array_data.Add (element);
5842 public override Expression CreateExpressionTree (EmitContext ec)
5846 if (array_data == null) {
5847 args = new ArrayList (arguments.Count + 1);
5848 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5849 foreach (Argument a in arguments) {
5850 if (arguments.Count == 1) {
5851 Constant c = a.Expr as Constant;
5852 if (c.IsDefaultValue)
5853 return CreateExpressionFactoryCall ("NewArrayInit", args);
5855 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5858 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5861 if (dimensions > 1) {
5862 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5866 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5867 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5868 if (array_data != null) {
5869 for (int i = 0; i < array_data.Count; ++i) {
5870 Expression e = (Expression) array_data [i];
5872 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5874 args.Add (new Argument (e.CreateExpressionTree (ec)));
5878 return CreateExpressionFactoryCall ("NewArrayInit", args);
5881 public void UpdateIndices ()
5884 for (ArrayList probe = initializers; probe != null;) {
5885 if (probe.Count > 0 && probe [0] is ArrayList) {
5886 Expression e = new IntConstant (probe.Count, Location.Null);
5887 arguments.Add (new Argument (e, Argument.AType.Expression));
5889 bounds [i++] = probe.Count;
5891 probe = (ArrayList) probe [0];
5894 Expression e = new IntConstant (probe.Count, Location.Null);
5895 arguments.Add (new Argument (e, Argument.AType.Expression));
5897 bounds [i++] = probe.Count;
5904 Expression first_emit;
5905 LocalTemporary first_emit_temp;
5907 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5909 element = element.Resolve (ec);
5910 if (element == null)
5913 if (element is CompoundAssign.TargetExpression) {
5914 if (first_emit != null)
5915 throw new InternalErrorException ("Can only handle one mutator at a time");
5916 first_emit = element;
5917 element = first_emit_temp = new LocalTemporary (element.Type);
5920 return Convert.ImplicitConversionRequired (
5921 ec, element, array_element_type, loc);
5924 protected bool ResolveInitializers (EmitContext ec)
5926 if (initializers == null) {
5927 return !expect_initializers;
5931 // We use this to store all the date values in the order in which we
5932 // will need to store them in the byte blob later
5934 array_data = new ArrayList ();
5935 bounds = new System.Collections.Specialized.HybridDictionary ();
5937 if (arguments != null)
5938 return CheckIndices (ec, initializers, 0, true);
5940 arguments = new ArrayList ();
5942 if (!CheckIndices (ec, initializers, 0, false))
5951 // Resolved the type of the array
5953 bool ResolveArrayType (EmitContext ec)
5955 if (requested_base_type == null) {
5956 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5960 if (requested_base_type is VarExpr) {
5961 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5965 StringBuilder array_qualifier = new StringBuilder (rank);
5968 // `In the first form allocates an array instace of the type that results
5969 // from deleting each of the individual expression from the expression list'
5971 if (num_arguments > 0) {
5972 array_qualifier.Append ("[");
5973 for (int i = num_arguments-1; i > 0; i--)
5974 array_qualifier.Append (",");
5975 array_qualifier.Append ("]");
5981 TypeExpr array_type_expr;
5982 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5983 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5984 if (array_type_expr == null)
5987 type = array_type_expr.Type;
5988 array_element_type = TypeManager.GetElementType (type);
5989 dimensions = type.GetArrayRank ();
5994 public override Expression DoResolve (EmitContext ec)
5999 if (!ResolveArrayType (ec))
6003 // First step is to validate the initializers and fill
6004 // in any missing bits
6006 if (!ResolveInitializers (ec))
6009 if (arguments.Count != dimensions) {
6010 Error_IncorrectArrayInitializer (loc);
6013 foreach (Argument a in arguments){
6014 if (!a.Resolve (ec, loc))
6017 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6020 eclass = ExprClass.Value;
6024 MethodInfo GetArrayMethod (int arguments)
6026 ModuleBuilder mb = CodeGen.Module.Builder;
6028 Type[] arg_types = new Type[arguments];
6029 for (int i = 0; i < arguments; i++)
6030 arg_types[i] = TypeManager.int32_type;
6032 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6036 Report.Error (-6, "New invocation: Can not find a constructor for " +
6037 "this argument list");
6044 byte [] MakeByteBlob ()
6049 int count = array_data.Count;
6051 if (TypeManager.IsEnumType (array_element_type))
6052 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6054 factor = GetTypeSize (array_element_type);
6056 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6058 data = new byte [(count * factor + 3) & ~3];
6061 for (int i = 0; i < count; ++i) {
6062 object v = array_data [i];
6064 if (v is EnumConstant)
6065 v = ((EnumConstant) v).Child;
6067 if (v is Constant && !(v is StringConstant))
6068 v = ((Constant) v).GetValue ();
6074 if (array_element_type == TypeManager.int64_type){
6075 if (!(v is Expression)){
6076 long val = (long) v;
6078 for (int j = 0; j < factor; ++j) {
6079 data [idx + j] = (byte) (val & 0xFF);
6083 } else if (array_element_type == TypeManager.uint64_type){
6084 if (!(v is Expression)){
6085 ulong val = (ulong) v;
6087 for (int j = 0; j < factor; ++j) {
6088 data [idx + j] = (byte) (val & 0xFF);
6092 } else if (array_element_type == TypeManager.float_type) {
6093 if (!(v is Expression)){
6094 element = BitConverter.GetBytes ((float) v);
6096 for (int j = 0; j < factor; ++j)
6097 data [idx + j] = element [j];
6098 if (!BitConverter.IsLittleEndian)
6099 System.Array.Reverse (data, idx, 4);
6101 } else if (array_element_type == TypeManager.double_type) {
6102 if (!(v is Expression)){
6103 element = BitConverter.GetBytes ((double) v);
6105 for (int j = 0; j < factor; ++j)
6106 data [idx + j] = element [j];
6108 // FIXME: Handle the ARM float format.
6109 if (!BitConverter.IsLittleEndian)
6110 System.Array.Reverse (data, idx, 8);
6112 } else if (array_element_type == TypeManager.char_type){
6113 if (!(v is Expression)){
6114 int val = (int) ((char) v);
6116 data [idx] = (byte) (val & 0xff);
6117 data [idx+1] = (byte) (val >> 8);
6119 } else if (array_element_type == TypeManager.short_type){
6120 if (!(v is Expression)){
6121 int val = (int) ((short) v);
6123 data [idx] = (byte) (val & 0xff);
6124 data [idx+1] = (byte) (val >> 8);
6126 } else if (array_element_type == TypeManager.ushort_type){
6127 if (!(v is Expression)){
6128 int val = (int) ((ushort) v);
6130 data [idx] = (byte) (val & 0xff);
6131 data [idx+1] = (byte) (val >> 8);
6133 } else if (array_element_type == TypeManager.int32_type) {
6134 if (!(v is Expression)){
6137 data [idx] = (byte) (val & 0xff);
6138 data [idx+1] = (byte) ((val >> 8) & 0xff);
6139 data [idx+2] = (byte) ((val >> 16) & 0xff);
6140 data [idx+3] = (byte) (val >> 24);
6142 } else if (array_element_type == TypeManager.uint32_type) {
6143 if (!(v is Expression)){
6144 uint val = (uint) v;
6146 data [idx] = (byte) (val & 0xff);
6147 data [idx+1] = (byte) ((val >> 8) & 0xff);
6148 data [idx+2] = (byte) ((val >> 16) & 0xff);
6149 data [idx+3] = (byte) (val >> 24);
6151 } else if (array_element_type == TypeManager.sbyte_type) {
6152 if (!(v is Expression)){
6153 sbyte val = (sbyte) v;
6154 data [idx] = (byte) val;
6156 } else if (array_element_type == TypeManager.byte_type) {
6157 if (!(v is Expression)){
6158 byte val = (byte) v;
6159 data [idx] = (byte) val;
6161 } else if (array_element_type == TypeManager.bool_type) {
6162 if (!(v is Expression)){
6163 bool val = (bool) v;
6164 data [idx] = (byte) (val ? 1 : 0);
6166 } else if (array_element_type == TypeManager.decimal_type){
6167 if (!(v is Expression)){
6168 int [] bits = Decimal.GetBits ((decimal) v);
6171 // FIXME: For some reason, this doesn't work on the MS runtime.
6172 int [] nbits = new int [4];
6173 nbits [0] = bits [3];
6174 nbits [1] = bits [2];
6175 nbits [2] = bits [0];
6176 nbits [3] = bits [1];
6178 for (int j = 0; j < 4; j++){
6179 data [p++] = (byte) (nbits [j] & 0xff);
6180 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6181 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6182 data [p++] = (byte) (nbits [j] >> 24);
6186 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6194 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6196 array_element_type = storey.MutateType (array_element_type);
6197 type = storey.MutateType (type);
6198 if (arguments != null) {
6199 foreach (Argument a in arguments)
6200 a.Expr.MutateHoistedGenericType (storey);
6203 if (array_data != null) {
6204 foreach (Expression e in array_data)
6205 e.MutateHoistedGenericType (storey);
6210 // Emits the initializers for the array
6212 void EmitStaticInitializers (EmitContext ec)
6214 // FIXME: This should go to Resolve !
6215 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6216 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6217 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6218 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6219 if (TypeManager.void_initializearray_array_fieldhandle == null)
6224 // First, the static data
6227 ILGenerator ig = ec.ig;
6229 byte [] data = MakeByteBlob ();
6231 fb = RootContext.MakeStaticData (data);
6233 ig.Emit (OpCodes.Dup);
6234 ig.Emit (OpCodes.Ldtoken, fb);
6235 ig.Emit (OpCodes.Call,
6236 TypeManager.void_initializearray_array_fieldhandle);
6240 // Emits pieces of the array that can not be computed at compile
6241 // time (variables and string locations).
6243 // This always expect the top value on the stack to be the array
6245 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6247 ILGenerator ig = ec.ig;
6248 int dims = bounds.Count;
6249 int [] current_pos = new int [dims];
6251 MethodInfo set = null;
6254 Type [] args = new Type [dims + 1];
6256 for (int j = 0; j < dims; j++)
6257 args [j] = TypeManager.int32_type;
6258 args [dims] = array_element_type;
6260 set = CodeGen.Module.Builder.GetArrayMethod (
6262 CallingConventions.HasThis | CallingConventions.Standard,
6263 TypeManager.void_type, args);
6266 for (int i = 0; i < array_data.Count; i++){
6268 Expression e = (Expression)array_data [i];
6270 // Constant can be initialized via StaticInitializer
6271 if (e != null && !(!emitConstants && e is Constant)) {
6272 Type etype = e.Type;
6274 ig.Emit (OpCodes.Dup);
6276 for (int idx = 0; idx < dims; idx++)
6277 IntConstant.EmitInt (ig, current_pos [idx]);
6280 // If we are dealing with a struct, get the
6281 // address of it, so we can store it.
6283 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6284 (!TypeManager.IsBuiltinOrEnum (etype) ||
6285 etype == TypeManager.decimal_type)) {
6287 ig.Emit (OpCodes.Ldelema, etype);
6293 bool is_stobj, has_type_arg;
6294 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6296 ig.Emit (OpCodes.Stobj, etype);
6297 else if (has_type_arg)
6298 ig.Emit (op, etype);
6302 ig.Emit (OpCodes.Call, set);
6309 for (int j = dims - 1; j >= 0; j--){
6311 if (current_pos [j] < (int) bounds [j])
6313 current_pos [j] = 0;
6318 public override void Emit (EmitContext ec)
6320 ILGenerator ig = ec.ig;
6322 if (first_emit != null) {
6323 first_emit.Emit (ec);
6324 first_emit_temp.Store (ec);
6327 foreach (Argument a in arguments)
6330 if (arguments.Count == 1)
6331 ig.Emit (OpCodes.Newarr, array_element_type);
6333 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6336 if (initializers == null)
6339 // Emit static initializer for arrays which have contain more than 4 items and
6340 // the static initializer will initialize at least 25% of array values.
6341 // NOTE: const_initializers_count does not contain default constant values.
6342 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6343 TypeManager.IsPrimitiveType (array_element_type)) {
6344 EmitStaticInitializers (ec);
6346 if (!only_constant_initializers)
6347 EmitDynamicInitializers (ec, false);
6349 EmitDynamicInitializers (ec, true);
6352 if (first_emit_temp != null)
6353 first_emit_temp.Release (ec);
6356 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6358 if (arguments.Count != 1) {
6359 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6360 return base.GetAttributableValue (ec, null, out value);
6363 if (array_data == null) {
6364 Constant c = (Constant)((Argument)arguments [0]).Expr;
6365 if (c.IsDefaultValue) {
6366 value = Array.CreateInstance (array_element_type, 0);
6369 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6370 return base.GetAttributableValue (ec, null, out value);
6373 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6374 object element_value;
6375 for (int i = 0; i < ret.Length; ++i)
6377 Expression e = (Expression)array_data [i];
6379 // Is null when an initializer is optimized (value == predefined value)
6383 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6387 ret.SetValue (element_value, i);
6393 protected override void CloneTo (CloneContext clonectx, Expression t)
6395 ArrayCreation target = (ArrayCreation) t;
6397 if (requested_base_type != null)
6398 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6400 if (arguments != null){
6401 target.arguments = new ArrayList (arguments.Count);
6402 foreach (Argument a in arguments)
6403 target.arguments.Add (a.Clone (clonectx));
6406 if (initializers != null){
6407 target.initializers = new ArrayList (initializers.Count);
6408 foreach (object initializer in initializers)
6409 if (initializer is ArrayList) {
6410 ArrayList this_al = (ArrayList)initializer;
6411 ArrayList al = new ArrayList (this_al.Count);
6412 target.initializers.Add (al);
6413 foreach (Expression e in this_al)
6414 al.Add (e.Clone (clonectx));
6416 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6423 // Represents an implicitly typed array epxression
6425 public class ImplicitlyTypedArrayCreation : ArrayCreation
6427 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6428 : base (null, rank, initializers, loc)
6430 if (RootContext.Version <= LanguageVersion.ISO_2)
6431 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6433 if (rank.Length > 2) {
6434 while (rank [++dimensions] == ',');
6440 public override Expression DoResolve (EmitContext ec)
6445 if (!ResolveInitializers (ec))
6448 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6449 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6450 arguments.Count != dimensions) {
6451 Error_NoBestType ();
6456 // At this point we found common base type for all initializer elements
6457 // but we have to be sure that all static initializer elements are of
6460 UnifyInitializerElement (ec);
6462 type = TypeManager.GetConstructedType (array_element_type, rank);
6463 eclass = ExprClass.Value;
6467 void Error_NoBestType ()
6469 Report.Error (826, loc,
6470 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6474 // Converts static initializer only
6476 void UnifyInitializerElement (EmitContext ec)
6478 for (int i = 0; i < array_data.Count; ++i) {
6479 Expression e = (Expression)array_data[i];
6481 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6485 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6487 element = element.Resolve (ec);
6488 if (element == null)
6491 if (array_element_type == null) {
6492 array_element_type = element.Type;
6496 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6500 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6501 array_element_type = element.Type;
6505 Error_NoBestType ();
6510 public sealed class CompilerGeneratedThis : This
6512 public static This Instance = new CompilerGeneratedThis ();
6514 private CompilerGeneratedThis ()
6515 : base (Location.Null)
6519 public CompilerGeneratedThis (Type type, Location loc)
6525 public override Expression DoResolve (EmitContext ec)
6527 eclass = ExprClass.Variable;
6529 type = ec.ContainerType;
6533 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6540 /// Represents the `this' construct
6543 public class This : VariableReference
6545 sealed class ThisVariable : ILocalVariable
6547 public static readonly ILocalVariable Instance = new ThisVariable ();
6549 public void Emit (EmitContext ec)
6551 ec.ig.Emit (OpCodes.Ldarg_0);
6554 public void EmitAssign (EmitContext ec)
6556 throw new InvalidOperationException ();
6559 public void EmitAddressOf (EmitContext ec)
6561 ec.ig.Emit (OpCodes.Ldarg_0);
6566 VariableInfo variable_info;
6569 public This (Block block, Location loc)
6575 public This (Location loc)
6580 public override VariableInfo VariableInfo {
6581 get { return variable_info; }
6584 public override bool IsFixed {
6585 get { return false; }
6588 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6590 // Is null when probing IsHoisted
6594 if (ec.CurrentAnonymousMethod == null)
6597 AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
6598 while (storey != null) {
6599 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6601 return storey.HoistedThis;
6609 public override bool IsRef {
6610 get { return is_struct; }
6613 protected override ILocalVariable Variable {
6614 get { return ThisVariable.Instance; }
6617 public static bool IsThisAvailable (EmitContext ec)
6619 if (ec.IsStatic || ec.IsInFieldInitializer)
6622 if (ec.CurrentAnonymousMethod == null)
6625 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6631 public bool ResolveBase (EmitContext ec)
6633 if (eclass != ExprClass.Invalid)
6636 eclass = ExprClass.Variable;
6638 if (ec.TypeContainer.CurrentType != null)
6639 type = ec.TypeContainer.CurrentType;
6641 type = ec.ContainerType;
6643 if (!IsThisAvailable (ec)) {
6645 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6647 Report.Error (1673, loc,
6648 "Anonymous methods inside structs cannot access instance members of `this'. " +
6649 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6653 is_struct = ec.TypeContainer is Struct;
6655 if (block != null) {
6656 if (block.Toplevel.ThisVariable != null)
6657 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6659 AnonymousExpression am = ec.CurrentAnonymousMethod;
6660 if (am != null && ec.IsVariableCapturingRequired) {
6661 am.SetHasThisAccess ();
6669 // Called from Invocation to check if the invocation is correct
6671 public override void CheckMarshalByRefAccess (EmitContext ec)
6673 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6674 !variable_info.IsAssigned (ec)) {
6675 Error (188, "The `this' object cannot be used before all of its " +
6676 "fields are assigned to");
6677 variable_info.SetAssigned (ec);
6681 public override Expression CreateExpressionTree (EmitContext ec)
6683 ArrayList args = new ArrayList (1);
6684 args.Add (new Argument (this));
6686 // Use typeless constant for ldarg.0 to save some
6687 // space and avoid problems with anonymous stories
6688 return CreateExpressionFactoryCall ("Constant", args);
6691 public override Expression DoResolve (EmitContext ec)
6693 if (!ResolveBase (ec))
6697 if (ec.IsInFieldInitializer) {
6698 Error (27, "Keyword `this' is not available in the current context");
6705 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6707 if (!ResolveBase (ec))
6710 if (variable_info != null)
6711 variable_info.SetAssigned (ec);
6713 if (ec.TypeContainer is Class){
6714 if (right_side == EmptyExpression.UnaryAddress)
6715 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6716 else if (right_side == EmptyExpression.OutAccess)
6717 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6719 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6725 public override int GetHashCode()
6727 return block.GetHashCode ();
6730 public override string Name {
6731 get { return "this"; }
6734 public override bool Equals (object obj)
6736 This t = obj as This;
6740 return block == t.block;
6743 protected override void CloneTo (CloneContext clonectx, Expression t)
6745 This target = (This) t;
6747 target.block = clonectx.LookupBlock (block);
6750 public override void SetHasAddressTaken ()
6757 /// Represents the `__arglist' construct
6759 public class ArglistAccess : Expression
6761 public ArglistAccess (Location loc)
6766 public override Expression CreateExpressionTree (EmitContext ec)
6768 throw new NotSupportedException ("ET");
6771 public override Expression DoResolve (EmitContext ec)
6773 eclass = ExprClass.Variable;
6774 type = TypeManager.runtime_argument_handle_type;
6776 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6778 Error (190, "The __arglist construct is valid only within " +
6779 "a variable argument method");
6786 public override void Emit (EmitContext ec)
6788 ec.ig.Emit (OpCodes.Arglist);
6791 protected override void CloneTo (CloneContext clonectx, Expression target)
6798 /// Represents the `__arglist (....)' construct
6800 public class Arglist : Expression
6802 Argument[] Arguments;
6804 public Arglist (Location loc)
6805 : this (Argument.Empty, loc)
6809 public Arglist (Argument[] args, Location l)
6815 public Type[] ArgumentTypes {
6817 Type[] retval = new Type [Arguments.Length];
6818 for (int i = 0; i < Arguments.Length; i++)
6819 retval [i] = Arguments [i].Type;
6824 public override Expression CreateExpressionTree (EmitContext ec)
6826 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6830 public override Expression DoResolve (EmitContext ec)
6832 eclass = ExprClass.Variable;
6833 type = TypeManager.runtime_argument_handle_type;
6835 foreach (Argument arg in Arguments) {
6836 if (!arg.Resolve (ec, loc))
6843 public override void Emit (EmitContext ec)
6845 foreach (Argument arg in Arguments)
6849 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6851 foreach (Argument arg in Arguments)
6852 arg.Expr.MutateHoistedGenericType (storey);
6855 protected override void CloneTo (CloneContext clonectx, Expression t)
6857 Arglist target = (Arglist) t;
6859 target.Arguments = new Argument [Arguments.Length];
6860 for (int i = 0; i < Arguments.Length; i++)
6861 target.Arguments [i] = Arguments [i].Clone (clonectx);
6866 /// Implements the typeof operator
6868 public class TypeOf : Expression {
6869 Expression QueriedType;
6870 protected Type typearg;
6872 public TypeOf (Expression queried_type, Location l)
6874 QueriedType = queried_type;
6878 public override Expression CreateExpressionTree (EmitContext ec)
6880 ArrayList args = new ArrayList (2);
6881 args.Add (new Argument (this));
6882 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6883 return CreateExpressionFactoryCall ("Constant", args);
6886 public override Expression DoResolve (EmitContext ec)
6888 if (eclass != ExprClass.Invalid)
6891 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6895 typearg = texpr.Type;
6897 if (typearg == TypeManager.void_type) {
6898 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6902 if (typearg.IsPointer && !ec.InUnsafe){
6907 type = TypeManager.type_type;
6909 return DoResolveBase ();
6912 protected Expression DoResolveBase ()
6914 if (TypeManager.system_type_get_type_from_handle == null) {
6915 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6916 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6919 // Even though what is returned is a type object, it's treated as a value by the compiler.
6920 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6921 eclass = ExprClass.Value;
6925 public override void Emit (EmitContext ec)
6927 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6928 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6931 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6933 if (TypeManager.ContainsGenericParameters (typearg) &&
6934 !TypeManager.IsGenericTypeDefinition (typearg)) {
6935 Report.SymbolRelatedToPreviousError (typearg);
6936 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6937 TypeManager.CSharpName (typearg));
6942 if (value_type == TypeManager.object_type) {
6943 value = (object)typearg;
6950 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6952 typearg = storey.MutateType (typearg);
6955 public Type TypeArgument {
6961 protected override void CloneTo (CloneContext clonectx, Expression t)
6963 TypeOf target = (TypeOf) t;
6964 if (QueriedType != null)
6965 target.QueriedType = QueriedType.Clone (clonectx);
6970 /// Implements the `typeof (void)' operator
6972 public class TypeOfVoid : TypeOf {
6973 public TypeOfVoid (Location l) : base (null, l)
6978 public override Expression DoResolve (EmitContext ec)
6980 type = TypeManager.type_type;
6981 typearg = TypeManager.void_type;
6983 return DoResolveBase ();
6987 class TypeOfMethodInfo : TypeOfMethod
6989 public TypeOfMethodInfo (MethodBase method, Location loc)
6990 : base (method, loc)
6994 public override Expression DoResolve (EmitContext ec)
6996 type = typeof (MethodInfo);
6997 return base.DoResolve (ec);
7000 public override void Emit (EmitContext ec)
7002 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7004 ec.ig.Emit (OpCodes.Castclass, type);
7008 class TypeOfConstructorInfo : TypeOfMethod
7010 public TypeOfConstructorInfo (MethodBase method, Location loc)
7011 : base (method, loc)
7015 public override Expression DoResolve (EmitContext ec)
7017 type = typeof (ConstructorInfo);
7018 return base.DoResolve (ec);
7021 public override void Emit (EmitContext ec)
7023 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7025 ec.ig.Emit (OpCodes.Castclass, type);
7029 abstract class TypeOfMethod : Expression
7031 protected readonly MethodBase method;
7033 protected TypeOfMethod (MethodBase method, Location loc)
7035 this.method = method;
7039 public override Expression CreateExpressionTree (EmitContext ec)
7041 ArrayList args = new ArrayList (2);
7042 args.Add (new Argument (this));
7043 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7044 return CreateExpressionFactoryCall ("Constant", args);
7047 public override Expression DoResolve (EmitContext ec)
7049 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7050 MethodInfo mi = is_generic ?
7051 TypeManager.methodbase_get_type_from_handle_generic :
7052 TypeManager.methodbase_get_type_from_handle;
7055 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7056 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7058 if (t == null || handle_type == null)
7061 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7063 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7064 new Type[] { handle_type } );
7067 TypeManager.methodbase_get_type_from_handle_generic = mi;
7069 TypeManager.methodbase_get_type_from_handle = mi;
7072 eclass = ExprClass.Value;
7076 public override void Emit (EmitContext ec)
7078 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7081 mi = TypeManager.methodbase_get_type_from_handle_generic;
7082 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7084 mi = TypeManager.methodbase_get_type_from_handle;
7087 ec.ig.Emit (OpCodes.Call, mi);
7091 internal class TypeOfField : Expression
7093 readonly FieldInfo field;
7095 public TypeOfField (FieldInfo field, Location loc)
7101 public override Expression CreateExpressionTree (EmitContext ec)
7103 throw new NotSupportedException ("ET");
7106 public override Expression DoResolve (EmitContext ec)
7108 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7109 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7110 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7112 if (t != null && handle_type != null)
7113 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7114 "GetFieldFromHandle", loc, handle_type);
7117 type = typeof (FieldInfo);
7118 eclass = ExprClass.Value;
7122 public override void Emit (EmitContext ec)
7124 ec.ig.Emit (OpCodes.Ldtoken, field);
7125 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7130 /// Implements the sizeof expression
7132 public class SizeOf : Expression {
7133 readonly Expression QueriedType;
7136 public SizeOf (Expression queried_type, Location l)
7138 this.QueriedType = queried_type;
7142 public override Expression CreateExpressionTree (EmitContext ec)
7144 Error_PointerInsideExpressionTree ();
7148 public override Expression DoResolve (EmitContext ec)
7150 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7154 type_queried = texpr.Type;
7155 if (TypeManager.IsEnumType (type_queried))
7156 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7158 int size_of = GetTypeSize (type_queried);
7160 return new IntConstant (size_of, loc);
7163 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7168 Report.Error (233, loc,
7169 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7170 TypeManager.CSharpName (type_queried));
7173 type = TypeManager.int32_type;
7174 eclass = ExprClass.Value;
7178 public override void Emit (EmitContext ec)
7180 int size = GetTypeSize (type_queried);
7183 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7185 IntConstant.EmitInt (ec.ig, size);
7188 protected override void CloneTo (CloneContext clonectx, Expression t)
7194 /// Implements the qualified-alias-member (::) expression.
7196 public class QualifiedAliasMember : MemberAccess
7198 readonly string alias;
7199 public static readonly string GlobalAlias = "global";
7201 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7202 : base (null, identifier, targs, l)
7207 public QualifiedAliasMember (string alias, string identifier, Location l)
7208 : base (null, identifier, l)
7213 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7215 if (alias == GlobalAlias) {
7216 expr = RootNamespace.Global;
7217 return base.ResolveAsTypeStep (ec, silent);
7220 int errors = Report.Errors;
7221 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7223 if (errors == Report.Errors)
7224 Report.Error (432, loc, "Alias `{0}' not found", alias);
7228 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7232 if (expr.eclass == ExprClass.Type) {
7234 Report.Error (431, loc,
7235 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7243 public override Expression DoResolve (EmitContext ec)
7245 return ResolveAsTypeStep (ec, false);
7248 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7250 Report.Error (687, loc,
7251 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7252 GetSignatureForError ());
7255 public override string GetSignatureForError ()
7258 if (targs != null) {
7259 name = TypeManager.RemoveGenericArity (Name) + "<" +
7260 targs.GetSignatureForError () + ">";
7263 return alias + "::" + name;
7266 protected override void CloneTo (CloneContext clonectx, Expression t)
7273 /// Implements the member access expression
7275 public class MemberAccess : ATypeNameExpression {
7276 protected Expression expr;
7278 public MemberAccess (Expression expr, string id)
7279 : base (id, expr.Location)
7284 public MemberAccess (Expression expr, string identifier, Location loc)
7285 : base (identifier, loc)
7290 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7291 : base (identifier, args, loc)
7296 Expression DoResolve (EmitContext ec, Expression right_side)
7299 throw new Exception ();
7302 // Resolve the expression with flow analysis turned off, we'll do the definite
7303 // assignment checks later. This is because we don't know yet what the expression
7304 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7305 // definite assignment check on the actual field and not on the whole struct.
7308 SimpleName original = expr as SimpleName;
7309 Expression expr_resolved = expr.Resolve (ec,
7310 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7311 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7313 if (expr_resolved == null)
7316 string LookupIdentifier = MemberName.MakeName (Name, targs);
7318 Namespace ns = expr_resolved as Namespace;
7320 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7323 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, LookupIdentifier);
7324 else if (targs != null)
7325 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7330 Type expr_type = expr_resolved.Type;
7331 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7332 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7333 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7337 Constant c = expr_resolved as Constant;
7338 if (c != null && c.GetValue () == null) {
7339 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7340 "System.NullReferenceException");
7343 if (targs != null) {
7344 if (!targs.Resolve (ec))
7348 Expression member_lookup;
7349 member_lookup = MemberLookup (
7350 ec.ContainerType, expr_type, expr_type, Name, loc);
7352 if ((member_lookup == null) && (targs != null)) {
7353 member_lookup = MemberLookup (
7354 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7357 if (member_lookup == null) {
7358 ExprClass expr_eclass = expr_resolved.eclass;
7361 // Extension methods are not allowed on all expression types
7363 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7364 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7365 expr_eclass == ExprClass.EventAccess) {
7366 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7367 if (ex_method_lookup != null) {
7368 ex_method_lookup.ExtensionExpression = expr_resolved;
7370 if (targs != null) {
7371 ex_method_lookup.SetTypeArguments (targs);
7374 return ex_method_lookup.DoResolve (ec);
7378 expr = expr_resolved;
7379 member_lookup = Error_MemberLookupFailed (
7380 ec.ContainerType, expr_type, expr_type, Name, null,
7381 AllMemberTypes, AllBindingFlags);
7382 if (member_lookup == null)
7386 TypeExpr texpr = member_lookup as TypeExpr;
7387 if (texpr != null) {
7388 if (!(expr_resolved is TypeExpr) &&
7389 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7390 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7391 Name, member_lookup.GetSignatureForError ());
7395 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7396 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7397 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7402 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7405 // When looking up a nested type in a generic instance
7406 // via reflection, we always get a generic type definition
7407 // and not a generic instance - so we have to do this here.
7409 // See gtest-172-lib.cs and gtest-172.cs for an example.
7411 ct = new GenericTypeExpr (
7412 member_lookup.Type, ct.TypeArguments, loc);
7414 return ct.ResolveAsTypeStep (ec, false);
7417 return member_lookup;
7420 MemberExpr me = (MemberExpr) member_lookup;
7421 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7425 if (targs != null) {
7426 me.SetTypeArguments (targs);
7429 if (original != null && !TypeManager.IsValueType (expr_type)) {
7430 if (me.IsInstance) {
7431 LocalVariableReference var = expr_resolved as LocalVariableReference;
7432 if (var != null && !var.VerifyAssigned (ec))
7437 // The following DoResolve/DoResolveLValue will do the definite assignment
7440 if (right_side != null)
7441 return me.DoResolveLValue (ec, right_side);
7443 return me.DoResolve (ec);
7446 public override Expression DoResolve (EmitContext ec)
7448 return DoResolve (ec, null);
7451 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7453 return DoResolve (ec, right_side);
7456 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7458 return ResolveNamespaceOrType (ec, silent);
7461 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7463 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7465 if (expr_resolved == null)
7468 string LookupIdentifier = MemberName.MakeName (Name, targs);
7470 Namespace ns = expr_resolved as Namespace;
7472 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7474 if (retval == null && !silent)
7475 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7476 else if (targs != null)
7477 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7482 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7483 if (tnew_expr == null)
7486 if (tnew_expr is TypeParameterExpr) {
7487 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7488 tnew_expr.GetSignatureForError ());
7492 Type expr_type = tnew_expr.Type;
7493 Expression member_lookup = MemberLookup (
7494 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7495 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7496 if (member_lookup == null) {
7500 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7504 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7509 TypeArguments the_args = targs;
7510 Type declaring_type = texpr.Type.DeclaringType;
7511 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7512 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7513 expr_type = expr_type.BaseType;
7516 TypeArguments new_args = new TypeArguments ();
7517 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7518 new_args.Add (new TypeExpression (decl, loc));
7521 new_args.Add (targs);
7523 the_args = new_args;
7526 if (the_args != null) {
7527 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7528 return ctype.ResolveAsTypeStep (rc, false);
7535 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7537 Expression member_lookup = MemberLookup (
7538 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7539 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7541 if (member_lookup != null) {
7542 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7543 if (expr_type == null)
7546 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7550 member_lookup = MemberLookup (
7551 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7552 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7554 if (member_lookup == null) {
7555 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7556 Name, expr_type.GetSignatureForError ());
7558 // TODO: Report.SymbolRelatedToPreviousError
7559 member_lookup.Error_UnexpectedKind (null, "type", loc);
7563 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7565 if (RootContext.Version > LanguageVersion.ISO_2 &&
7566 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7567 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7568 "extension method `{1}' of type `{0}' could be found " +
7569 "(are you missing a using directive or an assembly reference?)",
7570 TypeManager.CSharpName (type), name);
7574 base.Error_TypeDoesNotContainDefinition (type, name);
7577 public override string GetSignatureForError ()
7579 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7582 protected override void CloneTo (CloneContext clonectx, Expression t)
7584 MemberAccess target = (MemberAccess) t;
7586 target.expr = expr.Clone (clonectx);
7591 /// Implements checked expressions
7593 public class CheckedExpr : Expression {
7595 public Expression Expr;
7597 public CheckedExpr (Expression e, Location l)
7603 public override Expression CreateExpressionTree (EmitContext ec)
7605 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7606 return Expr.CreateExpressionTree (ec);
7609 public override Expression DoResolve (EmitContext ec)
7611 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7612 Expr = Expr.Resolve (ec);
7617 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7620 eclass = Expr.eclass;
7625 public override void Emit (EmitContext ec)
7627 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7631 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7633 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7634 Expr.EmitBranchable (ec, target, on_true);
7637 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7639 Expr.MutateHoistedGenericType (storey);
7642 protected override void CloneTo (CloneContext clonectx, Expression t)
7644 CheckedExpr target = (CheckedExpr) t;
7646 target.Expr = Expr.Clone (clonectx);
7651 /// Implements the unchecked expression
7653 public class UnCheckedExpr : Expression {
7655 public Expression Expr;
7657 public UnCheckedExpr (Expression e, Location l)
7663 public override Expression CreateExpressionTree (EmitContext ec)
7665 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7666 return Expr.CreateExpressionTree (ec);
7669 public override Expression DoResolve (EmitContext ec)
7671 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7672 Expr = Expr.Resolve (ec);
7677 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7680 eclass = Expr.eclass;
7685 public override void Emit (EmitContext ec)
7687 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7691 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7693 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7694 Expr.EmitBranchable (ec, target, on_true);
7697 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7699 Expr.MutateHoistedGenericType (storey);
7702 protected override void CloneTo (CloneContext clonectx, Expression t)
7704 UnCheckedExpr target = (UnCheckedExpr) t;
7706 target.Expr = Expr.Clone (clonectx);
7711 /// An Element Access expression.
7713 /// During semantic analysis these are transformed into
7714 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7716 public class ElementAccess : Expression {
7717 public ArrayList Arguments;
7718 public Expression Expr;
7720 public ElementAccess (Expression e, ArrayList e_list)
7728 Arguments = new ArrayList (e_list.Count);
7729 foreach (Expression tmp in e_list)
7730 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7733 bool CommonResolve (EmitContext ec)
7735 Expr = Expr.Resolve (ec);
7737 if (Arguments == null)
7740 foreach (Argument a in Arguments){
7741 if (!a.Resolve (ec, loc))
7745 return Expr != null;
7748 public override Expression CreateExpressionTree (EmitContext ec)
7750 ArrayList args = new ArrayList (Arguments.Count + 1);
7751 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7752 foreach (Argument a in Arguments)
7753 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7755 return CreateExpressionFactoryCall ("ArrayIndex", args);
7758 Expression MakePointerAccess (EmitContext ec, Type t)
7760 if (Arguments.Count != 1){
7761 Error (196, "A pointer must be indexed by only one value");
7765 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7768 return new Indirection (p, loc).Resolve (ec);
7771 public override Expression DoResolve (EmitContext ec)
7773 if (!CommonResolve (ec))
7777 // We perform some simple tests, and then to "split" the emit and store
7778 // code we create an instance of a different class, and return that.
7780 // I am experimenting with this pattern.
7784 if (t == TypeManager.array_type){
7785 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7790 return (new ArrayAccess (this, loc)).Resolve (ec);
7792 return MakePointerAccess (ec, t);
7794 FieldExpr fe = Expr as FieldExpr;
7796 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7798 return MakePointerAccess (ec, ff.ElementType);
7801 return (new IndexerAccess (this, loc)).Resolve (ec);
7804 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7806 if (!CommonResolve (ec))
7811 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7814 return MakePointerAccess (ec, type);
7816 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7817 Error_CannotModifyIntermediateExpressionValue (ec);
7819 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7822 public override void Emit (EmitContext ec)
7824 throw new Exception ("Should never be reached");
7827 public override string GetSignatureForError ()
7829 return Expr.GetSignatureForError ();
7832 protected override void CloneTo (CloneContext clonectx, Expression t)
7834 ElementAccess target = (ElementAccess) t;
7836 target.Expr = Expr.Clone (clonectx);
7837 target.Arguments = new ArrayList (Arguments.Count);
7838 foreach (Argument a in Arguments)
7839 target.Arguments.Add (a.Clone (clonectx));
7844 /// Implements array access
7846 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7848 // Points to our "data" repository
7852 LocalTemporary temp;
7856 public ArrayAccess (ElementAccess ea_data, Location l)
7862 public override Expression CreateExpressionTree (EmitContext ec)
7864 return ea.CreateExpressionTree (ec);
7867 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7869 return DoResolve (ec);
7872 public override Expression DoResolve (EmitContext ec)
7875 ExprClass eclass = ea.Expr.eclass;
7877 // As long as the type is valid
7878 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7879 eclass == ExprClass.Value)) {
7880 ea.Expr.Error_UnexpectedKind ("variable or value");
7885 if (eclass != ExprClass.Invalid)
7888 Type t = ea.Expr.Type;
7889 int rank = ea.Arguments.Count;
7890 if (t.GetArrayRank () != rank) {
7891 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7892 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7896 type = TypeManager.GetElementType (t);
7897 if (type.IsPointer && !ec.InUnsafe) {
7898 UnsafeError (ea.Location);
7902 foreach (Argument a in ea.Arguments) {
7903 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7906 eclass = ExprClass.Variable;
7912 /// Emits the right opcode to load an object of Type `t'
7913 /// from an array of T
7915 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7918 MethodInfo get = FetchGetMethod ();
7919 ig.Emit (OpCodes.Call, get);
7923 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7924 ig.Emit (OpCodes.Ldelem_U1);
7925 else if (type == TypeManager.sbyte_type)
7926 ig.Emit (OpCodes.Ldelem_I1);
7927 else if (type == TypeManager.short_type)
7928 ig.Emit (OpCodes.Ldelem_I2);
7929 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7930 ig.Emit (OpCodes.Ldelem_U2);
7931 else if (type == TypeManager.int32_type)
7932 ig.Emit (OpCodes.Ldelem_I4);
7933 else if (type == TypeManager.uint32_type)
7934 ig.Emit (OpCodes.Ldelem_U4);
7935 else if (type == TypeManager.uint64_type)
7936 ig.Emit (OpCodes.Ldelem_I8);
7937 else if (type == TypeManager.int64_type)
7938 ig.Emit (OpCodes.Ldelem_I8);
7939 else if (type == TypeManager.float_type)
7940 ig.Emit (OpCodes.Ldelem_R4);
7941 else if (type == TypeManager.double_type)
7942 ig.Emit (OpCodes.Ldelem_R8);
7943 else if (type == TypeManager.intptr_type)
7944 ig.Emit (OpCodes.Ldelem_I);
7945 else if (TypeManager.IsEnumType (type)){
7946 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7947 } else if (TypeManager.IsStruct (type)){
7948 ig.Emit (OpCodes.Ldelema, type);
7949 ig.Emit (OpCodes.Ldobj, type);
7951 } else if (type.IsGenericParameter) {
7952 ig.Emit (OpCodes.Ldelem, type);
7954 } else if (type.IsPointer)
7955 ig.Emit (OpCodes.Ldelem_I);
7957 ig.Emit (OpCodes.Ldelem_Ref);
7960 protected override void Error_NegativeArrayIndex (Location loc)
7962 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7966 /// Returns the right opcode to store an object of Type `t'
7967 /// from an array of T.
7969 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7971 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7972 has_type_arg = false; is_stobj = false;
7973 t = TypeManager.TypeToCoreType (t);
7974 if (TypeManager.IsEnumType (t))
7975 t = TypeManager.GetEnumUnderlyingType (t);
7976 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7977 t == TypeManager.bool_type)
7978 return OpCodes.Stelem_I1;
7979 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7980 t == TypeManager.char_type)
7981 return OpCodes.Stelem_I2;
7982 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7983 return OpCodes.Stelem_I4;
7984 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7985 return OpCodes.Stelem_I8;
7986 else if (t == TypeManager.float_type)
7987 return OpCodes.Stelem_R4;
7988 else if (t == TypeManager.double_type)
7989 return OpCodes.Stelem_R8;
7990 else if (t == TypeManager.intptr_type) {
7991 has_type_arg = true;
7993 return OpCodes.Stobj;
7994 } else if (TypeManager.IsStruct (t)) {
7995 has_type_arg = true;
7997 return OpCodes.Stobj;
7999 } else if (t.IsGenericParameter) {
8000 has_type_arg = true;
8001 return OpCodes.Stelem;
8004 } else if (t.IsPointer)
8005 return OpCodes.Stelem_I;
8007 return OpCodes.Stelem_Ref;
8010 MethodInfo FetchGetMethod ()
8012 ModuleBuilder mb = CodeGen.Module.Builder;
8013 int arg_count = ea.Arguments.Count;
8014 Type [] args = new Type [arg_count];
8017 for (int i = 0; i < arg_count; i++){
8018 //args [i++] = a.Type;
8019 args [i] = TypeManager.int32_type;
8022 get = mb.GetArrayMethod (
8023 ea.Expr.Type, "Get",
8024 CallingConventions.HasThis |
8025 CallingConventions.Standard,
8031 MethodInfo FetchAddressMethod ()
8033 ModuleBuilder mb = CodeGen.Module.Builder;
8034 int arg_count = ea.Arguments.Count;
8035 Type [] args = new Type [arg_count];
8039 ret_type = TypeManager.GetReferenceType (type);
8041 for (int i = 0; i < arg_count; i++){
8042 //args [i++] = a.Type;
8043 args [i] = TypeManager.int32_type;
8046 address = mb.GetArrayMethod (
8047 ea.Expr.Type, "Address",
8048 CallingConventions.HasThis |
8049 CallingConventions.Standard,
8056 // Load the array arguments into the stack.
8058 void LoadArrayAndArguments (EmitContext ec)
8062 for (int i = 0; i < ea.Arguments.Count; ++i) {
8063 ((Argument)ea.Arguments [i]).Emit (ec);
8067 public void Emit (EmitContext ec, bool leave_copy)
8069 int rank = ea.Expr.Type.GetArrayRank ();
8070 ILGenerator ig = ec.ig;
8073 LoadFromPtr (ig, this.type);
8075 LoadArrayAndArguments (ec);
8076 EmitLoadOpcode (ig, type, rank);
8080 ig.Emit (OpCodes.Dup);
8081 temp = new LocalTemporary (this.type);
8086 public override void Emit (EmitContext ec)
8091 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8093 int rank = ea.Expr.Type.GetArrayRank ();
8094 ILGenerator ig = ec.ig;
8095 Type t = source.Type;
8096 prepared = prepare_for_load;
8099 AddressOf (ec, AddressOp.LoadStore);
8100 ec.ig.Emit (OpCodes.Dup);
8102 LoadArrayAndArguments (ec);
8106 bool is_stobj, has_type_arg;
8107 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8111 // The stobj opcode used by value types will need
8112 // an address on the stack, not really an array/array
8116 ig.Emit (OpCodes.Ldelema, t);
8121 ec.ig.Emit (OpCodes.Dup);
8122 temp = new LocalTemporary (this.type);
8127 StoreFromPtr (ig, t);
8129 ig.Emit (OpCodes.Stobj, t);
8130 else if (has_type_arg)
8137 ec.ig.Emit (OpCodes.Dup);
8138 temp = new LocalTemporary (this.type);
8143 StoreFromPtr (ig, t);
8145 int arg_count = ea.Arguments.Count;
8146 Type [] args = new Type [arg_count + 1];
8147 for (int i = 0; i < arg_count; i++) {
8148 //args [i++] = a.Type;
8149 args [i] = TypeManager.int32_type;
8151 args [arg_count] = type;
8153 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8154 ea.Expr.Type, "Set",
8155 CallingConventions.HasThis |
8156 CallingConventions.Standard,
8157 TypeManager.void_type, args);
8159 ig.Emit (OpCodes.Call, set);
8169 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8171 if (!source.Emit (ec, this)) {
8173 throw new NotImplementedException ();
8178 throw new NotImplementedException ();
8181 public void AddressOf (EmitContext ec, AddressOp mode)
8183 int rank = ea.Expr.Type.GetArrayRank ();
8184 ILGenerator ig = ec.ig;
8186 LoadArrayAndArguments (ec);
8189 ig.Emit (OpCodes.Ldelema, type);
8191 MethodInfo address = FetchAddressMethod ();
8192 ig.Emit (OpCodes.Call, address);
8196 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8198 type = storey.MutateType (type);
8199 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8204 /// Expressions that represent an indexer call.
8206 public class IndexerAccess : Expression, IAssignMethod
8208 class IndexerMethodGroupExpr : MethodGroupExpr
8210 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8213 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8216 public override string Name {
8222 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8225 // Here is the trick, decrease number of arguments by 1 when only
8226 // available property method is setter. This makes overload resolution
8227 // work correctly for indexers.
8230 if (method.Name [0] == 'g')
8231 return parameters.Count;
8233 return parameters.Count - 1;
8239 // Contains either property getter or setter
8240 public ArrayList Methods;
8241 public ArrayList Properties;
8247 void Append (Type caller_type, MemberInfo [] mi)
8252 foreach (PropertyInfo property in mi) {
8253 MethodInfo accessor = property.GetGetMethod (true);
8254 if (accessor == null)
8255 accessor = property.GetSetMethod (true);
8257 if (Methods == null) {
8258 Methods = new ArrayList ();
8259 Properties = new ArrayList ();
8262 Methods.Add (accessor);
8263 Properties.Add (property);
8267 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8269 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8271 return TypeManager.MemberLookup (
8272 caller_type, caller_type, lookup_type, MemberTypes.Property,
8273 BindingFlags.Public | BindingFlags.Instance |
8274 BindingFlags.DeclaredOnly, p_name, null);
8277 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8279 Indexers ix = new Indexers ();
8282 if (lookup_type.IsGenericParameter) {
8283 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8287 if (gc.HasClassConstraint)
8288 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8290 Type[] ifaces = gc.InterfaceConstraints;
8291 foreach (Type itype in ifaces)
8292 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8298 Type copy = lookup_type;
8299 while (copy != TypeManager.object_type && copy != null){
8300 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8301 copy = copy.BaseType;
8304 if (lookup_type.IsInterface) {
8305 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8306 if (ifaces != null) {
8307 foreach (Type itype in ifaces)
8308 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8323 // Points to our "data" repository
8325 MethodInfo get, set;
8326 bool is_base_indexer;
8328 LocalTemporary temp;
8329 LocalTemporary prepared_value;
8330 Expression set_expr;
8332 protected Type indexer_type;
8333 protected Type current_type;
8334 protected Expression instance_expr;
8335 protected ArrayList arguments;
8337 public IndexerAccess (ElementAccess ea, Location loc)
8338 : this (ea.Expr, false, loc)
8340 this.arguments = ea.Arguments;
8343 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8346 this.instance_expr = instance_expr;
8347 this.is_base_indexer = is_base_indexer;
8348 this.eclass = ExprClass.Value;
8352 static string GetAccessorName (AccessorType at)
8354 if (at == AccessorType.Set)
8357 if (at == AccessorType.Get)
8360 throw new NotImplementedException (at.ToString ());
8363 public override Expression CreateExpressionTree (EmitContext ec)
8365 ArrayList args = new ArrayList (arguments.Count + 2);
8366 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8367 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8368 foreach (Argument a in arguments)
8369 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8371 return CreateExpressionFactoryCall ("Call", args);
8374 protected virtual bool CommonResolve (EmitContext ec)
8376 indexer_type = instance_expr.Type;
8377 current_type = ec.ContainerType;
8382 public override Expression DoResolve (EmitContext ec)
8384 return ResolveAccessor (ec, AccessorType.Get);
8387 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8389 if (right_side == EmptyExpression.OutAccess) {
8390 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8391 GetSignatureForError ());
8395 // if the indexer returns a value type, and we try to set a field in it
8396 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8397 Error_CannotModifyIntermediateExpressionValue (ec);
8400 Expression e = ResolveAccessor (ec, AccessorType.Set);
8404 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8408 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8410 if (!CommonResolve (ec))
8413 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8414 if (ilist.Methods == null) {
8415 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8416 TypeManager.CSharpName (indexer_type));
8420 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8421 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8425 MethodInfo mi = (MethodInfo) mg;
8426 PropertyInfo pi = null;
8427 for (int i = 0; i < ilist.Methods.Count; ++i) {
8428 if (ilist.Methods [i] == mi) {
8429 pi = (PropertyInfo) ilist.Properties [i];
8434 type = TypeManager.TypeToCoreType (pi.PropertyType);
8435 if (type.IsPointer && !ec.InUnsafe)
8438 MethodInfo accessor;
8439 if (accessorType == AccessorType.Get) {
8440 accessor = get = pi.GetGetMethod (true);
8442 accessor = set = pi.GetSetMethod (true);
8443 if (accessor == null && pi.GetGetMethod (true) != null) {
8444 Report.SymbolRelatedToPreviousError (pi);
8445 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8446 TypeManager.GetFullNameSignature (pi));
8451 if (accessor == null) {
8452 Report.SymbolRelatedToPreviousError (pi);
8453 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8454 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8459 // Only base will allow this invocation to happen.
8461 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8462 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8465 bool must_do_cs1540_check;
8466 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8468 set = pi.GetSetMethod (true);
8470 get = pi.GetGetMethod (true);
8472 if (set != null && get != null &&
8473 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8474 Report.SymbolRelatedToPreviousError (accessor);
8475 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8476 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8478 Report.SymbolRelatedToPreviousError (pi);
8479 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8483 instance_expr.CheckMarshalByRefAccess (ec);
8484 eclass = ExprClass.IndexerAccess;
8488 public void Emit (EmitContext ec, bool leave_copy)
8491 prepared_value.Emit (ec);
8493 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8494 arguments, loc, false, false);
8498 ec.ig.Emit (OpCodes.Dup);
8499 temp = new LocalTemporary (Type);
8505 // source is ignored, because we already have a copy of it from the
8506 // LValue resolution and we have already constructed a pre-cached
8507 // version of the arguments (ea.set_arguments);
8509 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8511 prepared = prepare_for_load;
8512 Expression value = set_expr;
8515 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8516 arguments, loc, true, false);
8518 prepared_value = new LocalTemporary (type);
8519 prepared_value.Store (ec);
8521 prepared_value.Release (ec);
8524 ec.ig.Emit (OpCodes.Dup);
8525 temp = new LocalTemporary (Type);
8528 } else if (leave_copy) {
8529 temp = new LocalTemporary (Type);
8535 arguments.Add (new Argument (value, Argument.AType.Expression));
8536 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8544 public override void Emit (EmitContext ec)
8549 public override string GetSignatureForError ()
8551 return TypeManager.CSharpSignature (get != null ? get : set, false);
8554 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8557 get = storey.MutateGenericMethod (get);
8559 set = storey.MutateGenericMethod (set);
8561 instance_expr.MutateHoistedGenericType (storey);
8562 foreach (Argument a in arguments)
8563 a.Expr.MutateHoistedGenericType (storey);
8565 type = storey.MutateType (type);
8568 protected override void CloneTo (CloneContext clonectx, Expression t)
8570 IndexerAccess target = (IndexerAccess) t;
8572 if (arguments != null){
8573 target.arguments = new ArrayList ();
8574 foreach (Argument a in arguments)
8575 target.arguments.Add (a.Clone (clonectx));
8577 if (instance_expr != null)
8578 target.instance_expr = instance_expr.Clone (clonectx);
8583 /// The base operator for method names
8585 public class BaseAccess : Expression {
8586 public readonly string Identifier;
8589 public BaseAccess (string member, Location l)
8591 this.Identifier = member;
8595 public BaseAccess (string member, TypeArguments args, Location l)
8601 public override Expression CreateExpressionTree (EmitContext ec)
8603 throw new NotSupportedException ("ET");
8606 public override Expression DoResolve (EmitContext ec)
8608 Expression c = CommonResolve (ec);
8614 // MethodGroups use this opportunity to flag an error on lacking ()
8616 if (!(c is MethodGroupExpr))
8617 return c.Resolve (ec);
8621 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8623 Expression c = CommonResolve (ec);
8629 // MethodGroups use this opportunity to flag an error on lacking ()
8631 if (! (c is MethodGroupExpr))
8632 return c.DoResolveLValue (ec, right_side);
8637 Expression CommonResolve (EmitContext ec)
8639 Expression member_lookup;
8640 Type current_type = ec.ContainerType;
8641 Type base_type = current_type.BaseType;
8643 if (!This.IsThisAvailable (ec)) {
8645 Error (1511, "Keyword `base' is not available in a static method");
8647 Error (1512, "Keyword `base' is not available in the current context");
8652 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8653 AllMemberTypes, AllBindingFlags, loc);
8654 if (member_lookup == null) {
8655 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8656 null, AllMemberTypes, AllBindingFlags);
8663 left = new TypeExpression (base_type, loc);
8665 left = ec.GetThis (loc);
8667 MemberExpr me = (MemberExpr) member_lookup;
8668 me = me.ResolveMemberAccess (ec, left, loc, null);
8675 me.SetTypeArguments (args);
8681 public override void Emit (EmitContext ec)
8683 throw new Exception ("Should never be called");
8686 protected override void CloneTo (CloneContext clonectx, Expression t)
8688 BaseAccess target = (BaseAccess) t;
8691 target.args = args.Clone ();
8696 /// The base indexer operator
8698 public class BaseIndexerAccess : IndexerAccess {
8699 public BaseIndexerAccess (ArrayList args, Location loc)
8700 : base (null, true, loc)
8702 arguments = new ArrayList ();
8703 foreach (Expression tmp in args)
8704 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8707 protected override bool CommonResolve (EmitContext ec)
8709 instance_expr = ec.GetThis (loc);
8711 current_type = ec.ContainerType.BaseType;
8712 indexer_type = current_type;
8714 foreach (Argument a in arguments){
8715 if (!a.Resolve (ec, loc))
8722 public override Expression CreateExpressionTree (EmitContext ec)
8724 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8725 return base.CreateExpressionTree (ec);
8730 /// This class exists solely to pass the Type around and to be a dummy
8731 /// that can be passed to the conversion functions (this is used by
8732 /// foreach implementation to typecast the object return value from
8733 /// get_Current into the proper type. All code has been generated and
8734 /// we only care about the side effect conversions to be performed
8736 /// This is also now used as a placeholder where a no-action expression
8737 /// is needed (the `New' class).
8739 public class EmptyExpression : Expression {
8740 public static readonly Expression Null = new EmptyExpression ();
8742 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8743 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8744 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8745 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8747 static EmptyExpression temp = new EmptyExpression ();
8748 public static EmptyExpression Grab ()
8750 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8755 public static void Release (EmptyExpression e)
8760 // TODO: should be protected
8761 public EmptyExpression ()
8763 type = TypeManager.object_type;
8764 eclass = ExprClass.Value;
8765 loc = Location.Null;
8768 public EmptyExpression (Type t)
8771 eclass = ExprClass.Value;
8772 loc = Location.Null;
8775 public override Expression CreateExpressionTree (EmitContext ec)
8777 throw new NotSupportedException ("ET");
8780 public override Expression DoResolve (EmitContext ec)
8785 public override void Emit (EmitContext ec)
8787 // nothing, as we only exist to not do anything.
8790 public override void EmitSideEffect (EmitContext ec)
8795 // This is just because we might want to reuse this bad boy
8796 // instead of creating gazillions of EmptyExpressions.
8797 // (CanImplicitConversion uses it)
8799 public void SetType (Type t)
8806 // Empty statement expression
8808 public sealed class EmptyExpressionStatement : ExpressionStatement
8810 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8812 private EmptyExpressionStatement ()
8814 eclass = ExprClass.Value;
8815 loc = Location.Null;
8818 public override Expression CreateExpressionTree (EmitContext ec)
8823 public override void EmitStatement (EmitContext ec)
8828 public override Expression DoResolve (EmitContext ec)
8830 type = TypeManager.object_type;
8834 public override void Emit (EmitContext ec)
8840 public class UserCast : Expression {
8844 public UserCast (MethodInfo method, Expression source, Location l)
8846 this.method = method;
8847 this.source = source;
8848 type = TypeManager.TypeToCoreType (method.ReturnType);
8852 public Expression Source {
8858 public override Expression CreateExpressionTree (EmitContext ec)
8860 ArrayList args = new ArrayList (3);
8861 args.Add (new Argument (source.CreateExpressionTree (ec)));
8862 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8863 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8864 return CreateExpressionFactoryCall ("Convert", args);
8867 public override Expression DoResolve (EmitContext ec)
8869 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8871 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8873 eclass = ExprClass.Value;
8877 public override void Emit (EmitContext ec)
8880 ec.ig.Emit (OpCodes.Call, method);
8883 public override string GetSignatureForError ()
8885 return TypeManager.CSharpSignature (method);
8888 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8890 source.MutateHoistedGenericType (storey);
8891 method = storey.MutateGenericMethod (method);
8896 // This class is used to "construct" the type during a typecast
8897 // operation. Since the Type.GetType class in .NET can parse
8898 // the type specification, we just use this to construct the type
8899 // one bit at a time.
8901 public class ComposedCast : TypeExpr {
8902 FullNamedExpression left;
8905 public ComposedCast (FullNamedExpression left, string dim)
8906 : this (left, dim, left.Location)
8910 public ComposedCast (FullNamedExpression left, string dim, Location l)
8917 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8919 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8923 Type ltype = lexpr.Type;
8925 if ((dim.Length > 0) && (dim [0] == '?')) {
8926 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8928 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8929 return nullable.ResolveAsTypeTerminal (ec, false);
8933 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8936 if (dim.Length != 0 && dim [0] == '[') {
8937 if (TypeManager.IsSpecialType (ltype)) {
8938 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8942 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8943 Report.SymbolRelatedToPreviousError (ltype);
8944 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8945 TypeManager.CSharpName (ltype));
8950 type = TypeManager.GetConstructedType (ltype, dim);
8955 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8957 if (type.IsPointer && !ec.IsInUnsafeScope){
8961 eclass = ExprClass.Type;
8965 public override string GetSignatureForError ()
8967 return left.GetSignatureForError () + dim;
8970 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8972 return ResolveAsBaseTerminal (ec, silent);
8976 public class FixedBufferPtr : Expression {
8979 public FixedBufferPtr (Expression array, Type array_type, Location l)
8984 type = TypeManager.GetPointerType (array_type);
8985 eclass = ExprClass.Value;
8988 public override Expression CreateExpressionTree (EmitContext ec)
8990 Error_PointerInsideExpressionTree ();
8994 public override void Emit(EmitContext ec)
8999 public override Expression DoResolve (EmitContext ec)
9002 // We are born fully resolved
9010 // This class is used to represent the address of an array, used
9011 // only by the Fixed statement, this generates "&a [0]" construct
9012 // for fixed (char *pa = a)
9014 public class ArrayPtr : FixedBufferPtr {
9017 public ArrayPtr (Expression array, Type array_type, Location l):
9018 base (array, array_type, l)
9020 this.array_type = array_type;
9023 public override void Emit (EmitContext ec)
9027 ILGenerator ig = ec.ig;
9028 IntLiteral.EmitInt (ig, 0);
9029 ig.Emit (OpCodes.Ldelema, array_type);
9034 // Encapsulates a conversion rules required for array indexes
9036 public class ArrayIndexCast : TypeCast
9038 public ArrayIndexCast (Expression expr)
9039 : base (expr, expr.Type)
9043 public override Expression CreateExpressionTree (EmitContext ec)
9045 ArrayList args = new ArrayList (2);
9046 args.Add (new Argument (child.CreateExpressionTree (ec)));
9047 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9048 return CreateExpressionFactoryCall ("ConvertChecked", args);
9051 public override void Emit (EmitContext ec)
9055 if (type == TypeManager.int32_type)
9058 if (type == TypeManager.uint32_type)
9059 ec.ig.Emit (OpCodes.Conv_U);
9060 else if (type == TypeManager.int64_type)
9061 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9062 else if (type == TypeManager.uint64_type)
9063 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9065 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9070 // Implements the `stackalloc' keyword
9072 public class StackAlloc : Expression {
9077 public StackAlloc (Expression type, Expression count, Location l)
9084 public override Expression CreateExpressionTree (EmitContext ec)
9086 throw new NotSupportedException ("ET");
9089 public override Expression DoResolve (EmitContext ec)
9091 count = count.Resolve (ec);
9095 if (count.Type != TypeManager.uint32_type){
9096 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9101 Constant c = count as Constant;
9102 if (c != null && c.IsNegative) {
9103 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9107 if (ec.InCatch || ec.InFinally) {
9108 Error (255, "Cannot use stackalloc in finally or catch");
9112 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9118 if (!TypeManager.VerifyUnManaged (otype, loc))
9121 type = TypeManager.GetPointerType (otype);
9122 eclass = ExprClass.Value;
9127 public override void Emit (EmitContext ec)
9129 int size = GetTypeSize (otype);
9130 ILGenerator ig = ec.ig;
9135 ig.Emit (OpCodes.Sizeof, otype);
9137 IntConstant.EmitInt (ig, size);
9139 ig.Emit (OpCodes.Mul_Ovf_Un);
9140 ig.Emit (OpCodes.Localloc);
9143 protected override void CloneTo (CloneContext clonectx, Expression t)
9145 StackAlloc target = (StackAlloc) t;
9146 target.count = count.Clone (clonectx);
9147 target.t = t.Clone (clonectx);
9152 // An object initializer expression
9154 public class ElementInitializer : Assign
9156 public readonly string Name;
9158 public ElementInitializer (string name, Expression initializer, Location loc)
9159 : base (null, initializer, loc)
9164 protected override void CloneTo (CloneContext clonectx, Expression t)
9166 ElementInitializer target = (ElementInitializer) t;
9167 target.source = source.Clone (clonectx);
9170 public override Expression CreateExpressionTree (EmitContext ec)
9172 ArrayList args = new ArrayList (2);
9173 FieldExpr fe = target as FieldExpr;
9175 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9177 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9179 args.Add (new Argument (source.CreateExpressionTree (ec)));
9180 return CreateExpressionFactoryCall (
9181 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9185 public override Expression DoResolve (EmitContext ec)
9188 return EmptyExpressionStatement.Instance;
9190 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9191 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9197 me.InstanceExpression = ec.CurrentInitializerVariable;
9199 if (source is CollectionOrObjectInitializers) {
9200 Expression previous = ec.CurrentInitializerVariable;
9201 ec.CurrentInitializerVariable = target;
9202 source = source.Resolve (ec);
9203 ec.CurrentInitializerVariable = previous;
9207 eclass = source.eclass;
9212 Expression expr = base.DoResolve (ec);
9217 // Ignore field initializers with default value
9219 Constant c = source as Constant;
9220 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9221 return EmptyExpressionStatement.Instance.DoResolve (ec);
9226 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9228 MemberInfo member = members [0];
9229 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9230 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9231 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9233 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9234 TypeManager.GetFullNameSignature (member));
9239 public override void EmitStatement (EmitContext ec)
9241 if (source is CollectionOrObjectInitializers)
9244 base.EmitStatement (ec);
9249 // A collection initializer expression
9251 public class CollectionElementInitializer : Invocation
9253 public class ElementInitializerArgument : Argument
9255 public ElementInitializerArgument (Expression e)
9261 sealed class AddMemberAccess : MemberAccess
9263 public AddMemberAccess (Expression expr, Location loc)
9264 : base (expr, "Add", loc)
9268 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9270 if (TypeManager.HasElementType (type))
9273 base.Error_TypeDoesNotContainDefinition (type, name);
9277 public CollectionElementInitializer (Expression argument)
9278 : base (null, new ArrayList (1), true)
9280 Arguments.Add (argument);
9281 this.loc = argument.Location;
9284 public CollectionElementInitializer (ArrayList arguments, Location loc)
9285 : base (null, arguments, true)
9290 public override Expression CreateExpressionTree (EmitContext ec)
9292 ArrayList args = new ArrayList (2);
9293 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9295 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9296 foreach (Argument a in Arguments)
9297 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9299 args.Add (new Argument (new ArrayCreation (
9300 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9301 return CreateExpressionFactoryCall ("ElementInit", args);
9304 protected override void CloneTo (CloneContext clonectx, Expression t)
9306 CollectionElementInitializer target = (CollectionElementInitializer) t;
9308 target.Arguments = new ArrayList (Arguments.Count);
9309 foreach (Expression e in Arguments)
9310 target.Arguments.Add (e.Clone (clonectx));
9313 public override Expression DoResolve (EmitContext ec)
9315 if (eclass != ExprClass.Invalid)
9318 // TODO: We could call a constructor which takes element count argument,
9319 // for known types like List<T>, Dictionary<T, U>
9321 for (int i = 0; i < Arguments.Count; ++i) {
9322 Expression expr = Arguments [i] as Expression;
9326 expr = expr.Resolve (ec);
9330 Arguments [i] = new ElementInitializerArgument (expr);
9333 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9335 return base.DoResolve (ec);
9340 // A block of object or collection initializers
9342 public class CollectionOrObjectInitializers : ExpressionStatement
9344 ArrayList initializers;
9346 public static readonly CollectionOrObjectInitializers Empty =
9347 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9349 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9351 this.initializers = initializers;
9355 public bool IsEmpty {
9357 return initializers.Count == 0;
9361 public bool IsCollectionInitializer {
9363 return type == typeof (CollectionOrObjectInitializers);
9367 protected override void CloneTo (CloneContext clonectx, Expression target)
9369 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9371 t.initializers = new ArrayList (initializers.Count);
9372 foreach (Expression e in initializers)
9373 t.initializers.Add (e.Clone (clonectx));
9376 public override Expression CreateExpressionTree (EmitContext ec)
9378 ArrayList expr_initializers = new ArrayList (initializers.Count);
9379 foreach (Expression e in initializers) {
9380 Expression expr = e.CreateExpressionTree (ec);
9382 expr_initializers.Add (expr);
9385 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9388 public override Expression DoResolve (EmitContext ec)
9390 if (eclass != ExprClass.Invalid)
9393 bool is_collection_initialization = false;
9394 ArrayList element_names = null;
9395 for (int i = 0; i < initializers.Count; ++i) {
9396 Expression initializer = (Expression) initializers [i];
9397 ElementInitializer element_initializer = initializer as ElementInitializer;
9400 if (element_initializer != null) {
9401 element_names = new ArrayList (initializers.Count);
9402 element_names.Add (element_initializer.Name);
9404 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9405 TypeManager.ienumerable_type)) {
9406 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9407 "object initializer because type `{1}' does not implement `{2}' interface",
9408 ec.CurrentInitializerVariable.GetSignatureForError (),
9409 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9410 TypeManager.CSharpName (TypeManager.ienumerable_type));
9413 is_collection_initialization = true;
9416 if (is_collection_initialization != (element_initializer == null)) {
9417 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9418 is_collection_initialization ? "collection initializer" : "object initializer");
9422 if (!is_collection_initialization) {
9423 if (element_names.Contains (element_initializer.Name)) {
9424 Report.Error (1912, element_initializer.Location,
9425 "An object initializer includes more than one member `{0}' initialization",
9426 element_initializer.Name);
9428 element_names.Add (element_initializer.Name);
9433 Expression e = initializer.Resolve (ec);
9434 if (e == EmptyExpressionStatement.Instance)
9435 initializers.RemoveAt (i--);
9437 initializers [i] = e;
9440 if (is_collection_initialization) {
9441 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9442 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9443 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9446 type = typeof (CollectionOrObjectInitializers);
9448 type = typeof (ElementInitializer);
9451 eclass = ExprClass.Variable;
9455 public override void Emit (EmitContext ec)
9460 public override void EmitStatement (EmitContext ec)
9462 foreach (ExpressionStatement e in initializers)
9463 e.EmitStatement (ec);
9466 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9468 foreach (Expression e in initializers)
9469 e.MutateHoistedGenericType (storey);
9474 // New expression with element/object initializers
9476 public class NewInitialize : New
9479 // This class serves as a proxy for variable initializer target instances.
9480 // A real variable is assigned later when we resolve left side of an
9483 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9485 NewInitialize new_instance;
9487 public InitializerTargetExpression (NewInitialize newInstance)
9489 this.type = newInstance.type;
9490 this.loc = newInstance.loc;
9491 this.eclass = newInstance.eclass;
9492 this.new_instance = newInstance;
9495 public override Expression CreateExpressionTree (EmitContext ec)
9497 // Should not be reached
9498 throw new NotSupportedException ("ET");
9501 public override Expression DoResolve (EmitContext ec)
9506 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9511 public override void Emit (EmitContext ec)
9513 Expression e = (Expression) new_instance.instance;
9517 #region IMemoryLocation Members
9519 public void AddressOf (EmitContext ec, AddressOp mode)
9521 new_instance.instance.AddressOf (ec, mode);
9527 CollectionOrObjectInitializers initializers;
9528 IMemoryLocation instance;
9530 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9531 : base (requested_type, arguments, l)
9533 this.initializers = initializers;
9536 protected override void CloneTo (CloneContext clonectx, Expression t)
9538 base.CloneTo (clonectx, t);
9540 NewInitialize target = (NewInitialize) t;
9541 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9544 public override Expression CreateExpressionTree (EmitContext ec)
9546 ArrayList args = new ArrayList (2);
9547 args.Add (new Argument (base.CreateExpressionTree (ec)));
9548 if (!initializers.IsEmpty)
9549 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9551 return CreateExpressionFactoryCall (
9552 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9556 public override Expression DoResolve (EmitContext ec)
9558 if (eclass != ExprClass.Invalid)
9561 Expression e = base.DoResolve (ec);
9565 // Empty initializer can be optimized to simple new
9566 if (initializers.IsEmpty) {
9567 initializers.Resolve (ec);
9568 return ReducedExpression.Create (e, this).Resolve (ec);
9571 Expression previous = ec.CurrentInitializerVariable;
9572 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9573 initializers.Resolve (ec);
9574 ec.CurrentInitializerVariable = previous;
9578 public override bool Emit (EmitContext ec, IMemoryLocation target)
9580 bool left_on_stack = base.Emit (ec, target);
9582 if (initializers.IsEmpty)
9583 return left_on_stack;
9585 LocalTemporary temp = null;
9588 // If target is non-hoisted variable, let's use it
9590 VariableReference variable = target as VariableReference;
9591 if (variable != null) {
9594 if (left_on_stack) {
9596 StoreFromPtr (ec.ig, type);
9598 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9600 left_on_stack = false;
9603 temp = target as LocalTemporary;
9606 throw new NotImplementedException ();
9608 temp = new LocalTemporary (type);
9616 initializers.Emit (ec);
9618 if (left_on_stack) {
9623 return left_on_stack;
9626 public override bool HasInitializer {
9628 return !initializers.IsEmpty;
9632 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9634 base.MutateHoistedGenericType (storey);
9635 initializers.MutateHoistedGenericType (storey);
9639 public class AnonymousTypeDeclaration : Expression
9641 ArrayList parameters;
9642 readonly TypeContainer parent;
9643 static readonly ArrayList EmptyParameters = new ArrayList (0);
9645 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9647 this.parameters = parameters;
9648 this.parent = parent;
9652 protected override void CloneTo (CloneContext clonectx, Expression target)
9654 if (parameters == null)
9657 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9658 t.parameters = new ArrayList (parameters.Count);
9659 foreach (AnonymousTypeParameter atp in parameters)
9660 t.parameters.Add (atp.Clone (clonectx));
9663 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9665 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9669 type = AnonymousTypeClass.Create (parent, parameters, loc);
9676 if (Report.Errors == 0)
9679 RootContext.ToplevelTypes.AddAnonymousType (type);
9683 public override Expression CreateExpressionTree (EmitContext ec)
9685 throw new NotSupportedException ("ET");
9688 public override Expression DoResolve (EmitContext ec)
9690 AnonymousTypeClass anonymous_type;
9692 if (!ec.IsAnonymousMethodAllowed) {
9693 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9697 if (parameters == null) {
9698 anonymous_type = CreateAnonymousType (EmptyParameters);
9699 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9700 null, loc).Resolve (ec);
9704 ArrayList arguments = new ArrayList (parameters.Count);
9705 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9706 for (int i = 0; i < parameters.Count; ++i) {
9707 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9713 arguments.Add (new Argument (e));
9714 t_args [i] = new TypeExpression (e.Type, e.Location);
9720 anonymous_type = CreateAnonymousType (parameters);
9721 if (anonymous_type == null)
9724 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9725 new TypeArguments (t_args), loc);
9727 return new New (te, arguments, loc).Resolve (ec);
9730 public override void Emit (EmitContext ec)
9732 throw new InternalErrorException ("Should not be reached");
9736 public class AnonymousTypeParameter : Expression
9738 public readonly string Name;
9739 Expression initializer;
9741 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9745 this.initializer = initializer;
9748 public AnonymousTypeParameter (Parameter parameter)
9750 this.Name = parameter.Name;
9751 this.loc = parameter.Location;
9752 this.initializer = new SimpleName (Name, loc);
9755 protected override void CloneTo (CloneContext clonectx, Expression target)
9757 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9758 t.initializer = initializer.Clone (clonectx);
9761 public override Expression CreateExpressionTree (EmitContext ec)
9763 throw new NotSupportedException ("ET");
9766 public override bool Equals (object o)
9768 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9769 return other != null && Name == other.Name;
9772 public override int GetHashCode ()
9774 return Name.GetHashCode ();
9777 public override Expression DoResolve (EmitContext ec)
9779 Expression e = initializer.Resolve (ec);
9783 if (e.eclass == ExprClass.MethodGroup) {
9784 Error_InvalidInitializer (e.ExprClassName);
9789 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9790 type == TypeManager.anonymous_method_type || type.IsPointer) {
9791 Error_InvalidInitializer (e.GetSignatureForError ());
9798 protected virtual void Error_InvalidInitializer (string initializer)
9800 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9804 public override void Emit (EmitContext ec)
9806 throw new InternalErrorException ("Should not be reached");