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
1549 sealed class DefaultValueNullLiteral : NullLiteral
1551 public DefaultValueNullLiteral (DefaultValueExpression expr)
1552 : base (expr.type, expr.loc)
1556 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
1558 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1565 public DefaultValueExpression (Expression expr, Location loc)
1571 public override Expression CreateExpressionTree (EmitContext ec)
1573 ArrayList args = new ArrayList (2);
1574 args.Add (new Argument (this));
1575 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1576 return CreateExpressionFactoryCall ("Constant", args);
1579 public override Expression DoResolve (EmitContext ec)
1581 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1587 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1588 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1592 return new NullLiteral (Location).ConvertImplicitly (type);
1594 if (TypeManager.IsReferenceType (type))
1595 return new DefaultValueNullLiteral (this);
1597 Constant c = New.Constantify (type);
1601 eclass = ExprClass.Variable;
1605 public override void Emit (EmitContext ec)
1607 LocalTemporary temp_storage = new LocalTemporary(type);
1609 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1610 ec.ig.Emit(OpCodes.Initobj, type);
1611 temp_storage.Emit(ec);
1614 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1616 type = storey.MutateType (type);
1619 protected override void CloneTo (CloneContext clonectx, Expression t)
1621 DefaultValueExpression target = (DefaultValueExpression) t;
1623 target.expr = expr.Clone (clonectx);
1628 /// Binary operators
1630 public class Binary : Expression {
1632 protected class PredefinedOperator {
1633 protected readonly Type left;
1634 protected readonly Type right;
1635 public readonly Operator OperatorsMask;
1636 public Type ReturnType;
1638 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1639 : this (ltype, rtype, op_mask, ltype)
1643 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1644 : this (type, type, op_mask, return_type)
1648 public PredefinedOperator (Type type, Operator op_mask)
1649 : this (type, type, op_mask, type)
1653 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1655 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1656 throw new InternalErrorException ("Only masked values can be used");
1660 this.OperatorsMask = op_mask;
1661 this.ReturnType = return_type;
1664 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1666 b.type = ReturnType;
1668 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1669 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1672 // A user operators does not support multiple user conversions, but decimal type
1673 // is considered to be predefined type therefore we apply predefined operators rules
1674 // and then look for decimal user-operator implementation
1676 if (left == TypeManager.decimal_type)
1677 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1682 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1685 // We are dealing with primitive types only
1687 return left == ltype && ltype == rtype;
1690 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1692 if (TypeManager.IsEqual (left, lexpr.Type) &&
1693 TypeManager.IsEqual (right, rexpr.Type))
1696 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1697 Convert.ImplicitConversionExists (ec, rexpr, right);
1700 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1703 if (left != null && best_operator.left != null) {
1704 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1708 // When second arguments are same as the first one, the result is same
1710 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1711 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1714 if (result == 0 || result > 2)
1717 return result == 1 ? best_operator : this;
1721 class PredefinedStringOperator : PredefinedOperator {
1722 public PredefinedStringOperator (Type type, Operator op_mask)
1723 : base (type, op_mask, type)
1725 ReturnType = TypeManager.string_type;
1728 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1729 : base (ltype, rtype, op_mask)
1731 ReturnType = TypeManager.string_type;
1734 public override Expression ConvertResult (EmitContext ec, Binary b)
1737 // Use original expression for nullable arguments
1739 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1741 b.left = unwrap.Original;
1743 unwrap = b.right as Nullable.Unwrap;
1745 b.right = unwrap.Original;
1747 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1748 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1751 // Start a new concat expression using converted expression
1753 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1757 class PredefinedShiftOperator : PredefinedOperator {
1758 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1759 base (ltype, TypeManager.int32_type, op_mask)
1763 public override Expression ConvertResult (EmitContext ec, Binary b)
1765 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1767 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1769 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1772 // b = b.left >> b.right & (0x1f|0x3f)
1774 b.right = new Binary (Operator.BitwiseAnd,
1775 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1778 // Expression tree representation does not use & mask
1780 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1781 b.type = ReturnType;
1786 class PredefinedPointerOperator : PredefinedOperator {
1787 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1788 : base (ltype, rtype, op_mask)
1792 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1793 : base (ltype, rtype, op_mask, retType)
1797 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1798 : base (type, op_mask, return_type)
1802 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1805 if (!lexpr.Type.IsPointer)
1808 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1812 if (right == null) {
1813 if (!rexpr.Type.IsPointer)
1816 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1823 public override Expression ConvertResult (EmitContext ec, Binary b)
1826 b.left = EmptyCast.Create (b.left, left);
1827 } else if (right != null) {
1828 b.right = EmptyCast.Create (b.right, right);
1831 Type r_type = ReturnType;
1832 Expression left_arg, right_arg;
1833 if (r_type == null) {
1836 right_arg = b.right;
1837 r_type = b.left.Type;
1841 r_type = b.right.Type;
1845 right_arg = b.right;
1848 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1853 public enum Operator {
1854 Multiply = 0 | ArithmeticMask,
1855 Division = 1 | ArithmeticMask,
1856 Modulus = 2 | ArithmeticMask,
1857 Addition = 3 | ArithmeticMask | AdditionMask,
1858 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1860 LeftShift = 5 | ShiftMask,
1861 RightShift = 6 | ShiftMask,
1863 LessThan = 7 | ComparisonMask | RelationalMask,
1864 GreaterThan = 8 | ComparisonMask | RelationalMask,
1865 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1866 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1867 Equality = 11 | ComparisonMask | EqualityMask,
1868 Inequality = 12 | ComparisonMask | EqualityMask,
1870 BitwiseAnd = 13 | BitwiseMask,
1871 ExclusiveOr = 14 | BitwiseMask,
1872 BitwiseOr = 15 | BitwiseMask,
1874 LogicalAnd = 16 | LogicalMask,
1875 LogicalOr = 17 | LogicalMask,
1880 ValuesOnlyMask = ArithmeticMask - 1,
1881 ArithmeticMask = 1 << 5,
1883 ComparisonMask = 1 << 7,
1884 EqualityMask = 1 << 8,
1885 BitwiseMask = 1 << 9,
1886 LogicalMask = 1 << 10,
1887 AdditionMask = 1 << 11,
1888 SubtractionMask = 1 << 12,
1889 RelationalMask = 1 << 13
1892 readonly Operator oper;
1893 protected Expression left, right;
1894 readonly bool is_compound;
1895 Expression enum_conversion;
1897 static PredefinedOperator [] standard_operators;
1898 static PredefinedOperator [] pointer_operators;
1900 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1901 : this (oper, left, right)
1903 this.is_compound = isCompound;
1906 public Binary (Operator oper, Expression left, Expression right)
1911 this.loc = left.Location;
1914 public Operator Oper {
1921 /// Returns a stringified representation of the Operator
1923 string OperName (Operator oper)
1927 case Operator.Multiply:
1930 case Operator.Division:
1933 case Operator.Modulus:
1936 case Operator.Addition:
1939 case Operator.Subtraction:
1942 case Operator.LeftShift:
1945 case Operator.RightShift:
1948 case Operator.LessThan:
1951 case Operator.GreaterThan:
1954 case Operator.LessThanOrEqual:
1957 case Operator.GreaterThanOrEqual:
1960 case Operator.Equality:
1963 case Operator.Inequality:
1966 case Operator.BitwiseAnd:
1969 case Operator.BitwiseOr:
1972 case Operator.ExclusiveOr:
1975 case Operator.LogicalOr:
1978 case Operator.LogicalAnd:
1982 s = oper.ToString ();
1992 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1994 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1997 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
2000 // TODO: This should be handled as Type of method group in CSharpName
2001 if (left.eclass == ExprClass.MethodGroup)
2002 l = left.ExprClassName;
2004 l = TypeManager.CSharpName (left.Type);
2006 if (right.eclass == ExprClass.MethodGroup)
2007 r = right.ExprClassName;
2009 r = TypeManager.CSharpName (right.Type);
2011 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2015 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2017 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2020 static string GetOperatorMetadataName (Operator op)
2022 CSharp.Operator.OpType op_type;
2024 case Operator.Addition:
2025 op_type = CSharp.Operator.OpType.Addition; break;
2026 case Operator.BitwiseAnd:
2027 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2028 case Operator.BitwiseOr:
2029 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2030 case Operator.Division:
2031 op_type = CSharp.Operator.OpType.Division; break;
2032 case Operator.Equality:
2033 op_type = CSharp.Operator.OpType.Equality; break;
2034 case Operator.ExclusiveOr:
2035 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2036 case Operator.GreaterThan:
2037 op_type = CSharp.Operator.OpType.GreaterThan; break;
2038 case Operator.GreaterThanOrEqual:
2039 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2040 case Operator.Inequality:
2041 op_type = CSharp.Operator.OpType.Inequality; break;
2042 case Operator.LeftShift:
2043 op_type = CSharp.Operator.OpType.LeftShift; break;
2044 case Operator.LessThan:
2045 op_type = CSharp.Operator.OpType.LessThan; break;
2046 case Operator.LessThanOrEqual:
2047 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2048 case Operator.Modulus:
2049 op_type = CSharp.Operator.OpType.Modulus; break;
2050 case Operator.Multiply:
2051 op_type = CSharp.Operator.OpType.Multiply; break;
2052 case Operator.RightShift:
2053 op_type = CSharp.Operator.OpType.RightShift; break;
2054 case Operator.Subtraction:
2055 op_type = CSharp.Operator.OpType.Subtraction; break;
2057 throw new InternalErrorException (op.ToString ());
2060 return CSharp.Operator.GetMetadataName (op_type);
2063 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2066 ILGenerator ig = ec.ig;
2069 case Operator.Multiply:
2071 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2072 opcode = OpCodes.Mul_Ovf;
2073 else if (!IsFloat (l))
2074 opcode = OpCodes.Mul_Ovf_Un;
2076 opcode = OpCodes.Mul;
2078 opcode = OpCodes.Mul;
2082 case Operator.Division:
2084 opcode = OpCodes.Div_Un;
2086 opcode = OpCodes.Div;
2089 case Operator.Modulus:
2091 opcode = OpCodes.Rem_Un;
2093 opcode = OpCodes.Rem;
2096 case Operator.Addition:
2098 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2099 opcode = OpCodes.Add_Ovf;
2100 else if (!IsFloat (l))
2101 opcode = OpCodes.Add_Ovf_Un;
2103 opcode = OpCodes.Add;
2105 opcode = OpCodes.Add;
2108 case Operator.Subtraction:
2110 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2111 opcode = OpCodes.Sub_Ovf;
2112 else if (!IsFloat (l))
2113 opcode = OpCodes.Sub_Ovf_Un;
2115 opcode = OpCodes.Sub;
2117 opcode = OpCodes.Sub;
2120 case Operator.RightShift:
2122 opcode = OpCodes.Shr_Un;
2124 opcode = OpCodes.Shr;
2127 case Operator.LeftShift:
2128 opcode = OpCodes.Shl;
2131 case Operator.Equality:
2132 opcode = OpCodes.Ceq;
2135 case Operator.Inequality:
2136 ig.Emit (OpCodes.Ceq);
2137 ig.Emit (OpCodes.Ldc_I4_0);
2139 opcode = OpCodes.Ceq;
2142 case Operator.LessThan:
2144 opcode = OpCodes.Clt_Un;
2146 opcode = OpCodes.Clt;
2149 case Operator.GreaterThan:
2151 opcode = OpCodes.Cgt_Un;
2153 opcode = OpCodes.Cgt;
2156 case Operator.LessThanOrEqual:
2157 if (IsUnsigned (l) || IsFloat (l))
2158 ig.Emit (OpCodes.Cgt_Un);
2160 ig.Emit (OpCodes.Cgt);
2161 ig.Emit (OpCodes.Ldc_I4_0);
2163 opcode = OpCodes.Ceq;
2166 case Operator.GreaterThanOrEqual:
2167 if (IsUnsigned (l) || IsFloat (l))
2168 ig.Emit (OpCodes.Clt_Un);
2170 ig.Emit (OpCodes.Clt);
2172 ig.Emit (OpCodes.Ldc_I4_0);
2174 opcode = OpCodes.Ceq;
2177 case Operator.BitwiseOr:
2178 opcode = OpCodes.Or;
2181 case Operator.BitwiseAnd:
2182 opcode = OpCodes.And;
2185 case Operator.ExclusiveOr:
2186 opcode = OpCodes.Xor;
2190 throw new InternalErrorException (oper.ToString ());
2196 static bool IsUnsigned (Type t)
2201 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2202 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2205 static bool IsFloat (Type t)
2207 return t == TypeManager.float_type || t == TypeManager.double_type;
2210 Expression ResolveOperator (EmitContext ec)
2213 Type r = right.Type;
2215 bool primitives_only = false;
2217 if (standard_operators == null)
2218 CreateStandardOperatorsTable ();
2221 // Handles predefined primitive types
2223 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2224 if ((oper & Operator.ShiftMask) == 0) {
2225 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2228 primitives_only = true;
2232 if (l.IsPointer || r.IsPointer)
2233 return ResolveOperatorPointer (ec, l, r);
2236 bool lenum = TypeManager.IsEnumType (l);
2237 bool renum = TypeManager.IsEnumType (r);
2238 if (lenum || renum) {
2239 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2241 // TODO: Can this be ambiguous
2247 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2248 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2250 expr = ResolveOperatorDelegate (ec, l, r);
2252 // TODO: Can this be ambiguous
2258 expr = ResolveUserOperator (ec, l, r);
2262 // Predefined reference types equality
2263 if ((oper & Operator.EqualityMask) != 0) {
2264 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2270 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2273 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2274 // if 'left' is not an enumeration constant, create one from the type of 'right'
2275 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2278 case Operator.BitwiseOr:
2279 case Operator.BitwiseAnd:
2280 case Operator.ExclusiveOr:
2281 case Operator.Equality:
2282 case Operator.Inequality:
2283 case Operator.LessThan:
2284 case Operator.LessThanOrEqual:
2285 case Operator.GreaterThan:
2286 case Operator.GreaterThanOrEqual:
2287 if (TypeManager.IsEnumType (left.Type))
2290 if (left.IsZeroInteger)
2291 return left.TryReduce (ec, right.Type, loc);
2295 case Operator.Addition:
2296 case Operator.Subtraction:
2299 case Operator.Multiply:
2300 case Operator.Division:
2301 case Operator.Modulus:
2302 case Operator.LeftShift:
2303 case Operator.RightShift:
2304 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2308 Error_OperatorCannotBeApplied (this.left, this.right);
2313 // The `|' operator used on types which were extended is dangerous
2315 void CheckBitwiseOrOnSignExtended ()
2317 OpcodeCast lcast = left as OpcodeCast;
2318 if (lcast != null) {
2319 if (IsUnsigned (lcast.UnderlyingType))
2323 OpcodeCast rcast = right as OpcodeCast;
2324 if (rcast != null) {
2325 if (IsUnsigned (rcast.UnderlyingType))
2329 if (lcast == null && rcast == null)
2332 // FIXME: consider constants
2334 Report.Warning (675, 3, loc,
2335 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2336 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2339 static void CreatePointerOperatorsTable ()
2341 ArrayList temp = new ArrayList ();
2344 // Pointer arithmetic:
2346 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2347 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2348 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2349 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2351 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2352 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2353 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2354 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2357 // T* operator + (int y, T* x);
2358 // T* operator + (uint y, T *x);
2359 // T* operator + (long y, T *x);
2360 // T* operator + (ulong y, T *x);
2362 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2363 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2364 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2365 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2368 // long operator - (T* x, T *y)
2370 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2372 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2375 static void CreateStandardOperatorsTable ()
2377 ArrayList temp = new ArrayList ();
2378 Type bool_type = TypeManager.bool_type;
2380 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2381 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2382 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2383 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2384 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2385 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2386 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2388 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2389 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2390 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2391 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2392 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2393 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2394 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2396 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2398 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2399 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2400 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2402 temp.Add (new PredefinedOperator (bool_type,
2403 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2405 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2406 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2407 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2408 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2410 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2414 // Rules used during binary numeric promotion
2416 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2421 Constant c = prim_expr as Constant;
2423 temp = c.ConvertImplicitly (type);
2430 if (type == TypeManager.uint32_type) {
2431 etype = prim_expr.Type;
2432 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2433 type = TypeManager.int64_type;
2435 if (type != second_expr.Type) {
2436 c = second_expr as Constant;
2438 temp = c.ConvertImplicitly (type);
2440 temp = Convert.ImplicitNumericConversion (second_expr, type);
2446 } else if (type == TypeManager.uint64_type) {
2448 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2450 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2451 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2455 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2464 // 7.2.6.2 Binary numeric promotions
2466 public bool DoBinaryOperatorPromotion (EmitContext ec)
2468 Type ltype = left.Type;
2469 Type rtype = right.Type;
2472 foreach (Type t in ConstantFold.binary_promotions) {
2474 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2477 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2480 Type int32 = TypeManager.int32_type;
2481 if (ltype != int32) {
2482 Constant c = left as Constant;
2484 temp = c.ConvertImplicitly (int32);
2486 temp = Convert.ImplicitNumericConversion (left, int32);
2493 if (rtype != int32) {
2494 Constant c = right as Constant;
2496 temp = c.ConvertImplicitly (int32);
2498 temp = Convert.ImplicitNumericConversion (right, int32);
2508 public override Expression DoResolve (EmitContext ec)
2513 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2514 left = ((ParenthesizedExpression) left).Expr;
2515 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2519 if (left.eclass == ExprClass.Type) {
2520 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2524 left = left.Resolve (ec);
2529 Constant lc = left as Constant;
2531 if (lc != null && lc.Type == TypeManager.bool_type &&
2532 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2533 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2535 // FIXME: resolve right expression as unreachable
2536 // right.Resolve (ec);
2538 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2542 right = right.Resolve (ec);
2546 eclass = ExprClass.Value;
2547 Constant rc = right as Constant;
2549 // The conversion rules are ignored in enum context but why
2550 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2551 lc = EnumLiftUp (ec, lc, rc, loc);
2553 rc = EnumLiftUp (ec, rc, lc, loc);
2556 if (rc != null && lc != null) {
2557 int prev_e = Report.Errors;
2558 Expression e = ConstantFold.BinaryFold (
2559 ec, oper, lc, rc, loc);
2560 if (e != null || Report.Errors != prev_e)
2563 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2564 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2566 if ((ResolveOperator (ec)) == null) {
2567 Error_OperatorCannotBeApplied (left, right);
2572 // The result is a constant with side-effect
2574 Constant side_effect = rc == null ?
2575 new SideEffectConstant (lc, right, loc) :
2576 new SideEffectConstant (rc, left, loc);
2578 return ReducedExpression.Create (side_effect, this);
2582 // Comparison warnings
2583 if ((oper & Operator.ComparisonMask) != 0) {
2584 if (left.Equals (right)) {
2585 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2587 CheckUselessComparison (lc, right.Type);
2588 CheckUselessComparison (rc, left.Type);
2591 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2592 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2593 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2594 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2595 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2596 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2598 return DoResolveCore (ec, left, right);
2601 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2603 Expression expr = ResolveOperator (ec);
2605 Error_OperatorCannotBeApplied (left_orig, right_orig);
2607 if (left == null || right == null)
2608 throw new InternalErrorException ("Invalid conversion");
2610 if (oper == Operator.BitwiseOr)
2611 CheckBitwiseOrOnSignExtended ();
2616 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2618 left.MutateHoistedGenericType (storey);
2619 right.MutateHoistedGenericType (storey);
2623 // D operator + (D x, D y)
2624 // D operator - (D x, D y)
2625 // bool operator == (D x, D y)
2626 // bool operator != (D x, D y)
2628 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2630 bool is_equality = (oper & Operator.EqualityMask) != 0;
2631 if (!TypeManager.IsEqual (l, r)) {
2633 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2634 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2639 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2640 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2651 // Resolve delegate equality as a user operator
2654 return ResolveUserOperator (ec, l, r);
2657 ArrayList args = new ArrayList (2);
2658 args.Add (new Argument (left, Argument.AType.Expression));
2659 args.Add (new Argument (right, Argument.AType.Expression));
2661 if (oper == Operator.Addition) {
2662 if (TypeManager.delegate_combine_delegate_delegate == null) {
2663 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2664 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2667 method = TypeManager.delegate_combine_delegate_delegate;
2669 if (TypeManager.delegate_remove_delegate_delegate == null) {
2670 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2671 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2674 method = TypeManager.delegate_remove_delegate_delegate;
2677 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2678 mg = mg.OverloadResolve (ec, ref args, false, loc);
2680 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2684 // Enumeration operators
2686 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2689 // bool operator == (E x, E y);
2690 // bool operator != (E x, E y);
2691 // bool operator < (E x, E y);
2692 // bool operator > (E x, E y);
2693 // bool operator <= (E x, E y);
2694 // bool operator >= (E x, E y);
2696 // E operator & (E x, E y);
2697 // E operator | (E x, E y);
2698 // E operator ^ (E x, E y);
2700 // U operator - (E e, E f)
2701 // E operator - (E e, U x)
2703 // E operator + (U x, E e)
2704 // E operator + (E e, U x)
2706 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2707 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2710 Expression ltemp = left;
2711 Expression rtemp = right;
2712 Type underlying_type;
2715 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2717 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2723 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2731 if (TypeManager.IsEqual (ltype, rtype)) {
2732 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2734 if (left is Constant)
2735 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2737 left = EmptyCast.Create (left, underlying_type);
2739 if (right is Constant)
2740 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2742 right = EmptyCast.Create (right, underlying_type);
2744 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2746 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2747 Constant c = right as Constant;
2748 if (c == null || !c.IsDefaultValue)
2751 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2754 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2757 if (left is Constant)
2758 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2760 left = EmptyCast.Create (left, underlying_type);
2763 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2765 if (oper != Operator.Addition) {
2766 Constant c = left as Constant;
2767 if (c == null || !c.IsDefaultValue)
2770 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2773 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2776 if (right is Constant)
2777 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2779 right = EmptyCast.Create (right, underlying_type);
2786 // C# specification uses explicit cast syntax which means binary promotion
2787 // should happen, however it seems that csc does not do that
2789 if (!DoBinaryOperatorPromotion (ec)) {
2795 Type res_type = null;
2796 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2797 Type promoted_type = lenum ? left.Type : right.Type;
2798 enum_conversion = Convert.ExplicitNumericConversion (
2799 new EmptyExpression (promoted_type), underlying_type);
2801 if (oper == Operator.Subtraction && renum && lenum)
2802 res_type = underlying_type;
2803 else if (oper == Operator.Addition && renum)
2809 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2810 if (!is_compound || expr == null)
2814 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2817 if (Convert.ImplicitConversionExists (ec, left, rtype))
2820 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2823 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2828 // 7.9.6 Reference type equality operators
2830 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2833 // operator != (object a, object b)
2834 // operator == (object a, object b)
2837 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2839 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2842 type = TypeManager.bool_type;
2843 GenericConstraints constraints;
2845 bool lgen = TypeManager.IsGenericParameter (l);
2847 if (TypeManager.IsEqual (l, r)) {
2850 // Only allow to compare same reference type parameter
2852 constraints = TypeManager.GetTypeParameterConstraints (l);
2853 if (constraints != null && constraints.IsReferenceType)
2859 if (l == TypeManager.anonymous_method_type)
2862 if (TypeManager.IsValueType (l))
2868 bool rgen = TypeManager.IsGenericParameter (r);
2871 // a, Both operands are reference-type values or the value null
2872 // b, One operand is a value of type T where T is a type-parameter and
2873 // the other operand is the value null. Furthermore T does not have the
2874 // value type constrain
2876 if (left is NullLiteral || right is NullLiteral) {
2878 constraints = TypeManager.GetTypeParameterConstraints (l);
2879 if (constraints != null && constraints.HasValueTypeConstraint)
2882 left = new BoxedCast (left, TypeManager.object_type);
2887 constraints = TypeManager.GetTypeParameterConstraints (r);
2888 if (constraints != null && constraints.HasValueTypeConstraint)
2891 right = new BoxedCast (right, TypeManager.object_type);
2897 // An interface is converted to the object before the
2898 // standard conversion is applied. It's not clear from the
2899 // standard but it looks like it works like that.
2902 constraints = TypeManager.GetTypeParameterConstraints (l);
2903 if (constraints == null || constraints.IsReferenceType)
2905 } else if (l.IsInterface) {
2906 l = TypeManager.object_type;
2907 } else if (TypeManager.IsStruct (l)) {
2912 constraints = TypeManager.GetTypeParameterConstraints (r);
2913 if (constraints == null || constraints.IsReferenceType)
2915 } else if (r.IsInterface) {
2916 r = TypeManager.object_type;
2917 } else if (TypeManager.IsStruct (r)) {
2922 const string ref_comparison = "Possible unintended reference comparison. " +
2923 "Consider casting the {0} side of the expression to `string' to compare the values";
2926 // A standard implicit conversion exists from the type of either
2927 // operand to the type of the other operand
2929 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2930 if (l == TypeManager.string_type)
2931 Report.Warning (253, 2, loc, ref_comparison, "right");
2936 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2937 if (r == TypeManager.string_type)
2938 Report.Warning (252, 2, loc, ref_comparison, "left");
2947 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2950 // bool operator == (void* x, void* y);
2951 // bool operator != (void* x, void* y);
2952 // bool operator < (void* x, void* y);
2953 // bool operator > (void* x, void* y);
2954 // bool operator <= (void* x, void* y);
2955 // bool operator >= (void* x, void* y);
2957 if ((oper & Operator.ComparisonMask) != 0) {
2960 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2967 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2973 type = TypeManager.bool_type;
2977 if (pointer_operators == null)
2978 CreatePointerOperatorsTable ();
2980 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2984 // Build-in operators method overloading
2986 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2988 PredefinedOperator best_operator = null;
2990 Type r = right.Type;
2991 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2993 foreach (PredefinedOperator po in operators) {
2994 if ((po.OperatorsMask & oper_mask) == 0)
2997 if (primitives_only) {
2998 if (!po.IsPrimitiveApplicable (l, r))
3001 if (!po.IsApplicable (ec, left, right))
3005 if (best_operator == null) {
3007 if (primitives_only)
3013 best_operator = po.ResolveBetterOperator (ec, best_operator);
3015 if (best_operator == null) {
3016 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3017 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3024 if (best_operator == null)
3027 Expression expr = best_operator.ConvertResult (ec, this);
3028 if (enum_type == null)
3032 // HACK: required by enum_conversion
3034 expr.Type = enum_type;
3035 return EmptyCast.Create (expr, enum_type);
3039 // Performs user-operator overloading
3041 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3044 if (oper == Operator.LogicalAnd)
3045 user_oper = Operator.BitwiseAnd;
3046 else if (oper == Operator.LogicalOr)
3047 user_oper = Operator.BitwiseOr;
3051 string op = GetOperatorMetadataName (user_oper);
3053 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3054 MethodGroupExpr right_operators = null;
3056 if (!TypeManager.IsEqual (r, l)) {
3057 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3058 if (right_operators == null && left_operators == null)
3060 } else if (left_operators == null) {
3064 ArrayList args = new ArrayList (2);
3065 Argument larg = new Argument (left);
3067 Argument rarg = new Argument (right);
3070 MethodGroupExpr union;
3073 // User-defined operator implementations always take precedence
3074 // over predefined operator implementations
3076 if (left_operators != null && right_operators != null) {
3077 if (IsPredefinedUserOperator (l, user_oper)) {
3078 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3080 union = left_operators;
3081 } else if (IsPredefinedUserOperator (r, user_oper)) {
3082 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3084 union = right_operators;
3086 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3088 } else if (left_operators != null) {
3089 union = left_operators;
3091 union = right_operators;
3094 union = union.OverloadResolve (ec, ref args, true, loc);
3098 Expression oper_expr;
3100 // TODO: CreateExpressionTree is allocated every time
3101 if (user_oper != oper) {
3102 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3103 oper == Operator.LogicalAnd, loc).Resolve (ec);
3105 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3108 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3109 // and not invoke user operator
3111 if ((oper & Operator.EqualityMask) != 0) {
3112 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3113 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3114 type = TypeManager.bool_type;
3115 if (left is NullLiteral || right is NullLiteral)
3116 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3117 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3119 // Two System.Delegate(s) are never equal
3131 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3136 private void CheckUselessComparison (Constant c, Type type)
3138 if (c == null || !IsTypeIntegral (type)
3139 || c is StringConstant
3140 || c is BoolConstant
3141 || c is FloatConstant
3142 || c is DoubleConstant
3143 || c is DecimalConstant
3149 if (c is ULongConstant) {
3150 ulong uvalue = ((ULongConstant) c).Value;
3151 if (uvalue > long.MaxValue) {
3152 if (type == TypeManager.byte_type ||
3153 type == TypeManager.sbyte_type ||
3154 type == TypeManager.short_type ||
3155 type == TypeManager.ushort_type ||
3156 type == TypeManager.int32_type ||
3157 type == TypeManager.uint32_type ||
3158 type == TypeManager.int64_type ||
3159 type == TypeManager.char_type)
3160 WarnUselessComparison (type);
3163 value = (long) uvalue;
3165 else if (c is ByteConstant)
3166 value = ((ByteConstant) c).Value;
3167 else if (c is SByteConstant)
3168 value = ((SByteConstant) c).Value;
3169 else if (c is ShortConstant)
3170 value = ((ShortConstant) c).Value;
3171 else if (c is UShortConstant)
3172 value = ((UShortConstant) c).Value;
3173 else if (c is IntConstant)
3174 value = ((IntConstant) c).Value;
3175 else if (c is UIntConstant)
3176 value = ((UIntConstant) c).Value;
3177 else if (c is LongConstant)
3178 value = ((LongConstant) c).Value;
3179 else if (c is CharConstant)
3180 value = ((CharConstant)c).Value;
3185 if (IsValueOutOfRange (value, type))
3186 WarnUselessComparison (type);
3189 static bool IsValueOutOfRange (long value, Type type)
3191 if (IsTypeUnsigned (type) && value < 0)
3193 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3194 type == TypeManager.byte_type && value >= 0x100 ||
3195 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3196 type == TypeManager.ushort_type && value >= 0x10000 ||
3197 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3198 type == TypeManager.uint32_type && value >= 0x100000000;
3201 static bool IsBuildInEqualityOperator (Type t)
3203 return t == TypeManager.object_type || t == TypeManager.string_type ||
3204 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3207 static bool IsPredefinedUserOperator (Type t, Operator op)
3210 // Some predefined types have user operators
3212 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3215 private static bool IsTypeIntegral (Type type)
3217 return type == TypeManager.uint64_type ||
3218 type == TypeManager.int64_type ||
3219 type == TypeManager.uint32_type ||
3220 type == TypeManager.int32_type ||
3221 type == TypeManager.ushort_type ||
3222 type == TypeManager.short_type ||
3223 type == TypeManager.sbyte_type ||
3224 type == TypeManager.byte_type ||
3225 type == TypeManager.char_type;
3228 private static bool IsTypeUnsigned (Type type)
3230 return type == TypeManager.uint64_type ||
3231 type == TypeManager.uint32_type ||
3232 type == TypeManager.ushort_type ||
3233 type == TypeManager.byte_type ||
3234 type == TypeManager.char_type;
3237 private void WarnUselessComparison (Type type)
3239 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}'",
3240 TypeManager.CSharpName (type));
3244 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3245 /// context of a conditional bool expression. This function will return
3246 /// false if it is was possible to use EmitBranchable, or true if it was.
3248 /// The expression's code is generated, and we will generate a branch to `target'
3249 /// if the resulting expression value is equal to isTrue
3251 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3253 ILGenerator ig = ec.ig;
3256 // This is more complicated than it looks, but its just to avoid
3257 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3258 // but on top of that we want for == and != to use a special path
3259 // if we are comparing against null
3261 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3262 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3265 // put the constant on the rhs, for simplicity
3267 if (left is Constant) {
3268 Expression swap = right;
3273 if (((Constant) right).IsZeroInteger) {
3274 left.EmitBranchable (ec, target, my_on_true);
3277 if (right.Type == TypeManager.bool_type) {
3278 // right is a boolean, and it's not 'false' => it is 'true'
3279 left.EmitBranchable (ec, target, !my_on_true);
3283 } else if (oper == Operator.LogicalAnd) {
3286 Label tests_end = ig.DefineLabel ();
3288 left.EmitBranchable (ec, tests_end, false);
3289 right.EmitBranchable (ec, target, true);
3290 ig.MarkLabel (tests_end);
3293 // This optimizes code like this
3294 // if (true && i > 4)
3296 if (!(left is Constant))
3297 left.EmitBranchable (ec, target, false);
3299 if (!(right is Constant))
3300 right.EmitBranchable (ec, target, false);
3305 } else if (oper == Operator.LogicalOr){
3307 left.EmitBranchable (ec, target, true);
3308 right.EmitBranchable (ec, target, true);
3311 Label tests_end = ig.DefineLabel ();
3312 left.EmitBranchable (ec, tests_end, true);
3313 right.EmitBranchable (ec, target, false);
3314 ig.MarkLabel (tests_end);
3319 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3320 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3321 oper == Operator.Equality || oper == Operator.Inequality)) {
3322 base.EmitBranchable (ec, target, on_true);
3330 bool is_float = IsFloat (t);
3331 bool is_unsigned = is_float || IsUnsigned (t);
3334 case Operator.Equality:
3336 ig.Emit (OpCodes.Beq, target);
3338 ig.Emit (OpCodes.Bne_Un, target);
3341 case Operator.Inequality:
3343 ig.Emit (OpCodes.Bne_Un, target);
3345 ig.Emit (OpCodes.Beq, target);
3348 case Operator.LessThan:
3350 if (is_unsigned && !is_float)
3351 ig.Emit (OpCodes.Blt_Un, target);
3353 ig.Emit (OpCodes.Blt, target);
3356 ig.Emit (OpCodes.Bge_Un, target);
3358 ig.Emit (OpCodes.Bge, target);
3361 case Operator.GreaterThan:
3363 if (is_unsigned && !is_float)
3364 ig.Emit (OpCodes.Bgt_Un, target);
3366 ig.Emit (OpCodes.Bgt, target);
3369 ig.Emit (OpCodes.Ble_Un, target);
3371 ig.Emit (OpCodes.Ble, target);
3374 case Operator.LessThanOrEqual:
3376 if (is_unsigned && !is_float)
3377 ig.Emit (OpCodes.Ble_Un, target);
3379 ig.Emit (OpCodes.Ble, target);
3382 ig.Emit (OpCodes.Bgt_Un, target);
3384 ig.Emit (OpCodes.Bgt, target);
3388 case Operator.GreaterThanOrEqual:
3390 if (is_unsigned && !is_float)
3391 ig.Emit (OpCodes.Bge_Un, target);
3393 ig.Emit (OpCodes.Bge, target);
3396 ig.Emit (OpCodes.Blt_Un, target);
3398 ig.Emit (OpCodes.Blt, target);
3401 throw new InternalErrorException (oper.ToString ());
3405 public override void Emit (EmitContext ec)
3407 EmitOperator (ec, left.Type);
3410 protected virtual void EmitOperator (EmitContext ec, Type l)
3412 ILGenerator ig = ec.ig;
3415 // Handle short-circuit operators differently
3418 if ((oper & Operator.LogicalMask) != 0) {
3419 Label load_result = ig.DefineLabel ();
3420 Label end = ig.DefineLabel ();
3422 bool is_or = oper == Operator.LogicalOr;
3423 left.EmitBranchable (ec, load_result, is_or);
3425 ig.Emit (OpCodes.Br_S, end);
3427 ig.MarkLabel (load_result);
3428 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3436 // Optimize zero-based operations
3438 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3440 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3441 Constant rc = right as Constant;
3442 if (rc != null && rc.IsDefaultValue) {
3448 EmitOperatorOpcode (ec, oper, l);
3451 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3452 // expression because that would wrap lifted binary operation
3454 if (enum_conversion != null)
3455 enum_conversion.Emit (ec);
3458 public override void EmitSideEffect (EmitContext ec)
3460 if ((oper & Operator.LogicalMask) != 0 ||
3461 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3462 base.EmitSideEffect (ec);
3464 left.EmitSideEffect (ec);
3465 right.EmitSideEffect (ec);
3469 protected override void CloneTo (CloneContext clonectx, Expression t)
3471 Binary target = (Binary) t;
3473 target.left = left.Clone (clonectx);
3474 target.right = right.Clone (clonectx);
3477 public override Expression CreateExpressionTree (EmitContext ec)
3479 return CreateExpressionTree (ec, null);
3482 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3485 bool lift_arg = false;
3488 case Operator.Addition:
3489 if (method == null && ec.CheckState && !IsFloat (type))
3490 method_name = "AddChecked";
3492 method_name = "Add";
3494 case Operator.BitwiseAnd:
3495 method_name = "And";
3497 case Operator.BitwiseOr:
3500 case Operator.Division:
3501 method_name = "Divide";
3503 case Operator.Equality:
3504 method_name = "Equal";
3507 case Operator.ExclusiveOr:
3508 method_name = "ExclusiveOr";
3510 case Operator.GreaterThan:
3511 method_name = "GreaterThan";
3514 case Operator.GreaterThanOrEqual:
3515 method_name = "GreaterThanOrEqual";
3518 case Operator.Inequality:
3519 method_name = "NotEqual";
3522 case Operator.LeftShift:
3523 method_name = "LeftShift";
3525 case Operator.LessThan:
3526 method_name = "LessThan";
3529 case Operator.LessThanOrEqual:
3530 method_name = "LessThanOrEqual";
3533 case Operator.LogicalAnd:
3534 method_name = "AndAlso";
3536 case Operator.LogicalOr:
3537 method_name = "OrElse";
3539 case Operator.Modulus:
3540 method_name = "Modulo";
3542 case Operator.Multiply:
3543 if (method == null && ec.CheckState && !IsFloat (type))
3544 method_name = "MultiplyChecked";
3546 method_name = "Multiply";
3548 case Operator.RightShift:
3549 method_name = "RightShift";
3551 case Operator.Subtraction:
3552 if (method == null && ec.CheckState && !IsFloat (type))
3553 method_name = "SubtractChecked";
3555 method_name = "Subtract";
3559 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3562 ArrayList args = new ArrayList (2);
3563 args.Add (new Argument (left.CreateExpressionTree (ec)));
3564 args.Add (new Argument (right.CreateExpressionTree (ec)));
3565 if (method != null) {
3567 args.Add (new Argument (new BoolConstant (false, loc)));
3569 args.Add (new Argument (method.CreateExpressionTree (ec)));
3572 return CreateExpressionFactoryCall (method_name, args);
3577 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3578 // b, c, d... may be strings or objects.
3580 public class StringConcat : Expression {
3581 ArrayList arguments;
3583 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3586 type = TypeManager.string_type;
3587 eclass = ExprClass.Value;
3589 arguments = new ArrayList (2);
3594 public override Expression CreateExpressionTree (EmitContext ec)
3596 Argument arg = (Argument) arguments [0];
3597 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3601 // Creates nested calls tree from an array of arguments used for IL emit
3603 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3605 ArrayList concat_args = new ArrayList (2);
3606 ArrayList add_args = new ArrayList (3);
3608 concat_args.Add (left);
3609 add_args.Add (new Argument (left_etree));
3611 concat_args.Add (arguments [pos]);
3612 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3614 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3618 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3622 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3624 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3625 if (++pos == arguments.Count)
3628 left = new Argument (new EmptyExpression (method.Type));
3629 return CreateExpressionAddCall (ec, left, expr, pos);
3632 public override Expression DoResolve (EmitContext ec)
3637 public void Append (EmitContext ec, Expression operand)
3642 StringConstant sc = operand as StringConstant;
3644 if (arguments.Count != 0) {
3645 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3646 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3647 if (last_expr_constant != null) {
3648 last_argument.Expr = new StringConstant (
3649 last_expr_constant.Value + sc.Value, sc.Location);
3655 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3657 StringConcat concat_oper = operand as StringConcat;
3658 if (concat_oper != null) {
3659 arguments.AddRange (concat_oper.arguments);
3664 arguments.Add (new Argument (operand));
3667 Expression CreateConcatMemberExpression ()
3669 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3672 public override void Emit (EmitContext ec)
3674 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3675 concat = concat.Resolve (ec);
3680 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3682 foreach (Argument a in arguments)
3683 a.Expr.MutateHoistedGenericType (storey);
3688 // User-defined conditional logical operator
3690 public class ConditionalLogicalOperator : UserOperatorCall {
3691 readonly bool is_and;
3694 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3695 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3696 : base (oper_method, arguments, expr_tree, loc)
3698 this.is_and = is_and;
3701 public override Expression DoResolve (EmitContext ec)
3703 MethodInfo method = (MethodInfo)mg;
3704 type = TypeManager.TypeToCoreType (method.ReturnType);
3705 AParametersCollection pd = TypeManager.GetParameterData (method);
3706 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3707 Report.Error (217, loc,
3708 "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",
3709 TypeManager.CSharpSignature (method));
3713 Expression left_dup = new EmptyExpression (type);
3714 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3715 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3716 if (op_true == null || op_false == null) {
3717 Report.Error (218, loc,
3718 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3719 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3723 oper = is_and ? op_false : op_true;
3724 eclass = ExprClass.Value;
3728 public override void Emit (EmitContext ec)
3730 ILGenerator ig = ec.ig;
3731 Label end_target = ig.DefineLabel ();
3734 // Emit and duplicate left argument
3736 ((Argument)arguments [0]).Expr.Emit (ec);
3737 ig.Emit (OpCodes.Dup);
3738 arguments.RemoveAt (0);
3740 oper.EmitBranchable (ec, end_target, true);
3742 ig.MarkLabel (end_target);
3746 public class PointerArithmetic : Expression {
3747 Expression left, right;
3751 // We assume that `l' is always a pointer
3753 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3762 public override Expression CreateExpressionTree (EmitContext ec)
3764 Error_PointerInsideExpressionTree ();
3768 public override Expression DoResolve (EmitContext ec)
3770 eclass = ExprClass.Variable;
3772 if (left.Type == TypeManager.void_ptr_type) {
3773 Error (242, "The operation in question is undefined on void pointers");
3780 public override void Emit (EmitContext ec)
3782 Type op_type = left.Type;
3783 ILGenerator ig = ec.ig;
3785 // It must be either array or fixed buffer
3787 if (TypeManager.HasElementType (op_type)) {
3788 element = TypeManager.GetElementType (op_type);
3790 FieldExpr fe = left as FieldExpr;
3792 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3797 int size = GetTypeSize (element);
3798 Type rtype = right.Type;
3800 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3802 // handle (pointer - pointer)
3806 ig.Emit (OpCodes.Sub);
3810 ig.Emit (OpCodes.Sizeof, element);
3812 IntLiteral.EmitInt (ig, size);
3813 ig.Emit (OpCodes.Div);
3815 ig.Emit (OpCodes.Conv_I8);
3818 // handle + and - on (pointer op int)
3820 Constant left_const = left as Constant;
3821 if (left_const != null) {
3823 // Optimize ((T*)null) pointer operations
3825 if (left_const.IsDefaultValue) {
3826 left = EmptyExpression.Null;
3834 Constant right_const = right as Constant;
3835 if (right_const != null) {
3837 // Optimize 0-based arithmetic
3839 if (right_const.IsDefaultValue)
3843 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3847 ig.Emit (OpCodes.Sizeof, element);
3848 right = EmptyExpression.Null;
3853 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3854 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3855 ig.Emit (OpCodes.Conv_I);
3856 } else if (rtype == TypeManager.uint32_type) {
3857 ig.Emit (OpCodes.Conv_U);
3860 if (right_const == null && size != 1){
3862 ig.Emit (OpCodes.Sizeof, element);
3864 IntLiteral.EmitInt (ig, size);
3865 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3866 ig.Emit (OpCodes.Conv_I8);
3868 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3871 if (left_const == null) {
3872 if (rtype == TypeManager.int64_type)
3873 ig.Emit (OpCodes.Conv_I);
3874 else if (rtype == TypeManager.uint64_type)
3875 ig.Emit (OpCodes.Conv_U);
3877 Binary.EmitOperatorOpcode (ec, op, op_type);
3884 /// Implements the ternary conditional operator (?:)
3886 public class Conditional : Expression {
3887 Expression expr, true_expr, false_expr;
3889 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3892 this.true_expr = true_expr;
3893 this.false_expr = false_expr;
3894 this.loc = expr.Location;
3897 public Expression Expr {
3903 public Expression TrueExpr {
3909 public Expression FalseExpr {
3915 public override Expression CreateExpressionTree (EmitContext ec)
3917 ArrayList args = new ArrayList (3);
3918 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3919 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3920 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3921 return CreateExpressionFactoryCall ("Condition", args);
3924 public override Expression DoResolve (EmitContext ec)
3926 expr = expr.Resolve (ec);
3931 if (expr.Type != TypeManager.bool_type){
3932 expr = Expression.ResolveBoolean (
3939 Assign ass = expr as Assign;
3940 if (ass != null && ass.Source is Constant) {
3941 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3944 true_expr = true_expr.Resolve (ec);
3945 false_expr = false_expr.Resolve (ec);
3947 if (true_expr == null || false_expr == null)
3950 eclass = ExprClass.Value;
3951 Type true_type = true_expr.Type;
3952 Type false_type = false_expr.Type;
3956 // First, if an implicit conversion exists from true_expr
3957 // to false_expr, then the result type is of type false_expr.Type
3959 if (!TypeManager.IsEqual (true_type, false_type)) {
3960 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3963 // Check if both can convert implicitl to each other's type
3965 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3967 "Can not compute type of conditional expression " +
3968 "as `" + TypeManager.CSharpName (true_expr.Type) +
3969 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3970 "' convert implicitly to each other");
3975 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3978 Report.Error (173, loc,
3979 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3980 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3985 // Dead code optimalization
3986 Constant c = expr as Constant;
3988 bool is_false = c.IsDefaultValue;
3989 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3990 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3996 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3998 expr.MutateHoistedGenericType (storey);
3999 true_expr.MutateHoistedGenericType (storey);
4000 false_expr.MutateHoistedGenericType (storey);
4001 type = storey.MutateType (type);
4004 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
4009 public override void Emit (EmitContext ec)
4011 ILGenerator ig = ec.ig;
4012 Label false_target = ig.DefineLabel ();
4013 Label end_target = ig.DefineLabel ();
4015 expr.EmitBranchable (ec, false_target, false);
4016 true_expr.Emit (ec);
4018 if (type.IsInterface) {
4019 LocalBuilder temp = ec.GetTemporaryLocal (type);
4020 ig.Emit (OpCodes.Stloc, temp);
4021 ig.Emit (OpCodes.Ldloc, temp);
4022 ec.FreeTemporaryLocal (temp, type);
4025 ig.Emit (OpCodes.Br, end_target);
4026 ig.MarkLabel (false_target);
4027 false_expr.Emit (ec);
4028 ig.MarkLabel (end_target);
4031 protected override void CloneTo (CloneContext clonectx, Expression t)
4033 Conditional target = (Conditional) t;
4035 target.expr = expr.Clone (clonectx);
4036 target.true_expr = true_expr.Clone (clonectx);
4037 target.false_expr = false_expr.Clone (clonectx);
4041 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4042 LocalTemporary temp;
4045 public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
4046 public abstract bool IsFixed { get; }
4047 public abstract bool IsRef { get; }
4048 public abstract string Name { get; }
4049 public abstract void SetHasAddressTaken ();
4052 // Variable IL data, it has to be protected to encapsulate hoisted variables
4054 protected abstract ILocalVariable Variable { get; }
4057 // Variable flow-analysis data
4059 public abstract VariableInfo VariableInfo { get; }
4062 public void AddressOf (EmitContext ec, AddressOp mode)
4064 HoistedVariable hv = GetHoistedVariable (ec);
4066 hv.AddressOf (ec, mode);
4070 Variable.EmitAddressOf (ec);
4073 public override void Emit (EmitContext ec)
4078 public override void EmitSideEffect (EmitContext ec)
4084 // This method is used by parameters that are references, that are
4085 // being passed as references: we only want to pass the pointer (that
4086 // is already stored in the parameter, not the address of the pointer,
4087 // and not the value of the variable).
4089 public void EmitLoad (EmitContext ec)
4094 public void Emit (EmitContext ec, bool leave_copy)
4096 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4098 HoistedVariable hv = GetHoistedVariable (ec);
4100 hv.Emit (ec, leave_copy);
4108 // If we are a reference, we loaded on the stack a pointer
4109 // Now lets load the real value
4111 LoadFromPtr (ec.ig, type);
4115 ec.ig.Emit (OpCodes.Dup);
4118 temp = new LocalTemporary (Type);
4124 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4125 bool prepare_for_load)
4127 HoistedVariable hv = GetHoistedVariable (ec);
4129 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4133 New n_source = source as New;
4134 if (n_source != null) {
4135 if (!n_source.Emit (ec, this)) {
4148 ec.ig.Emit (OpCodes.Dup);
4150 temp = new LocalTemporary (Type);
4156 StoreFromPtr (ec.ig, type);
4158 Variable.EmitAssign (ec);
4166 public bool IsHoisted {
4167 get { return GetHoistedVariable (null) != null; }
4170 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4172 type = storey.MutateType (type);
4179 public class LocalVariableReference : VariableReference {
4180 readonly string name;
4182 public LocalInfo local_info;
4185 public LocalVariableReference (Block block, string name, Location l)
4190 eclass = ExprClass.Variable;
4194 // Setting `is_readonly' to false will allow you to create a writable
4195 // reference to a read-only variable. This is used by foreach and using.
4197 public LocalVariableReference (Block block, string name, Location l,
4198 LocalInfo local_info, bool is_readonly)
4199 : this (block, name, l)
4201 this.local_info = local_info;
4202 this.is_readonly = is_readonly;
4205 public override VariableInfo VariableInfo {
4206 get { return local_info.VariableInfo; }
4209 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4211 return local_info.HoistedVariableReference;
4215 // A local variable is always fixed
4217 public override bool IsFixed {
4218 get { return true; }
4221 public override bool IsRef {
4222 get { return false; }
4225 public bool IsReadOnly {
4226 get { return is_readonly; }
4229 public override string Name {
4230 get { return name; }
4233 public bool VerifyAssigned (EmitContext ec)
4235 VariableInfo variable_info = local_info.VariableInfo;
4236 return variable_info == null || variable_info.IsAssigned (ec, loc);
4239 void ResolveLocalInfo ()
4241 if (local_info == null) {
4242 local_info = Block.GetLocalInfo (Name);
4243 type = local_info.VariableType;
4244 is_readonly = local_info.ReadOnly;
4248 public override void SetHasAddressTaken ()
4250 local_info.AddressTaken = true;
4253 public override Expression CreateExpressionTree (EmitContext ec)
4255 HoistedVariable hv = GetHoistedVariable (ec);
4257 return hv.CreateExpressionTree (ec);
4259 ArrayList arg = new ArrayList (1);
4260 arg.Add (new Argument (this));
4261 return CreateExpressionFactoryCall ("Constant", arg);
4264 Expression DoResolveBase (EmitContext ec)
4266 type = local_info.VariableType;
4268 Expression e = Block.GetConstantExpression (Name);
4270 return e.Resolve (ec);
4272 VerifyAssigned (ec);
4275 // If we are referencing a variable from the external block
4276 // flag it for capturing
4278 if (ec.MustCaptureVariable (local_info)) {
4279 if (local_info.AddressTaken)
4280 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4282 if (ec.IsVariableCapturingRequired) {
4283 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4284 storey.CaptureLocalVariable (ec, local_info);
4291 public override Expression DoResolve (EmitContext ec)
4293 ResolveLocalInfo ();
4294 local_info.Used = true;
4296 if (type == null && local_info.Type is VarExpr) {
4297 local_info.VariableType = TypeManager.object_type;
4298 Error_VariableIsUsedBeforeItIsDeclared (Name);
4302 return DoResolveBase (ec);
4305 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4307 ResolveLocalInfo ();
4310 if (right_side == EmptyExpression.OutAccess)
4311 local_info.Used = true;
4313 // Infer implicitly typed local variable
4315 VarExpr ve = local_info.Type as VarExpr;
4317 if (!ve.InferType (ec, right_side))
4319 type = local_info.VariableType = ve.Type;
4326 if (right_side == EmptyExpression.OutAccess) {
4327 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4328 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4329 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4330 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4331 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4332 } else if (right_side == EmptyExpression.UnaryAddress) {
4333 code = 459; msg = "Cannot take the address of {1} `{0}'";
4335 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4337 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4338 } else if (VariableInfo != null) {
4339 VariableInfo.SetAssigned (ec);
4342 return DoResolveBase (ec);
4345 public override int GetHashCode ()
4347 return Name.GetHashCode ();
4350 public override bool Equals (object obj)
4352 LocalVariableReference lvr = obj as LocalVariableReference;
4356 return Name == lvr.Name && Block == lvr.Block;
4359 protected override ILocalVariable Variable {
4360 get { return local_info; }
4363 public override string ToString ()
4365 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4368 protected override void CloneTo (CloneContext clonectx, Expression t)
4370 LocalVariableReference target = (LocalVariableReference) t;
4372 target.Block = clonectx.LookupBlock (Block);
4373 if (local_info != null)
4374 target.local_info = clonectx.LookupVariable (local_info);
4379 /// This represents a reference to a parameter in the intermediate
4382 public class ParameterReference : VariableReference {
4383 readonly ToplevelParameterInfo pi;
4385 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4391 public override bool IsRef {
4392 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4395 bool HasOutModifier {
4396 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4399 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4401 return pi.Parameter.HoistedVariableReference;
4405 // A ref or out parameter is classified as a moveable variable, even
4406 // if the argument given for the parameter is a fixed variable
4408 public override bool IsFixed {
4409 get { return !IsRef; }
4412 public override string Name {
4413 get { return Parameter.Name; }
4416 public Parameter Parameter {
4417 get { return pi.Parameter; }
4420 public override VariableInfo VariableInfo {
4421 get { return pi.VariableInfo; }
4424 protected override ILocalVariable Variable {
4425 get { return Parameter; }
4428 public bool IsAssigned (EmitContext ec, Location loc)
4430 // HACK: Variables are not captured in probing mode
4431 if (ec.IsInProbingMode)
4434 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4437 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4441 public override void SetHasAddressTaken ()
4443 Parameter.HasAddressTaken = true;
4446 void SetAssigned (EmitContext ec)
4448 if (HasOutModifier && ec.DoFlowAnalysis)
4449 ec.CurrentBranching.SetAssigned (VariableInfo);
4452 bool DoResolveBase (EmitContext ec)
4454 type = pi.ParameterType;
4455 eclass = ExprClass.Variable;
4457 AnonymousExpression am = ec.CurrentAnonymousMethod;
4461 Block b = ec.CurrentBlock;
4463 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4464 for (int i = 0; i < p.Length; ++i) {
4465 if (p [i] != Parameter)
4469 // Skip closest anonymous method parameters
4471 if (b == ec.CurrentBlock && !am.IsIterator)
4475 Report.Error (1628, loc,
4476 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4477 Name, am.ContainerType);
4485 b = b.Toplevel.Parent;
4488 if (pi.Parameter.HasAddressTaken)
4489 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4491 if (ec.IsVariableCapturingRequired) {
4492 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4493 storey.CaptureParameter (ec, this);
4499 public override int GetHashCode ()
4501 return Name.GetHashCode ();
4504 public override bool Equals (object obj)
4506 ParameterReference pr = obj as ParameterReference;
4510 return Name == pr.Name;
4513 protected override void CloneTo (CloneContext clonectx, Expression target)
4518 public override Expression CreateExpressionTree (EmitContext ec)
4520 HoistedVariable hv = GetHoistedVariable (ec);
4522 return hv.CreateExpressionTree (ec);
4524 return Parameter.ExpressionTreeVariableReference ();
4528 // Notice that for ref/out parameters, the type exposed is not the
4529 // same type exposed externally.
4532 // externally we expose "int&"
4533 // here we expose "int".
4535 // We record this in "is_ref". This means that the type system can treat
4536 // the type as it is expected, but when we generate the code, we generate
4537 // the alternate kind of code.
4539 public override Expression DoResolve (EmitContext ec)
4541 if (!DoResolveBase (ec))
4544 // HACK: Variables are not captured in probing mode
4545 if (ec.IsInProbingMode)
4548 if (HasOutModifier && ec.DoFlowAnalysis &&
4549 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4555 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4557 if (!DoResolveBase (ec))
4560 // HACK: parameters are not captured when probing is on
4561 if (!ec.IsInProbingMode)
4567 static public void EmitLdArg (ILGenerator ig, int x)
4570 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4571 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4572 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4573 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4575 if (x > byte.MaxValue)
4576 ig.Emit (OpCodes.Ldarg, x);
4578 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4585 /// Used for arguments to New(), Invocation()
4587 public class Argument {
4588 public enum AType : byte {
4595 public static readonly Argument[] Empty = new Argument [0];
4597 public readonly AType ArgType;
4598 public Expression Expr;
4600 public Argument (Expression expr, AType type)
4603 this.ArgType = type;
4606 public Argument (Expression expr)
4609 this.ArgType = AType.Expression;
4613 get { return Expr.Type; }
4616 public Parameter.Modifier Modifier
4621 return Parameter.Modifier.OUT;
4624 return Parameter.Modifier.REF;
4627 return Parameter.Modifier.NONE;
4632 public string GetSignatureForError ()
4634 if (Expr.eclass == ExprClass.MethodGroup)
4635 return Expr.ExprClassName;
4637 return TypeManager.CSharpName (Expr.Type);
4640 public bool ResolveMethodGroup (EmitContext ec)
4642 SimpleName sn = Expr as SimpleName;
4644 Expr = sn.GetMethodGroup ();
4646 // FIXME: csc doesn't report any error if you try to use `ref' or
4647 // `out' in a delegate creation expression.
4648 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4655 public bool Resolve (EmitContext ec, Location loc)
4660 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4661 // Verify that the argument is readable
4662 if (ArgType != AType.Out)
4663 Expr = Expr.Resolve (ec);
4665 // Verify that the argument is writeable
4666 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4667 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4669 return Expr != null;
4673 public void Emit (EmitContext ec)
4675 if (ArgType != AType.Ref && ArgType != AType.Out) {
4680 AddressOp mode = AddressOp.Store;
4681 if (ArgType == AType.Ref)
4682 mode |= AddressOp.Load;
4684 IMemoryLocation ml = (IMemoryLocation) Expr;
4685 ParameterReference pr = ml as ParameterReference;
4688 // ParameterReferences might already be references, so we want
4689 // to pass just the value
4691 if (pr != null && pr.IsRef)
4694 ml.AddressOf (ec, mode);
4697 public Argument Clone (CloneContext clonectx)
4699 return new Argument (Expr.Clone (clonectx), ArgType);
4704 /// Invocation of methods or delegates.
4706 public class Invocation : ExpressionStatement {
4707 protected ArrayList Arguments;
4708 protected Expression expr;
4709 protected MethodGroupExpr mg;
4710 bool arguments_resolved;
4713 // arguments is an ArrayList, but we do not want to typecast,
4714 // as it might be null.
4716 public Invocation (Expression expr, ArrayList arguments)
4718 SimpleName sn = expr as SimpleName;
4720 this.expr = sn.GetMethodGroup ();
4724 Arguments = arguments;
4726 loc = expr.Location;
4729 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4730 : this (expr, arguments)
4732 this.arguments_resolved = arguments_resolved;
4735 public override Expression CreateExpressionTree (EmitContext ec)
4740 // Special conversion for nested expression trees
4742 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4743 args = new ArrayList (1);
4744 args.Add (new Argument (this));
4745 return CreateExpressionFactoryCall ("Quote", args);
4748 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4750 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4753 args = new ArrayList (arg_count);
4756 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4758 args.Add (new Argument (new NullLiteral (loc)));
4760 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4763 // Use extension argument when exists
4766 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4768 args.Add (new Argument (e));
4771 if (Arguments != null) {
4772 foreach (Argument a in Arguments) {
4773 Expression e = a.Expr.CreateExpressionTree (ec);
4775 args.Add (new Argument (e));
4780 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4782 return CreateExpressionFactoryCall ("Call", args);
4785 public override Expression DoResolve (EmitContext ec)
4787 // Don't resolve already resolved expression
4788 if (eclass != ExprClass.Invalid)
4791 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4792 if (expr_resolved == null)
4795 mg = expr_resolved as MethodGroupExpr;
4797 Type expr_type = expr_resolved.Type;
4799 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4800 return (new DelegateInvocation (
4801 expr_resolved, Arguments, loc)).Resolve (ec);
4804 MemberExpr me = expr_resolved as MemberExpr;
4806 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4810 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4812 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4813 expr_resolved.GetSignatureForError ());
4817 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4821 // Next, evaluate all the expressions in the argument list
4823 if (Arguments != null && !arguments_resolved) {
4824 for (int i = 0; i < Arguments.Count; ++i)
4826 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4831 mg = DoResolveOverload (ec);
4835 MethodInfo method = (MethodInfo)mg;
4836 if (method != null) {
4837 type = TypeManager.TypeToCoreType (method.ReturnType);
4839 // TODO: this is a copy of mg.ResolveMemberAccess method
4840 Expression iexpr = mg.InstanceExpression;
4841 if (method.IsStatic) {
4842 if (iexpr == null ||
4843 iexpr is This || iexpr is EmptyExpression ||
4844 mg.IdenticalTypeName) {
4845 mg.InstanceExpression = null;
4847 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4851 if (iexpr == null || iexpr == EmptyExpression.Null) {
4852 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4857 if (type.IsPointer){
4865 // Only base will allow this invocation to happen.
4867 if (mg.IsBase && method.IsAbstract){
4868 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4872 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4874 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4876 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4880 IsSpecialMethodInvocation (method, loc);
4882 if (mg.InstanceExpression != null)
4883 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4885 eclass = ExprClass.Value;
4889 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4891 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4894 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4896 if (!TypeManager.IsSpecialMethod (method))
4899 Report.SymbolRelatedToPreviousError (method);
4900 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4901 TypeManager.CSharpSignature (method, true));
4907 /// Emits a list of resolved Arguments that are in the arguments
4910 /// The MethodBase argument might be null if the
4911 /// emission of the arguments is known not to contain
4912 /// a `params' field (for example in constructors or other routines
4913 /// that keep their arguments in this structure)
4915 /// if `dup_args' is true, a copy of the arguments will be left
4916 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4917 /// which will be duplicated before any other args. Only EmitCall
4918 /// should be using this interface.
4920 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4922 if (arguments == null)
4925 int top = arguments.Count;
4926 LocalTemporary [] temps = null;
4928 if (dup_args && top != 0)
4929 temps = new LocalTemporary [top];
4931 int argument_index = 0;
4933 for (int i = 0; i < top; i++) {
4934 a = (Argument) arguments [argument_index++];
4937 ec.ig.Emit (OpCodes.Dup);
4938 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4943 if (this_arg != null)
4946 for (int i = 0; i < top; i ++) {
4947 temps [i].Emit (ec);
4948 temps [i].Release (ec);
4953 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4955 AParametersCollection pd = TypeManager.GetParameterData (mb);
4957 Argument a = (Argument) arguments [pd.Count - 1];
4958 Arglist list = (Arglist) a.Expr;
4960 return list.ArgumentTypes;
4964 /// This checks the ConditionalAttribute on the method
4966 public static bool IsMethodExcluded (MethodBase method, Location loc)
4968 if (method.IsConstructor)
4971 method = TypeManager.DropGenericMethodArguments (method);
4972 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4973 IMethodData md = TypeManager.GetMethod (method);
4975 return md.IsExcluded ();
4977 // For some methods (generated by delegate class) GetMethod returns null
4978 // because they are not included in builder_to_method table
4982 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4986 /// is_base tells whether we want to force the use of the `call'
4987 /// opcode instead of using callvirt. Call is required to call
4988 /// a specific method, while callvirt will always use the most
4989 /// recent method in the vtable.
4991 /// is_static tells whether this is an invocation on a static method
4993 /// instance_expr is an expression that represents the instance
4994 /// it must be non-null if is_static is false.
4996 /// method is the method to invoke.
4998 /// Arguments is the list of arguments to pass to the method or constructor.
5000 public static void EmitCall (EmitContext ec, bool is_base,
5001 Expression instance_expr,
5002 MethodBase method, ArrayList Arguments, Location loc)
5004 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5007 // `dup_args' leaves an extra copy of the arguments on the stack
5008 // `omit_args' does not leave any arguments at all.
5009 // So, basically, you could make one call with `dup_args' set to true,
5010 // and then another with `omit_args' set to true, and the two calls
5011 // would have the same set of arguments. However, each argument would
5012 // only have been evaluated once.
5013 public static void EmitCall (EmitContext ec, bool is_base,
5014 Expression instance_expr,
5015 MethodBase method, ArrayList Arguments, Location loc,
5016 bool dup_args, bool omit_args)
5018 ILGenerator ig = ec.ig;
5019 bool struct_call = false;
5020 bool this_call = false;
5021 LocalTemporary this_arg = null;
5023 Type decl_type = method.DeclaringType;
5025 if (IsMethodExcluded (method, loc))
5028 bool is_static = method.IsStatic;
5030 this_call = instance_expr is This;
5031 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5035 // If this is ourselves, push "this"
5039 Type iexpr_type = instance_expr.Type;
5042 // Push the instance expression
5044 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5046 // Special case: calls to a function declared in a
5047 // reference-type with a value-type argument need
5048 // to have their value boxed.
5049 if (TypeManager.IsStruct (decl_type) ||
5050 TypeManager.IsGenericParameter (iexpr_type)) {
5052 // If the expression implements IMemoryLocation, then
5053 // we can optimize and use AddressOf on the
5056 // If not we have to use some temporary storage for
5058 if (instance_expr is IMemoryLocation) {
5059 ((IMemoryLocation)instance_expr).
5060 AddressOf (ec, AddressOp.LoadStore);
5062 LocalTemporary temp = new LocalTemporary (iexpr_type);
5063 instance_expr.Emit (ec);
5065 temp.AddressOf (ec, AddressOp.Load);
5068 // avoid the overhead of doing this all the time.
5070 t = TypeManager.GetReferenceType (iexpr_type);
5072 instance_expr.Emit (ec);
5074 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5075 // to help JIT to produce better code
5076 ig.Emit (OpCodes.Box, instance_expr.Type);
5077 t = TypeManager.object_type;
5080 instance_expr.Emit (ec);
5081 t = instance_expr.Type;
5085 ig.Emit (OpCodes.Dup);
5086 if (Arguments != null && Arguments.Count != 0) {
5087 this_arg = new LocalTemporary (t);
5088 this_arg.Store (ec);
5095 EmitArguments (ec, Arguments, dup_args, this_arg);
5098 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5099 call_op = OpCodes.Call;
5101 call_op = OpCodes.Callvirt;
5104 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5105 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5109 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5110 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5111 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5118 // and DoFoo is not virtual, you can omit the callvirt,
5119 // because you don't need the null checking behavior.
5121 if (method is MethodInfo)
5122 ig.Emit (call_op, (MethodInfo) method);
5124 ig.Emit (call_op, (ConstructorInfo) method);
5127 public override void Emit (EmitContext ec)
5129 mg.EmitCall (ec, Arguments);
5132 public override void EmitStatement (EmitContext ec)
5137 // Pop the return value if there is one
5139 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5140 ec.ig.Emit (OpCodes.Pop);
5143 protected override void CloneTo (CloneContext clonectx, Expression t)
5145 Invocation target = (Invocation) t;
5147 if (Arguments != null) {
5148 target.Arguments = new ArrayList (Arguments.Count);
5149 foreach (Argument a in Arguments)
5150 target.Arguments.Add (a.Clone (clonectx));
5153 target.expr = expr.Clone (clonectx);
5156 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5158 mg.MutateHoistedGenericType (storey);
5159 if (Arguments != null) {
5160 foreach (Argument a in Arguments)
5161 a.Expr.MutateHoistedGenericType (storey);
5167 // It's either a cast or delegate invocation
5169 public class InvocationOrCast : ExpressionStatement
5172 Expression argument;
5174 public InvocationOrCast (Expression expr, Expression argument)
5177 this.argument = argument;
5178 this.loc = expr.Location;
5181 public override Expression CreateExpressionTree (EmitContext ec)
5183 throw new NotSupportedException ("ET");
5186 public override Expression DoResolve (EmitContext ec)
5188 Expression e = ResolveCore (ec);
5192 return e.Resolve (ec);
5195 Expression ResolveCore (EmitContext ec)
5198 // First try to resolve it as a cast.
5200 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5202 return new Cast (te, argument, loc);
5206 // This can either be a type or a delegate invocation.
5207 // Let's just resolve it and see what we'll get.
5209 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5214 // Ok, so it's a Cast.
5216 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5217 return new Cast (expr, argument, loc);
5220 if (expr.eclass == ExprClass.Namespace) {
5221 expr.Error_UnexpectedKind (null, "type", loc);
5226 // It's a delegate invocation.
5228 if (!TypeManager.IsDelegateType (expr.Type)) {
5229 Error (149, "Method name expected");
5233 ArrayList args = new ArrayList (1);
5234 args.Add (new Argument (argument, Argument.AType.Expression));
5235 return new DelegateInvocation (expr, args, loc);
5238 public override ExpressionStatement ResolveStatement (EmitContext ec)
5240 Expression e = ResolveCore (ec);
5244 ExpressionStatement s = e as ExpressionStatement;
5246 Error_InvalidExpressionStatement ();
5250 return s.ResolveStatement (ec);
5253 public override void Emit (EmitContext ec)
5255 throw new Exception ("Cannot happen");
5258 public override void EmitStatement (EmitContext ec)
5260 throw new Exception ("Cannot happen");
5263 protected override void CloneTo (CloneContext clonectx, Expression t)
5265 InvocationOrCast target = (InvocationOrCast) t;
5267 target.expr = expr.Clone (clonectx);
5268 target.argument = argument.Clone (clonectx);
5274 /// Implements the new expression
5276 public class New : ExpressionStatement, IMemoryLocation {
5277 ArrayList Arguments;
5280 // During bootstrap, it contains the RequestedType,
5281 // but if `type' is not null, it *might* contain a NewDelegate
5282 // (because of field multi-initialization)
5284 Expression RequestedType;
5286 MethodGroupExpr method;
5288 bool is_type_parameter;
5290 public New (Expression requested_type, ArrayList arguments, Location l)
5292 RequestedType = requested_type;
5293 Arguments = arguments;
5298 /// Converts complex core type syntax like 'new int ()' to simple constant
5300 public static Constant Constantify (Type t)
5302 if (t == TypeManager.int32_type)
5303 return new IntConstant (0, Location.Null);
5304 if (t == TypeManager.uint32_type)
5305 return new UIntConstant (0, Location.Null);
5306 if (t == TypeManager.int64_type)
5307 return new LongConstant (0, Location.Null);
5308 if (t == TypeManager.uint64_type)
5309 return new ULongConstant (0, Location.Null);
5310 if (t == TypeManager.float_type)
5311 return new FloatConstant (0, Location.Null);
5312 if (t == TypeManager.double_type)
5313 return new DoubleConstant (0, Location.Null);
5314 if (t == TypeManager.short_type)
5315 return new ShortConstant (0, Location.Null);
5316 if (t == TypeManager.ushort_type)
5317 return new UShortConstant (0, Location.Null);
5318 if (t == TypeManager.sbyte_type)
5319 return new SByteConstant (0, Location.Null);
5320 if (t == TypeManager.byte_type)
5321 return new ByteConstant (0, Location.Null);
5322 if (t == TypeManager.char_type)
5323 return new CharConstant ('\0', Location.Null);
5324 if (t == TypeManager.bool_type)
5325 return new BoolConstant (false, Location.Null);
5326 if (t == TypeManager.decimal_type)
5327 return new DecimalConstant (0, Location.Null);
5328 if (TypeManager.IsEnumType (t))
5329 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5330 if (TypeManager.IsNullableType (t))
5331 return Nullable.LiftedNull.Create (t, Location.Null);
5337 // Checks whether the type is an interface that has the
5338 // [ComImport, CoClass] attributes and must be treated
5341 public Expression CheckComImport (EmitContext ec)
5343 if (!type.IsInterface)
5347 // Turn the call into:
5348 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5350 Type real_class = AttributeTester.GetCoClassAttribute (type);
5351 if (real_class == null)
5354 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5355 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5356 return cast.Resolve (ec);
5359 public override Expression CreateExpressionTree (EmitContext ec)
5361 ArrayList args = Arguments == null ?
5362 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5364 if (method == null) {
5365 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5367 args.Add (new Argument (method.CreateExpressionTree (ec)));
5368 if (Arguments != null) {
5370 foreach (Argument a in Arguments) {
5371 expr = a.Expr.CreateExpressionTree (ec);
5373 args.Add (new Argument (expr));
5378 return CreateExpressionFactoryCall ("New", args);
5381 public override Expression DoResolve (EmitContext ec)
5384 // The New DoResolve might be called twice when initializing field
5385 // expressions (see EmitFieldInitializers, the call to
5386 // GetInitializerExpression will perform a resolve on the expression,
5387 // and later the assign will trigger another resolution
5389 // This leads to bugs (#37014)
5392 if (RequestedType is NewDelegate)
5393 return RequestedType;
5397 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5403 if (type.IsPointer) {
5404 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5405 TypeManager.CSharpName (type));
5409 if (Arguments == null) {
5410 Constant c = Constantify (type);
5412 return ReducedExpression.Create (c, this);
5415 if (TypeManager.IsDelegateType (type)) {
5416 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5420 if (type.IsGenericParameter) {
5421 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5423 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5424 Error (304, String.Format (
5425 "Cannot create an instance of the " +
5426 "variable type '{0}' because it " +
5427 "doesn't have the new() constraint",
5432 if ((Arguments != null) && (Arguments.Count != 0)) {
5433 Error (417, String.Format (
5434 "`{0}': cannot provide arguments " +
5435 "when creating an instance of a " +
5436 "variable type.", type));
5440 if (TypeManager.activator_create_instance == null) {
5441 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5442 if (activator_type != null) {
5443 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5444 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5448 is_type_parameter = true;
5449 eclass = ExprClass.Value;
5454 if (type.IsAbstract && type.IsSealed) {
5455 Report.SymbolRelatedToPreviousError (type);
5456 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5460 if (type.IsInterface || type.IsAbstract){
5461 if (!TypeManager.IsGenericType (type)) {
5462 RequestedType = CheckComImport (ec);
5463 if (RequestedType != null)
5464 return RequestedType;
5467 Report.SymbolRelatedToPreviousError (type);
5468 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5472 bool is_struct = TypeManager.IsStruct (type);
5473 eclass = ExprClass.Value;
5476 // SRE returns a match for .ctor () on structs (the object constructor),
5477 // so we have to manually ignore it.
5479 if (is_struct && Arguments == null)
5482 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5483 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5484 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5486 if (Arguments != null){
5487 foreach (Argument a in Arguments){
5488 if (!a.Resolve (ec, loc))
5496 method = ml as MethodGroupExpr;
5497 if (method == null) {
5498 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5502 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5509 bool DoEmitTypeParameter (EmitContext ec)
5512 ILGenerator ig = ec.ig;
5513 // IMemoryLocation ml;
5515 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5516 new Type [] { type });
5518 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5519 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5520 ig.Emit (OpCodes.Call, ci);
5524 // Allow DoEmit() to be called multiple times.
5525 // We need to create a new LocalTemporary each time since
5526 // you can't share LocalBuilders among ILGeneators.
5527 LocalTemporary temp = new LocalTemporary (type);
5529 Label label_activator = ig.DefineLabel ();
5530 Label label_end = ig.DefineLabel ();
5532 temp.AddressOf (ec, AddressOp.Store);
5533 ig.Emit (OpCodes.Initobj, type);
5536 ig.Emit (OpCodes.Box, type);
5537 ig.Emit (OpCodes.Brfalse, label_activator);
5539 temp.AddressOf (ec, AddressOp.Store);
5540 ig.Emit (OpCodes.Initobj, type);
5542 ig.Emit (OpCodes.Br, label_end);
5544 ig.MarkLabel (label_activator);
5546 ig.Emit (OpCodes.Call, ci);
5547 ig.MarkLabel (label_end);
5550 throw new InternalErrorException ();
5555 // This Emit can be invoked in two contexts:
5556 // * As a mechanism that will leave a value on the stack (new object)
5557 // * As one that wont (init struct)
5559 // If we are dealing with a ValueType, we have a few
5560 // situations to deal with:
5562 // * The target is a ValueType, and we have been provided
5563 // the instance (this is easy, we are being assigned).
5565 // * The target of New is being passed as an argument,
5566 // to a boxing operation or a function that takes a
5569 // In this case, we need to create a temporary variable
5570 // that is the argument of New.
5572 // Returns whether a value is left on the stack
5574 // *** Implementation note ***
5576 // To benefit from this optimization, each assignable expression
5577 // has to manually cast to New and call this Emit.
5579 // TODO: It's worth to implement it for arrays and fields
5581 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5583 if (is_type_parameter)
5584 return DoEmitTypeParameter (ec);
5586 bool is_value_type = TypeManager.IsValueType (type);
5587 ILGenerator ig = ec.ig;
5588 VariableReference vr = target as VariableReference;
5590 if (target != null && is_value_type && (vr != null || method == null)) {
5591 target.AddressOf (ec, AddressOp.Store);
5592 } else if (vr != null && vr.IsRef) {
5597 method.EmitArguments (ec, Arguments);
5599 if (is_value_type) {
5600 if (method == null) {
5601 ig.Emit (OpCodes.Initobj, type);
5606 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5611 ConstructorInfo ci = (ConstructorInfo) method;
5613 if (TypeManager.IsGenericType (type))
5614 ci = TypeBuilder.GetConstructor (type, ci);
5617 ig.Emit (OpCodes.Newobj, ci);
5621 public override void Emit (EmitContext ec)
5623 LocalTemporary v = null;
5624 if (method == null && TypeManager.IsValueType (type)) {
5625 // TODO: Use temporary variable from pool
5626 v = new LocalTemporary (type);
5633 public override void EmitStatement (EmitContext ec)
5635 LocalTemporary v = null;
5636 if (method == null && TypeManager.IsValueType (type)) {
5637 // TODO: Use temporary variable from pool
5638 v = new LocalTemporary (type);
5642 ec.ig.Emit (OpCodes.Pop);
5645 public virtual bool HasInitializer {
5651 public void AddressOf (EmitContext ec, AddressOp Mode)
5653 if (is_type_parameter) {
5654 LocalTemporary temp = new LocalTemporary (type);
5655 DoEmitTypeParameter (ec);
5657 temp.AddressOf (ec, Mode);
5661 if (!TypeManager.IsStruct (type)){
5663 // We throw an exception. So far, I believe we only need to support
5665 // foreach (int j in new StructType ())
5668 throw new Exception ("AddressOf should not be used for classes");
5671 LocalTemporary value_target = new LocalTemporary (type);
5672 IMemoryLocation ml = (IMemoryLocation) value_target;
5674 ml.AddressOf (ec, AddressOp.Store);
5675 if (method == null) {
5676 ec.ig.Emit (OpCodes.Initobj, type);
5678 method.EmitArguments (ec, Arguments);
5679 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5682 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5685 protected override void CloneTo (CloneContext clonectx, Expression t)
5687 New target = (New) t;
5689 target.RequestedType = RequestedType.Clone (clonectx);
5690 if (Arguments != null){
5691 target.Arguments = new ArrayList ();
5692 foreach (Argument a in Arguments){
5693 target.Arguments.Add (a.Clone (clonectx));
5698 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5700 if (method != null) {
5701 method.MutateHoistedGenericType (storey);
5702 if (Arguments != null) {
5703 foreach (Argument a in Arguments)
5704 a.Expr.MutateHoistedGenericType (storey);
5708 type = storey.MutateType (type);
5713 /// 14.5.10.2: Represents an array creation expression.
5717 /// There are two possible scenarios here: one is an array creation
5718 /// expression that specifies the dimensions and optionally the
5719 /// initialization data and the other which does not need dimensions
5720 /// specified but where initialization data is mandatory.
5722 public class ArrayCreation : Expression {
5723 FullNamedExpression requested_base_type;
5724 ArrayList initializers;
5727 // The list of Argument types.
5728 // This is used to construct the `newarray' or constructor signature
5730 protected ArrayList arguments;
5732 protected Type array_element_type;
5733 bool expect_initializers = false;
5734 int num_arguments = 0;
5735 protected int dimensions;
5736 protected readonly string rank;
5738 protected ArrayList array_data;
5742 // The number of constants in array initializers
5743 int const_initializers_count;
5744 bool only_constant_initializers;
5746 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5748 this.requested_base_type = requested_base_type;
5749 this.initializers = initializers;
5753 arguments = new ArrayList (exprs.Count);
5755 foreach (Expression e in exprs) {
5756 arguments.Add (new Argument (e, Argument.AType.Expression));
5761 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5763 this.requested_base_type = requested_base_type;
5764 this.initializers = initializers;
5768 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5770 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5772 //dimensions = tmp.Length - 1;
5773 expect_initializers = true;
5776 public static void Error_IncorrectArrayInitializer (Location loc)
5778 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5781 protected override void Error_NegativeArrayIndex (Location loc)
5783 Report.Error (248, loc, "Cannot create an array with a negative size");
5786 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5788 if (specified_dims) {
5789 Argument a = (Argument) arguments [idx];
5791 if (!a.Resolve (ec, loc))
5794 Constant c = a.Expr as Constant;
5796 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5800 Report.Error (150, a.Expr.Location, "A constant value is expected");
5804 int value = (int) c.GetValue ();
5806 if (value != probe.Count) {
5807 Error_IncorrectArrayInitializer (loc);
5811 bounds [idx] = value;
5814 int child_bounds = -1;
5815 only_constant_initializers = true;
5816 for (int i = 0; i < probe.Count; ++i) {
5817 object o = probe [i];
5818 if (o is ArrayList) {
5819 ArrayList sub_probe = o as ArrayList;
5820 int current_bounds = sub_probe.Count;
5822 if (child_bounds == -1)
5823 child_bounds = current_bounds;
5825 else if (child_bounds != current_bounds){
5826 Error_IncorrectArrayInitializer (loc);
5829 if (idx + 1 >= dimensions){
5830 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5834 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5838 if (child_bounds != -1){
5839 Error_IncorrectArrayInitializer (loc);
5843 Expression element = ResolveArrayElement (ec, (Expression) o);
5844 if (element == null)
5847 // Initializers with the default values can be ignored
5848 Constant c = element as Constant;
5850 if (c.IsDefaultInitializer (array_element_type)) {
5854 ++const_initializers_count;
5857 only_constant_initializers = false;
5860 array_data.Add (element);
5867 public override Expression CreateExpressionTree (EmitContext ec)
5871 if (array_data == null) {
5872 args = new ArrayList (arguments.Count + 1);
5873 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5874 foreach (Argument a in arguments) {
5875 if (arguments.Count == 1) {
5876 Constant c = a.Expr as Constant;
5877 if (c.IsDefaultValue)
5878 return CreateExpressionFactoryCall ("NewArrayInit", args);
5880 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5883 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5886 if (dimensions > 1) {
5887 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5891 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5892 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5893 if (array_data != null) {
5894 for (int i = 0; i < array_data.Count; ++i) {
5895 Expression e = (Expression) array_data [i];
5897 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5899 args.Add (new Argument (e.CreateExpressionTree (ec)));
5903 return CreateExpressionFactoryCall ("NewArrayInit", args);
5906 public void UpdateIndices ()
5909 for (ArrayList probe = initializers; probe != null;) {
5910 if (probe.Count > 0 && probe [0] is ArrayList) {
5911 Expression e = new IntConstant (probe.Count, Location.Null);
5912 arguments.Add (new Argument (e, Argument.AType.Expression));
5914 bounds [i++] = probe.Count;
5916 probe = (ArrayList) probe [0];
5919 Expression e = new IntConstant (probe.Count, Location.Null);
5920 arguments.Add (new Argument (e, Argument.AType.Expression));
5922 bounds [i++] = probe.Count;
5929 Expression first_emit;
5930 LocalTemporary first_emit_temp;
5932 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5934 element = element.Resolve (ec);
5935 if (element == null)
5938 if (element is CompoundAssign.TargetExpression) {
5939 if (first_emit != null)
5940 throw new InternalErrorException ("Can only handle one mutator at a time");
5941 first_emit = element;
5942 element = first_emit_temp = new LocalTemporary (element.Type);
5945 return Convert.ImplicitConversionRequired (
5946 ec, element, array_element_type, loc);
5949 protected bool ResolveInitializers (EmitContext ec)
5951 if (initializers == null) {
5952 return !expect_initializers;
5956 // We use this to store all the date values in the order in which we
5957 // will need to store them in the byte blob later
5959 array_data = new ArrayList ();
5960 bounds = new System.Collections.Specialized.HybridDictionary ();
5962 if (arguments != null)
5963 return CheckIndices (ec, initializers, 0, true);
5965 arguments = new ArrayList ();
5967 if (!CheckIndices (ec, initializers, 0, false))
5976 // Resolved the type of the array
5978 bool ResolveArrayType (EmitContext ec)
5980 if (requested_base_type == null) {
5981 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5985 if (requested_base_type is VarExpr) {
5986 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5990 StringBuilder array_qualifier = new StringBuilder (rank);
5993 // `In the first form allocates an array instace of the type that results
5994 // from deleting each of the individual expression from the expression list'
5996 if (num_arguments > 0) {
5997 array_qualifier.Append ("[");
5998 for (int i = num_arguments-1; i > 0; i--)
5999 array_qualifier.Append (",");
6000 array_qualifier.Append ("]");
6006 TypeExpr array_type_expr;
6007 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6008 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6009 if (array_type_expr == null)
6012 type = array_type_expr.Type;
6013 array_element_type = TypeManager.GetElementType (type);
6014 dimensions = type.GetArrayRank ();
6019 public override Expression DoResolve (EmitContext ec)
6024 if (!ResolveArrayType (ec))
6028 // First step is to validate the initializers and fill
6029 // in any missing bits
6031 if (!ResolveInitializers (ec))
6034 if (arguments.Count != dimensions) {
6035 Error_IncorrectArrayInitializer (loc);
6038 foreach (Argument a in arguments){
6039 if (!a.Resolve (ec, loc))
6042 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6045 eclass = ExprClass.Value;
6049 MethodInfo GetArrayMethod (int arguments)
6051 ModuleBuilder mb = CodeGen.Module.Builder;
6053 Type[] arg_types = new Type[arguments];
6054 for (int i = 0; i < arguments; i++)
6055 arg_types[i] = TypeManager.int32_type;
6057 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6061 Report.Error (-6, "New invocation: Can not find a constructor for " +
6062 "this argument list");
6069 byte [] MakeByteBlob ()
6074 int count = array_data.Count;
6076 if (TypeManager.IsEnumType (array_element_type))
6077 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6079 factor = GetTypeSize (array_element_type);
6081 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6083 data = new byte [(count * factor + 3) & ~3];
6086 for (int i = 0; i < count; ++i) {
6087 object v = array_data [i];
6089 if (v is EnumConstant)
6090 v = ((EnumConstant) v).Child;
6092 if (v is Constant && !(v is StringConstant))
6093 v = ((Constant) v).GetValue ();
6099 if (array_element_type == TypeManager.int64_type){
6100 if (!(v is Expression)){
6101 long val = (long) v;
6103 for (int j = 0; j < factor; ++j) {
6104 data [idx + j] = (byte) (val & 0xFF);
6108 } else if (array_element_type == TypeManager.uint64_type){
6109 if (!(v is Expression)){
6110 ulong val = (ulong) v;
6112 for (int j = 0; j < factor; ++j) {
6113 data [idx + j] = (byte) (val & 0xFF);
6117 } else if (array_element_type == TypeManager.float_type) {
6118 if (!(v is Expression)){
6119 element = BitConverter.GetBytes ((float) v);
6121 for (int j = 0; j < factor; ++j)
6122 data [idx + j] = element [j];
6123 if (!BitConverter.IsLittleEndian)
6124 System.Array.Reverse (data, idx, 4);
6126 } else if (array_element_type == TypeManager.double_type) {
6127 if (!(v is Expression)){
6128 element = BitConverter.GetBytes ((double) v);
6130 for (int j = 0; j < factor; ++j)
6131 data [idx + j] = element [j];
6133 // FIXME: Handle the ARM float format.
6134 if (!BitConverter.IsLittleEndian)
6135 System.Array.Reverse (data, idx, 8);
6137 } else if (array_element_type == TypeManager.char_type){
6138 if (!(v is Expression)){
6139 int val = (int) ((char) v);
6141 data [idx] = (byte) (val & 0xff);
6142 data [idx+1] = (byte) (val >> 8);
6144 } else if (array_element_type == TypeManager.short_type){
6145 if (!(v is Expression)){
6146 int val = (int) ((short) v);
6148 data [idx] = (byte) (val & 0xff);
6149 data [idx+1] = (byte) (val >> 8);
6151 } else if (array_element_type == TypeManager.ushort_type){
6152 if (!(v is Expression)){
6153 int val = (int) ((ushort) v);
6155 data [idx] = (byte) (val & 0xff);
6156 data [idx+1] = (byte) (val >> 8);
6158 } else if (array_element_type == TypeManager.int32_type) {
6159 if (!(v is Expression)){
6162 data [idx] = (byte) (val & 0xff);
6163 data [idx+1] = (byte) ((val >> 8) & 0xff);
6164 data [idx+2] = (byte) ((val >> 16) & 0xff);
6165 data [idx+3] = (byte) (val >> 24);
6167 } else if (array_element_type == TypeManager.uint32_type) {
6168 if (!(v is Expression)){
6169 uint val = (uint) v;
6171 data [idx] = (byte) (val & 0xff);
6172 data [idx+1] = (byte) ((val >> 8) & 0xff);
6173 data [idx+2] = (byte) ((val >> 16) & 0xff);
6174 data [idx+3] = (byte) (val >> 24);
6176 } else if (array_element_type == TypeManager.sbyte_type) {
6177 if (!(v is Expression)){
6178 sbyte val = (sbyte) v;
6179 data [idx] = (byte) val;
6181 } else if (array_element_type == TypeManager.byte_type) {
6182 if (!(v is Expression)){
6183 byte val = (byte) v;
6184 data [idx] = (byte) val;
6186 } else if (array_element_type == TypeManager.bool_type) {
6187 if (!(v is Expression)){
6188 bool val = (bool) v;
6189 data [idx] = (byte) (val ? 1 : 0);
6191 } else if (array_element_type == TypeManager.decimal_type){
6192 if (!(v is Expression)){
6193 int [] bits = Decimal.GetBits ((decimal) v);
6196 // FIXME: For some reason, this doesn't work on the MS runtime.
6197 int [] nbits = new int [4];
6198 nbits [0] = bits [3];
6199 nbits [1] = bits [2];
6200 nbits [2] = bits [0];
6201 nbits [3] = bits [1];
6203 for (int j = 0; j < 4; j++){
6204 data [p++] = (byte) (nbits [j] & 0xff);
6205 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6206 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6207 data [p++] = (byte) (nbits [j] >> 24);
6211 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6219 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6221 array_element_type = storey.MutateType (array_element_type);
6222 type = storey.MutateType (type);
6223 if (arguments != null) {
6224 foreach (Argument a in arguments)
6225 a.Expr.MutateHoistedGenericType (storey);
6228 if (array_data != null) {
6229 foreach (Expression e in array_data) {
6230 // Don't mutate values optimized away
6234 e.MutateHoistedGenericType (storey);
6240 // Emits the initializers for the array
6242 void EmitStaticInitializers (EmitContext ec)
6244 // FIXME: This should go to Resolve !
6245 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6246 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6247 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6248 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6249 if (TypeManager.void_initializearray_array_fieldhandle == null)
6254 // First, the static data
6257 ILGenerator ig = ec.ig;
6259 byte [] data = MakeByteBlob ();
6261 fb = RootContext.MakeStaticData (data);
6263 ig.Emit (OpCodes.Dup);
6264 ig.Emit (OpCodes.Ldtoken, fb);
6265 ig.Emit (OpCodes.Call,
6266 TypeManager.void_initializearray_array_fieldhandle);
6270 // Emits pieces of the array that can not be computed at compile
6271 // time (variables and string locations).
6273 // This always expect the top value on the stack to be the array
6275 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6277 ILGenerator ig = ec.ig;
6278 int dims = bounds.Count;
6279 int [] current_pos = new int [dims];
6281 MethodInfo set = null;
6284 Type [] args = new Type [dims + 1];
6286 for (int j = 0; j < dims; j++)
6287 args [j] = TypeManager.int32_type;
6288 args [dims] = array_element_type;
6290 set = CodeGen.Module.Builder.GetArrayMethod (
6292 CallingConventions.HasThis | CallingConventions.Standard,
6293 TypeManager.void_type, args);
6296 for (int i = 0; i < array_data.Count; i++){
6298 Expression e = (Expression)array_data [i];
6300 // Constant can be initialized via StaticInitializer
6301 if (e != null && !(!emitConstants && e is Constant)) {
6302 Type etype = e.Type;
6304 ig.Emit (OpCodes.Dup);
6306 for (int idx = 0; idx < dims; idx++)
6307 IntConstant.EmitInt (ig, current_pos [idx]);
6310 // If we are dealing with a struct, get the
6311 // address of it, so we can store it.
6313 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6314 (!TypeManager.IsBuiltinOrEnum (etype) ||
6315 etype == TypeManager.decimal_type)) {
6317 ig.Emit (OpCodes.Ldelema, etype);
6323 bool is_stobj, has_type_arg;
6324 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6326 ig.Emit (OpCodes.Stobj, etype);
6327 else if (has_type_arg)
6328 ig.Emit (op, etype);
6332 ig.Emit (OpCodes.Call, set);
6339 for (int j = dims - 1; j >= 0; j--){
6341 if (current_pos [j] < (int) bounds [j])
6343 current_pos [j] = 0;
6348 public override void Emit (EmitContext ec)
6350 ILGenerator ig = ec.ig;
6352 if (first_emit != null) {
6353 first_emit.Emit (ec);
6354 first_emit_temp.Store (ec);
6357 foreach (Argument a in arguments)
6360 if (arguments.Count == 1)
6361 ig.Emit (OpCodes.Newarr, array_element_type);
6363 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6366 if (initializers == null)
6369 // Emit static initializer for arrays which have contain more than 4 items and
6370 // the static initializer will initialize at least 25% of array values.
6371 // NOTE: const_initializers_count does not contain default constant values.
6372 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6373 TypeManager.IsPrimitiveType (array_element_type)) {
6374 EmitStaticInitializers (ec);
6376 if (!only_constant_initializers)
6377 EmitDynamicInitializers (ec, false);
6379 EmitDynamicInitializers (ec, true);
6382 if (first_emit_temp != null)
6383 first_emit_temp.Release (ec);
6386 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6388 if (arguments.Count != 1) {
6389 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6390 return base.GetAttributableValue (ec, null, out value);
6393 if (array_data == null) {
6394 Constant c = (Constant)((Argument)arguments [0]).Expr;
6395 if (c.IsDefaultValue) {
6396 value = Array.CreateInstance (array_element_type, 0);
6399 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6400 return base.GetAttributableValue (ec, null, out value);
6403 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6404 object element_value;
6405 for (int i = 0; i < ret.Length; ++i)
6407 Expression e = (Expression)array_data [i];
6409 // Is null when an initializer is optimized (value == predefined value)
6413 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6417 ret.SetValue (element_value, i);
6423 protected override void CloneTo (CloneContext clonectx, Expression t)
6425 ArrayCreation target = (ArrayCreation) t;
6427 if (requested_base_type != null)
6428 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6430 if (arguments != null){
6431 target.arguments = new ArrayList (arguments.Count);
6432 foreach (Argument a in arguments)
6433 target.arguments.Add (a.Clone (clonectx));
6436 if (initializers != null){
6437 target.initializers = new ArrayList (initializers.Count);
6438 foreach (object initializer in initializers)
6439 if (initializer is ArrayList) {
6440 ArrayList this_al = (ArrayList)initializer;
6441 ArrayList al = new ArrayList (this_al.Count);
6442 target.initializers.Add (al);
6443 foreach (Expression e in this_al)
6444 al.Add (e.Clone (clonectx));
6446 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6453 // Represents an implicitly typed array epxression
6455 public class ImplicitlyTypedArrayCreation : ArrayCreation
6457 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6458 : base (null, rank, initializers, loc)
6460 if (RootContext.Version <= LanguageVersion.ISO_2)
6461 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6463 if (rank.Length > 2) {
6464 while (rank [++dimensions] == ',');
6470 public override Expression DoResolve (EmitContext ec)
6475 if (!ResolveInitializers (ec))
6478 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6479 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6480 arguments.Count != dimensions) {
6481 Error_NoBestType ();
6486 // At this point we found common base type for all initializer elements
6487 // but we have to be sure that all static initializer elements are of
6490 UnifyInitializerElement (ec);
6492 type = TypeManager.GetConstructedType (array_element_type, rank);
6493 eclass = ExprClass.Value;
6497 void Error_NoBestType ()
6499 Report.Error (826, loc,
6500 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6504 // Converts static initializer only
6506 void UnifyInitializerElement (EmitContext ec)
6508 for (int i = 0; i < array_data.Count; ++i) {
6509 Expression e = (Expression)array_data[i];
6511 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6515 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6517 element = element.Resolve (ec);
6518 if (element == null)
6521 if (array_element_type == null) {
6522 if (element.Type != TypeManager.null_type)
6523 array_element_type = element.Type;
6528 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6532 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6533 array_element_type = element.Type;
6537 Error_NoBestType ();
6542 public sealed class CompilerGeneratedThis : This
6544 public static This Instance = new CompilerGeneratedThis ();
6546 private CompilerGeneratedThis ()
6547 : base (Location.Null)
6551 public CompilerGeneratedThis (Type type, Location loc)
6557 public override Expression DoResolve (EmitContext ec)
6559 eclass = ExprClass.Variable;
6561 type = ec.ContainerType;
6565 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6572 /// Represents the `this' construct
6575 public class This : VariableReference
6577 sealed class ThisVariable : ILocalVariable
6579 public static readonly ILocalVariable Instance = new ThisVariable ();
6581 public void Emit (EmitContext ec)
6583 ec.ig.Emit (OpCodes.Ldarg_0);
6586 public void EmitAssign (EmitContext ec)
6588 throw new InvalidOperationException ();
6591 public void EmitAddressOf (EmitContext ec)
6593 ec.ig.Emit (OpCodes.Ldarg_0);
6598 VariableInfo variable_info;
6601 public This (Block block, Location loc)
6607 public This (Location loc)
6612 public override VariableInfo VariableInfo {
6613 get { return variable_info; }
6616 public override bool IsFixed {
6617 get { return false; }
6620 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6622 // Is null when probing IsHoisted
6626 if (ec.CurrentAnonymousMethod == null)
6629 AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
6630 while (storey != null) {
6631 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6633 return storey.HoistedThis;
6641 public override bool IsRef {
6642 get { return is_struct; }
6645 protected override ILocalVariable Variable {
6646 get { return ThisVariable.Instance; }
6649 public static bool IsThisAvailable (EmitContext ec)
6651 if (ec.IsStatic || ec.IsInFieldInitializer)
6654 if (ec.CurrentAnonymousMethod == null)
6657 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6663 public bool ResolveBase (EmitContext ec)
6665 if (eclass != ExprClass.Invalid)
6668 eclass = ExprClass.Variable;
6670 if (ec.TypeContainer.CurrentType != null)
6671 type = ec.TypeContainer.CurrentType;
6673 type = ec.ContainerType;
6675 if (!IsThisAvailable (ec)) {
6677 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6679 Report.Error (1673, loc,
6680 "Anonymous methods inside structs cannot access instance members of `this'. " +
6681 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6685 is_struct = ec.TypeContainer is Struct;
6687 if (block != null) {
6688 if (block.Toplevel.ThisVariable != null)
6689 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6691 AnonymousExpression am = ec.CurrentAnonymousMethod;
6692 if (am != null && ec.IsVariableCapturingRequired) {
6693 am.SetHasThisAccess ();
6701 // Called from Invocation to check if the invocation is correct
6703 public override void CheckMarshalByRefAccess (EmitContext ec)
6705 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6706 !variable_info.IsAssigned (ec)) {
6707 Error (188, "The `this' object cannot be used before all of its " +
6708 "fields are assigned to");
6709 variable_info.SetAssigned (ec);
6713 public override Expression CreateExpressionTree (EmitContext ec)
6715 ArrayList args = new ArrayList (1);
6716 args.Add (new Argument (this));
6718 // Use typeless constant for ldarg.0 to save some
6719 // space and avoid problems with anonymous stories
6720 return CreateExpressionFactoryCall ("Constant", args);
6723 public override Expression DoResolve (EmitContext ec)
6725 if (!ResolveBase (ec))
6729 if (ec.IsInFieldInitializer) {
6730 Error (27, "Keyword `this' is not available in the current context");
6737 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6739 if (!ResolveBase (ec))
6742 if (variable_info != null)
6743 variable_info.SetAssigned (ec);
6745 if (ec.TypeContainer is Class){
6746 if (right_side == EmptyExpression.UnaryAddress)
6747 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6748 else if (right_side == EmptyExpression.OutAccess)
6749 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6751 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6757 public override int GetHashCode()
6759 return block.GetHashCode ();
6762 public override string Name {
6763 get { return "this"; }
6766 public override bool Equals (object obj)
6768 This t = obj as This;
6772 return block == t.block;
6775 protected override void CloneTo (CloneContext clonectx, Expression t)
6777 This target = (This) t;
6779 target.block = clonectx.LookupBlock (block);
6782 public override void SetHasAddressTaken ()
6789 /// Represents the `__arglist' construct
6791 public class ArglistAccess : Expression
6793 public ArglistAccess (Location loc)
6798 public override Expression CreateExpressionTree (EmitContext ec)
6800 throw new NotSupportedException ("ET");
6803 public override Expression DoResolve (EmitContext ec)
6805 eclass = ExprClass.Variable;
6806 type = TypeManager.runtime_argument_handle_type;
6808 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6810 Error (190, "The __arglist construct is valid only within " +
6811 "a variable argument method");
6818 public override void Emit (EmitContext ec)
6820 ec.ig.Emit (OpCodes.Arglist);
6823 protected override void CloneTo (CloneContext clonectx, Expression target)
6830 /// Represents the `__arglist (....)' construct
6832 public class Arglist : Expression
6834 Argument[] Arguments;
6836 public Arglist (Location loc)
6837 : this (Argument.Empty, loc)
6841 public Arglist (Argument[] args, Location l)
6847 public Type[] ArgumentTypes {
6849 Type[] retval = new Type [Arguments.Length];
6850 for (int i = 0; i < Arguments.Length; i++)
6851 retval [i] = Arguments [i].Type;
6856 public override Expression CreateExpressionTree (EmitContext ec)
6858 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6862 public override Expression DoResolve (EmitContext ec)
6864 eclass = ExprClass.Variable;
6865 type = TypeManager.runtime_argument_handle_type;
6867 foreach (Argument arg in Arguments) {
6868 if (!arg.Resolve (ec, loc))
6875 public override void Emit (EmitContext ec)
6877 foreach (Argument arg in Arguments)
6881 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6883 foreach (Argument arg in Arguments)
6884 arg.Expr.MutateHoistedGenericType (storey);
6887 protected override void CloneTo (CloneContext clonectx, Expression t)
6889 Arglist target = (Arglist) t;
6891 target.Arguments = new Argument [Arguments.Length];
6892 for (int i = 0; i < Arguments.Length; i++)
6893 target.Arguments [i] = Arguments [i].Clone (clonectx);
6898 /// Implements the typeof operator
6900 public class TypeOf : Expression {
6901 Expression QueriedType;
6902 protected Type typearg;
6904 public TypeOf (Expression queried_type, Location l)
6906 QueriedType = queried_type;
6910 public override Expression CreateExpressionTree (EmitContext ec)
6912 ArrayList args = new ArrayList (2);
6913 args.Add (new Argument (this));
6914 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6915 return CreateExpressionFactoryCall ("Constant", args);
6918 public override Expression DoResolve (EmitContext ec)
6920 if (eclass != ExprClass.Invalid)
6923 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6927 typearg = texpr.Type;
6929 if (typearg == TypeManager.void_type) {
6930 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6934 if (typearg.IsPointer && !ec.InUnsafe){
6939 type = TypeManager.type_type;
6941 return DoResolveBase ();
6944 protected Expression DoResolveBase ()
6946 if (TypeManager.system_type_get_type_from_handle == null) {
6947 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6948 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6951 // Even though what is returned is a type object, it's treated as a value by the compiler.
6952 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6953 eclass = ExprClass.Value;
6957 public override void Emit (EmitContext ec)
6959 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6960 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6963 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6965 if (TypeManager.ContainsGenericParameters (typearg) &&
6966 !TypeManager.IsGenericTypeDefinition (typearg)) {
6967 Report.SymbolRelatedToPreviousError (typearg);
6968 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6969 TypeManager.CSharpName (typearg));
6974 if (value_type == TypeManager.object_type) {
6975 value = (object)typearg;
6982 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6984 typearg = storey.MutateType (typearg);
6987 public Type TypeArgument {
6993 protected override void CloneTo (CloneContext clonectx, Expression t)
6995 TypeOf target = (TypeOf) t;
6996 if (QueriedType != null)
6997 target.QueriedType = QueriedType.Clone (clonectx);
7002 /// Implements the `typeof (void)' operator
7004 public class TypeOfVoid : TypeOf {
7005 public TypeOfVoid (Location l) : base (null, l)
7010 public override Expression DoResolve (EmitContext ec)
7012 type = TypeManager.type_type;
7013 typearg = TypeManager.void_type;
7015 return DoResolveBase ();
7019 class TypeOfMethodInfo : TypeOfMethod
7021 public TypeOfMethodInfo (MethodBase method, Location loc)
7022 : base (method, loc)
7026 public override Expression DoResolve (EmitContext ec)
7028 type = typeof (MethodInfo);
7029 return base.DoResolve (ec);
7032 public override void Emit (EmitContext ec)
7034 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7036 ec.ig.Emit (OpCodes.Castclass, type);
7040 class TypeOfConstructorInfo : TypeOfMethod
7042 public TypeOfConstructorInfo (MethodBase method, Location loc)
7043 : base (method, loc)
7047 public override Expression DoResolve (EmitContext ec)
7049 type = typeof (ConstructorInfo);
7050 return base.DoResolve (ec);
7053 public override void Emit (EmitContext ec)
7055 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7057 ec.ig.Emit (OpCodes.Castclass, type);
7061 abstract class TypeOfMethod : Expression
7063 protected readonly MethodBase method;
7065 protected TypeOfMethod (MethodBase method, Location loc)
7067 this.method = method;
7071 public override Expression CreateExpressionTree (EmitContext ec)
7073 ArrayList args = new ArrayList (2);
7074 args.Add (new Argument (this));
7075 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7076 return CreateExpressionFactoryCall ("Constant", args);
7079 public override Expression DoResolve (EmitContext ec)
7081 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7082 MethodInfo mi = is_generic ?
7083 TypeManager.methodbase_get_type_from_handle_generic :
7084 TypeManager.methodbase_get_type_from_handle;
7087 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7088 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7090 if (t == null || handle_type == null)
7093 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7095 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7096 new Type[] { handle_type } );
7099 TypeManager.methodbase_get_type_from_handle_generic = mi;
7101 TypeManager.methodbase_get_type_from_handle = mi;
7104 eclass = ExprClass.Value;
7108 public override void Emit (EmitContext ec)
7110 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7113 mi = TypeManager.methodbase_get_type_from_handle_generic;
7114 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7116 mi = TypeManager.methodbase_get_type_from_handle;
7119 ec.ig.Emit (OpCodes.Call, mi);
7123 internal class TypeOfField : Expression
7125 readonly FieldInfo field;
7127 public TypeOfField (FieldInfo field, Location loc)
7133 public override Expression CreateExpressionTree (EmitContext ec)
7135 throw new NotSupportedException ("ET");
7138 public override Expression DoResolve (EmitContext ec)
7140 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7141 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7142 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7144 if (t != null && handle_type != null)
7145 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7146 "GetFieldFromHandle", loc, handle_type);
7149 type = typeof (FieldInfo);
7150 eclass = ExprClass.Value;
7154 public override void Emit (EmitContext ec)
7156 ec.ig.Emit (OpCodes.Ldtoken, field);
7157 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7162 /// Implements the sizeof expression
7164 public class SizeOf : Expression {
7165 readonly Expression QueriedType;
7168 public SizeOf (Expression queried_type, Location l)
7170 this.QueriedType = queried_type;
7174 public override Expression CreateExpressionTree (EmitContext ec)
7176 Error_PointerInsideExpressionTree ();
7180 public override Expression DoResolve (EmitContext ec)
7182 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7186 type_queried = texpr.Type;
7187 if (TypeManager.IsEnumType (type_queried))
7188 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7190 int size_of = GetTypeSize (type_queried);
7192 return new IntConstant (size_of, loc);
7195 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7200 Report.Error (233, loc,
7201 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7202 TypeManager.CSharpName (type_queried));
7205 type = TypeManager.int32_type;
7206 eclass = ExprClass.Value;
7210 public override void Emit (EmitContext ec)
7212 int size = GetTypeSize (type_queried);
7215 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7217 IntConstant.EmitInt (ec.ig, size);
7220 protected override void CloneTo (CloneContext clonectx, Expression t)
7226 /// Implements the qualified-alias-member (::) expression.
7228 public class QualifiedAliasMember : MemberAccess
7230 readonly string alias;
7231 public static readonly string GlobalAlias = "global";
7233 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7234 : base (null, identifier, targs, l)
7239 public QualifiedAliasMember (string alias, string identifier, Location l)
7240 : base (null, identifier, l)
7245 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7247 if (alias == GlobalAlias) {
7248 expr = RootNamespace.Global;
7249 return base.ResolveAsTypeStep (ec, silent);
7252 int errors = Report.Errors;
7253 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7255 if (errors == Report.Errors)
7256 Report.Error (432, loc, "Alias `{0}' not found", alias);
7260 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7264 if (expr.eclass == ExprClass.Type) {
7266 Report.Error (431, loc,
7267 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7275 public override Expression DoResolve (EmitContext ec)
7277 return ResolveAsTypeStep (ec, false);
7280 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7282 Report.Error (687, loc,
7283 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7284 GetSignatureForError ());
7287 public override string GetSignatureForError ()
7290 if (targs != null) {
7291 name = TypeManager.RemoveGenericArity (Name) + "<" +
7292 targs.GetSignatureForError () + ">";
7295 return alias + "::" + name;
7298 protected override void CloneTo (CloneContext clonectx, Expression t)
7305 /// Implements the member access expression
7307 public class MemberAccess : ATypeNameExpression {
7308 protected Expression expr;
7310 public MemberAccess (Expression expr, string id)
7311 : base (id, expr.Location)
7316 public MemberAccess (Expression expr, string identifier, Location loc)
7317 : base (identifier, loc)
7322 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7323 : base (identifier, args, loc)
7328 Expression DoResolve (EmitContext ec, Expression right_side)
7331 throw new Exception ();
7334 // Resolve the expression with flow analysis turned off, we'll do the definite
7335 // assignment checks later. This is because we don't know yet what the expression
7336 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7337 // definite assignment check on the actual field and not on the whole struct.
7340 SimpleName original = expr as SimpleName;
7341 Expression expr_resolved = expr.Resolve (ec,
7342 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7343 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7345 if (expr_resolved == null)
7348 string LookupIdentifier = MemberName.MakeName (Name, targs);
7350 Namespace ns = expr_resolved as Namespace;
7352 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7355 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, LookupIdentifier);
7356 else if (targs != null)
7357 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7362 Type expr_type = expr_resolved.Type;
7363 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7364 expr_type == TypeManager.null_type || expr_type == TypeManager.anonymous_method_type) {
7365 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7369 Constant c = expr_resolved as Constant;
7370 if (c != null && c.GetValue () == null) {
7371 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7372 "System.NullReferenceException");
7375 if (targs != null) {
7376 if (!targs.Resolve (ec))
7380 Expression member_lookup;
7381 member_lookup = MemberLookup (
7382 ec.ContainerType, expr_type, expr_type, Name, loc);
7384 if ((member_lookup == null) && (targs != null)) {
7385 member_lookup = MemberLookup (
7386 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7389 if (member_lookup == null) {
7390 ExprClass expr_eclass = expr_resolved.eclass;
7393 // Extension methods are not allowed on all expression types
7395 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7396 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7397 expr_eclass == ExprClass.EventAccess) {
7398 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7399 if (ex_method_lookup != null) {
7400 ex_method_lookup.ExtensionExpression = expr_resolved;
7402 if (targs != null) {
7403 ex_method_lookup.SetTypeArguments (targs);
7406 return ex_method_lookup.DoResolve (ec);
7410 expr = expr_resolved;
7411 member_lookup = Error_MemberLookupFailed (
7412 ec.ContainerType, expr_type, expr_type, Name, null,
7413 AllMemberTypes, AllBindingFlags);
7414 if (member_lookup == null)
7418 TypeExpr texpr = member_lookup as TypeExpr;
7419 if (texpr != null) {
7420 if (!(expr_resolved is TypeExpr) &&
7421 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7422 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7423 Name, member_lookup.GetSignatureForError ());
7427 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7428 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7429 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7434 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7437 // When looking up a nested type in a generic instance
7438 // via reflection, we always get a generic type definition
7439 // and not a generic instance - so we have to do this here.
7441 // See gtest-172-lib.cs and gtest-172.cs for an example.
7443 ct = new GenericTypeExpr (
7444 member_lookup.Type, ct.TypeArguments, loc);
7446 return ct.ResolveAsTypeStep (ec, false);
7449 return member_lookup;
7452 MemberExpr me = (MemberExpr) member_lookup;
7453 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7457 if (targs != null) {
7458 me.SetTypeArguments (targs);
7461 if (original != null && !TypeManager.IsValueType (expr_type)) {
7462 if (me.IsInstance) {
7463 LocalVariableReference var = expr_resolved as LocalVariableReference;
7464 if (var != null && !var.VerifyAssigned (ec))
7469 // The following DoResolve/DoResolveLValue will do the definite assignment
7472 if (right_side != null)
7473 return me.DoResolveLValue (ec, right_side);
7475 return me.DoResolve (ec);
7478 public override Expression DoResolve (EmitContext ec)
7480 return DoResolve (ec, null);
7483 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7485 return DoResolve (ec, right_side);
7488 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7490 return ResolveNamespaceOrType (ec, silent);
7493 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7495 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7497 if (expr_resolved == null)
7500 string LookupIdentifier = MemberName.MakeName (Name, targs);
7502 Namespace ns = expr_resolved as Namespace;
7504 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7506 if (retval == null && !silent)
7507 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7508 else if (targs != null)
7509 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7514 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7515 if (tnew_expr == null)
7518 if (tnew_expr is TypeParameterExpr) {
7519 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7520 tnew_expr.GetSignatureForError ());
7524 Type expr_type = tnew_expr.Type;
7525 Expression member_lookup = MemberLookup (
7526 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7527 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7528 if (member_lookup == null) {
7532 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7536 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7541 TypeArguments the_args = targs;
7542 Type declaring_type = texpr.Type.DeclaringType;
7543 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7544 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7545 expr_type = expr_type.BaseType;
7548 TypeArguments new_args = new TypeArguments ();
7549 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7550 new_args.Add (new TypeExpression (decl, loc));
7553 new_args.Add (targs);
7555 the_args = new_args;
7558 if (the_args != null) {
7559 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7560 return ctype.ResolveAsTypeStep (rc, false);
7567 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7569 Expression member_lookup = MemberLookup (
7570 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7571 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7573 if (member_lookup != null) {
7574 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7575 if (expr_type == null)
7578 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7582 member_lookup = MemberLookup (
7583 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7584 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7586 if (member_lookup == null) {
7587 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7588 Name, expr_type.GetSignatureForError ());
7590 // TODO: Report.SymbolRelatedToPreviousError
7591 member_lookup.Error_UnexpectedKind (null, "type", loc);
7595 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7597 if (RootContext.Version > LanguageVersion.ISO_2 &&
7598 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7599 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7600 "extension method `{1}' of type `{0}' could be found " +
7601 "(are you missing a using directive or an assembly reference?)",
7602 TypeManager.CSharpName (type), name);
7606 base.Error_TypeDoesNotContainDefinition (type, name);
7609 public override string GetSignatureForError ()
7611 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7614 protected override void CloneTo (CloneContext clonectx, Expression t)
7616 MemberAccess target = (MemberAccess) t;
7618 target.expr = expr.Clone (clonectx);
7623 /// Implements checked expressions
7625 public class CheckedExpr : Expression {
7627 public Expression Expr;
7629 public CheckedExpr (Expression e, Location l)
7635 public override Expression CreateExpressionTree (EmitContext ec)
7637 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7638 return Expr.CreateExpressionTree (ec);
7641 public override Expression DoResolve (EmitContext ec)
7643 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7644 Expr = Expr.Resolve (ec);
7649 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7652 eclass = Expr.eclass;
7657 public override void Emit (EmitContext ec)
7659 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7663 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7665 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7666 Expr.EmitBranchable (ec, target, on_true);
7669 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7671 Expr.MutateHoistedGenericType (storey);
7674 protected override void CloneTo (CloneContext clonectx, Expression t)
7676 CheckedExpr target = (CheckedExpr) t;
7678 target.Expr = Expr.Clone (clonectx);
7683 /// Implements the unchecked expression
7685 public class UnCheckedExpr : Expression {
7687 public Expression Expr;
7689 public UnCheckedExpr (Expression e, Location l)
7695 public override Expression CreateExpressionTree (EmitContext ec)
7697 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7698 return Expr.CreateExpressionTree (ec);
7701 public override Expression DoResolve (EmitContext ec)
7703 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7704 Expr = Expr.Resolve (ec);
7709 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7712 eclass = Expr.eclass;
7717 public override void Emit (EmitContext ec)
7719 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7723 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7725 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7726 Expr.EmitBranchable (ec, target, on_true);
7729 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7731 Expr.MutateHoistedGenericType (storey);
7734 protected override void CloneTo (CloneContext clonectx, Expression t)
7736 UnCheckedExpr target = (UnCheckedExpr) t;
7738 target.Expr = Expr.Clone (clonectx);
7743 /// An Element Access expression.
7745 /// During semantic analysis these are transformed into
7746 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7748 public class ElementAccess : Expression {
7749 public ArrayList Arguments;
7750 public Expression Expr;
7752 public ElementAccess (Expression e, ArrayList e_list)
7760 Arguments = new ArrayList (e_list.Count);
7761 foreach (Expression tmp in e_list)
7762 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7765 bool CommonResolve (EmitContext ec)
7767 Expr = Expr.Resolve (ec);
7769 if (Arguments == null)
7772 foreach (Argument a in Arguments){
7773 if (!a.Resolve (ec, loc))
7777 return Expr != null;
7780 public override Expression CreateExpressionTree (EmitContext ec)
7782 ArrayList args = new ArrayList (Arguments.Count + 1);
7783 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7784 foreach (Argument a in Arguments)
7785 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7787 return CreateExpressionFactoryCall ("ArrayIndex", args);
7790 Expression MakePointerAccess (EmitContext ec, Type t)
7792 if (Arguments.Count != 1){
7793 Error (196, "A pointer must be indexed by only one value");
7797 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7800 return new Indirection (p, loc).Resolve (ec);
7803 public override Expression DoResolve (EmitContext ec)
7805 if (!CommonResolve (ec))
7809 // We perform some simple tests, and then to "split" the emit and store
7810 // code we create an instance of a different class, and return that.
7812 // I am experimenting with this pattern.
7816 if (t == TypeManager.array_type){
7817 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7822 return (new ArrayAccess (this, loc)).Resolve (ec);
7824 return MakePointerAccess (ec, t);
7826 FieldExpr fe = Expr as FieldExpr;
7828 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7830 return MakePointerAccess (ec, ff.ElementType);
7833 return (new IndexerAccess (this, loc)).Resolve (ec);
7836 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7838 if (!CommonResolve (ec))
7843 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7846 return MakePointerAccess (ec, type);
7848 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7849 Error_CannotModifyIntermediateExpressionValue (ec);
7851 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7854 public override void Emit (EmitContext ec)
7856 throw new Exception ("Should never be reached");
7859 public override string GetSignatureForError ()
7861 return Expr.GetSignatureForError ();
7864 protected override void CloneTo (CloneContext clonectx, Expression t)
7866 ElementAccess target = (ElementAccess) t;
7868 target.Expr = Expr.Clone (clonectx);
7869 target.Arguments = new ArrayList (Arguments.Count);
7870 foreach (Argument a in Arguments)
7871 target.Arguments.Add (a.Clone (clonectx));
7876 /// Implements array access
7878 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7880 // Points to our "data" repository
7884 LocalTemporary temp;
7888 public ArrayAccess (ElementAccess ea_data, Location l)
7894 public override Expression CreateExpressionTree (EmitContext ec)
7896 return ea.CreateExpressionTree (ec);
7899 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7901 return DoResolve (ec);
7904 public override Expression DoResolve (EmitContext ec)
7907 ExprClass eclass = ea.Expr.eclass;
7909 // As long as the type is valid
7910 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7911 eclass == ExprClass.Value)) {
7912 ea.Expr.Error_UnexpectedKind ("variable or value");
7917 if (eclass != ExprClass.Invalid)
7920 Type t = ea.Expr.Type;
7921 int rank = ea.Arguments.Count;
7922 if (t.GetArrayRank () != rank) {
7923 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7924 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7928 type = TypeManager.GetElementType (t);
7929 if (type.IsPointer && !ec.InUnsafe) {
7930 UnsafeError (ea.Location);
7934 foreach (Argument a in ea.Arguments) {
7935 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7938 eclass = ExprClass.Variable;
7944 /// Emits the right opcode to load an object of Type `t'
7945 /// from an array of T
7947 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7950 MethodInfo get = FetchGetMethod ();
7951 ig.Emit (OpCodes.Call, get);
7955 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7956 ig.Emit (OpCodes.Ldelem_U1);
7957 else if (type == TypeManager.sbyte_type)
7958 ig.Emit (OpCodes.Ldelem_I1);
7959 else if (type == TypeManager.short_type)
7960 ig.Emit (OpCodes.Ldelem_I2);
7961 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7962 ig.Emit (OpCodes.Ldelem_U2);
7963 else if (type == TypeManager.int32_type)
7964 ig.Emit (OpCodes.Ldelem_I4);
7965 else if (type == TypeManager.uint32_type)
7966 ig.Emit (OpCodes.Ldelem_U4);
7967 else if (type == TypeManager.uint64_type)
7968 ig.Emit (OpCodes.Ldelem_I8);
7969 else if (type == TypeManager.int64_type)
7970 ig.Emit (OpCodes.Ldelem_I8);
7971 else if (type == TypeManager.float_type)
7972 ig.Emit (OpCodes.Ldelem_R4);
7973 else if (type == TypeManager.double_type)
7974 ig.Emit (OpCodes.Ldelem_R8);
7975 else if (type == TypeManager.intptr_type)
7976 ig.Emit (OpCodes.Ldelem_I);
7977 else if (TypeManager.IsEnumType (type)){
7978 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7979 } else if (TypeManager.IsStruct (type)){
7980 ig.Emit (OpCodes.Ldelema, type);
7981 ig.Emit (OpCodes.Ldobj, type);
7983 } else if (type.IsGenericParameter) {
7984 ig.Emit (OpCodes.Ldelem, type);
7986 } else if (type.IsPointer)
7987 ig.Emit (OpCodes.Ldelem_I);
7989 ig.Emit (OpCodes.Ldelem_Ref);
7992 protected override void Error_NegativeArrayIndex (Location loc)
7994 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7998 /// Returns the right opcode to store an object of Type `t'
7999 /// from an array of T.
8001 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8003 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8004 has_type_arg = false; is_stobj = false;
8005 t = TypeManager.TypeToCoreType (t);
8006 if (TypeManager.IsEnumType (t))
8007 t = TypeManager.GetEnumUnderlyingType (t);
8008 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8009 t == TypeManager.bool_type)
8010 return OpCodes.Stelem_I1;
8011 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8012 t == TypeManager.char_type)
8013 return OpCodes.Stelem_I2;
8014 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8015 return OpCodes.Stelem_I4;
8016 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8017 return OpCodes.Stelem_I8;
8018 else if (t == TypeManager.float_type)
8019 return OpCodes.Stelem_R4;
8020 else if (t == TypeManager.double_type)
8021 return OpCodes.Stelem_R8;
8022 else if (t == TypeManager.intptr_type) {
8023 has_type_arg = true;
8025 return OpCodes.Stobj;
8026 } else if (TypeManager.IsStruct (t)) {
8027 has_type_arg = true;
8029 return OpCodes.Stobj;
8031 } else if (t.IsGenericParameter) {
8032 has_type_arg = true;
8033 return OpCodes.Stelem;
8036 } else if (t.IsPointer)
8037 return OpCodes.Stelem_I;
8039 return OpCodes.Stelem_Ref;
8042 MethodInfo FetchGetMethod ()
8044 ModuleBuilder mb = CodeGen.Module.Builder;
8045 int arg_count = ea.Arguments.Count;
8046 Type [] args = new Type [arg_count];
8049 for (int i = 0; i < arg_count; i++){
8050 //args [i++] = a.Type;
8051 args [i] = TypeManager.int32_type;
8054 get = mb.GetArrayMethod (
8055 ea.Expr.Type, "Get",
8056 CallingConventions.HasThis |
8057 CallingConventions.Standard,
8063 MethodInfo FetchAddressMethod ()
8065 ModuleBuilder mb = CodeGen.Module.Builder;
8066 int arg_count = ea.Arguments.Count;
8067 Type [] args = new Type [arg_count];
8071 ret_type = TypeManager.GetReferenceType (type);
8073 for (int i = 0; i < arg_count; i++){
8074 //args [i++] = a.Type;
8075 args [i] = TypeManager.int32_type;
8078 address = mb.GetArrayMethod (
8079 ea.Expr.Type, "Address",
8080 CallingConventions.HasThis |
8081 CallingConventions.Standard,
8088 // Load the array arguments into the stack.
8090 void LoadArrayAndArguments (EmitContext ec)
8094 for (int i = 0; i < ea.Arguments.Count; ++i) {
8095 ((Argument)ea.Arguments [i]).Emit (ec);
8099 public void Emit (EmitContext ec, bool leave_copy)
8101 int rank = ea.Expr.Type.GetArrayRank ();
8102 ILGenerator ig = ec.ig;
8105 LoadFromPtr (ig, this.type);
8107 LoadArrayAndArguments (ec);
8108 EmitLoadOpcode (ig, type, rank);
8112 ig.Emit (OpCodes.Dup);
8113 temp = new LocalTemporary (this.type);
8118 public override void Emit (EmitContext ec)
8123 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8125 int rank = ea.Expr.Type.GetArrayRank ();
8126 ILGenerator ig = ec.ig;
8127 Type t = source.Type;
8128 prepared = prepare_for_load;
8131 AddressOf (ec, AddressOp.LoadStore);
8132 ec.ig.Emit (OpCodes.Dup);
8134 LoadArrayAndArguments (ec);
8138 bool is_stobj, has_type_arg;
8139 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8143 // The stobj opcode used by value types will need
8144 // an address on the stack, not really an array/array
8148 ig.Emit (OpCodes.Ldelema, t);
8153 ec.ig.Emit (OpCodes.Dup);
8154 temp = new LocalTemporary (this.type);
8159 StoreFromPtr (ig, t);
8161 ig.Emit (OpCodes.Stobj, t);
8162 else if (has_type_arg)
8169 ec.ig.Emit (OpCodes.Dup);
8170 temp = new LocalTemporary (this.type);
8175 StoreFromPtr (ig, t);
8177 int arg_count = ea.Arguments.Count;
8178 Type [] args = new Type [arg_count + 1];
8179 for (int i = 0; i < arg_count; i++) {
8180 //args [i++] = a.Type;
8181 args [i] = TypeManager.int32_type;
8183 args [arg_count] = type;
8185 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8186 ea.Expr.Type, "Set",
8187 CallingConventions.HasThis |
8188 CallingConventions.Standard,
8189 TypeManager.void_type, args);
8191 ig.Emit (OpCodes.Call, set);
8201 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8203 if (!source.Emit (ec, this)) {
8205 throw new NotImplementedException ();
8210 throw new NotImplementedException ();
8213 public void AddressOf (EmitContext ec, AddressOp mode)
8215 int rank = ea.Expr.Type.GetArrayRank ();
8216 ILGenerator ig = ec.ig;
8218 LoadArrayAndArguments (ec);
8221 ig.Emit (OpCodes.Ldelema, type);
8223 MethodInfo address = FetchAddressMethod ();
8224 ig.Emit (OpCodes.Call, address);
8228 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8230 type = storey.MutateType (type);
8231 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8236 /// Expressions that represent an indexer call.
8238 public class IndexerAccess : Expression, IAssignMethod
8240 class IndexerMethodGroupExpr : MethodGroupExpr
8242 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8245 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8248 public override string Name {
8254 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8257 // Here is the trick, decrease number of arguments by 1 when only
8258 // available property method is setter. This makes overload resolution
8259 // work correctly for indexers.
8262 if (method.Name [0] == 'g')
8263 return parameters.Count;
8265 return parameters.Count - 1;
8271 // Contains either property getter or setter
8272 public ArrayList Methods;
8273 public ArrayList Properties;
8279 void Append (Type caller_type, MemberInfo [] mi)
8284 foreach (PropertyInfo property in mi) {
8285 MethodInfo accessor = property.GetGetMethod (true);
8286 if (accessor == null)
8287 accessor = property.GetSetMethod (true);
8289 if (Methods == null) {
8290 Methods = new ArrayList ();
8291 Properties = new ArrayList ();
8294 Methods.Add (accessor);
8295 Properties.Add (property);
8299 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8301 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8303 return TypeManager.MemberLookup (
8304 caller_type, caller_type, lookup_type, MemberTypes.Property,
8305 BindingFlags.Public | BindingFlags.Instance |
8306 BindingFlags.DeclaredOnly, p_name, null);
8309 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8311 Indexers ix = new Indexers ();
8314 if (lookup_type.IsGenericParameter) {
8315 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8319 if (gc.HasClassConstraint)
8320 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8322 Type[] ifaces = gc.InterfaceConstraints;
8323 foreach (Type itype in ifaces)
8324 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8330 Type copy = lookup_type;
8331 while (copy != TypeManager.object_type && copy != null){
8332 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8333 copy = copy.BaseType;
8336 if (lookup_type.IsInterface) {
8337 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8338 if (ifaces != null) {
8339 foreach (Type itype in ifaces)
8340 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8355 // Points to our "data" repository
8357 MethodInfo get, set;
8358 bool is_base_indexer;
8360 LocalTemporary temp;
8361 LocalTemporary prepared_value;
8362 Expression set_expr;
8364 protected Type indexer_type;
8365 protected Type current_type;
8366 protected Expression instance_expr;
8367 protected ArrayList arguments;
8369 public IndexerAccess (ElementAccess ea, Location loc)
8370 : this (ea.Expr, false, loc)
8372 this.arguments = ea.Arguments;
8375 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8378 this.instance_expr = instance_expr;
8379 this.is_base_indexer = is_base_indexer;
8380 this.eclass = ExprClass.Value;
8384 static string GetAccessorName (AccessorType at)
8386 if (at == AccessorType.Set)
8389 if (at == AccessorType.Get)
8392 throw new NotImplementedException (at.ToString ());
8395 public override Expression CreateExpressionTree (EmitContext ec)
8397 ArrayList args = new ArrayList (arguments.Count + 2);
8398 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8399 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8400 foreach (Argument a in arguments)
8401 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8403 return CreateExpressionFactoryCall ("Call", args);
8406 protected virtual bool CommonResolve (EmitContext ec)
8408 indexer_type = instance_expr.Type;
8409 current_type = ec.ContainerType;
8414 public override Expression DoResolve (EmitContext ec)
8416 return ResolveAccessor (ec, AccessorType.Get);
8419 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8421 if (right_side == EmptyExpression.OutAccess) {
8422 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8423 GetSignatureForError ());
8427 // if the indexer returns a value type, and we try to set a field in it
8428 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8429 Error_CannotModifyIntermediateExpressionValue (ec);
8432 Expression e = ResolveAccessor (ec, AccessorType.Set);
8436 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8440 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8442 if (!CommonResolve (ec))
8445 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8446 if (ilist.Methods == null) {
8447 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8448 TypeManager.CSharpName (indexer_type));
8452 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8453 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8457 MethodInfo mi = (MethodInfo) mg;
8458 PropertyInfo pi = null;
8459 for (int i = 0; i < ilist.Methods.Count; ++i) {
8460 if (ilist.Methods [i] == mi) {
8461 pi = (PropertyInfo) ilist.Properties [i];
8466 type = TypeManager.TypeToCoreType (pi.PropertyType);
8467 if (type.IsPointer && !ec.InUnsafe)
8470 MethodInfo accessor;
8471 if (accessorType == AccessorType.Get) {
8472 accessor = get = pi.GetGetMethod (true);
8474 accessor = set = pi.GetSetMethod (true);
8475 if (accessor == null && pi.GetGetMethod (true) != null) {
8476 Report.SymbolRelatedToPreviousError (pi);
8477 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8478 TypeManager.GetFullNameSignature (pi));
8483 if (accessor == null) {
8484 Report.SymbolRelatedToPreviousError (pi);
8485 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8486 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8491 // Only base will allow this invocation to happen.
8493 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8494 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8497 bool must_do_cs1540_check;
8498 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8500 set = pi.GetSetMethod (true);
8502 get = pi.GetGetMethod (true);
8504 if (set != null && get != null &&
8505 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8506 Report.SymbolRelatedToPreviousError (accessor);
8507 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8508 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8510 Report.SymbolRelatedToPreviousError (pi);
8511 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8515 instance_expr.CheckMarshalByRefAccess (ec);
8516 eclass = ExprClass.IndexerAccess;
8520 public void Emit (EmitContext ec, bool leave_copy)
8523 prepared_value.Emit (ec);
8525 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8526 arguments, loc, false, false);
8530 ec.ig.Emit (OpCodes.Dup);
8531 temp = new LocalTemporary (Type);
8537 // source is ignored, because we already have a copy of it from the
8538 // LValue resolution and we have already constructed a pre-cached
8539 // version of the arguments (ea.set_arguments);
8541 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8543 prepared = prepare_for_load;
8544 Expression value = set_expr;
8547 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8548 arguments, loc, true, false);
8550 prepared_value = new LocalTemporary (type);
8551 prepared_value.Store (ec);
8553 prepared_value.Release (ec);
8556 ec.ig.Emit (OpCodes.Dup);
8557 temp = new LocalTemporary (Type);
8560 } else if (leave_copy) {
8561 temp = new LocalTemporary (Type);
8567 arguments.Add (new Argument (value, Argument.AType.Expression));
8568 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8576 public override void Emit (EmitContext ec)
8581 public override string GetSignatureForError ()
8583 return TypeManager.CSharpSignature (get != null ? get : set, false);
8586 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8589 get = storey.MutateGenericMethod (get);
8591 set = storey.MutateGenericMethod (set);
8593 instance_expr.MutateHoistedGenericType (storey);
8594 foreach (Argument a in arguments)
8595 a.Expr.MutateHoistedGenericType (storey);
8597 type = storey.MutateType (type);
8600 protected override void CloneTo (CloneContext clonectx, Expression t)
8602 IndexerAccess target = (IndexerAccess) t;
8604 if (arguments != null){
8605 target.arguments = new ArrayList ();
8606 foreach (Argument a in arguments)
8607 target.arguments.Add (a.Clone (clonectx));
8609 if (instance_expr != null)
8610 target.instance_expr = instance_expr.Clone (clonectx);
8615 /// The base operator for method names
8617 public class BaseAccess : Expression {
8618 public readonly string Identifier;
8621 public BaseAccess (string member, Location l)
8623 this.Identifier = member;
8627 public BaseAccess (string member, TypeArguments args, Location l)
8633 public override Expression CreateExpressionTree (EmitContext ec)
8635 throw new NotSupportedException ("ET");
8638 public override Expression DoResolve (EmitContext ec)
8640 Expression c = CommonResolve (ec);
8646 // MethodGroups use this opportunity to flag an error on lacking ()
8648 if (!(c is MethodGroupExpr))
8649 return c.Resolve (ec);
8653 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8655 Expression c = CommonResolve (ec);
8661 // MethodGroups use this opportunity to flag an error on lacking ()
8663 if (! (c is MethodGroupExpr))
8664 return c.DoResolveLValue (ec, right_side);
8669 Expression CommonResolve (EmitContext ec)
8671 Expression member_lookup;
8672 Type current_type = ec.ContainerType;
8673 Type base_type = current_type.BaseType;
8675 if (!This.IsThisAvailable (ec)) {
8677 Error (1511, "Keyword `base' is not available in a static method");
8679 Error (1512, "Keyword `base' is not available in the current context");
8684 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8685 AllMemberTypes, AllBindingFlags, loc);
8686 if (member_lookup == null) {
8687 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8688 null, AllMemberTypes, AllBindingFlags);
8695 left = new TypeExpression (base_type, loc);
8697 left = ec.GetThis (loc);
8699 MemberExpr me = (MemberExpr) member_lookup;
8700 me = me.ResolveMemberAccess (ec, left, loc, null);
8707 me.SetTypeArguments (args);
8713 public override void Emit (EmitContext ec)
8715 throw new Exception ("Should never be called");
8718 protected override void CloneTo (CloneContext clonectx, Expression t)
8720 BaseAccess target = (BaseAccess) t;
8723 target.args = args.Clone ();
8728 /// The base indexer operator
8730 public class BaseIndexerAccess : IndexerAccess {
8731 public BaseIndexerAccess (ArrayList args, Location loc)
8732 : base (null, true, loc)
8734 arguments = new ArrayList ();
8735 foreach (Expression tmp in args)
8736 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8739 protected override bool CommonResolve (EmitContext ec)
8741 instance_expr = ec.GetThis (loc);
8743 current_type = ec.ContainerType.BaseType;
8744 indexer_type = current_type;
8746 foreach (Argument a in arguments){
8747 if (!a.Resolve (ec, loc))
8754 public override Expression CreateExpressionTree (EmitContext ec)
8756 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8757 return base.CreateExpressionTree (ec);
8762 /// This class exists solely to pass the Type around and to be a dummy
8763 /// that can be passed to the conversion functions (this is used by
8764 /// foreach implementation to typecast the object return value from
8765 /// get_Current into the proper type. All code has been generated and
8766 /// we only care about the side effect conversions to be performed
8768 /// This is also now used as a placeholder where a no-action expression
8769 /// is needed (the `New' class).
8771 public class EmptyExpression : Expression {
8772 public static readonly Expression Null = new EmptyExpression ();
8774 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8775 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8776 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8777 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8779 static EmptyExpression temp = new EmptyExpression ();
8780 public static EmptyExpression Grab ()
8782 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8787 public static void Release (EmptyExpression e)
8794 // FIXME: Don't set to object
8795 type = TypeManager.object_type;
8796 eclass = ExprClass.Value;
8797 loc = Location.Null;
8800 public EmptyExpression (Type t)
8803 eclass = ExprClass.Value;
8804 loc = Location.Null;
8807 public override Expression CreateExpressionTree (EmitContext ec)
8809 throw new NotSupportedException ("ET");
8812 public override Expression DoResolve (EmitContext ec)
8817 public override void Emit (EmitContext ec)
8819 // nothing, as we only exist to not do anything.
8822 public override void EmitSideEffect (EmitContext ec)
8827 // This is just because we might want to reuse this bad boy
8828 // instead of creating gazillions of EmptyExpressions.
8829 // (CanImplicitConversion uses it)
8831 public void SetType (Type t)
8838 // Empty statement expression
8840 public sealed class EmptyExpressionStatement : ExpressionStatement
8842 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8844 private EmptyExpressionStatement ()
8846 eclass = ExprClass.Value;
8847 loc = Location.Null;
8850 public override Expression CreateExpressionTree (EmitContext ec)
8855 public override void EmitStatement (EmitContext ec)
8860 public override Expression DoResolve (EmitContext ec)
8862 type = TypeManager.object_type;
8866 public override void Emit (EmitContext ec)
8872 public class UserCast : Expression {
8876 public UserCast (MethodInfo method, Expression source, Location l)
8878 this.method = method;
8879 this.source = source;
8880 type = TypeManager.TypeToCoreType (method.ReturnType);
8884 public Expression Source {
8890 public override Expression CreateExpressionTree (EmitContext ec)
8892 ArrayList args = new ArrayList (3);
8893 args.Add (new Argument (source.CreateExpressionTree (ec)));
8894 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8895 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8896 return CreateExpressionFactoryCall ("Convert", args);
8899 public override Expression DoResolve (EmitContext ec)
8901 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8903 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8905 eclass = ExprClass.Value;
8909 public override void Emit (EmitContext ec)
8912 ec.ig.Emit (OpCodes.Call, method);
8915 public override string GetSignatureForError ()
8917 return TypeManager.CSharpSignature (method);
8920 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8922 source.MutateHoistedGenericType (storey);
8923 method = storey.MutateGenericMethod (method);
8928 // This class is used to "construct" the type during a typecast
8929 // operation. Since the Type.GetType class in .NET can parse
8930 // the type specification, we just use this to construct the type
8931 // one bit at a time.
8933 public class ComposedCast : TypeExpr {
8934 FullNamedExpression left;
8937 public ComposedCast (FullNamedExpression left, string dim)
8938 : this (left, dim, left.Location)
8942 public ComposedCast (FullNamedExpression left, string dim, Location l)
8949 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8951 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8955 Type ltype = lexpr.Type;
8957 if ((dim.Length > 0) && (dim [0] == '?')) {
8958 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8960 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8961 return nullable.ResolveAsTypeTerminal (ec, false);
8965 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8968 if (dim.Length != 0 && dim [0] == '[') {
8969 if (TypeManager.IsSpecialType (ltype)) {
8970 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8974 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8975 Report.SymbolRelatedToPreviousError (ltype);
8976 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8977 TypeManager.CSharpName (ltype));
8982 type = TypeManager.GetConstructedType (ltype, dim);
8987 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8989 if (type.IsPointer && !ec.IsInUnsafeScope){
8993 eclass = ExprClass.Type;
8997 public override string GetSignatureForError ()
8999 return left.GetSignatureForError () + dim;
9002 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
9004 return ResolveAsBaseTerminal (ec, silent);
9008 public class FixedBufferPtr : Expression {
9011 public FixedBufferPtr (Expression array, Type array_type, Location l)
9016 type = TypeManager.GetPointerType (array_type);
9017 eclass = ExprClass.Value;
9020 public override Expression CreateExpressionTree (EmitContext ec)
9022 Error_PointerInsideExpressionTree ();
9026 public override void Emit(EmitContext ec)
9031 public override Expression DoResolve (EmitContext ec)
9034 // We are born fully resolved
9042 // This class is used to represent the address of an array, used
9043 // only by the Fixed statement, this generates "&a [0]" construct
9044 // for fixed (char *pa = a)
9046 public class ArrayPtr : FixedBufferPtr {
9049 public ArrayPtr (Expression array, Type array_type, Location l):
9050 base (array, array_type, l)
9052 this.array_type = array_type;
9055 public override void Emit (EmitContext ec)
9059 ILGenerator ig = ec.ig;
9060 IntLiteral.EmitInt (ig, 0);
9061 ig.Emit (OpCodes.Ldelema, array_type);
9066 // Encapsulates a conversion rules required for array indexes
9068 public class ArrayIndexCast : TypeCast
9070 public ArrayIndexCast (Expression expr)
9071 : base (expr, expr.Type)
9075 public override Expression CreateExpressionTree (EmitContext ec)
9077 ArrayList args = new ArrayList (2);
9078 args.Add (new Argument (child.CreateExpressionTree (ec)));
9079 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9080 return CreateExpressionFactoryCall ("ConvertChecked", args);
9083 public override void Emit (EmitContext ec)
9087 if (type == TypeManager.int32_type)
9090 if (type == TypeManager.uint32_type)
9091 ec.ig.Emit (OpCodes.Conv_U);
9092 else if (type == TypeManager.int64_type)
9093 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9094 else if (type == TypeManager.uint64_type)
9095 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9097 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9102 // Implements the `stackalloc' keyword
9104 public class StackAlloc : Expression {
9109 public StackAlloc (Expression type, Expression count, Location l)
9116 public override Expression CreateExpressionTree (EmitContext ec)
9118 throw new NotSupportedException ("ET");
9121 public override Expression DoResolve (EmitContext ec)
9123 count = count.Resolve (ec);
9127 if (count.Type != TypeManager.uint32_type){
9128 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9133 Constant c = count as Constant;
9134 if (c != null && c.IsNegative) {
9135 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9139 if (ec.InCatch || ec.InFinally) {
9140 Error (255, "Cannot use stackalloc in finally or catch");
9144 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9150 if (!TypeManager.VerifyUnManaged (otype, loc))
9153 type = TypeManager.GetPointerType (otype);
9154 eclass = ExprClass.Value;
9159 public override void Emit (EmitContext ec)
9161 int size = GetTypeSize (otype);
9162 ILGenerator ig = ec.ig;
9167 ig.Emit (OpCodes.Sizeof, otype);
9169 IntConstant.EmitInt (ig, size);
9171 ig.Emit (OpCodes.Mul_Ovf_Un);
9172 ig.Emit (OpCodes.Localloc);
9175 protected override void CloneTo (CloneContext clonectx, Expression t)
9177 StackAlloc target = (StackAlloc) t;
9178 target.count = count.Clone (clonectx);
9179 target.t = t.Clone (clonectx);
9184 // An object initializer expression
9186 public class ElementInitializer : Assign
9188 public readonly string Name;
9190 public ElementInitializer (string name, Expression initializer, Location loc)
9191 : base (null, initializer, loc)
9196 protected override void CloneTo (CloneContext clonectx, Expression t)
9198 ElementInitializer target = (ElementInitializer) t;
9199 target.source = source.Clone (clonectx);
9202 public override Expression CreateExpressionTree (EmitContext ec)
9204 ArrayList args = new ArrayList (2);
9205 FieldExpr fe = target as FieldExpr;
9207 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9209 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9211 args.Add (new Argument (source.CreateExpressionTree (ec)));
9212 return CreateExpressionFactoryCall (
9213 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9217 public override Expression DoResolve (EmitContext ec)
9220 return EmptyExpressionStatement.Instance;
9222 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9223 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9229 me.InstanceExpression = ec.CurrentInitializerVariable;
9231 if (source is CollectionOrObjectInitializers) {
9232 Expression previous = ec.CurrentInitializerVariable;
9233 ec.CurrentInitializerVariable = target;
9234 source = source.Resolve (ec);
9235 ec.CurrentInitializerVariable = previous;
9239 eclass = source.eclass;
9244 Expression expr = base.DoResolve (ec);
9249 // Ignore field initializers with default value
9251 Constant c = source as Constant;
9252 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9253 return EmptyExpressionStatement.Instance.DoResolve (ec);
9258 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9260 MemberInfo member = members [0];
9261 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9262 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9263 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9265 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9266 TypeManager.GetFullNameSignature (member));
9271 public override void EmitStatement (EmitContext ec)
9273 if (source is CollectionOrObjectInitializers)
9276 base.EmitStatement (ec);
9281 // A collection initializer expression
9283 public class CollectionElementInitializer : Invocation
9285 public class ElementInitializerArgument : Argument
9287 public ElementInitializerArgument (Expression e)
9293 sealed class AddMemberAccess : MemberAccess
9295 public AddMemberAccess (Expression expr, Location loc)
9296 : base (expr, "Add", loc)
9300 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9302 if (TypeManager.HasElementType (type))
9305 base.Error_TypeDoesNotContainDefinition (type, name);
9309 public CollectionElementInitializer (Expression argument)
9310 : base (null, new ArrayList (1), true)
9312 Arguments.Add (argument);
9313 this.loc = argument.Location;
9316 public CollectionElementInitializer (ArrayList arguments, Location loc)
9317 : base (null, arguments, true)
9322 public override Expression CreateExpressionTree (EmitContext ec)
9324 ArrayList args = new ArrayList (2);
9325 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9327 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9328 foreach (Argument a in Arguments)
9329 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9331 args.Add (new Argument (new ArrayCreation (
9332 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9333 return CreateExpressionFactoryCall ("ElementInit", args);
9336 protected override void CloneTo (CloneContext clonectx, Expression t)
9338 CollectionElementInitializer target = (CollectionElementInitializer) t;
9340 target.Arguments = new ArrayList (Arguments.Count);
9341 foreach (Expression e in Arguments)
9342 target.Arguments.Add (e.Clone (clonectx));
9345 public override Expression DoResolve (EmitContext ec)
9347 if (eclass != ExprClass.Invalid)
9350 // TODO: We could call a constructor which takes element count argument,
9351 // for known types like List<T>, Dictionary<T, U>
9353 for (int i = 0; i < Arguments.Count; ++i) {
9354 Expression expr = Arguments [i] as Expression;
9358 expr = expr.Resolve (ec);
9362 Arguments [i] = new ElementInitializerArgument (expr);
9365 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9367 return base.DoResolve (ec);
9372 // A block of object or collection initializers
9374 public class CollectionOrObjectInitializers : ExpressionStatement
9376 ArrayList initializers;
9377 bool is_collection_initialization;
9379 public static readonly CollectionOrObjectInitializers Empty =
9380 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9382 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9384 this.initializers = initializers;
9388 public bool IsEmpty {
9390 return initializers.Count == 0;
9394 public bool IsCollectionInitializer {
9396 return is_collection_initialization;
9400 protected override void CloneTo (CloneContext clonectx, Expression target)
9402 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9404 t.initializers = new ArrayList (initializers.Count);
9405 foreach (Expression e in initializers)
9406 t.initializers.Add (e.Clone (clonectx));
9409 public override Expression CreateExpressionTree (EmitContext ec)
9411 ArrayList expr_initializers = new ArrayList (initializers.Count);
9412 foreach (Expression e in initializers) {
9413 Expression expr = e.CreateExpressionTree (ec);
9415 expr_initializers.Add (expr);
9418 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9421 public override Expression DoResolve (EmitContext ec)
9423 if (eclass != ExprClass.Invalid)
9426 ArrayList element_names = null;
9427 for (int i = 0; i < initializers.Count; ++i) {
9428 Expression initializer = (Expression) initializers [i];
9429 ElementInitializer element_initializer = initializer as ElementInitializer;
9432 if (element_initializer != null) {
9433 element_names = new ArrayList (initializers.Count);
9434 element_names.Add (element_initializer.Name);
9436 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9437 TypeManager.ienumerable_type)) {
9438 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9439 "object initializer because type `{1}' does not implement `{2}' interface",
9440 ec.CurrentInitializerVariable.GetSignatureForError (),
9441 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9442 TypeManager.CSharpName (TypeManager.ienumerable_type));
9445 is_collection_initialization = true;
9448 if (is_collection_initialization != (element_initializer == null)) {
9449 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9450 is_collection_initialization ? "collection initializer" : "object initializer");
9454 if (!is_collection_initialization) {
9455 if (element_names.Contains (element_initializer.Name)) {
9456 Report.Error (1912, element_initializer.Location,
9457 "An object initializer includes more than one member `{0}' initialization",
9458 element_initializer.Name);
9460 element_names.Add (element_initializer.Name);
9465 Expression e = initializer.Resolve (ec);
9466 if (e == EmptyExpressionStatement.Instance)
9467 initializers.RemoveAt (i--);
9469 initializers [i] = e;
9472 type = ec.CurrentInitializerVariable.Type;
9473 if (is_collection_initialization) {
9474 if (TypeManager.HasElementType (type)) {
9475 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9476 TypeManager.CSharpName (type));
9480 eclass = ExprClass.Variable;
9484 public override void Emit (EmitContext ec)
9489 public override void EmitStatement (EmitContext ec)
9491 foreach (ExpressionStatement e in initializers)
9492 e.EmitStatement (ec);
9495 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9497 foreach (Expression e in initializers)
9498 e.MutateHoistedGenericType (storey);
9503 // New expression with element/object initializers
9505 public class NewInitialize : New
9508 // This class serves as a proxy for variable initializer target instances.
9509 // A real variable is assigned later when we resolve left side of an
9512 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9514 NewInitialize new_instance;
9516 public InitializerTargetExpression (NewInitialize newInstance)
9518 this.type = newInstance.type;
9519 this.loc = newInstance.loc;
9520 this.eclass = newInstance.eclass;
9521 this.new_instance = newInstance;
9524 public override Expression CreateExpressionTree (EmitContext ec)
9526 // Should not be reached
9527 throw new NotSupportedException ("ET");
9530 public override Expression DoResolve (EmitContext ec)
9535 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9540 public override void Emit (EmitContext ec)
9542 Expression e = (Expression) new_instance.instance;
9546 #region IMemoryLocation Members
9548 public void AddressOf (EmitContext ec, AddressOp mode)
9550 new_instance.instance.AddressOf (ec, mode);
9556 CollectionOrObjectInitializers initializers;
9557 IMemoryLocation instance;
9559 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9560 : base (requested_type, arguments, l)
9562 this.initializers = initializers;
9565 protected override void CloneTo (CloneContext clonectx, Expression t)
9567 base.CloneTo (clonectx, t);
9569 NewInitialize target = (NewInitialize) t;
9570 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9573 public override Expression CreateExpressionTree (EmitContext ec)
9575 ArrayList args = new ArrayList (2);
9576 args.Add (new Argument (base.CreateExpressionTree (ec)));
9577 if (!initializers.IsEmpty)
9578 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9580 return CreateExpressionFactoryCall (
9581 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9585 public override Expression DoResolve (EmitContext ec)
9587 if (eclass != ExprClass.Invalid)
9590 Expression e = base.DoResolve (ec);
9594 Expression previous = ec.CurrentInitializerVariable;
9595 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9596 initializers.Resolve (ec);
9598 // Empty initializer can be optimized to simple new
9599 if (initializers.IsEmpty) {
9600 e = ReducedExpression.Create (e, this).Resolve (ec);
9603 ec.CurrentInitializerVariable = previous;
9607 public override bool Emit (EmitContext ec, IMemoryLocation target)
9609 bool left_on_stack = base.Emit (ec, target);
9611 if (initializers.IsEmpty)
9612 return left_on_stack;
9614 LocalTemporary temp = null;
9617 // If target is non-hoisted variable, let's use it
9619 VariableReference variable = target as VariableReference;
9620 if (variable != null && !variable.IsRef) {
9623 if (left_on_stack) {
9624 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9625 left_on_stack = false;
9628 temp = target as LocalTemporary;
9629 bool is_address = false;
9631 if (!left_on_stack) {
9633 target.AddressOf (ec, AddressOp.Load);
9634 left_on_stack = true;
9637 temp = new LocalTemporary (type);
9641 if (left_on_stack && !is_address)
9645 initializers.Emit (ec);
9647 if (left_on_stack) {
9652 return left_on_stack;
9655 public override bool HasInitializer {
9657 return !initializers.IsEmpty;
9661 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9663 base.MutateHoistedGenericType (storey);
9664 initializers.MutateHoistedGenericType (storey);
9668 public class AnonymousTypeDeclaration : Expression
9670 ArrayList parameters;
9671 readonly TypeContainer parent;
9672 static readonly ArrayList EmptyParameters = new ArrayList (0);
9674 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9676 this.parameters = parameters;
9677 this.parent = parent;
9681 protected override void CloneTo (CloneContext clonectx, Expression target)
9683 if (parameters == null)
9686 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9687 t.parameters = new ArrayList (parameters.Count);
9688 foreach (AnonymousTypeParameter atp in parameters)
9689 t.parameters.Add (atp.Clone (clonectx));
9692 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9694 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9698 type = AnonymousTypeClass.Create (parent, parameters, loc);
9705 if (Report.Errors == 0)
9708 RootContext.ToplevelTypes.AddAnonymousType (type);
9712 public override Expression CreateExpressionTree (EmitContext ec)
9714 throw new NotSupportedException ("ET");
9717 public override Expression DoResolve (EmitContext ec)
9719 AnonymousTypeClass anonymous_type;
9721 if (!ec.IsAnonymousMethodAllowed) {
9722 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9726 if (parameters == null) {
9727 anonymous_type = CreateAnonymousType (EmptyParameters);
9728 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9729 null, loc).Resolve (ec);
9733 ArrayList arguments = new ArrayList (parameters.Count);
9734 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9735 for (int i = 0; i < parameters.Count; ++i) {
9736 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9742 arguments.Add (new Argument (e));
9743 t_args [i] = new TypeExpression (e.Type, e.Location);
9749 anonymous_type = CreateAnonymousType (parameters);
9750 if (anonymous_type == null)
9753 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9754 new TypeArguments (t_args), loc);
9756 return new New (te, arguments, loc).Resolve (ec);
9759 public override void Emit (EmitContext ec)
9761 throw new InternalErrorException ("Should not be reached");
9765 public class AnonymousTypeParameter : Expression
9767 public readonly string Name;
9768 Expression initializer;
9770 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9774 this.initializer = initializer;
9777 public AnonymousTypeParameter (Parameter parameter)
9779 this.Name = parameter.Name;
9780 this.loc = parameter.Location;
9781 this.initializer = new SimpleName (Name, loc);
9784 protected override void CloneTo (CloneContext clonectx, Expression target)
9786 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9787 t.initializer = initializer.Clone (clonectx);
9790 public override Expression CreateExpressionTree (EmitContext ec)
9792 throw new NotSupportedException ("ET");
9795 public override bool Equals (object o)
9797 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9798 return other != null && Name == other.Name;
9801 public override int GetHashCode ()
9803 return Name.GetHashCode ();
9806 public override Expression DoResolve (EmitContext ec)
9808 Expression e = initializer.Resolve (ec);
9812 if (e.eclass == ExprClass.MethodGroup) {
9813 Error_InvalidInitializer (e.ExprClassName);
9818 if (type == TypeManager.void_type || e is NullLiteral ||
9819 type == TypeManager.anonymous_method_type || type.IsPointer) {
9820 Error_InvalidInitializer (e.GetSignatureForError ());
9827 protected virtual void Error_InvalidInitializer (string initializer)
9829 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9833 public override void Emit (EmitContext ec)
9835 throw new InternalErrorException ("Should not be reached");