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.IsNullableType (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;
1003 if (TypeManager.IsNullableType (expr.Type))
1004 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1006 return ResolveOperator (ec);
1010 // Loads the proper "1" into the stack based on the type, then it emits the
1011 // opcode for the operation requested
1013 void LoadOneAndEmitOp (EmitContext ec, Type t)
1016 // Measure if getting the typecode and using that is more/less efficient
1017 // that comparing types. t.GetTypeCode() is an internal call.
1019 ILGenerator ig = ec.ig;
1021 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1022 LongConstant.EmitLong (ig, 1);
1023 else if (t == TypeManager.double_type)
1024 ig.Emit (OpCodes.Ldc_R8, 1.0);
1025 else if (t == TypeManager.float_type)
1026 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1027 else if (t.IsPointer){
1028 Type et = TypeManager.GetElementType (t);
1029 int n = GetTypeSize (et);
1032 ig.Emit (OpCodes.Sizeof, et);
1034 IntConstant.EmitInt (ig, n);
1035 ig.Emit (OpCodes.Conv_I);
1038 ig.Emit (OpCodes.Ldc_I4_1);
1041 // Now emit the operation
1044 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1045 Binary.EmitOperatorOpcode (ec, op, t);
1047 if (t == TypeManager.sbyte_type){
1049 ig.Emit (OpCodes.Conv_Ovf_I1);
1051 ig.Emit (OpCodes.Conv_I1);
1052 } else if (t == TypeManager.byte_type){
1054 ig.Emit (OpCodes.Conv_Ovf_U1);
1056 ig.Emit (OpCodes.Conv_U1);
1057 } else if (t == TypeManager.short_type){
1059 ig.Emit (OpCodes.Conv_Ovf_I2);
1061 ig.Emit (OpCodes.Conv_I2);
1062 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1064 ig.Emit (OpCodes.Conv_Ovf_U2);
1066 ig.Emit (OpCodes.Conv_U2);
1071 void EmitCode (EmitContext ec, bool is_expr)
1074 this.is_expr = is_expr;
1075 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1078 public override void Emit (EmitContext ec)
1081 // We use recurse to allow ourselfs to be the source
1082 // of an assignment. This little hack prevents us from
1083 // having to allocate another expression
1086 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1088 LoadOneAndEmitOp (ec, expr.Type);
1090 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1095 EmitCode (ec, true);
1098 public override void EmitStatement (EmitContext ec)
1100 EmitCode (ec, false);
1103 protected override void CloneTo (CloneContext clonectx, Expression t)
1105 UnaryMutator target = (UnaryMutator) t;
1107 target.expr = expr.Clone (clonectx);
1112 /// Base class for the `Is' and `As' classes.
1116 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1119 public abstract class Probe : Expression {
1120 public Expression ProbeType;
1121 protected Expression expr;
1122 protected TypeExpr probe_type_expr;
1124 public Probe (Expression expr, Expression probe_type, Location l)
1126 ProbeType = probe_type;
1131 public Expression Expr {
1137 public override Expression DoResolve (EmitContext ec)
1139 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1140 if (probe_type_expr == null)
1143 expr = expr.Resolve (ec);
1147 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1148 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1152 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1153 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1158 if (expr.Type == TypeManager.anonymous_method_type) {
1159 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1167 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1169 expr.MutateHoistedGenericType (storey);
1170 probe_type_expr.MutateHoistedGenericType (storey);
1173 protected abstract string OperatorName { get; }
1175 protected override void CloneTo (CloneContext clonectx, Expression t)
1177 Probe target = (Probe) t;
1179 target.expr = expr.Clone (clonectx);
1180 target.ProbeType = ProbeType.Clone (clonectx);
1186 /// Implementation of the `is' operator.
1188 public class Is : Probe {
1189 Nullable.Unwrap expr_unwrap;
1191 public Is (Expression expr, Expression probe_type, Location l)
1192 : base (expr, probe_type, l)
1196 public override Expression CreateExpressionTree (EmitContext ec)
1198 ArrayList args = new ArrayList (2);
1199 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1200 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1201 return CreateExpressionFactoryCall ("TypeIs", args);
1204 public override void Emit (EmitContext ec)
1206 ILGenerator ig = ec.ig;
1207 if (expr_unwrap != null) {
1208 expr_unwrap.EmitCheck (ec);
1213 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1214 ig.Emit (OpCodes.Ldnull);
1215 ig.Emit (OpCodes.Cgt_Un);
1218 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1220 ILGenerator ig = ec.ig;
1221 if (expr_unwrap != null) {
1222 expr_unwrap.EmitCheck (ec);
1225 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1227 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1230 Expression CreateConstantResult (bool result)
1233 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1234 TypeManager.CSharpName (probe_type_expr.Type));
1236 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1237 TypeManager.CSharpName (probe_type_expr.Type));
1239 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1242 public override Expression DoResolve (EmitContext ec)
1244 if (base.DoResolve (ec) == null)
1248 bool d_is_nullable = false;
1251 // If E is a method group or the null literal, or if the type of E is a reference
1252 // type or a nullable type and the value of E is null, the result is false
1254 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1255 return CreateConstantResult (false);
1257 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1258 d = TypeManager.GetTypeArguments (d) [0];
1259 d_is_nullable = true;
1262 type = TypeManager.bool_type;
1263 eclass = ExprClass.Value;
1264 Type t = probe_type_expr.Type;
1265 bool t_is_nullable = false;
1266 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1267 t = TypeManager.GetTypeArguments (t) [0];
1268 t_is_nullable = true;
1271 if (TypeManager.IsStruct (t)) {
1274 // D and T are the same value types but D can be null
1276 if (d_is_nullable && !t_is_nullable) {
1277 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1282 // The result is true if D and T are the same value types
1284 return CreateConstantResult (true);
1287 if (TypeManager.IsGenericParameter (d))
1288 return ResolveGenericParameter (t, d);
1291 // An unboxing conversion exists
1293 if (Convert.ExplicitReferenceConversionExists (d, t))
1296 if (TypeManager.IsGenericParameter (t))
1297 return ResolveGenericParameter (d, t);
1299 if (TypeManager.IsStruct (d)) {
1301 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1302 return CreateConstantResult (true);
1304 if (TypeManager.IsGenericParameter (d))
1305 return ResolveGenericParameter (t, d);
1307 if (TypeManager.ContainsGenericParameters (d))
1310 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1311 Convert.ExplicitReferenceConversionExists (d, t)) {
1317 return CreateConstantResult (false);
1320 Expression ResolveGenericParameter (Type d, Type t)
1322 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1323 if (constraints != null) {
1324 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1325 return CreateConstantResult (false);
1327 if (constraints.IsValueType && !TypeManager.IsStruct (d))
1328 return CreateConstantResult (TypeManager.IsEqual (d, t));
1331 if (!TypeManager.IsReferenceType (expr.Type))
1332 expr = new BoxedCast (expr, d);
1337 protected override string OperatorName {
1338 get { return "is"; }
1343 /// Implementation of the `as' operator.
1345 public class As : Probe {
1347 Expression resolved_type;
1349 public As (Expression expr, Expression probe_type, Location l)
1350 : base (expr, probe_type, l)
1354 public override Expression CreateExpressionTree (EmitContext ec)
1356 ArrayList args = new ArrayList (2);
1357 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1358 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1359 return CreateExpressionFactoryCall ("TypeAs", args);
1362 public override void Emit (EmitContext ec)
1364 ILGenerator ig = ec.ig;
1369 ig.Emit (OpCodes.Isinst, type);
1372 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1373 ig.Emit (OpCodes.Unbox_Any, type);
1377 public override Expression DoResolve (EmitContext ec)
1379 // Because expr is modified
1380 if (eclass != ExprClass.Invalid)
1383 if (resolved_type == null) {
1384 resolved_type = base.DoResolve (ec);
1386 if (resolved_type == null)
1390 type = probe_type_expr.Type;
1391 eclass = ExprClass.Value;
1392 Type etype = expr.Type;
1394 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1395 if (probe_type_expr is TypeParameterExpr) {
1396 Report.Error (413, loc,
1397 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1398 probe_type_expr.GetSignatureForError ());
1400 Report.Error (77, loc,
1401 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1402 TypeManager.CSharpName (type));
1407 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1408 return Nullable.LiftedNull.CreateFromExpression (this);
1411 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1418 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1419 if (TypeManager.IsGenericParameter (etype))
1420 expr = new BoxedCast (expr, etype);
1426 if (TypeManager.ContainsGenericParameters (etype) ||
1427 TypeManager.ContainsGenericParameters (type)) {
1428 expr = new BoxedCast (expr, etype);
1433 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1434 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1439 protected override string OperatorName {
1440 get { return "as"; }
1443 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1445 type = storey.MutateType (type);
1446 base.MutateHoistedGenericType (storey);
1449 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1451 return expr.GetAttributableValue (ec, value_type, out value);
1456 /// This represents a typecast in the source language.
1458 /// FIXME: Cast expressions have an unusual set of parsing
1459 /// rules, we need to figure those out.
1461 public class Cast : Expression {
1462 Expression target_type;
1465 public Cast (Expression cast_type, Expression expr)
1466 : this (cast_type, expr, cast_type.Location)
1470 public Cast (Expression cast_type, Expression expr, Location loc)
1472 this.target_type = cast_type;
1477 public Expression TargetType {
1478 get { return target_type; }
1481 public Expression Expr {
1482 get { return expr; }
1485 public override Expression CreateExpressionTree (EmitContext ec)
1487 throw new NotSupportedException ("ET");
1490 public override Expression DoResolve (EmitContext ec)
1492 expr = expr.Resolve (ec);
1496 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1502 if (type.IsAbstract && type.IsSealed) {
1503 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1507 eclass = ExprClass.Value;
1509 Constant c = expr as Constant;
1511 c = c.TryReduce (ec, type, loc);
1516 if (type.IsPointer && !ec.InUnsafe) {
1520 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1524 public override void Emit (EmitContext ec)
1526 throw new Exception ("Should not happen");
1529 protected override void CloneTo (CloneContext clonectx, Expression t)
1531 Cast target = (Cast) t;
1533 target.target_type = target_type.Clone (clonectx);
1534 target.expr = expr.Clone (clonectx);
1539 // C# 2.0 Default value expression
1541 public class DefaultValueExpression : Expression
1543 sealed class DefaultValueNullLiteral : NullLiteral
1545 public DefaultValueNullLiteral (DefaultValueExpression expr)
1546 : base (expr.type, expr.loc)
1550 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
1552 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1559 public DefaultValueExpression (Expression expr, Location loc)
1565 public override Expression CreateExpressionTree (EmitContext ec)
1567 ArrayList args = new ArrayList (2);
1568 args.Add (new Argument (this));
1569 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1570 return CreateExpressionFactoryCall ("Constant", args);
1573 public override Expression DoResolve (EmitContext ec)
1575 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1581 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1582 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1586 return new NullLiteral (Location).ConvertImplicitly (type);
1588 if (TypeManager.IsReferenceType (type))
1589 return new DefaultValueNullLiteral (this);
1591 Constant c = New.Constantify (type);
1595 eclass = ExprClass.Variable;
1599 public override void Emit (EmitContext ec)
1601 LocalTemporary temp_storage = new LocalTemporary(type);
1603 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1604 ec.ig.Emit(OpCodes.Initobj, type);
1605 temp_storage.Emit(ec);
1608 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1610 type = storey.MutateType (type);
1613 protected override void CloneTo (CloneContext clonectx, Expression t)
1615 DefaultValueExpression target = (DefaultValueExpression) t;
1617 target.expr = expr.Clone (clonectx);
1622 /// Binary operators
1624 public class Binary : Expression {
1626 protected class PredefinedOperator {
1627 protected readonly Type left;
1628 protected readonly Type right;
1629 public readonly Operator OperatorsMask;
1630 public Type ReturnType;
1632 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1633 : this (ltype, rtype, op_mask, ltype)
1637 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1638 : this (type, type, op_mask, return_type)
1642 public PredefinedOperator (Type type, Operator op_mask)
1643 : this (type, type, op_mask, type)
1647 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1649 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1650 throw new InternalErrorException ("Only masked values can be used");
1654 this.OperatorsMask = op_mask;
1655 this.ReturnType = return_type;
1658 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1660 b.type = ReturnType;
1662 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1663 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1666 // A user operators does not support multiple user conversions, but decimal type
1667 // is considered to be predefined type therefore we apply predefined operators rules
1668 // and then look for decimal user-operator implementation
1670 if (left == TypeManager.decimal_type)
1671 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1676 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1679 // We are dealing with primitive types only
1681 return left == ltype && ltype == rtype;
1684 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1686 if (TypeManager.IsEqual (left, lexpr.Type) &&
1687 TypeManager.IsEqual (right, rexpr.Type))
1690 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1691 Convert.ImplicitConversionExists (ec, rexpr, right);
1694 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1697 if (left != null && best_operator.left != null) {
1698 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1702 // When second arguments are same as the first one, the result is same
1704 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1705 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1708 if (result == 0 || result > 2)
1711 return result == 1 ? best_operator : this;
1715 class PredefinedStringOperator : PredefinedOperator {
1716 public PredefinedStringOperator (Type type, Operator op_mask)
1717 : base (type, op_mask, type)
1719 ReturnType = TypeManager.string_type;
1722 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1723 : base (ltype, rtype, op_mask)
1725 ReturnType = TypeManager.string_type;
1728 public override Expression ConvertResult (EmitContext ec, Binary b)
1731 // Use original expression for nullable arguments
1733 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1735 b.left = unwrap.Original;
1737 unwrap = b.right as Nullable.Unwrap;
1739 b.right = unwrap.Original;
1741 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1742 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1745 // Start a new concat expression using converted expression
1747 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1751 class PredefinedShiftOperator : PredefinedOperator {
1752 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1753 base (ltype, TypeManager.int32_type, op_mask)
1757 public override Expression ConvertResult (EmitContext ec, Binary b)
1759 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1761 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1763 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1766 // b = b.left >> b.right & (0x1f|0x3f)
1768 b.right = new Binary (Operator.BitwiseAnd,
1769 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1772 // Expression tree representation does not use & mask
1774 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1775 b.type = ReturnType;
1780 class PredefinedPointerOperator : PredefinedOperator {
1781 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1782 : base (ltype, rtype, op_mask)
1786 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1787 : base (ltype, rtype, op_mask, retType)
1791 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1792 : base (type, op_mask, return_type)
1796 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1799 if (!lexpr.Type.IsPointer)
1802 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1806 if (right == null) {
1807 if (!rexpr.Type.IsPointer)
1810 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1817 public override Expression ConvertResult (EmitContext ec, Binary b)
1820 b.left = EmptyCast.Create (b.left, left);
1821 } else if (right != null) {
1822 b.right = EmptyCast.Create (b.right, right);
1825 Type r_type = ReturnType;
1826 Expression left_arg, right_arg;
1827 if (r_type == null) {
1830 right_arg = b.right;
1831 r_type = b.left.Type;
1835 r_type = b.right.Type;
1839 right_arg = b.right;
1842 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1847 public enum Operator {
1848 Multiply = 0 | ArithmeticMask,
1849 Division = 1 | ArithmeticMask,
1850 Modulus = 2 | ArithmeticMask,
1851 Addition = 3 | ArithmeticMask | AdditionMask,
1852 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1854 LeftShift = 5 | ShiftMask,
1855 RightShift = 6 | ShiftMask,
1857 LessThan = 7 | ComparisonMask | RelationalMask,
1858 GreaterThan = 8 | ComparisonMask | RelationalMask,
1859 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1860 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1861 Equality = 11 | ComparisonMask | EqualityMask,
1862 Inequality = 12 | ComparisonMask | EqualityMask,
1864 BitwiseAnd = 13 | BitwiseMask,
1865 ExclusiveOr = 14 | BitwiseMask,
1866 BitwiseOr = 15 | BitwiseMask,
1868 LogicalAnd = 16 | LogicalMask,
1869 LogicalOr = 17 | LogicalMask,
1874 ValuesOnlyMask = ArithmeticMask - 1,
1875 ArithmeticMask = 1 << 5,
1877 ComparisonMask = 1 << 7,
1878 EqualityMask = 1 << 8,
1879 BitwiseMask = 1 << 9,
1880 LogicalMask = 1 << 10,
1881 AdditionMask = 1 << 11,
1882 SubtractionMask = 1 << 12,
1883 RelationalMask = 1 << 13
1886 readonly Operator oper;
1887 protected Expression left, right;
1888 readonly bool is_compound;
1889 Expression enum_conversion;
1891 static PredefinedOperator [] standard_operators;
1892 static PredefinedOperator [] pointer_operators;
1894 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1895 : this (oper, left, right)
1897 this.is_compound = isCompound;
1900 public Binary (Operator oper, Expression left, Expression right)
1905 this.loc = left.Location;
1908 public Operator Oper {
1915 /// Returns a stringified representation of the Operator
1917 string OperName (Operator oper)
1921 case Operator.Multiply:
1924 case Operator.Division:
1927 case Operator.Modulus:
1930 case Operator.Addition:
1933 case Operator.Subtraction:
1936 case Operator.LeftShift:
1939 case Operator.RightShift:
1942 case Operator.LessThan:
1945 case Operator.GreaterThan:
1948 case Operator.LessThanOrEqual:
1951 case Operator.GreaterThanOrEqual:
1954 case Operator.Equality:
1957 case Operator.Inequality:
1960 case Operator.BitwiseAnd:
1963 case Operator.BitwiseOr:
1966 case Operator.ExclusiveOr:
1969 case Operator.LogicalOr:
1972 case Operator.LogicalAnd:
1976 s = oper.ToString ();
1986 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1988 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1991 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1994 l = TypeManager.CSharpName (left.Type);
1995 r = TypeManager.CSharpName (right.Type);
1997 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2001 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2003 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2006 static string GetOperatorMetadataName (Operator op)
2008 CSharp.Operator.OpType op_type;
2010 case Operator.Addition:
2011 op_type = CSharp.Operator.OpType.Addition; break;
2012 case Operator.BitwiseAnd:
2013 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2014 case Operator.BitwiseOr:
2015 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2016 case Operator.Division:
2017 op_type = CSharp.Operator.OpType.Division; break;
2018 case Operator.Equality:
2019 op_type = CSharp.Operator.OpType.Equality; break;
2020 case Operator.ExclusiveOr:
2021 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2022 case Operator.GreaterThan:
2023 op_type = CSharp.Operator.OpType.GreaterThan; break;
2024 case Operator.GreaterThanOrEqual:
2025 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2026 case Operator.Inequality:
2027 op_type = CSharp.Operator.OpType.Inequality; break;
2028 case Operator.LeftShift:
2029 op_type = CSharp.Operator.OpType.LeftShift; break;
2030 case Operator.LessThan:
2031 op_type = CSharp.Operator.OpType.LessThan; break;
2032 case Operator.LessThanOrEqual:
2033 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2034 case Operator.Modulus:
2035 op_type = CSharp.Operator.OpType.Modulus; break;
2036 case Operator.Multiply:
2037 op_type = CSharp.Operator.OpType.Multiply; break;
2038 case Operator.RightShift:
2039 op_type = CSharp.Operator.OpType.RightShift; break;
2040 case Operator.Subtraction:
2041 op_type = CSharp.Operator.OpType.Subtraction; break;
2043 throw new InternalErrorException (op.ToString ());
2046 return CSharp.Operator.GetMetadataName (op_type);
2049 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2052 ILGenerator ig = ec.ig;
2055 case Operator.Multiply:
2057 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2058 opcode = OpCodes.Mul_Ovf;
2059 else if (!IsFloat (l))
2060 opcode = OpCodes.Mul_Ovf_Un;
2062 opcode = OpCodes.Mul;
2064 opcode = OpCodes.Mul;
2068 case Operator.Division:
2070 opcode = OpCodes.Div_Un;
2072 opcode = OpCodes.Div;
2075 case Operator.Modulus:
2077 opcode = OpCodes.Rem_Un;
2079 opcode = OpCodes.Rem;
2082 case Operator.Addition:
2084 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2085 opcode = OpCodes.Add_Ovf;
2086 else if (!IsFloat (l))
2087 opcode = OpCodes.Add_Ovf_Un;
2089 opcode = OpCodes.Add;
2091 opcode = OpCodes.Add;
2094 case Operator.Subtraction:
2096 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2097 opcode = OpCodes.Sub_Ovf;
2098 else if (!IsFloat (l))
2099 opcode = OpCodes.Sub_Ovf_Un;
2101 opcode = OpCodes.Sub;
2103 opcode = OpCodes.Sub;
2106 case Operator.RightShift:
2108 opcode = OpCodes.Shr_Un;
2110 opcode = OpCodes.Shr;
2113 case Operator.LeftShift:
2114 opcode = OpCodes.Shl;
2117 case Operator.Equality:
2118 opcode = OpCodes.Ceq;
2121 case Operator.Inequality:
2122 ig.Emit (OpCodes.Ceq);
2123 ig.Emit (OpCodes.Ldc_I4_0);
2125 opcode = OpCodes.Ceq;
2128 case Operator.LessThan:
2130 opcode = OpCodes.Clt_Un;
2132 opcode = OpCodes.Clt;
2135 case Operator.GreaterThan:
2137 opcode = OpCodes.Cgt_Un;
2139 opcode = OpCodes.Cgt;
2142 case Operator.LessThanOrEqual:
2143 if (IsUnsigned (l) || IsFloat (l))
2144 ig.Emit (OpCodes.Cgt_Un);
2146 ig.Emit (OpCodes.Cgt);
2147 ig.Emit (OpCodes.Ldc_I4_0);
2149 opcode = OpCodes.Ceq;
2152 case Operator.GreaterThanOrEqual:
2153 if (IsUnsigned (l) || IsFloat (l))
2154 ig.Emit (OpCodes.Clt_Un);
2156 ig.Emit (OpCodes.Clt);
2158 ig.Emit (OpCodes.Ldc_I4_0);
2160 opcode = OpCodes.Ceq;
2163 case Operator.BitwiseOr:
2164 opcode = OpCodes.Or;
2167 case Operator.BitwiseAnd:
2168 opcode = OpCodes.And;
2171 case Operator.ExclusiveOr:
2172 opcode = OpCodes.Xor;
2176 throw new InternalErrorException (oper.ToString ());
2182 static bool IsUnsigned (Type t)
2187 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2188 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2191 static bool IsFloat (Type t)
2193 return t == TypeManager.float_type || t == TypeManager.double_type;
2196 Expression ResolveOperator (EmitContext ec)
2199 Type r = right.Type;
2201 bool primitives_only = false;
2203 if (standard_operators == null)
2204 CreateStandardOperatorsTable ();
2207 // Handles predefined primitive types
2209 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2210 if ((oper & Operator.ShiftMask) == 0) {
2211 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2214 primitives_only = true;
2218 if (l.IsPointer || r.IsPointer)
2219 return ResolveOperatorPointer (ec, l, r);
2222 bool lenum = TypeManager.IsEnumType (l);
2223 bool renum = TypeManager.IsEnumType (r);
2224 if (lenum || renum) {
2225 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2227 // TODO: Can this be ambiguous
2233 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2234 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2236 expr = ResolveOperatorDelegate (ec, l, r);
2238 // TODO: Can this be ambiguous
2244 expr = ResolveUserOperator (ec, l, r);
2248 // Predefined reference types equality
2249 if ((oper & Operator.EqualityMask) != 0) {
2250 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2256 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2259 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2260 // if 'left' is not an enumeration constant, create one from the type of 'right'
2261 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2264 case Operator.BitwiseOr:
2265 case Operator.BitwiseAnd:
2266 case Operator.ExclusiveOr:
2267 case Operator.Equality:
2268 case Operator.Inequality:
2269 case Operator.LessThan:
2270 case Operator.LessThanOrEqual:
2271 case Operator.GreaterThan:
2272 case Operator.GreaterThanOrEqual:
2273 if (TypeManager.IsEnumType (left.Type))
2276 if (left.IsZeroInteger)
2277 return left.TryReduce (ec, right.Type, loc);
2281 case Operator.Addition:
2282 case Operator.Subtraction:
2285 case Operator.Multiply:
2286 case Operator.Division:
2287 case Operator.Modulus:
2288 case Operator.LeftShift:
2289 case Operator.RightShift:
2290 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2294 Error_OperatorCannotBeApplied (this.left, this.right);
2299 // The `|' operator used on types which were extended is dangerous
2301 void CheckBitwiseOrOnSignExtended ()
2303 OpcodeCast lcast = left as OpcodeCast;
2304 if (lcast != null) {
2305 if (IsUnsigned (lcast.UnderlyingType))
2309 OpcodeCast rcast = right as OpcodeCast;
2310 if (rcast != null) {
2311 if (IsUnsigned (rcast.UnderlyingType))
2315 if (lcast == null && rcast == null)
2318 // FIXME: consider constants
2320 Report.Warning (675, 3, loc,
2321 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2322 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2325 static void CreatePointerOperatorsTable ()
2327 ArrayList temp = new ArrayList ();
2330 // Pointer arithmetic:
2332 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2333 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2334 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2335 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2337 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2338 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2339 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2340 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2343 // T* operator + (int y, T* x);
2344 // T* operator + (uint y, T *x);
2345 // T* operator + (long y, T *x);
2346 // T* operator + (ulong y, T *x);
2348 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2349 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2350 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2351 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2354 // long operator - (T* x, T *y)
2356 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2358 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2361 static void CreateStandardOperatorsTable ()
2363 ArrayList temp = new ArrayList ();
2364 Type bool_type = TypeManager.bool_type;
2366 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2367 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2368 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2369 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2370 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2371 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2372 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2374 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2375 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2377 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2378 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2379 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2380 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2382 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2384 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2385 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2386 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2388 temp.Add (new PredefinedOperator (bool_type,
2389 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2391 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2392 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2393 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2394 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2396 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2400 // Rules used during binary numeric promotion
2402 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2407 Constant c = prim_expr as Constant;
2409 temp = c.ConvertImplicitly (type);
2416 if (type == TypeManager.uint32_type) {
2417 etype = prim_expr.Type;
2418 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2419 type = TypeManager.int64_type;
2421 if (type != second_expr.Type) {
2422 c = second_expr as Constant;
2424 temp = c.ConvertImplicitly (type);
2426 temp = Convert.ImplicitNumericConversion (second_expr, type);
2432 } else if (type == TypeManager.uint64_type) {
2434 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2436 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2437 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2441 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2450 // 7.2.6.2 Binary numeric promotions
2452 public bool DoBinaryOperatorPromotion (EmitContext ec)
2454 Type ltype = left.Type;
2455 Type rtype = right.Type;
2458 foreach (Type t in ConstantFold.binary_promotions) {
2460 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2463 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2466 Type int32 = TypeManager.int32_type;
2467 if (ltype != int32) {
2468 Constant c = left as Constant;
2470 temp = c.ConvertImplicitly (int32);
2472 temp = Convert.ImplicitNumericConversion (left, int32);
2479 if (rtype != int32) {
2480 Constant c = right as Constant;
2482 temp = c.ConvertImplicitly (int32);
2484 temp = Convert.ImplicitNumericConversion (right, int32);
2494 public override Expression DoResolve (EmitContext ec)
2499 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2500 left = ((ParenthesizedExpression) left).Expr;
2501 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2505 if (left.eclass == ExprClass.Type) {
2506 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2510 left = left.Resolve (ec);
2515 Constant lc = left as Constant;
2517 if (lc != null && lc.Type == TypeManager.bool_type &&
2518 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2519 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2521 // FIXME: resolve right expression as unreachable
2522 // right.Resolve (ec);
2524 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2528 right = right.Resolve (ec);
2532 eclass = ExprClass.Value;
2533 Constant rc = right as Constant;
2535 // The conversion rules are ignored in enum context but why
2536 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2537 lc = EnumLiftUp (ec, lc, rc, loc);
2539 rc = EnumLiftUp (ec, rc, lc, loc);
2542 if (rc != null && lc != null) {
2543 int prev_e = Report.Errors;
2544 Expression e = ConstantFold.BinaryFold (
2545 ec, oper, lc, rc, loc);
2546 if (e != null || Report.Errors != prev_e)
2549 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2550 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2552 if ((ResolveOperator (ec)) == null) {
2553 Error_OperatorCannotBeApplied (left, right);
2558 // The result is a constant with side-effect
2560 Constant side_effect = rc == null ?
2561 new SideEffectConstant (lc, right, loc) :
2562 new SideEffectConstant (rc, left, loc);
2564 return ReducedExpression.Create (side_effect, this);
2568 // Comparison warnings
2569 if ((oper & Operator.ComparisonMask) != 0) {
2570 if (left.Equals (right)) {
2571 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2573 CheckUselessComparison (lc, right.Type);
2574 CheckUselessComparison (rc, left.Type);
2577 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2578 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2579 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2580 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2581 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2582 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2584 return DoResolveCore (ec, left, right);
2587 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2589 Expression expr = ResolveOperator (ec);
2591 Error_OperatorCannotBeApplied (left_orig, right_orig);
2593 if (left == null || right == null)
2594 throw new InternalErrorException ("Invalid conversion");
2596 if (oper == Operator.BitwiseOr)
2597 CheckBitwiseOrOnSignExtended ();
2602 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2604 left.MutateHoistedGenericType (storey);
2605 right.MutateHoistedGenericType (storey);
2609 // D operator + (D x, D y)
2610 // D operator - (D x, D y)
2611 // bool operator == (D x, D y)
2612 // bool operator != (D x, D y)
2614 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2616 bool is_equality = (oper & Operator.EqualityMask) != 0;
2617 if (!TypeManager.IsEqual (l, r)) {
2619 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2620 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2625 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2626 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2637 // Resolve delegate equality as a user operator
2640 return ResolveUserOperator (ec, l, r);
2643 ArrayList args = new ArrayList (2);
2644 args.Add (new Argument (left, Argument.AType.Expression));
2645 args.Add (new Argument (right, Argument.AType.Expression));
2647 if (oper == Operator.Addition) {
2648 if (TypeManager.delegate_combine_delegate_delegate == null) {
2649 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2650 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2653 method = TypeManager.delegate_combine_delegate_delegate;
2655 if (TypeManager.delegate_remove_delegate_delegate == null) {
2656 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2657 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2660 method = TypeManager.delegate_remove_delegate_delegate;
2663 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2664 mg = mg.OverloadResolve (ec, ref args, false, loc);
2666 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2670 // Enumeration operators
2672 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2675 // bool operator == (E x, E y);
2676 // bool operator != (E x, E y);
2677 // bool operator < (E x, E y);
2678 // bool operator > (E x, E y);
2679 // bool operator <= (E x, E y);
2680 // bool operator >= (E x, E y);
2682 // E operator & (E x, E y);
2683 // E operator | (E x, E y);
2684 // E operator ^ (E x, E y);
2686 // U operator - (E e, E f)
2687 // E operator - (E e, U x)
2689 // E operator + (U x, E e)
2690 // E operator + (E e, U x)
2692 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2693 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2696 Expression ltemp = left;
2697 Expression rtemp = right;
2698 Type underlying_type;
2701 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2703 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2709 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2717 if (TypeManager.IsEqual (ltype, rtype)) {
2718 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2720 if (left is Constant)
2721 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2723 left = EmptyCast.Create (left, underlying_type);
2725 if (right is Constant)
2726 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2728 right = EmptyCast.Create (right, underlying_type);
2730 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2732 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2733 Constant c = right as Constant;
2734 if (c == null || !c.IsDefaultValue)
2737 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2740 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2743 if (left is Constant)
2744 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2746 left = EmptyCast.Create (left, underlying_type);
2749 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2751 if (oper != Operator.Addition) {
2752 Constant c = left as Constant;
2753 if (c == null || !c.IsDefaultValue)
2756 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2759 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2762 if (right is Constant)
2763 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2765 right = EmptyCast.Create (right, underlying_type);
2772 // C# specification uses explicit cast syntax which means binary promotion
2773 // should happen, however it seems that csc does not do that
2775 if (!DoBinaryOperatorPromotion (ec)) {
2781 Type res_type = null;
2782 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2783 Type promoted_type = lenum ? left.Type : right.Type;
2784 enum_conversion = Convert.ExplicitNumericConversion (
2785 new EmptyExpression (promoted_type), underlying_type);
2787 if (oper == Operator.Subtraction && renum && lenum)
2788 res_type = underlying_type;
2789 else if (oper == Operator.Addition && renum)
2795 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2796 if (!is_compound || expr == null)
2800 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2803 if (Convert.ImplicitConversionExists (ec, left, rtype))
2806 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2809 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2814 // 7.9.6 Reference type equality operators
2816 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2819 // operator != (object a, object b)
2820 // operator == (object a, object b)
2823 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2825 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2828 type = TypeManager.bool_type;
2829 GenericConstraints constraints;
2831 bool lgen = TypeManager.IsGenericParameter (l);
2833 if (TypeManager.IsEqual (l, r)) {
2836 // Only allow to compare same reference type parameter
2838 constraints = TypeManager.GetTypeParameterConstraints (l);
2839 if (constraints != null && constraints.IsReferenceType)
2845 if (l == TypeManager.anonymous_method_type)
2848 if (TypeManager.IsValueType (l))
2854 bool rgen = TypeManager.IsGenericParameter (r);
2857 // a, Both operands are reference-type values or the value null
2858 // b, One operand is a value of type T where T is a type-parameter and
2859 // the other operand is the value null. Furthermore T does not have the
2860 // value type constrain
2862 if (left is NullLiteral || right is NullLiteral) {
2864 constraints = TypeManager.GetTypeParameterConstraints (l);
2865 if (constraints != null && constraints.HasValueTypeConstraint)
2868 left = new BoxedCast (left, TypeManager.object_type);
2873 constraints = TypeManager.GetTypeParameterConstraints (r);
2874 if (constraints != null && constraints.HasValueTypeConstraint)
2877 right = new BoxedCast (right, TypeManager.object_type);
2883 // An interface is converted to the object before the
2884 // standard conversion is applied. It's not clear from the
2885 // standard but it looks like it works like that.
2888 constraints = TypeManager.GetTypeParameterConstraints (l);
2889 if (constraints == null || constraints.IsReferenceType)
2891 } else if (l.IsInterface) {
2892 l = TypeManager.object_type;
2893 } else if (TypeManager.IsStruct (l)) {
2898 constraints = TypeManager.GetTypeParameterConstraints (r);
2899 if (constraints == null || constraints.IsReferenceType)
2901 } else if (r.IsInterface) {
2902 r = TypeManager.object_type;
2903 } else if (TypeManager.IsStruct (r)) {
2908 const string ref_comparison = "Possible unintended reference comparison. " +
2909 "Consider casting the {0} side of the expression to `string' to compare the values";
2912 // A standard implicit conversion exists from the type of either
2913 // operand to the type of the other operand
2915 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2916 if (l == TypeManager.string_type)
2917 Report.Warning (253, 2, loc, ref_comparison, "right");
2922 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2923 if (r == TypeManager.string_type)
2924 Report.Warning (252, 2, loc, ref_comparison, "left");
2933 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2936 // bool operator == (void* x, void* y);
2937 // bool operator != (void* x, void* y);
2938 // bool operator < (void* x, void* y);
2939 // bool operator > (void* x, void* y);
2940 // bool operator <= (void* x, void* y);
2941 // bool operator >= (void* x, void* y);
2943 if ((oper & Operator.ComparisonMask) != 0) {
2946 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2953 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2959 type = TypeManager.bool_type;
2963 if (pointer_operators == null)
2964 CreatePointerOperatorsTable ();
2966 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2970 // Build-in operators method overloading
2972 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2974 PredefinedOperator best_operator = null;
2976 Type r = right.Type;
2977 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2979 foreach (PredefinedOperator po in operators) {
2980 if ((po.OperatorsMask & oper_mask) == 0)
2983 if (primitives_only) {
2984 if (!po.IsPrimitiveApplicable (l, r))
2987 if (!po.IsApplicable (ec, left, right))
2991 if (best_operator == null) {
2993 if (primitives_only)
2999 best_operator = po.ResolveBetterOperator (ec, best_operator);
3001 if (best_operator == null) {
3002 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3003 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3010 if (best_operator == null)
3013 Expression expr = best_operator.ConvertResult (ec, this);
3014 if (enum_type == null)
3018 // HACK: required by enum_conversion
3020 expr.Type = enum_type;
3021 return EmptyCast.Create (expr, enum_type);
3025 // Performs user-operator overloading
3027 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3030 if (oper == Operator.LogicalAnd)
3031 user_oper = Operator.BitwiseAnd;
3032 else if (oper == Operator.LogicalOr)
3033 user_oper = Operator.BitwiseOr;
3037 string op = GetOperatorMetadataName (user_oper);
3039 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3040 MethodGroupExpr right_operators = null;
3042 if (!TypeManager.IsEqual (r, l)) {
3043 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3044 if (right_operators == null && left_operators == null)
3046 } else if (left_operators == null) {
3050 ArrayList args = new ArrayList (2);
3051 Argument larg = new Argument (left);
3053 Argument rarg = new Argument (right);
3056 MethodGroupExpr union;
3059 // User-defined operator implementations always take precedence
3060 // over predefined operator implementations
3062 if (left_operators != null && right_operators != null) {
3063 if (IsPredefinedUserOperator (l, user_oper)) {
3064 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3066 union = left_operators;
3067 } else if (IsPredefinedUserOperator (r, user_oper)) {
3068 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3070 union = right_operators;
3072 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3074 } else if (left_operators != null) {
3075 union = left_operators;
3077 union = right_operators;
3080 union = union.OverloadResolve (ec, ref args, true, loc);
3084 Expression oper_expr;
3086 // TODO: CreateExpressionTree is allocated every time
3087 if (user_oper != oper) {
3088 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3089 oper == Operator.LogicalAnd, loc).Resolve (ec);
3091 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3094 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3095 // and not invoke user operator
3097 if ((oper & Operator.EqualityMask) != 0) {
3098 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3099 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3100 type = TypeManager.bool_type;
3101 if (left is NullLiteral || right is NullLiteral)
3102 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3103 } else if (l != r) {
3104 MethodInfo mi = (MethodInfo) union;
3107 // Two System.Delegate(s) are never equal
3109 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3120 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3125 private void CheckUselessComparison (Constant c, Type type)
3127 if (c == null || !IsTypeIntegral (type)
3128 || c is StringConstant
3129 || c is BoolConstant
3130 || c is FloatConstant
3131 || c is DoubleConstant
3132 || c is DecimalConstant
3138 if (c is ULongConstant) {
3139 ulong uvalue = ((ULongConstant) c).Value;
3140 if (uvalue > long.MaxValue) {
3141 if (type == TypeManager.byte_type ||
3142 type == TypeManager.sbyte_type ||
3143 type == TypeManager.short_type ||
3144 type == TypeManager.ushort_type ||
3145 type == TypeManager.int32_type ||
3146 type == TypeManager.uint32_type ||
3147 type == TypeManager.int64_type ||
3148 type == TypeManager.char_type)
3149 WarnUselessComparison (type);
3152 value = (long) uvalue;
3154 else if (c is ByteConstant)
3155 value = ((ByteConstant) c).Value;
3156 else if (c is SByteConstant)
3157 value = ((SByteConstant) c).Value;
3158 else if (c is ShortConstant)
3159 value = ((ShortConstant) c).Value;
3160 else if (c is UShortConstant)
3161 value = ((UShortConstant) c).Value;
3162 else if (c is IntConstant)
3163 value = ((IntConstant) c).Value;
3164 else if (c is UIntConstant)
3165 value = ((UIntConstant) c).Value;
3166 else if (c is LongConstant)
3167 value = ((LongConstant) c).Value;
3168 else if (c is CharConstant)
3169 value = ((CharConstant)c).Value;
3174 if (IsValueOutOfRange (value, type))
3175 WarnUselessComparison (type);
3178 static bool IsValueOutOfRange (long value, Type type)
3180 if (IsTypeUnsigned (type) && value < 0)
3182 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3183 type == TypeManager.byte_type && value >= 0x100 ||
3184 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3185 type == TypeManager.ushort_type && value >= 0x10000 ||
3186 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3187 type == TypeManager.uint32_type && value >= 0x100000000;
3190 static bool IsBuildInEqualityOperator (Type t)
3192 return t == TypeManager.object_type || t == TypeManager.string_type ||
3193 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3196 static bool IsPredefinedUserOperator (Type t, Operator op)
3199 // Some predefined types have user operators
3201 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3204 private static bool IsTypeIntegral (Type type)
3206 return type == TypeManager.uint64_type ||
3207 type == TypeManager.int64_type ||
3208 type == TypeManager.uint32_type ||
3209 type == TypeManager.int32_type ||
3210 type == TypeManager.ushort_type ||
3211 type == TypeManager.short_type ||
3212 type == TypeManager.sbyte_type ||
3213 type == TypeManager.byte_type ||
3214 type == TypeManager.char_type;
3217 private static bool IsTypeUnsigned (Type type)
3219 return type == TypeManager.uint64_type ||
3220 type == TypeManager.uint32_type ||
3221 type == TypeManager.ushort_type ||
3222 type == TypeManager.byte_type ||
3223 type == TypeManager.char_type;
3226 private void WarnUselessComparison (Type type)
3228 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}'",
3229 TypeManager.CSharpName (type));
3233 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3234 /// context of a conditional bool expression. This function will return
3235 /// false if it is was possible to use EmitBranchable, or true if it was.
3237 /// The expression's code is generated, and we will generate a branch to `target'
3238 /// if the resulting expression value is equal to isTrue
3240 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3242 ILGenerator ig = ec.ig;
3245 // This is more complicated than it looks, but its just to avoid
3246 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3247 // but on top of that we want for == and != to use a special path
3248 // if we are comparing against null
3250 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3251 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3254 // put the constant on the rhs, for simplicity
3256 if (left is Constant) {
3257 Expression swap = right;
3262 if (((Constant) right).IsZeroInteger) {
3263 left.EmitBranchable (ec, target, my_on_true);
3266 if (right.Type == TypeManager.bool_type) {
3267 // right is a boolean, and it's not 'false' => it is 'true'
3268 left.EmitBranchable (ec, target, !my_on_true);
3272 } else if (oper == Operator.LogicalAnd) {
3275 Label tests_end = ig.DefineLabel ();
3277 left.EmitBranchable (ec, tests_end, false);
3278 right.EmitBranchable (ec, target, true);
3279 ig.MarkLabel (tests_end);
3282 // This optimizes code like this
3283 // if (true && i > 4)
3285 if (!(left is Constant))
3286 left.EmitBranchable (ec, target, false);
3288 if (!(right is Constant))
3289 right.EmitBranchable (ec, target, false);
3294 } else if (oper == Operator.LogicalOr){
3296 left.EmitBranchable (ec, target, true);
3297 right.EmitBranchable (ec, target, true);
3300 Label tests_end = ig.DefineLabel ();
3301 left.EmitBranchable (ec, tests_end, true);
3302 right.EmitBranchable (ec, target, false);
3303 ig.MarkLabel (tests_end);
3308 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3309 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3310 oper == Operator.Equality || oper == Operator.Inequality)) {
3311 base.EmitBranchable (ec, target, on_true);
3319 bool is_float = IsFloat (t);
3320 bool is_unsigned = is_float || IsUnsigned (t);
3323 case Operator.Equality:
3325 ig.Emit (OpCodes.Beq, target);
3327 ig.Emit (OpCodes.Bne_Un, target);
3330 case Operator.Inequality:
3332 ig.Emit (OpCodes.Bne_Un, target);
3334 ig.Emit (OpCodes.Beq, target);
3337 case Operator.LessThan:
3339 if (is_unsigned && !is_float)
3340 ig.Emit (OpCodes.Blt_Un, target);
3342 ig.Emit (OpCodes.Blt, target);
3345 ig.Emit (OpCodes.Bge_Un, target);
3347 ig.Emit (OpCodes.Bge, target);
3350 case Operator.GreaterThan:
3352 if (is_unsigned && !is_float)
3353 ig.Emit (OpCodes.Bgt_Un, target);
3355 ig.Emit (OpCodes.Bgt, target);
3358 ig.Emit (OpCodes.Ble_Un, target);
3360 ig.Emit (OpCodes.Ble, target);
3363 case Operator.LessThanOrEqual:
3365 if (is_unsigned && !is_float)
3366 ig.Emit (OpCodes.Ble_Un, target);
3368 ig.Emit (OpCodes.Ble, target);
3371 ig.Emit (OpCodes.Bgt_Un, target);
3373 ig.Emit (OpCodes.Bgt, target);
3377 case Operator.GreaterThanOrEqual:
3379 if (is_unsigned && !is_float)
3380 ig.Emit (OpCodes.Bge_Un, target);
3382 ig.Emit (OpCodes.Bge, target);
3385 ig.Emit (OpCodes.Blt_Un, target);
3387 ig.Emit (OpCodes.Blt, target);
3390 throw new InternalErrorException (oper.ToString ());
3394 public override void Emit (EmitContext ec)
3396 EmitOperator (ec, left.Type);
3399 protected virtual void EmitOperator (EmitContext ec, Type l)
3401 ILGenerator ig = ec.ig;
3404 // Handle short-circuit operators differently
3407 if ((oper & Operator.LogicalMask) != 0) {
3408 Label load_result = ig.DefineLabel ();
3409 Label end = ig.DefineLabel ();
3411 bool is_or = oper == Operator.LogicalOr;
3412 left.EmitBranchable (ec, load_result, is_or);
3414 ig.Emit (OpCodes.Br_S, end);
3416 ig.MarkLabel (load_result);
3417 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3425 // Optimize zero-based operations
3427 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3429 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3430 Constant rc = right as Constant;
3431 if (rc != null && rc.IsDefaultValue) {
3437 EmitOperatorOpcode (ec, oper, l);
3440 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3441 // expression because that would wrap lifted binary operation
3443 if (enum_conversion != null)
3444 enum_conversion.Emit (ec);
3447 public override void EmitSideEffect (EmitContext ec)
3449 if ((oper & Operator.LogicalMask) != 0 ||
3450 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3451 base.EmitSideEffect (ec);
3453 left.EmitSideEffect (ec);
3454 right.EmitSideEffect (ec);
3458 protected override void CloneTo (CloneContext clonectx, Expression t)
3460 Binary target = (Binary) t;
3462 target.left = left.Clone (clonectx);
3463 target.right = right.Clone (clonectx);
3466 public override Expression CreateExpressionTree (EmitContext ec)
3468 return CreateExpressionTree (ec, null);
3471 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3474 bool lift_arg = false;
3477 case Operator.Addition:
3478 if (method == null && ec.CheckState && !IsFloat (type))
3479 method_name = "AddChecked";
3481 method_name = "Add";
3483 case Operator.BitwiseAnd:
3484 method_name = "And";
3486 case Operator.BitwiseOr:
3489 case Operator.Division:
3490 method_name = "Divide";
3492 case Operator.Equality:
3493 method_name = "Equal";
3496 case Operator.ExclusiveOr:
3497 method_name = "ExclusiveOr";
3499 case Operator.GreaterThan:
3500 method_name = "GreaterThan";
3503 case Operator.GreaterThanOrEqual:
3504 method_name = "GreaterThanOrEqual";
3507 case Operator.Inequality:
3508 method_name = "NotEqual";
3511 case Operator.LeftShift:
3512 method_name = "LeftShift";
3514 case Operator.LessThan:
3515 method_name = "LessThan";
3518 case Operator.LessThanOrEqual:
3519 method_name = "LessThanOrEqual";
3522 case Operator.LogicalAnd:
3523 method_name = "AndAlso";
3525 case Operator.LogicalOr:
3526 method_name = "OrElse";
3528 case Operator.Modulus:
3529 method_name = "Modulo";
3531 case Operator.Multiply:
3532 if (method == null && ec.CheckState && !IsFloat (type))
3533 method_name = "MultiplyChecked";
3535 method_name = "Multiply";
3537 case Operator.RightShift:
3538 method_name = "RightShift";
3540 case Operator.Subtraction:
3541 if (method == null && ec.CheckState && !IsFloat (type))
3542 method_name = "SubtractChecked";
3544 method_name = "Subtract";
3548 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3551 ArrayList args = new ArrayList (2);
3552 args.Add (new Argument (left.CreateExpressionTree (ec)));
3553 args.Add (new Argument (right.CreateExpressionTree (ec)));
3554 if (method != null) {
3556 args.Add (new Argument (new BoolConstant (false, loc)));
3558 args.Add (new Argument (method.CreateExpressionTree (ec)));
3561 return CreateExpressionFactoryCall (method_name, args);
3566 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3567 // b, c, d... may be strings or objects.
3569 public class StringConcat : Expression {
3570 ArrayList arguments;
3572 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3575 type = TypeManager.string_type;
3576 eclass = ExprClass.Value;
3578 arguments = new ArrayList (2);
3583 public override Expression CreateExpressionTree (EmitContext ec)
3585 Argument arg = (Argument) arguments [0];
3586 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3590 // Creates nested calls tree from an array of arguments used for IL emit
3592 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3594 ArrayList concat_args = new ArrayList (2);
3595 ArrayList add_args = new ArrayList (3);
3597 concat_args.Add (left);
3598 add_args.Add (new Argument (left_etree));
3600 concat_args.Add (arguments [pos]);
3601 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3603 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3607 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3611 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3613 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3614 if (++pos == arguments.Count)
3617 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3618 return CreateExpressionAddCall (ec, left, expr, pos);
3621 public override Expression DoResolve (EmitContext ec)
3626 public void Append (EmitContext ec, Expression operand)
3631 StringConstant sc = operand as StringConstant;
3633 if (arguments.Count != 0) {
3634 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3635 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3636 if (last_expr_constant != null) {
3637 last_argument.Expr = new StringConstant (
3638 last_expr_constant.Value + sc.Value, sc.Location);
3644 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3646 StringConcat concat_oper = operand as StringConcat;
3647 if (concat_oper != null) {
3648 arguments.AddRange (concat_oper.arguments);
3653 arguments.Add (new Argument (operand));
3656 Expression CreateConcatMemberExpression ()
3658 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3661 public override void Emit (EmitContext ec)
3663 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3664 concat = concat.Resolve (ec);
3669 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3671 foreach (Argument a in arguments)
3672 a.Expr.MutateHoistedGenericType (storey);
3677 // User-defined conditional logical operator
3679 public class ConditionalLogicalOperator : UserOperatorCall {
3680 readonly bool is_and;
3683 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3684 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3685 : base (oper_method, arguments, expr_tree, loc)
3687 this.is_and = is_and;
3690 public override Expression DoResolve (EmitContext ec)
3692 MethodInfo method = (MethodInfo)mg;
3693 type = TypeManager.TypeToCoreType (method.ReturnType);
3694 AParametersCollection pd = TypeManager.GetParameterData (method);
3695 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3696 Report.Error (217, loc,
3697 "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",
3698 TypeManager.CSharpSignature (method));
3702 Expression left_dup = new EmptyExpression (type);
3703 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3704 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3705 if (op_true == null || op_false == null) {
3706 Report.Error (218, loc,
3707 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3708 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3712 oper = is_and ? op_false : op_true;
3713 eclass = ExprClass.Value;
3717 public override void Emit (EmitContext ec)
3719 ILGenerator ig = ec.ig;
3720 Label end_target = ig.DefineLabel ();
3723 // Emit and duplicate left argument
3725 ((Argument)arguments [0]).Expr.Emit (ec);
3726 ig.Emit (OpCodes.Dup);
3727 arguments.RemoveAt (0);
3729 oper.EmitBranchable (ec, end_target, true);
3731 ig.MarkLabel (end_target);
3735 public class PointerArithmetic : Expression {
3736 Expression left, right;
3740 // We assume that `l' is always a pointer
3742 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3751 public override Expression CreateExpressionTree (EmitContext ec)
3753 Error_PointerInsideExpressionTree ();
3757 public override Expression DoResolve (EmitContext ec)
3759 eclass = ExprClass.Variable;
3761 if (left.Type == TypeManager.void_ptr_type) {
3762 Error (242, "The operation in question is undefined on void pointers");
3769 public override void Emit (EmitContext ec)
3771 Type op_type = left.Type;
3772 ILGenerator ig = ec.ig;
3774 // It must be either array or fixed buffer
3776 if (TypeManager.HasElementType (op_type)) {
3777 element = TypeManager.GetElementType (op_type);
3779 FieldExpr fe = left as FieldExpr;
3781 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3786 int size = GetTypeSize (element);
3787 Type rtype = right.Type;
3789 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3791 // handle (pointer - pointer)
3795 ig.Emit (OpCodes.Sub);
3799 ig.Emit (OpCodes.Sizeof, element);
3801 IntLiteral.EmitInt (ig, size);
3802 ig.Emit (OpCodes.Div);
3804 ig.Emit (OpCodes.Conv_I8);
3807 // handle + and - on (pointer op int)
3809 Constant left_const = left as Constant;
3810 if (left_const != null) {
3812 // Optimize ((T*)null) pointer operations
3814 if (left_const.IsDefaultValue) {
3815 left = EmptyExpression.Null;
3823 Constant right_const = right as Constant;
3824 if (right_const != null) {
3826 // Optimize 0-based arithmetic
3828 if (right_const.IsDefaultValue)
3832 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3836 ig.Emit (OpCodes.Sizeof, element);
3837 right = EmptyExpression.Null;
3842 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3843 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3844 ig.Emit (OpCodes.Conv_I);
3845 } else if (rtype == TypeManager.uint32_type) {
3846 ig.Emit (OpCodes.Conv_U);
3849 if (right_const == null && size != 1){
3851 ig.Emit (OpCodes.Sizeof, element);
3853 IntLiteral.EmitInt (ig, size);
3854 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3855 ig.Emit (OpCodes.Conv_I8);
3857 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3860 if (left_const == null) {
3861 if (rtype == TypeManager.int64_type)
3862 ig.Emit (OpCodes.Conv_I);
3863 else if (rtype == TypeManager.uint64_type)
3864 ig.Emit (OpCodes.Conv_U);
3866 Binary.EmitOperatorOpcode (ec, op, op_type);
3873 /// Implements the ternary conditional operator (?:)
3875 public class Conditional : Expression {
3876 Expression expr, true_expr, false_expr;
3878 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3881 this.true_expr = true_expr;
3882 this.false_expr = false_expr;
3883 this.loc = expr.Location;
3886 public Expression Expr {
3892 public Expression TrueExpr {
3898 public Expression FalseExpr {
3904 public override Expression CreateExpressionTree (EmitContext ec)
3906 ArrayList args = new ArrayList (3);
3907 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3908 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3909 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3910 return CreateExpressionFactoryCall ("Condition", args);
3913 public override Expression DoResolve (EmitContext ec)
3915 expr = expr.Resolve (ec);
3920 if (expr.Type != TypeManager.bool_type){
3921 expr = Expression.ResolveBoolean (
3928 Assign ass = expr as Assign;
3929 if (ass != null && ass.Source is Constant) {
3930 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3933 true_expr = true_expr.Resolve (ec);
3934 false_expr = false_expr.Resolve (ec);
3936 if (true_expr == null || false_expr == null)
3939 eclass = ExprClass.Value;
3940 Type true_type = true_expr.Type;
3941 Type false_type = false_expr.Type;
3945 // First, if an implicit conversion exists from true_expr
3946 // to false_expr, then the result type is of type false_expr.Type
3948 if (!TypeManager.IsEqual (true_type, false_type)) {
3949 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3952 // Check if both can convert implicitl to each other's type
3954 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3956 "Can not compute type of conditional expression " +
3957 "as `" + TypeManager.CSharpName (true_expr.Type) +
3958 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3959 "' convert implicitly to each other");
3964 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3967 Report.Error (173, loc,
3968 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3969 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3974 // Dead code optimalization
3975 Constant c = expr as Constant;
3977 bool is_false = c.IsDefaultValue;
3978 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3979 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3985 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3987 expr.MutateHoistedGenericType (storey);
3988 true_expr.MutateHoistedGenericType (storey);
3989 false_expr.MutateHoistedGenericType (storey);
3990 type = storey.MutateType (type);
3993 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3998 public override void Emit (EmitContext ec)
4000 ILGenerator ig = ec.ig;
4001 Label false_target = ig.DefineLabel ();
4002 Label end_target = ig.DefineLabel ();
4004 expr.EmitBranchable (ec, false_target, false);
4005 true_expr.Emit (ec);
4007 if (type.IsInterface) {
4008 LocalBuilder temp = ec.GetTemporaryLocal (type);
4009 ig.Emit (OpCodes.Stloc, temp);
4010 ig.Emit (OpCodes.Ldloc, temp);
4011 ec.FreeTemporaryLocal (temp, type);
4014 ig.Emit (OpCodes.Br, end_target);
4015 ig.MarkLabel (false_target);
4016 false_expr.Emit (ec);
4017 ig.MarkLabel (end_target);
4020 protected override void CloneTo (CloneContext clonectx, Expression t)
4022 Conditional target = (Conditional) t;
4024 target.expr = expr.Clone (clonectx);
4025 target.true_expr = true_expr.Clone (clonectx);
4026 target.false_expr = false_expr.Clone (clonectx);
4030 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4031 LocalTemporary temp;
4034 public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
4035 public abstract bool IsFixed { get; }
4036 public abstract bool IsRef { get; }
4037 public abstract string Name { get; }
4038 public abstract void SetHasAddressTaken ();
4041 // Variable IL data, it has to be protected to encapsulate hoisted variables
4043 protected abstract ILocalVariable Variable { get; }
4046 // Variable flow-analysis data
4048 public abstract VariableInfo VariableInfo { get; }
4051 public void AddressOf (EmitContext ec, AddressOp mode)
4053 HoistedVariable hv = GetHoistedVariable (ec);
4055 hv.AddressOf (ec, mode);
4059 Variable.EmitAddressOf (ec);
4062 public override void Emit (EmitContext ec)
4067 public override void EmitSideEffect (EmitContext ec)
4073 // This method is used by parameters that are references, that are
4074 // being passed as references: we only want to pass the pointer (that
4075 // is already stored in the parameter, not the address of the pointer,
4076 // and not the value of the variable).
4078 public void EmitLoad (EmitContext ec)
4083 public void Emit (EmitContext ec, bool leave_copy)
4085 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4087 HoistedVariable hv = GetHoistedVariable (ec);
4089 hv.Emit (ec, leave_copy);
4097 // If we are a reference, we loaded on the stack a pointer
4098 // Now lets load the real value
4100 LoadFromPtr (ec.ig, type);
4104 ec.ig.Emit (OpCodes.Dup);
4107 temp = new LocalTemporary (Type);
4113 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4114 bool prepare_for_load)
4116 HoistedVariable hv = GetHoistedVariable (ec);
4118 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4122 New n_source = source as New;
4123 if (n_source != null) {
4124 if (!n_source.Emit (ec, this)) {
4137 ec.ig.Emit (OpCodes.Dup);
4139 temp = new LocalTemporary (Type);
4145 StoreFromPtr (ec.ig, type);
4147 Variable.EmitAssign (ec);
4155 public bool IsHoisted {
4156 get { return GetHoistedVariable (null) != null; }
4159 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4161 type = storey.MutateType (type);
4168 public class LocalVariableReference : VariableReference {
4169 readonly string name;
4171 public LocalInfo local_info;
4174 public LocalVariableReference (Block block, string name, Location l)
4179 eclass = ExprClass.Variable;
4183 // Setting `is_readonly' to false will allow you to create a writable
4184 // reference to a read-only variable. This is used by foreach and using.
4186 public LocalVariableReference (Block block, string name, Location l,
4187 LocalInfo local_info, bool is_readonly)
4188 : this (block, name, l)
4190 this.local_info = local_info;
4191 this.is_readonly = is_readonly;
4194 public override VariableInfo VariableInfo {
4195 get { return local_info.VariableInfo; }
4198 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4200 return local_info.HoistedVariableReference;
4204 // A local variable is always fixed
4206 public override bool IsFixed {
4207 get { return true; }
4210 public override bool IsRef {
4211 get { return false; }
4214 public bool IsReadOnly {
4215 get { return is_readonly; }
4218 public override string Name {
4219 get { return name; }
4222 public bool VerifyAssigned (EmitContext ec)
4224 VariableInfo variable_info = local_info.VariableInfo;
4225 return variable_info == null || variable_info.IsAssigned (ec, loc);
4228 void ResolveLocalInfo ()
4230 if (local_info == null) {
4231 local_info = Block.GetLocalInfo (Name);
4232 type = local_info.VariableType;
4233 is_readonly = local_info.ReadOnly;
4237 public override void SetHasAddressTaken ()
4239 local_info.AddressTaken = true;
4242 public override Expression CreateExpressionTree (EmitContext ec)
4244 HoistedVariable hv = GetHoistedVariable (ec);
4246 return hv.CreateExpressionTree (ec);
4248 ArrayList arg = new ArrayList (1);
4249 arg.Add (new Argument (this));
4250 return CreateExpressionFactoryCall ("Constant", arg);
4253 Expression DoResolveBase (EmitContext ec)
4255 type = local_info.VariableType;
4257 Expression e = Block.GetConstantExpression (Name);
4259 return e.Resolve (ec);
4261 VerifyAssigned (ec);
4264 // If we are referencing a variable from the external block
4265 // flag it for capturing
4267 if (ec.MustCaptureVariable (local_info)) {
4268 if (local_info.AddressTaken)
4269 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4271 if (ec.IsVariableCapturingRequired) {
4272 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4273 storey.CaptureLocalVariable (ec, local_info);
4280 public override Expression DoResolve (EmitContext ec)
4282 ResolveLocalInfo ();
4283 local_info.Used = true;
4285 if (type == null && local_info.Type is VarExpr) {
4286 local_info.VariableType = TypeManager.object_type;
4287 Error_VariableIsUsedBeforeItIsDeclared (Name);
4291 return DoResolveBase (ec);
4294 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4296 ResolveLocalInfo ();
4299 if (right_side == EmptyExpression.OutAccess)
4300 local_info.Used = true;
4302 // Infer implicitly typed local variable
4304 VarExpr ve = local_info.Type as VarExpr;
4306 if (!ve.InferType (ec, right_side))
4308 type = local_info.VariableType = ve.Type;
4315 if (right_side == EmptyExpression.OutAccess) {
4316 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4317 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4318 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4319 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4320 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4321 } else if (right_side == EmptyExpression.UnaryAddress) {
4322 code = 459; msg = "Cannot take the address of {1} `{0}'";
4324 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4326 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4327 } else if (VariableInfo != null) {
4328 VariableInfo.SetAssigned (ec);
4331 return DoResolveBase (ec);
4334 public override int GetHashCode ()
4336 return Name.GetHashCode ();
4339 public override bool Equals (object obj)
4341 LocalVariableReference lvr = obj as LocalVariableReference;
4345 return Name == lvr.Name && Block == lvr.Block;
4348 protected override ILocalVariable Variable {
4349 get { return local_info; }
4352 public override string ToString ()
4354 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4357 protected override void CloneTo (CloneContext clonectx, Expression t)
4359 LocalVariableReference target = (LocalVariableReference) t;
4361 target.Block = clonectx.LookupBlock (Block);
4362 if (local_info != null)
4363 target.local_info = clonectx.LookupVariable (local_info);
4368 /// This represents a reference to a parameter in the intermediate
4371 public class ParameterReference : VariableReference {
4372 readonly ToplevelParameterInfo pi;
4374 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4380 public override bool IsRef {
4381 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4384 bool HasOutModifier {
4385 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4388 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4390 return pi.Parameter.HoistedVariableReference;
4394 // A ref or out parameter is classified as a moveable variable, even
4395 // if the argument given for the parameter is a fixed variable
4397 public override bool IsFixed {
4398 get { return !IsRef; }
4401 public override string Name {
4402 get { return Parameter.Name; }
4405 public Parameter Parameter {
4406 get { return pi.Parameter; }
4409 public override VariableInfo VariableInfo {
4410 get { return pi.VariableInfo; }
4413 protected override ILocalVariable Variable {
4414 get { return Parameter; }
4417 public bool IsAssigned (EmitContext ec, Location loc)
4419 // HACK: Variables are not captured in probing mode
4420 if (ec.IsInProbingMode)
4423 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4426 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4430 public override void SetHasAddressTaken ()
4432 Parameter.HasAddressTaken = true;
4435 void SetAssigned (EmitContext ec)
4437 if (HasOutModifier && ec.DoFlowAnalysis)
4438 ec.CurrentBranching.SetAssigned (VariableInfo);
4441 bool DoResolveBase (EmitContext ec)
4443 type = pi.ParameterType;
4444 eclass = ExprClass.Variable;
4446 AnonymousExpression am = ec.CurrentAnonymousMethod;
4450 Block b = ec.CurrentBlock;
4452 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4453 for (int i = 0; i < p.Length; ++i) {
4454 if (p [i] != Parameter)
4458 // Skip closest anonymous method parameters
4460 if (b == ec.CurrentBlock && !am.IsIterator)
4464 Report.Error (1628, loc,
4465 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4466 Name, am.ContainerType);
4474 b = b.Toplevel.Parent;
4477 if (pi.Parameter.HasAddressTaken)
4478 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4480 if (ec.IsVariableCapturingRequired) {
4481 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4482 storey.CaptureParameter (ec, this);
4488 public override int GetHashCode ()
4490 return Name.GetHashCode ();
4493 public override bool Equals (object obj)
4495 ParameterReference pr = obj as ParameterReference;
4499 return Name == pr.Name;
4502 protected override void CloneTo (CloneContext clonectx, Expression target)
4507 public override Expression CreateExpressionTree (EmitContext ec)
4509 HoistedVariable hv = GetHoistedVariable (ec);
4511 return hv.CreateExpressionTree (ec);
4513 return Parameter.ExpressionTreeVariableReference ();
4517 // Notice that for ref/out parameters, the type exposed is not the
4518 // same type exposed externally.
4521 // externally we expose "int&"
4522 // here we expose "int".
4524 // We record this in "is_ref". This means that the type system can treat
4525 // the type as it is expected, but when we generate the code, we generate
4526 // the alternate kind of code.
4528 public override Expression DoResolve (EmitContext ec)
4530 if (!DoResolveBase (ec))
4533 // HACK: Variables are not captured in probing mode
4534 if (ec.IsInProbingMode)
4537 if (HasOutModifier && ec.DoFlowAnalysis &&
4538 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4544 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4546 if (!DoResolveBase (ec))
4549 // HACK: parameters are not captured when probing is on
4550 if (!ec.IsInProbingMode)
4556 static public void EmitLdArg (ILGenerator ig, int x)
4559 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4560 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4561 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4562 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4564 if (x > byte.MaxValue)
4565 ig.Emit (OpCodes.Ldarg, x);
4567 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4574 /// Used for arguments to New(), Invocation()
4576 public class Argument {
4577 public enum AType : byte {
4584 public static readonly Argument[] Empty = new Argument [0];
4586 public readonly AType ArgType;
4587 public Expression Expr;
4589 public Argument (Expression expr, AType type)
4592 this.ArgType = type;
4595 public Argument (Expression expr)
4598 this.ArgType = AType.Expression;
4602 get { return Expr.Type; }
4605 public Parameter.Modifier Modifier
4610 return Parameter.Modifier.OUT;
4613 return Parameter.Modifier.REF;
4616 return Parameter.Modifier.NONE;
4621 public string GetSignatureForError ()
4623 if (Expr.eclass == ExprClass.MethodGroup)
4624 return Expr.ExprClassName;
4626 return TypeManager.CSharpName (Expr.Type);
4629 public bool ResolveMethodGroup (EmitContext ec)
4631 SimpleName sn = Expr as SimpleName;
4633 Expr = sn.GetMethodGroup ();
4635 // FIXME: csc doesn't report any error if you try to use `ref' or
4636 // `out' in a delegate creation expression.
4637 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4644 public bool Resolve (EmitContext ec, Location loc)
4649 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4650 // Verify that the argument is readable
4651 if (ArgType != AType.Out)
4652 Expr = Expr.Resolve (ec);
4654 // Verify that the argument is writeable
4655 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4656 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4658 return Expr != null;
4662 public void Emit (EmitContext ec)
4664 if (ArgType != AType.Ref && ArgType != AType.Out) {
4669 AddressOp mode = AddressOp.Store;
4670 if (ArgType == AType.Ref)
4671 mode |= AddressOp.Load;
4673 IMemoryLocation ml = (IMemoryLocation) Expr;
4674 ParameterReference pr = ml as ParameterReference;
4677 // ParameterReferences might already be references, so we want
4678 // to pass just the value
4680 if (pr != null && pr.IsRef)
4683 ml.AddressOf (ec, mode);
4686 public Argument Clone (CloneContext clonectx)
4688 return new Argument (Expr.Clone (clonectx), ArgType);
4693 /// Invocation of methods or delegates.
4695 public class Invocation : ExpressionStatement {
4696 protected ArrayList Arguments;
4697 protected Expression expr;
4698 protected MethodGroupExpr mg;
4699 bool arguments_resolved;
4702 // arguments is an ArrayList, but we do not want to typecast,
4703 // as it might be null.
4705 public Invocation (Expression expr, ArrayList arguments)
4707 SimpleName sn = expr as SimpleName;
4709 this.expr = sn.GetMethodGroup ();
4713 Arguments = arguments;
4715 loc = expr.Location;
4718 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4719 : this (expr, arguments)
4721 this.arguments_resolved = arguments_resolved;
4724 public override Expression CreateExpressionTree (EmitContext ec)
4729 // Special conversion for nested expression trees
4731 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4732 args = new ArrayList (1);
4733 args.Add (new Argument (this));
4734 return CreateExpressionFactoryCall ("Quote", args);
4737 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4739 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4742 args = new ArrayList (arg_count);
4745 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4747 args.Add (new Argument (new NullLiteral (loc)));
4749 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4752 // Use extension argument when exists
4755 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4757 args.Add (new Argument (e));
4760 if (Arguments != null) {
4761 foreach (Argument a in Arguments) {
4762 Expression e = a.Expr.CreateExpressionTree (ec);
4764 args.Add (new Argument (e));
4769 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4771 return CreateExpressionFactoryCall ("Call", args);
4774 public override Expression DoResolve (EmitContext ec)
4776 // Don't resolve already resolved expression
4777 if (eclass != ExprClass.Invalid)
4780 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4781 if (expr_resolved == null)
4784 mg = expr_resolved as MethodGroupExpr;
4786 Type expr_type = expr_resolved.Type;
4788 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4789 return (new DelegateInvocation (
4790 expr_resolved, Arguments, loc)).Resolve (ec);
4793 MemberExpr me = expr_resolved as MemberExpr;
4795 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4799 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4801 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4802 expr_resolved.GetSignatureForError ());
4806 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4810 // Next, evaluate all the expressions in the argument list
4812 if (Arguments != null && !arguments_resolved) {
4813 for (int i = 0; i < Arguments.Count; ++i)
4815 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4820 mg = DoResolveOverload (ec);
4824 MethodInfo method = (MethodInfo)mg;
4825 if (method != null) {
4826 type = TypeManager.TypeToCoreType (method.ReturnType);
4828 // TODO: this is a copy of mg.ResolveMemberAccess method
4829 Expression iexpr = mg.InstanceExpression;
4830 if (method.IsStatic) {
4831 if (iexpr == null ||
4832 iexpr is This || iexpr is EmptyExpression ||
4833 mg.IdenticalTypeName) {
4834 mg.InstanceExpression = null;
4836 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4840 if (iexpr == null || iexpr == EmptyExpression.Null) {
4841 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4846 if (type.IsPointer){
4854 // Only base will allow this invocation to happen.
4856 if (mg.IsBase && method.IsAbstract){
4857 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4861 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4863 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4865 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4869 IsSpecialMethodInvocation (method, loc);
4871 if (mg.InstanceExpression != null)
4872 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4874 eclass = ExprClass.Value;
4878 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4880 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4883 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4885 if (!TypeManager.IsSpecialMethod (method))
4888 Report.SymbolRelatedToPreviousError (method);
4889 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4890 TypeManager.CSharpSignature (method, true));
4896 /// Emits a list of resolved Arguments that are in the arguments
4899 /// The MethodBase argument might be null if the
4900 /// emission of the arguments is known not to contain
4901 /// a `params' field (for example in constructors or other routines
4902 /// that keep their arguments in this structure)
4904 /// if `dup_args' is true, a copy of the arguments will be left
4905 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4906 /// which will be duplicated before any other args. Only EmitCall
4907 /// should be using this interface.
4909 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4911 if (arguments == null)
4914 int top = arguments.Count;
4915 LocalTemporary [] temps = null;
4917 if (dup_args && top != 0)
4918 temps = new LocalTemporary [top];
4920 int argument_index = 0;
4922 for (int i = 0; i < top; i++) {
4923 a = (Argument) arguments [argument_index++];
4926 ec.ig.Emit (OpCodes.Dup);
4927 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4932 if (this_arg != null)
4935 for (int i = 0; i < top; i ++) {
4936 temps [i].Emit (ec);
4937 temps [i].Release (ec);
4942 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4944 AParametersCollection pd = TypeManager.GetParameterData (mb);
4946 Argument a = (Argument) arguments [pd.Count - 1];
4947 Arglist list = (Arglist) a.Expr;
4949 return list.ArgumentTypes;
4953 /// This checks the ConditionalAttribute on the method
4955 public static bool IsMethodExcluded (MethodBase method, Location loc)
4957 if (method.IsConstructor)
4960 method = TypeManager.DropGenericMethodArguments (method);
4961 if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
4962 IMethodData md = TypeManager.GetMethod (method);
4964 return md.IsExcluded ();
4966 // For some methods (generated by delegate class) GetMethod returns null
4967 // because they are not included in builder_to_method table
4971 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4975 /// is_base tells whether we want to force the use of the `call'
4976 /// opcode instead of using callvirt. Call is required to call
4977 /// a specific method, while callvirt will always use the most
4978 /// recent method in the vtable.
4980 /// is_static tells whether this is an invocation on a static method
4982 /// instance_expr is an expression that represents the instance
4983 /// it must be non-null if is_static is false.
4985 /// method is the method to invoke.
4987 /// Arguments is the list of arguments to pass to the method or constructor.
4989 public static void EmitCall (EmitContext ec, bool is_base,
4990 Expression instance_expr,
4991 MethodBase method, ArrayList Arguments, Location loc)
4993 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4996 // `dup_args' leaves an extra copy of the arguments on the stack
4997 // `omit_args' does not leave any arguments at all.
4998 // So, basically, you could make one call with `dup_args' set to true,
4999 // and then another with `omit_args' set to true, and the two calls
5000 // would have the same set of arguments. However, each argument would
5001 // only have been evaluated once.
5002 public static void EmitCall (EmitContext ec, bool is_base,
5003 Expression instance_expr,
5004 MethodBase method, ArrayList Arguments, Location loc,
5005 bool dup_args, bool omit_args)
5007 ILGenerator ig = ec.ig;
5008 bool struct_call = false;
5009 bool this_call = false;
5010 LocalTemporary this_arg = null;
5012 Type decl_type = method.DeclaringType;
5014 if (IsMethodExcluded (method, loc))
5017 bool is_static = method.IsStatic;
5019 this_call = instance_expr is This;
5020 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5024 // If this is ourselves, push "this"
5028 Type iexpr_type = instance_expr.Type;
5031 // Push the instance expression
5033 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5035 // Special case: calls to a function declared in a
5036 // reference-type with a value-type argument need
5037 // to have their value boxed.
5038 if (TypeManager.IsStruct (decl_type) ||
5039 TypeManager.IsGenericParameter (iexpr_type)) {
5041 // If the expression implements IMemoryLocation, then
5042 // we can optimize and use AddressOf on the
5045 // If not we have to use some temporary storage for
5047 if (instance_expr is IMemoryLocation) {
5048 ((IMemoryLocation)instance_expr).
5049 AddressOf (ec, AddressOp.LoadStore);
5051 LocalTemporary temp = new LocalTemporary (iexpr_type);
5052 instance_expr.Emit (ec);
5054 temp.AddressOf (ec, AddressOp.Load);
5057 // avoid the overhead of doing this all the time.
5059 t = TypeManager.GetReferenceType (iexpr_type);
5061 instance_expr.Emit (ec);
5063 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5064 // to help JIT to produce better code
5065 ig.Emit (OpCodes.Box, instance_expr.Type);
5066 t = TypeManager.object_type;
5069 instance_expr.Emit (ec);
5070 t = instance_expr.Type;
5074 ig.Emit (OpCodes.Dup);
5075 if (Arguments != null && Arguments.Count != 0) {
5076 this_arg = new LocalTemporary (t);
5077 this_arg.Store (ec);
5084 EmitArguments (ec, Arguments, dup_args, this_arg);
5087 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5088 call_op = OpCodes.Call;
5090 call_op = OpCodes.Callvirt;
5093 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5094 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5098 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5099 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5100 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5107 // and DoFoo is not virtual, you can omit the callvirt,
5108 // because you don't need the null checking behavior.
5110 if (method is MethodInfo)
5111 ig.Emit (call_op, (MethodInfo) method);
5113 ig.Emit (call_op, (ConstructorInfo) method);
5116 public override void Emit (EmitContext ec)
5118 mg.EmitCall (ec, Arguments);
5121 public override void EmitStatement (EmitContext ec)
5126 // Pop the return value if there is one
5128 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5129 ec.ig.Emit (OpCodes.Pop);
5132 protected override void CloneTo (CloneContext clonectx, Expression t)
5134 Invocation target = (Invocation) t;
5136 if (Arguments != null) {
5137 target.Arguments = new ArrayList (Arguments.Count);
5138 foreach (Argument a in Arguments)
5139 target.Arguments.Add (a.Clone (clonectx));
5142 target.expr = expr.Clone (clonectx);
5145 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5147 mg.MutateHoistedGenericType (storey);
5148 if (Arguments != null) {
5149 foreach (Argument a in Arguments)
5150 a.Expr.MutateHoistedGenericType (storey);
5156 // It's either a cast or delegate invocation
5158 public class InvocationOrCast : ExpressionStatement
5161 Expression argument;
5163 public InvocationOrCast (Expression expr, Expression argument)
5166 this.argument = argument;
5167 this.loc = expr.Location;
5170 public override Expression CreateExpressionTree (EmitContext ec)
5172 throw new NotSupportedException ("ET");
5175 public override Expression DoResolve (EmitContext ec)
5177 Expression e = ResolveCore (ec);
5181 return e.Resolve (ec);
5184 Expression ResolveCore (EmitContext ec)
5187 // First try to resolve it as a cast.
5189 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5191 return new Cast (te, argument, loc);
5195 // This can either be a type or a delegate invocation.
5196 // Let's just resolve it and see what we'll get.
5198 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5203 // Ok, so it's a Cast.
5205 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5206 return new Cast (expr, argument, loc);
5209 if (expr.eclass == ExprClass.Namespace) {
5210 expr.Error_UnexpectedKind (null, "type", loc);
5215 // It's a delegate invocation.
5217 if (!TypeManager.IsDelegateType (expr.Type)) {
5218 Error (149, "Method name expected");
5222 ArrayList args = new ArrayList (1);
5223 args.Add (new Argument (argument, Argument.AType.Expression));
5224 return new DelegateInvocation (expr, args, loc);
5227 public override ExpressionStatement ResolveStatement (EmitContext ec)
5229 Expression e = ResolveCore (ec);
5233 ExpressionStatement s = e as ExpressionStatement;
5235 Error_InvalidExpressionStatement ();
5239 return s.ResolveStatement (ec);
5242 public override void Emit (EmitContext ec)
5244 throw new Exception ("Cannot happen");
5247 public override void EmitStatement (EmitContext ec)
5249 throw new Exception ("Cannot happen");
5252 protected override void CloneTo (CloneContext clonectx, Expression t)
5254 InvocationOrCast target = (InvocationOrCast) t;
5256 target.expr = expr.Clone (clonectx);
5257 target.argument = argument.Clone (clonectx);
5263 /// Implements the new expression
5265 public class New : ExpressionStatement, IMemoryLocation {
5266 ArrayList Arguments;
5269 // During bootstrap, it contains the RequestedType,
5270 // but if `type' is not null, it *might* contain a NewDelegate
5271 // (because of field multi-initialization)
5273 Expression RequestedType;
5275 MethodGroupExpr method;
5277 bool is_type_parameter;
5279 public New (Expression requested_type, ArrayList arguments, Location l)
5281 RequestedType = requested_type;
5282 Arguments = arguments;
5287 /// Converts complex core type syntax like 'new int ()' to simple constant
5289 public static Constant Constantify (Type t)
5291 if (t == TypeManager.int32_type)
5292 return new IntConstant (0, Location.Null);
5293 if (t == TypeManager.uint32_type)
5294 return new UIntConstant (0, Location.Null);
5295 if (t == TypeManager.int64_type)
5296 return new LongConstant (0, Location.Null);
5297 if (t == TypeManager.uint64_type)
5298 return new ULongConstant (0, Location.Null);
5299 if (t == TypeManager.float_type)
5300 return new FloatConstant (0, Location.Null);
5301 if (t == TypeManager.double_type)
5302 return new DoubleConstant (0, Location.Null);
5303 if (t == TypeManager.short_type)
5304 return new ShortConstant (0, Location.Null);
5305 if (t == TypeManager.ushort_type)
5306 return new UShortConstant (0, Location.Null);
5307 if (t == TypeManager.sbyte_type)
5308 return new SByteConstant (0, Location.Null);
5309 if (t == TypeManager.byte_type)
5310 return new ByteConstant (0, Location.Null);
5311 if (t == TypeManager.char_type)
5312 return new CharConstant ('\0', Location.Null);
5313 if (t == TypeManager.bool_type)
5314 return new BoolConstant (false, Location.Null);
5315 if (t == TypeManager.decimal_type)
5316 return new DecimalConstant (0, Location.Null);
5317 if (TypeManager.IsEnumType (t))
5318 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5319 if (TypeManager.IsNullableType (t))
5320 return Nullable.LiftedNull.Create (t, Location.Null);
5326 // Checks whether the type is an interface that has the
5327 // [ComImport, CoClass] attributes and must be treated
5330 public Expression CheckComImport (EmitContext ec)
5332 if (!type.IsInterface)
5336 // Turn the call into:
5337 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5339 Type real_class = AttributeTester.GetCoClassAttribute (type);
5340 if (real_class == null)
5343 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5344 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5345 return cast.Resolve (ec);
5348 public override Expression CreateExpressionTree (EmitContext ec)
5350 ArrayList args = Arguments == null ?
5351 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5353 if (method == null) {
5354 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5356 args.Add (new Argument (method.CreateExpressionTree (ec)));
5357 if (Arguments != null) {
5359 foreach (Argument a in Arguments) {
5360 expr = a.Expr.CreateExpressionTree (ec);
5362 args.Add (new Argument (expr));
5367 return CreateExpressionFactoryCall ("New", args);
5370 public override Expression DoResolve (EmitContext ec)
5373 // The New DoResolve might be called twice when initializing field
5374 // expressions (see EmitFieldInitializers, the call to
5375 // GetInitializerExpression will perform a resolve on the expression,
5376 // and later the assign will trigger another resolution
5378 // This leads to bugs (#37014)
5381 if (RequestedType is NewDelegate)
5382 return RequestedType;
5386 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5392 if (type.IsPointer) {
5393 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5394 TypeManager.CSharpName (type));
5398 if (Arguments == null) {
5399 Constant c = Constantify (type);
5401 return ReducedExpression.Create (c, this);
5404 if (TypeManager.IsDelegateType (type)) {
5405 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5408 if (TypeManager.IsGenericParameter (type)) {
5409 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5411 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5412 Error (304, String.Format (
5413 "Cannot create an instance of the " +
5414 "variable type '{0}' because it " +
5415 "doesn't have the new() constraint",
5420 if ((Arguments != null) && (Arguments.Count != 0)) {
5421 Error (417, String.Format (
5422 "`{0}': cannot provide arguments " +
5423 "when creating an instance of a " +
5424 "variable type.", type));
5428 if (TypeManager.activator_create_instance == null) {
5429 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5430 if (activator_type != null) {
5431 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5432 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5436 is_type_parameter = true;
5437 eclass = ExprClass.Value;
5441 if (type.IsAbstract && type.IsSealed) {
5442 Report.SymbolRelatedToPreviousError (type);
5443 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5447 if (type.IsInterface || type.IsAbstract){
5448 if (!TypeManager.IsGenericType (type)) {
5449 RequestedType = CheckComImport (ec);
5450 if (RequestedType != null)
5451 return RequestedType;
5454 Report.SymbolRelatedToPreviousError (type);
5455 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5459 bool is_struct = TypeManager.IsStruct (type);
5460 eclass = ExprClass.Value;
5463 // SRE returns a match for .ctor () on structs (the object constructor),
5464 // so we have to manually ignore it.
5466 if (is_struct && Arguments == null)
5469 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5470 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5471 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5473 if (Arguments != null){
5474 foreach (Argument a in Arguments){
5475 if (!a.Resolve (ec, loc))
5483 method = ml as MethodGroupExpr;
5484 if (method == null) {
5485 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5489 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5496 bool DoEmitTypeParameter (EmitContext ec)
5499 ILGenerator ig = ec.ig;
5500 // IMemoryLocation ml;
5502 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5503 new Type [] { type });
5505 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5506 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5507 ig.Emit (OpCodes.Call, ci);
5511 // Allow DoEmit() to be called multiple times.
5512 // We need to create a new LocalTemporary each time since
5513 // you can't share LocalBuilders among ILGeneators.
5514 LocalTemporary temp = new LocalTemporary (type);
5516 Label label_activator = ig.DefineLabel ();
5517 Label label_end = ig.DefineLabel ();
5519 temp.AddressOf (ec, AddressOp.Store);
5520 ig.Emit (OpCodes.Initobj, type);
5523 ig.Emit (OpCodes.Box, type);
5524 ig.Emit (OpCodes.Brfalse, label_activator);
5526 temp.AddressOf (ec, AddressOp.Store);
5527 ig.Emit (OpCodes.Initobj, type);
5529 ig.Emit (OpCodes.Br_S, label_end);
5531 ig.MarkLabel (label_activator);
5533 ig.Emit (OpCodes.Call, ci);
5534 ig.MarkLabel (label_end);
5537 throw new InternalErrorException ();
5542 // This Emit can be invoked in two contexts:
5543 // * As a mechanism that will leave a value on the stack (new object)
5544 // * As one that wont (init struct)
5546 // If we are dealing with a ValueType, we have a few
5547 // situations to deal with:
5549 // * The target is a ValueType, and we have been provided
5550 // the instance (this is easy, we are being assigned).
5552 // * The target of New is being passed as an argument,
5553 // to a boxing operation or a function that takes a
5556 // In this case, we need to create a temporary variable
5557 // that is the argument of New.
5559 // Returns whether a value is left on the stack
5561 // *** Implementation note ***
5563 // To benefit from this optimization, each assignable expression
5564 // has to manually cast to New and call this Emit.
5566 // TODO: It's worth to implement it for arrays and fields
5568 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5570 bool is_value_type = TypeManager.IsValueType (type);
5571 ILGenerator ig = ec.ig;
5572 VariableReference vr = target as VariableReference;
5574 if (target != null && is_value_type && (vr != null || method == null)) {
5575 target.AddressOf (ec, AddressOp.Store);
5576 } else if (vr != null && vr.IsRef) {
5580 if (is_type_parameter)
5581 return DoEmitTypeParameter (ec);
5584 method.EmitArguments (ec, Arguments);
5586 if (is_value_type) {
5587 if (method == null) {
5588 ig.Emit (OpCodes.Initobj, type);
5593 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5598 ConstructorInfo ci = (ConstructorInfo) method;
5600 if (TypeManager.IsGenericType (type))
5601 ci = TypeBuilder.GetConstructor (type, ci);
5604 ig.Emit (OpCodes.Newobj, ci);
5608 public override void Emit (EmitContext ec)
5610 LocalTemporary v = null;
5611 if (method == null && TypeManager.IsValueType (type)) {
5612 // TODO: Use temporary variable from pool
5613 v = new LocalTemporary (type);
5620 public override void EmitStatement (EmitContext ec)
5622 LocalTemporary v = null;
5623 if (method == null && TypeManager.IsValueType (type)) {
5624 // TODO: Use temporary variable from pool
5625 v = new LocalTemporary (type);
5629 ec.ig.Emit (OpCodes.Pop);
5632 public virtual bool HasInitializer {
5638 public void AddressOf (EmitContext ec, AddressOp mode)
5640 EmitAddressOf (ec, mode);
5643 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5645 LocalTemporary value_target = new LocalTemporary (type);
5647 if (is_type_parameter) {
5648 DoEmitTypeParameter (ec);
5649 value_target.Store (ec);
5650 value_target.AddressOf (ec, mode);
5651 return value_target;
5654 if (!TypeManager.IsStruct (type)){
5656 // We throw an exception. So far, I believe we only need to support
5658 // foreach (int j in new StructType ())
5661 throw new Exception ("AddressOf should not be used for classes");
5664 value_target.AddressOf (ec, AddressOp.Store);
5666 if (method == null) {
5667 ec.ig.Emit (OpCodes.Initobj, type);
5669 method.EmitArguments (ec, Arguments);
5670 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5673 value_target.AddressOf (ec, mode);
5674 return value_target;
5677 protected override void CloneTo (CloneContext clonectx, Expression t)
5679 New target = (New) t;
5681 target.RequestedType = RequestedType.Clone (clonectx);
5682 if (Arguments != null){
5683 target.Arguments = new ArrayList ();
5684 foreach (Argument a in Arguments){
5685 target.Arguments.Add (a.Clone (clonectx));
5690 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5692 if (method != null) {
5693 method.MutateHoistedGenericType (storey);
5694 if (Arguments != null) {
5695 foreach (Argument a in Arguments)
5696 a.Expr.MutateHoistedGenericType (storey);
5700 type = storey.MutateType (type);
5705 /// 14.5.10.2: Represents an array creation expression.
5709 /// There are two possible scenarios here: one is an array creation
5710 /// expression that specifies the dimensions and optionally the
5711 /// initialization data and the other which does not need dimensions
5712 /// specified but where initialization data is mandatory.
5714 public class ArrayCreation : Expression {
5715 FullNamedExpression requested_base_type;
5716 ArrayList initializers;
5719 // The list of Argument types.
5720 // This is used to construct the `newarray' or constructor signature
5722 protected ArrayList arguments;
5724 protected Type array_element_type;
5725 bool expect_initializers = false;
5726 int num_arguments = 0;
5727 protected int dimensions;
5728 protected readonly string rank;
5730 protected ArrayList array_data;
5734 // The number of constants in array initializers
5735 int const_initializers_count;
5736 bool only_constant_initializers;
5738 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5740 this.requested_base_type = requested_base_type;
5741 this.initializers = initializers;
5745 arguments = new ArrayList (exprs.Count);
5747 foreach (Expression e in exprs) {
5748 arguments.Add (new Argument (e, Argument.AType.Expression));
5753 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5755 this.requested_base_type = requested_base_type;
5756 this.initializers = initializers;
5760 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5762 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5764 //dimensions = tmp.Length - 1;
5765 expect_initializers = true;
5768 public static void Error_IncorrectArrayInitializer (Location loc)
5770 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5773 protected override void Error_NegativeArrayIndex (Location loc)
5775 Report.Error (248, loc, "Cannot create an array with a negative size");
5778 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5780 if (specified_dims) {
5781 Argument a = (Argument) arguments [idx];
5783 if (!a.Resolve (ec, loc))
5786 Constant c = a.Expr as Constant;
5788 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5792 Report.Error (150, a.Expr.Location, "A constant value is expected");
5796 int value = (int) c.GetValue ();
5798 if (value != probe.Count) {
5799 Error_IncorrectArrayInitializer (loc);
5803 bounds [idx] = value;
5806 int child_bounds = -1;
5807 only_constant_initializers = true;
5808 for (int i = 0; i < probe.Count; ++i) {
5809 object o = probe [i];
5810 if (o is ArrayList) {
5811 ArrayList sub_probe = o as ArrayList;
5812 int current_bounds = sub_probe.Count;
5814 if (child_bounds == -1)
5815 child_bounds = current_bounds;
5817 else if (child_bounds != current_bounds){
5818 Error_IncorrectArrayInitializer (loc);
5821 if (idx + 1 >= dimensions){
5822 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5826 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5830 if (child_bounds != -1){
5831 Error_IncorrectArrayInitializer (loc);
5835 Expression element = ResolveArrayElement (ec, (Expression) o);
5836 if (element == null)
5839 // Initializers with the default values can be ignored
5840 Constant c = element as Constant;
5842 if (c.IsDefaultInitializer (array_element_type)) {
5846 ++const_initializers_count;
5849 only_constant_initializers = false;
5852 array_data.Add (element);
5859 public override Expression CreateExpressionTree (EmitContext ec)
5863 if (array_data == null) {
5864 args = new ArrayList (arguments.Count + 1);
5865 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5866 foreach (Argument a in arguments) {
5867 if (arguments.Count == 1) {
5868 Constant c = a.Expr as Constant;
5869 if (c.IsDefaultValue)
5870 return CreateExpressionFactoryCall ("NewArrayInit", args);
5872 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5875 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5878 if (dimensions > 1) {
5879 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5883 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5884 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5885 if (array_data != null) {
5886 for (int i = 0; i < array_data.Count; ++i) {
5887 Expression e = (Expression) array_data [i];
5889 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5891 args.Add (new Argument (e.CreateExpressionTree (ec)));
5895 return CreateExpressionFactoryCall ("NewArrayInit", args);
5898 public void UpdateIndices ()
5901 for (ArrayList probe = initializers; probe != null;) {
5902 if (probe.Count > 0 && probe [0] is ArrayList) {
5903 Expression e = new IntConstant (probe.Count, Location.Null);
5904 arguments.Add (new Argument (e, Argument.AType.Expression));
5906 bounds [i++] = probe.Count;
5908 probe = (ArrayList) probe [0];
5911 Expression e = new IntConstant (probe.Count, Location.Null);
5912 arguments.Add (new Argument (e, Argument.AType.Expression));
5914 bounds [i++] = probe.Count;
5921 Expression first_emit;
5922 LocalTemporary first_emit_temp;
5924 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5926 element = element.Resolve (ec);
5927 if (element == null)
5930 if (element is CompoundAssign.TargetExpression) {
5931 if (first_emit != null)
5932 throw new InternalErrorException ("Can only handle one mutator at a time");
5933 first_emit = element;
5934 element = first_emit_temp = new LocalTemporary (element.Type);
5937 return Convert.ImplicitConversionRequired (
5938 ec, element, array_element_type, loc);
5941 protected bool ResolveInitializers (EmitContext ec)
5943 if (initializers == null) {
5944 return !expect_initializers;
5948 // We use this to store all the date values in the order in which we
5949 // will need to store them in the byte blob later
5951 array_data = new ArrayList ();
5952 bounds = new System.Collections.Specialized.HybridDictionary ();
5954 if (arguments != null)
5955 return CheckIndices (ec, initializers, 0, true);
5957 arguments = new ArrayList ();
5959 if (!CheckIndices (ec, initializers, 0, false))
5968 // Resolved the type of the array
5970 bool ResolveArrayType (EmitContext ec)
5972 if (requested_base_type == null) {
5973 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5977 if (requested_base_type is VarExpr) {
5978 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5982 StringBuilder array_qualifier = new StringBuilder (rank);
5985 // `In the first form allocates an array instace of the type that results
5986 // from deleting each of the individual expression from the expression list'
5988 if (num_arguments > 0) {
5989 array_qualifier.Append ("[");
5990 for (int i = num_arguments-1; i > 0; i--)
5991 array_qualifier.Append (",");
5992 array_qualifier.Append ("]");
5998 TypeExpr array_type_expr;
5999 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6000 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6001 if (array_type_expr == null)
6004 type = array_type_expr.Type;
6005 array_element_type = TypeManager.GetElementType (type);
6006 dimensions = type.GetArrayRank ();
6011 public override Expression DoResolve (EmitContext ec)
6016 if (!ResolveArrayType (ec))
6020 // First step is to validate the initializers and fill
6021 // in any missing bits
6023 if (!ResolveInitializers (ec))
6026 if (arguments.Count != dimensions) {
6027 Error_IncorrectArrayInitializer (loc);
6030 foreach (Argument a in arguments){
6031 if (!a.Resolve (ec, loc))
6034 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6037 eclass = ExprClass.Value;
6041 MethodInfo GetArrayMethod (int arguments)
6043 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6045 Type[] arg_types = new Type[arguments];
6046 for (int i = 0; i < arguments; i++)
6047 arg_types[i] = TypeManager.int32_type;
6049 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6053 Report.Error (-6, "New invocation: Can not find a constructor for " +
6054 "this argument list");
6061 byte [] MakeByteBlob ()
6066 int count = array_data.Count;
6068 if (TypeManager.IsEnumType (array_element_type))
6069 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6071 factor = GetTypeSize (array_element_type);
6073 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6075 data = new byte [(count * factor + 3) & ~3];
6078 for (int i = 0; i < count; ++i) {
6079 object v = array_data [i];
6081 if (v is EnumConstant)
6082 v = ((EnumConstant) v).Child;
6084 if (v is Constant && !(v is StringConstant))
6085 v = ((Constant) v).GetValue ();
6091 if (array_element_type == TypeManager.int64_type){
6092 if (!(v is Expression)){
6093 long val = (long) v;
6095 for (int j = 0; j < factor; ++j) {
6096 data [idx + j] = (byte) (val & 0xFF);
6100 } else if (array_element_type == TypeManager.uint64_type){
6101 if (!(v is Expression)){
6102 ulong val = (ulong) v;
6104 for (int j = 0; j < factor; ++j) {
6105 data [idx + j] = (byte) (val & 0xFF);
6109 } else if (array_element_type == TypeManager.float_type) {
6110 if (!(v is Expression)){
6111 element = BitConverter.GetBytes ((float) v);
6113 for (int j = 0; j < factor; ++j)
6114 data [idx + j] = element [j];
6115 if (!BitConverter.IsLittleEndian)
6116 System.Array.Reverse (data, idx, 4);
6118 } else if (array_element_type == TypeManager.double_type) {
6119 if (!(v is Expression)){
6120 element = BitConverter.GetBytes ((double) v);
6122 for (int j = 0; j < factor; ++j)
6123 data [idx + j] = element [j];
6125 // FIXME: Handle the ARM float format.
6126 if (!BitConverter.IsLittleEndian)
6127 System.Array.Reverse (data, idx, 8);
6129 } else if (array_element_type == TypeManager.char_type){
6130 if (!(v is Expression)){
6131 int val = (int) ((char) v);
6133 data [idx] = (byte) (val & 0xff);
6134 data [idx+1] = (byte) (val >> 8);
6136 } else if (array_element_type == TypeManager.short_type){
6137 if (!(v is Expression)){
6138 int val = (int) ((short) v);
6140 data [idx] = (byte) (val & 0xff);
6141 data [idx+1] = (byte) (val >> 8);
6143 } else if (array_element_type == TypeManager.ushort_type){
6144 if (!(v is Expression)){
6145 int val = (int) ((ushort) v);
6147 data [idx] = (byte) (val & 0xff);
6148 data [idx+1] = (byte) (val >> 8);
6150 } else if (array_element_type == TypeManager.int32_type) {
6151 if (!(v is Expression)){
6154 data [idx] = (byte) (val & 0xff);
6155 data [idx+1] = (byte) ((val >> 8) & 0xff);
6156 data [idx+2] = (byte) ((val >> 16) & 0xff);
6157 data [idx+3] = (byte) (val >> 24);
6159 } else if (array_element_type == TypeManager.uint32_type) {
6160 if (!(v is Expression)){
6161 uint val = (uint) v;
6163 data [idx] = (byte) (val & 0xff);
6164 data [idx+1] = (byte) ((val >> 8) & 0xff);
6165 data [idx+2] = (byte) ((val >> 16) & 0xff);
6166 data [idx+3] = (byte) (val >> 24);
6168 } else if (array_element_type == TypeManager.sbyte_type) {
6169 if (!(v is Expression)){
6170 sbyte val = (sbyte) v;
6171 data [idx] = (byte) val;
6173 } else if (array_element_type == TypeManager.byte_type) {
6174 if (!(v is Expression)){
6175 byte val = (byte) v;
6176 data [idx] = (byte) val;
6178 } else if (array_element_type == TypeManager.bool_type) {
6179 if (!(v is Expression)){
6180 bool val = (bool) v;
6181 data [idx] = (byte) (val ? 1 : 0);
6183 } else if (array_element_type == TypeManager.decimal_type){
6184 if (!(v is Expression)){
6185 int [] bits = Decimal.GetBits ((decimal) v);
6188 // FIXME: For some reason, this doesn't work on the MS runtime.
6189 int [] nbits = new int [4];
6190 nbits [0] = bits [3];
6191 nbits [1] = bits [2];
6192 nbits [2] = bits [0];
6193 nbits [3] = bits [1];
6195 for (int j = 0; j < 4; j++){
6196 data [p++] = (byte) (nbits [j] & 0xff);
6197 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6198 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6199 data [p++] = (byte) (nbits [j] >> 24);
6203 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6211 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6213 array_element_type = storey.MutateType (array_element_type);
6214 type = storey.MutateType (type);
6215 if (arguments != null) {
6216 foreach (Argument a in arguments)
6217 a.Expr.MutateHoistedGenericType (storey);
6220 if (array_data != null) {
6221 foreach (Expression e in array_data) {
6222 // Don't mutate values optimized away
6226 e.MutateHoistedGenericType (storey);
6232 // Emits the initializers for the array
6234 void EmitStaticInitializers (EmitContext ec)
6236 // FIXME: This should go to Resolve !
6237 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6238 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6239 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6240 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6241 if (TypeManager.void_initializearray_array_fieldhandle == null)
6246 // First, the static data
6249 ILGenerator ig = ec.ig;
6251 byte [] data = MakeByteBlob ();
6253 fb = RootContext.MakeStaticData (data);
6255 ig.Emit (OpCodes.Dup);
6256 ig.Emit (OpCodes.Ldtoken, fb);
6257 ig.Emit (OpCodes.Call,
6258 TypeManager.void_initializearray_array_fieldhandle);
6262 // Emits pieces of the array that can not be computed at compile
6263 // time (variables and string locations).
6265 // This always expect the top value on the stack to be the array
6267 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6269 ILGenerator ig = ec.ig;
6270 int dims = bounds.Count;
6271 int [] current_pos = new int [dims];
6273 MethodInfo set = null;
6276 Type [] args = new Type [dims + 1];
6278 for (int j = 0; j < dims; j++)
6279 args [j] = TypeManager.int32_type;
6280 args [dims] = array_element_type;
6282 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6284 CallingConventions.HasThis | CallingConventions.Standard,
6285 TypeManager.void_type, args);
6288 for (int i = 0; i < array_data.Count; i++){
6290 Expression e = (Expression)array_data [i];
6292 // Constant can be initialized via StaticInitializer
6293 if (e != null && !(!emitConstants && e is Constant)) {
6294 Type etype = e.Type;
6296 ig.Emit (OpCodes.Dup);
6298 for (int idx = 0; idx < dims; idx++)
6299 IntConstant.EmitInt (ig, current_pos [idx]);
6302 // If we are dealing with a struct, get the
6303 // address of it, so we can store it.
6305 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6306 (!TypeManager.IsBuiltinOrEnum (etype) ||
6307 etype == TypeManager.decimal_type)) {
6309 ig.Emit (OpCodes.Ldelema, etype);
6315 bool is_stobj, has_type_arg;
6316 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6318 ig.Emit (OpCodes.Stobj, etype);
6319 else if (has_type_arg)
6320 ig.Emit (op, etype);
6324 ig.Emit (OpCodes.Call, set);
6331 for (int j = dims - 1; j >= 0; j--){
6333 if (current_pos [j] < (int) bounds [j])
6335 current_pos [j] = 0;
6340 public override void Emit (EmitContext ec)
6342 ILGenerator ig = ec.ig;
6344 if (first_emit != null) {
6345 first_emit.Emit (ec);
6346 first_emit_temp.Store (ec);
6349 foreach (Argument a in arguments)
6352 if (arguments.Count == 1)
6353 ig.Emit (OpCodes.Newarr, array_element_type);
6355 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6358 if (initializers == null)
6361 // Emit static initializer for arrays which have contain more than 4 items and
6362 // the static initializer will initialize at least 25% of array values.
6363 // NOTE: const_initializers_count does not contain default constant values.
6364 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6365 TypeManager.IsPrimitiveType (array_element_type)) {
6366 EmitStaticInitializers (ec);
6368 if (!only_constant_initializers)
6369 EmitDynamicInitializers (ec, false);
6371 EmitDynamicInitializers (ec, true);
6374 if (first_emit_temp != null)
6375 first_emit_temp.Release (ec);
6378 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6380 if (arguments.Count != 1) {
6381 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6382 return base.GetAttributableValue (ec, null, out value);
6385 if (array_data == null) {
6386 Constant c = (Constant)((Argument)arguments [0]).Expr;
6387 if (c.IsDefaultValue) {
6388 value = Array.CreateInstance (array_element_type, 0);
6391 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6392 return base.GetAttributableValue (ec, null, out value);
6395 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6396 object element_value;
6397 for (int i = 0; i < ret.Length; ++i)
6399 Expression e = (Expression)array_data [i];
6401 // Is null when an initializer is optimized (value == predefined value)
6405 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6409 ret.SetValue (element_value, i);
6415 protected override void CloneTo (CloneContext clonectx, Expression t)
6417 ArrayCreation target = (ArrayCreation) t;
6419 if (requested_base_type != null)
6420 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6422 if (arguments != null){
6423 target.arguments = new ArrayList (arguments.Count);
6424 foreach (Argument a in arguments)
6425 target.arguments.Add (a.Clone (clonectx));
6428 if (initializers != null){
6429 target.initializers = new ArrayList (initializers.Count);
6430 foreach (object initializer in initializers)
6431 if (initializer is ArrayList) {
6432 ArrayList this_al = (ArrayList)initializer;
6433 ArrayList al = new ArrayList (this_al.Count);
6434 target.initializers.Add (al);
6435 foreach (Expression e in this_al)
6436 al.Add (e.Clone (clonectx));
6438 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6445 // Represents an implicitly typed array epxression
6447 public class ImplicitlyTypedArrayCreation : ArrayCreation
6449 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6450 : base (null, rank, initializers, loc)
6452 if (RootContext.Version <= LanguageVersion.ISO_2)
6453 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6455 if (rank.Length > 2) {
6456 while (rank [++dimensions] == ',');
6462 public override Expression DoResolve (EmitContext ec)
6467 if (!ResolveInitializers (ec))
6470 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6471 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6472 arguments.Count != dimensions) {
6473 Error_NoBestType ();
6478 // At this point we found common base type for all initializer elements
6479 // but we have to be sure that all static initializer elements are of
6482 UnifyInitializerElement (ec);
6484 type = TypeManager.GetConstructedType (array_element_type, rank);
6485 eclass = ExprClass.Value;
6489 void Error_NoBestType ()
6491 Report.Error (826, loc,
6492 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6496 // Converts static initializer only
6498 void UnifyInitializerElement (EmitContext ec)
6500 for (int i = 0; i < array_data.Count; ++i) {
6501 Expression e = (Expression)array_data[i];
6503 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6507 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6509 element = element.Resolve (ec);
6510 if (element == null)
6513 if (array_element_type == null) {
6514 if (element.Type != TypeManager.null_type)
6515 array_element_type = element.Type;
6520 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6524 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6525 array_element_type = element.Type;
6529 Error_NoBestType ();
6534 public sealed class CompilerGeneratedThis : This
6536 public static This Instance = new CompilerGeneratedThis ();
6538 private CompilerGeneratedThis ()
6539 : base (Location.Null)
6543 public CompilerGeneratedThis (Type type, Location loc)
6549 public override Expression DoResolve (EmitContext ec)
6551 eclass = ExprClass.Variable;
6553 type = ec.ContainerType;
6557 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6564 /// Represents the `this' construct
6567 public class This : VariableReference
6569 sealed class ThisVariable : ILocalVariable
6571 public static readonly ILocalVariable Instance = new ThisVariable ();
6573 public void Emit (EmitContext ec)
6575 ec.ig.Emit (OpCodes.Ldarg_0);
6578 public void EmitAssign (EmitContext ec)
6580 throw new InvalidOperationException ();
6583 public void EmitAddressOf (EmitContext ec)
6585 ec.ig.Emit (OpCodes.Ldarg_0);
6590 VariableInfo variable_info;
6593 public This (Block block, Location loc)
6599 public This (Location loc)
6604 public override VariableInfo VariableInfo {
6605 get { return variable_info; }
6608 public override bool IsFixed {
6609 get { return false; }
6612 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6614 // Is null when probing IsHoisted
6618 if (ec.CurrentAnonymousMethod == null)
6621 AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
6622 while (storey != null) {
6623 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6625 return storey.HoistedThis;
6633 public override bool IsRef {
6634 get { return is_struct; }
6637 protected override ILocalVariable Variable {
6638 get { return ThisVariable.Instance; }
6641 public static bool IsThisAvailable (EmitContext ec)
6643 if (ec.IsStatic || ec.IsInFieldInitializer)
6646 if (ec.CurrentAnonymousMethod == null)
6649 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6655 public bool ResolveBase (EmitContext ec)
6657 if (eclass != ExprClass.Invalid)
6660 eclass = ExprClass.Variable;
6662 if (ec.TypeContainer.CurrentType != null)
6663 type = ec.TypeContainer.CurrentType;
6665 type = ec.ContainerType;
6667 if (!IsThisAvailable (ec)) {
6669 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6671 Report.Error (1673, loc,
6672 "Anonymous methods inside structs cannot access instance members of `this'. " +
6673 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6677 is_struct = ec.TypeContainer is Struct;
6679 if (block != null) {
6680 if (block.Toplevel.ThisVariable != null)
6681 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6683 AnonymousExpression am = ec.CurrentAnonymousMethod;
6684 if (am != null && ec.IsVariableCapturingRequired) {
6685 am.SetHasThisAccess ();
6693 // Called from Invocation to check if the invocation is correct
6695 public override void CheckMarshalByRefAccess (EmitContext ec)
6697 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6698 !variable_info.IsAssigned (ec)) {
6699 Error (188, "The `this' object cannot be used before all of its " +
6700 "fields are assigned to");
6701 variable_info.SetAssigned (ec);
6705 public override Expression CreateExpressionTree (EmitContext ec)
6707 ArrayList args = new ArrayList (1);
6708 args.Add (new Argument (this));
6710 // Use typeless constant for ldarg.0 to save some
6711 // space and avoid problems with anonymous stories
6712 return CreateExpressionFactoryCall ("Constant", args);
6715 public override Expression DoResolve (EmitContext ec)
6717 if (!ResolveBase (ec))
6721 if (ec.IsInFieldInitializer) {
6722 Error (27, "Keyword `this' is not available in the current context");
6729 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6731 if (!ResolveBase (ec))
6734 if (variable_info != null)
6735 variable_info.SetAssigned (ec);
6737 if (ec.TypeContainer is Class){
6738 if (right_side == EmptyExpression.UnaryAddress)
6739 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6740 else if (right_side == EmptyExpression.OutAccess)
6741 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6743 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6749 public override int GetHashCode()
6751 return block.GetHashCode ();
6754 public override string Name {
6755 get { return "this"; }
6758 public override bool Equals (object obj)
6760 This t = obj as This;
6764 return block == t.block;
6767 protected override void CloneTo (CloneContext clonectx, Expression t)
6769 This target = (This) t;
6771 target.block = clonectx.LookupBlock (block);
6774 public override void SetHasAddressTaken ()
6781 /// Represents the `__arglist' construct
6783 public class ArglistAccess : Expression
6785 public ArglistAccess (Location loc)
6790 public override Expression CreateExpressionTree (EmitContext ec)
6792 throw new NotSupportedException ("ET");
6795 public override Expression DoResolve (EmitContext ec)
6797 eclass = ExprClass.Variable;
6798 type = typeof (ArglistAccess);
6800 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6802 Error (190, "The __arglist construct is valid only within " +
6803 "a variable argument method");
6810 public override void Emit (EmitContext ec)
6812 ec.ig.Emit (OpCodes.Arglist);
6815 protected override void CloneTo (CloneContext clonectx, Expression target)
6822 /// Represents the `__arglist (....)' construct
6824 public class Arglist : Expression
6826 Argument[] Arguments;
6828 public Arglist (Location loc)
6829 : this (Argument.Empty, loc)
6833 public Arglist (Argument[] args, Location l)
6839 public Type[] ArgumentTypes {
6841 Type[] retval = new Type [Arguments.Length];
6842 for (int i = 0; i < Arguments.Length; i++)
6843 retval [i] = Arguments [i].Type;
6848 public override Expression CreateExpressionTree (EmitContext ec)
6850 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6854 public override Expression DoResolve (EmitContext ec)
6856 eclass = ExprClass.Variable;
6857 type = typeof (ArglistAccess);
6859 foreach (Argument arg in Arguments) {
6860 if (!arg.Resolve (ec, loc))
6867 public override void Emit (EmitContext ec)
6869 foreach (Argument arg in Arguments)
6873 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6875 foreach (Argument arg in Arguments)
6876 arg.Expr.MutateHoistedGenericType (storey);
6879 protected override void CloneTo (CloneContext clonectx, Expression t)
6881 Arglist target = (Arglist) t;
6883 target.Arguments = new Argument [Arguments.Length];
6884 for (int i = 0; i < Arguments.Length; i++)
6885 target.Arguments [i] = Arguments [i].Clone (clonectx);
6890 /// Implements the typeof operator
6892 public class TypeOf : Expression {
6893 Expression QueriedType;
6894 protected Type typearg;
6896 public TypeOf (Expression queried_type, Location l)
6898 QueriedType = queried_type;
6902 public override Expression CreateExpressionTree (EmitContext ec)
6904 ArrayList args = new ArrayList (2);
6905 args.Add (new Argument (this));
6906 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6907 return CreateExpressionFactoryCall ("Constant", args);
6910 public override Expression DoResolve (EmitContext ec)
6912 if (eclass != ExprClass.Invalid)
6915 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6919 typearg = texpr.Type;
6921 if (typearg == TypeManager.void_type) {
6922 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6926 if (typearg.IsPointer && !ec.InUnsafe){
6931 type = TypeManager.type_type;
6933 return DoResolveBase ();
6936 protected Expression DoResolveBase ()
6938 if (TypeManager.system_type_get_type_from_handle == null) {
6939 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6940 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6943 // Even though what is returned is a type object, it's treated as a value by the compiler.
6944 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6945 eclass = ExprClass.Value;
6949 public override void Emit (EmitContext ec)
6951 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6952 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6955 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6957 if (TypeManager.ContainsGenericParameters (typearg) &&
6958 !TypeManager.IsGenericTypeDefinition (typearg)) {
6959 Report.SymbolRelatedToPreviousError (typearg);
6960 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6961 TypeManager.CSharpName (typearg));
6966 if (value_type == TypeManager.object_type) {
6967 value = (object)typearg;
6974 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6976 typearg = storey.MutateType (typearg);
6979 public Type TypeArgument {
6985 protected override void CloneTo (CloneContext clonectx, Expression t)
6987 TypeOf target = (TypeOf) t;
6988 if (QueriedType != null)
6989 target.QueriedType = QueriedType.Clone (clonectx);
6994 /// Implements the `typeof (void)' operator
6996 public class TypeOfVoid : TypeOf {
6997 public TypeOfVoid (Location l) : base (null, l)
7002 public override Expression DoResolve (EmitContext ec)
7004 type = TypeManager.type_type;
7005 typearg = TypeManager.void_type;
7007 return DoResolveBase ();
7011 class TypeOfMethodInfo : TypeOfMethod
7013 public TypeOfMethodInfo (MethodBase method, Location loc)
7014 : base (method, loc)
7018 public override Expression DoResolve (EmitContext ec)
7020 type = typeof (MethodInfo);
7021 return base.DoResolve (ec);
7024 public override void Emit (EmitContext ec)
7026 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7028 ec.ig.Emit (OpCodes.Castclass, type);
7032 class TypeOfConstructorInfo : TypeOfMethod
7034 public TypeOfConstructorInfo (MethodBase method, Location loc)
7035 : base (method, loc)
7039 public override Expression DoResolve (EmitContext ec)
7041 type = typeof (ConstructorInfo);
7042 return base.DoResolve (ec);
7045 public override void Emit (EmitContext ec)
7047 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7049 ec.ig.Emit (OpCodes.Castclass, type);
7053 abstract class TypeOfMethod : Expression
7055 protected readonly MethodBase method;
7057 protected TypeOfMethod (MethodBase method, Location loc)
7059 this.method = method;
7063 public override Expression CreateExpressionTree (EmitContext ec)
7065 ArrayList args = new ArrayList (2);
7066 args.Add (new Argument (this));
7067 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7068 return CreateExpressionFactoryCall ("Constant", args);
7071 public override Expression DoResolve (EmitContext ec)
7073 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7074 MethodInfo mi = is_generic ?
7075 TypeManager.methodbase_get_type_from_handle_generic :
7076 TypeManager.methodbase_get_type_from_handle;
7079 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7080 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7082 if (t == null || handle_type == null)
7085 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7087 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7088 new Type[] { handle_type } );
7091 TypeManager.methodbase_get_type_from_handle_generic = mi;
7093 TypeManager.methodbase_get_type_from_handle = mi;
7096 eclass = ExprClass.Value;
7100 public override void Emit (EmitContext ec)
7102 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7105 mi = TypeManager.methodbase_get_type_from_handle_generic;
7106 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7108 mi = TypeManager.methodbase_get_type_from_handle;
7111 ec.ig.Emit (OpCodes.Call, mi);
7115 internal class TypeOfField : Expression
7117 readonly FieldInfo field;
7119 public TypeOfField (FieldInfo field, Location loc)
7125 public override Expression CreateExpressionTree (EmitContext ec)
7127 throw new NotSupportedException ("ET");
7130 public override Expression DoResolve (EmitContext ec)
7132 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7133 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7134 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7136 if (t != null && handle_type != null)
7137 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7138 "GetFieldFromHandle", loc, handle_type);
7141 type = typeof (FieldInfo);
7142 eclass = ExprClass.Value;
7146 public override void Emit (EmitContext ec)
7148 ec.ig.Emit (OpCodes.Ldtoken, field);
7149 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7154 /// Implements the sizeof expression
7156 public class SizeOf : Expression {
7157 readonly Expression QueriedType;
7160 public SizeOf (Expression queried_type, Location l)
7162 this.QueriedType = queried_type;
7166 public override Expression CreateExpressionTree (EmitContext ec)
7168 Error_PointerInsideExpressionTree ();
7172 public override Expression DoResolve (EmitContext ec)
7174 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7178 type_queried = texpr.Type;
7179 if (TypeManager.IsEnumType (type_queried))
7180 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7182 int size_of = GetTypeSize (type_queried);
7184 return new IntConstant (size_of, loc);
7187 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7192 Report.Error (233, loc,
7193 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7194 TypeManager.CSharpName (type_queried));
7197 type = TypeManager.int32_type;
7198 eclass = ExprClass.Value;
7202 public override void Emit (EmitContext ec)
7204 int size = GetTypeSize (type_queried);
7207 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7209 IntConstant.EmitInt (ec.ig, size);
7212 protected override void CloneTo (CloneContext clonectx, Expression t)
7218 /// Implements the qualified-alias-member (::) expression.
7220 public class QualifiedAliasMember : MemberAccess
7222 readonly string alias;
7223 public static readonly string GlobalAlias = "global";
7225 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7226 : base (null, identifier, targs, l)
7231 public QualifiedAliasMember (string alias, string identifier, Location l)
7232 : base (null, identifier, l)
7237 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7239 if (alias == GlobalAlias) {
7240 expr = GlobalRootNamespace.Instance;
7241 return base.ResolveAsTypeStep (ec, silent);
7244 int errors = Report.Errors;
7245 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7247 if (errors == Report.Errors)
7248 Report.Error (432, loc, "Alias `{0}' not found", alias);
7252 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7256 if (expr.eclass == ExprClass.Type) {
7258 Report.Error (431, loc,
7259 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7267 public override Expression DoResolve (EmitContext ec)
7269 return ResolveAsTypeStep (ec, false);
7272 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7274 Report.Error (687, loc,
7275 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7276 GetSignatureForError ());
7279 public override string GetSignatureForError ()
7282 if (targs != null) {
7283 name = TypeManager.RemoveGenericArity (Name) + "<" +
7284 targs.GetSignatureForError () + ">";
7287 return alias + "::" + name;
7290 protected override void CloneTo (CloneContext clonectx, Expression t)
7297 /// Implements the member access expression
7299 public class MemberAccess : ATypeNameExpression {
7300 protected Expression expr;
7302 public MemberAccess (Expression expr, string id)
7303 : base (id, expr.Location)
7308 public MemberAccess (Expression expr, string identifier, Location loc)
7309 : base (identifier, loc)
7314 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7315 : base (identifier, args, loc)
7320 Expression DoResolve (EmitContext ec, Expression right_side)
7323 throw new Exception ();
7326 // Resolve the expression with flow analysis turned off, we'll do the definite
7327 // assignment checks later. This is because we don't know yet what the expression
7328 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7329 // definite assignment check on the actual field and not on the whole struct.
7332 SimpleName original = expr as SimpleName;
7333 Expression expr_resolved = expr.Resolve (ec,
7334 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7335 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7337 if (expr_resolved == null)
7340 string LookupIdentifier = MemberName.MakeName (Name, targs);
7342 Namespace ns = expr_resolved as Namespace;
7344 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7347 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, LookupIdentifier);
7348 else if (targs != null)
7349 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7354 Type expr_type = expr_resolved.Type;
7355 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7356 expr_type == TypeManager.null_type || expr_type == TypeManager.anonymous_method_type) {
7357 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7361 Constant c = expr_resolved as Constant;
7362 if (c != null && c.GetValue () == null) {
7363 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7364 "System.NullReferenceException");
7367 if (targs != null) {
7368 if (!targs.Resolve (ec))
7372 Expression member_lookup;
7373 member_lookup = MemberLookup (
7374 ec.ContainerType, expr_type, expr_type, Name, loc);
7376 if (member_lookup == null && targs != null) {
7377 member_lookup = MemberLookup (
7378 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7381 if (member_lookup == null) {
7382 ExprClass expr_eclass = expr_resolved.eclass;
7385 // Extension methods are not allowed on all expression types
7387 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7388 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7389 expr_eclass == ExprClass.EventAccess) {
7390 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7391 if (ex_method_lookup != null) {
7392 ex_method_lookup.ExtensionExpression = expr_resolved;
7394 if (targs != null) {
7395 ex_method_lookup.SetTypeArguments (targs);
7398 return ex_method_lookup.DoResolve (ec);
7402 expr = expr_resolved;
7403 member_lookup = Error_MemberLookupFailed (
7404 ec.ContainerType, expr_type, expr_type, Name, null,
7405 AllMemberTypes, AllBindingFlags);
7406 if (member_lookup == null)
7410 TypeExpr texpr = member_lookup as TypeExpr;
7411 if (texpr != null) {
7412 if (!(expr_resolved is TypeExpr) &&
7413 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7414 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7415 Name, member_lookup.GetSignatureForError ());
7419 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7420 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7421 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7425 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7428 // When looking up a nested type in a generic instance
7429 // via reflection, we always get a generic type definition
7430 // and not a generic instance - so we have to do this here.
7432 // See gtest-172-lib.cs and gtest-172.cs for an example.
7434 ct = new GenericTypeExpr (
7435 member_lookup.Type, ct.TypeArguments, loc);
7437 return ct.ResolveAsTypeStep (ec, false);
7440 return member_lookup;
7443 MemberExpr me = (MemberExpr) member_lookup;
7444 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7448 if (targs != null) {
7449 me.SetTypeArguments (targs);
7452 if (original != null && !TypeManager.IsValueType (expr_type)) {
7453 if (me.IsInstance) {
7454 LocalVariableReference var = expr_resolved as LocalVariableReference;
7455 if (var != null && !var.VerifyAssigned (ec))
7460 // The following DoResolve/DoResolveLValue will do the definite assignment
7463 if (right_side != null)
7464 return me.DoResolveLValue (ec, right_side);
7466 return me.DoResolve (ec);
7469 public override Expression DoResolve (EmitContext ec)
7471 return DoResolve (ec, null);
7474 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7476 return DoResolve (ec, right_side);
7479 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7481 return ResolveNamespaceOrType (ec, silent);
7484 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7486 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7488 if (expr_resolved == null)
7491 string LookupIdentifier = MemberName.MakeName (Name, targs);
7493 Namespace ns = expr_resolved as Namespace;
7495 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7497 if (retval == null && !silent)
7498 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7499 else if (targs != null)
7500 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7505 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7506 if (tnew_expr == null)
7509 if (tnew_expr is TypeParameterExpr) {
7510 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7511 tnew_expr.GetSignatureForError ());
7515 Type expr_type = tnew_expr.Type;
7516 Expression member_lookup = MemberLookup (
7517 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7518 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7519 if (member_lookup == null) {
7523 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7527 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7531 TypeArguments the_args = targs;
7532 Type declaring_type = texpr.Type.DeclaringType;
7533 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7534 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7535 expr_type = expr_type.BaseType;
7538 TypeArguments new_args = new TypeArguments ();
7539 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7540 new_args.Add (new TypeExpression (decl, loc));
7543 new_args.Add (targs);
7545 the_args = new_args;
7548 if (the_args != null) {
7549 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7550 return ctype.ResolveAsTypeStep (rc, false);
7556 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7558 Expression member_lookup = MemberLookup (
7559 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7560 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7562 if (member_lookup != null) {
7563 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7564 if (expr_type == null)
7567 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7571 member_lookup = MemberLookup (
7572 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7573 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7575 if (member_lookup == null) {
7576 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7577 Name, expr_type.GetSignatureForError ());
7579 // TODO: Report.SymbolRelatedToPreviousError
7580 member_lookup.Error_UnexpectedKind (null, "type", loc);
7584 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7586 if (RootContext.Version > LanguageVersion.ISO_2 &&
7587 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7588 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7589 "extension method `{1}' of type `{0}' could be found " +
7590 "(are you missing a using directive or an assembly reference?)",
7591 TypeManager.CSharpName (type), name);
7595 base.Error_TypeDoesNotContainDefinition (type, name);
7598 public override string GetSignatureForError ()
7600 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7603 protected override void CloneTo (CloneContext clonectx, Expression t)
7605 MemberAccess target = (MemberAccess) t;
7607 target.expr = expr.Clone (clonectx);
7612 /// Implements checked expressions
7614 public class CheckedExpr : Expression {
7616 public Expression Expr;
7618 public CheckedExpr (Expression e, Location l)
7624 public override Expression CreateExpressionTree (EmitContext ec)
7626 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7627 return Expr.CreateExpressionTree (ec);
7630 public override Expression DoResolve (EmitContext ec)
7632 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7633 Expr = Expr.Resolve (ec);
7638 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7641 eclass = Expr.eclass;
7646 public override void Emit (EmitContext ec)
7648 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7652 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7654 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7655 Expr.EmitBranchable (ec, target, on_true);
7658 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7660 Expr.MutateHoistedGenericType (storey);
7663 protected override void CloneTo (CloneContext clonectx, Expression t)
7665 CheckedExpr target = (CheckedExpr) t;
7667 target.Expr = Expr.Clone (clonectx);
7672 /// Implements the unchecked expression
7674 public class UnCheckedExpr : Expression {
7676 public Expression Expr;
7678 public UnCheckedExpr (Expression e, Location l)
7684 public override Expression CreateExpressionTree (EmitContext ec)
7686 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7687 return Expr.CreateExpressionTree (ec);
7690 public override Expression DoResolve (EmitContext ec)
7692 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7693 Expr = Expr.Resolve (ec);
7698 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7701 eclass = Expr.eclass;
7706 public override void Emit (EmitContext ec)
7708 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7712 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7714 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7715 Expr.EmitBranchable (ec, target, on_true);
7718 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7720 Expr.MutateHoistedGenericType (storey);
7723 protected override void CloneTo (CloneContext clonectx, Expression t)
7725 UnCheckedExpr target = (UnCheckedExpr) t;
7727 target.Expr = Expr.Clone (clonectx);
7732 /// An Element Access expression.
7734 /// During semantic analysis these are transformed into
7735 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7737 public class ElementAccess : Expression {
7738 public ArrayList Arguments;
7739 public Expression Expr;
7741 public ElementAccess (Expression e, ArrayList e_list)
7749 Arguments = new ArrayList (e_list.Count);
7750 foreach (Expression tmp in e_list)
7751 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7754 bool CommonResolve (EmitContext ec)
7756 Expr = Expr.Resolve (ec);
7758 if (Arguments == null)
7761 foreach (Argument a in Arguments){
7762 if (!a.Resolve (ec, loc))
7766 return Expr != null;
7769 public override Expression CreateExpressionTree (EmitContext ec)
7771 ArrayList args = new ArrayList (Arguments.Count + 1);
7772 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7773 foreach (Argument a in Arguments)
7774 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7776 return CreateExpressionFactoryCall ("ArrayIndex", args);
7779 Expression MakePointerAccess (EmitContext ec, Type t)
7781 if (Arguments.Count != 1){
7782 Error (196, "A pointer must be indexed by only one value");
7786 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7789 return new Indirection (p, loc).Resolve (ec);
7792 public override Expression DoResolve (EmitContext ec)
7794 if (!CommonResolve (ec))
7798 // We perform some simple tests, and then to "split" the emit and store
7799 // code we create an instance of a different class, and return that.
7801 // I am experimenting with this pattern.
7805 if (t == TypeManager.array_type){
7806 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7811 return (new ArrayAccess (this, loc)).Resolve (ec);
7813 return MakePointerAccess (ec, t);
7815 FieldExpr fe = Expr as FieldExpr;
7817 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7819 return MakePointerAccess (ec, ff.ElementType);
7822 return (new IndexerAccess (this, loc)).Resolve (ec);
7825 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7827 if (!CommonResolve (ec))
7832 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7835 return MakePointerAccess (ec, type);
7837 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7838 Error_CannotModifyIntermediateExpressionValue (ec);
7840 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7843 public override void Emit (EmitContext ec)
7845 throw new Exception ("Should never be reached");
7848 public override string GetSignatureForError ()
7850 return Expr.GetSignatureForError ();
7853 protected override void CloneTo (CloneContext clonectx, Expression t)
7855 ElementAccess target = (ElementAccess) t;
7857 target.Expr = Expr.Clone (clonectx);
7858 target.Arguments = new ArrayList (Arguments.Count);
7859 foreach (Argument a in Arguments)
7860 target.Arguments.Add (a.Clone (clonectx));
7865 /// Implements array access
7867 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7869 // Points to our "data" repository
7873 LocalTemporary temp;
7877 public ArrayAccess (ElementAccess ea_data, Location l)
7883 public override Expression CreateExpressionTree (EmitContext ec)
7885 return ea.CreateExpressionTree (ec);
7888 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7890 return DoResolve (ec);
7893 public override Expression DoResolve (EmitContext ec)
7896 ExprClass eclass = ea.Expr.eclass;
7898 // As long as the type is valid
7899 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7900 eclass == ExprClass.Value)) {
7901 ea.Expr.Error_UnexpectedKind ("variable or value");
7906 if (eclass != ExprClass.Invalid)
7909 Type t = ea.Expr.Type;
7910 int rank = ea.Arguments.Count;
7911 if (t.GetArrayRank () != rank) {
7912 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7913 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7917 type = TypeManager.GetElementType (t);
7918 if (type.IsPointer && !ec.InUnsafe) {
7919 UnsafeError (ea.Location);
7923 foreach (Argument a in ea.Arguments) {
7924 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7927 eclass = ExprClass.Variable;
7933 /// Emits the right opcode to load an object of Type `t'
7934 /// from an array of T
7936 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7939 MethodInfo get = FetchGetMethod ();
7940 ig.Emit (OpCodes.Call, get);
7944 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7945 ig.Emit (OpCodes.Ldelem_U1);
7946 else if (type == TypeManager.sbyte_type)
7947 ig.Emit (OpCodes.Ldelem_I1);
7948 else if (type == TypeManager.short_type)
7949 ig.Emit (OpCodes.Ldelem_I2);
7950 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7951 ig.Emit (OpCodes.Ldelem_U2);
7952 else if (type == TypeManager.int32_type)
7953 ig.Emit (OpCodes.Ldelem_I4);
7954 else if (type == TypeManager.uint32_type)
7955 ig.Emit (OpCodes.Ldelem_U4);
7956 else if (type == TypeManager.uint64_type)
7957 ig.Emit (OpCodes.Ldelem_I8);
7958 else if (type == TypeManager.int64_type)
7959 ig.Emit (OpCodes.Ldelem_I8);
7960 else if (type == TypeManager.float_type)
7961 ig.Emit (OpCodes.Ldelem_R4);
7962 else if (type == TypeManager.double_type)
7963 ig.Emit (OpCodes.Ldelem_R8);
7964 else if (type == TypeManager.intptr_type)
7965 ig.Emit (OpCodes.Ldelem_I);
7966 else if (TypeManager.IsEnumType (type)){
7967 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7968 } else if (TypeManager.IsStruct (type)){
7969 ig.Emit (OpCodes.Ldelema, type);
7970 ig.Emit (OpCodes.Ldobj, type);
7972 } else if (type.IsGenericParameter) {
7973 ig.Emit (OpCodes.Ldelem, type);
7975 } else if (type.IsPointer)
7976 ig.Emit (OpCodes.Ldelem_I);
7978 ig.Emit (OpCodes.Ldelem_Ref);
7981 protected override void Error_NegativeArrayIndex (Location loc)
7983 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7987 /// Returns the right opcode to store an object of Type `t'
7988 /// from an array of T.
7990 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7992 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7993 has_type_arg = false; is_stobj = false;
7994 t = TypeManager.TypeToCoreType (t);
7995 if (TypeManager.IsEnumType (t))
7996 t = TypeManager.GetEnumUnderlyingType (t);
7997 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7998 t == TypeManager.bool_type)
7999 return OpCodes.Stelem_I1;
8000 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8001 t == TypeManager.char_type)
8002 return OpCodes.Stelem_I2;
8003 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8004 return OpCodes.Stelem_I4;
8005 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8006 return OpCodes.Stelem_I8;
8007 else if (t == TypeManager.float_type)
8008 return OpCodes.Stelem_R4;
8009 else if (t == TypeManager.double_type)
8010 return OpCodes.Stelem_R8;
8011 else if (t == TypeManager.intptr_type) {
8012 has_type_arg = true;
8014 return OpCodes.Stobj;
8015 } else if (TypeManager.IsStruct (t)) {
8016 has_type_arg = true;
8018 return OpCodes.Stobj;
8020 } else if (t.IsGenericParameter) {
8021 has_type_arg = true;
8022 return OpCodes.Stelem;
8025 } else if (t.IsPointer)
8026 return OpCodes.Stelem_I;
8028 return OpCodes.Stelem_Ref;
8031 MethodInfo FetchGetMethod ()
8033 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8034 int arg_count = ea.Arguments.Count;
8035 Type [] args = new Type [arg_count];
8038 for (int i = 0; i < arg_count; i++){
8039 //args [i++] = a.Type;
8040 args [i] = TypeManager.int32_type;
8043 get = mb.GetArrayMethod (
8044 ea.Expr.Type, "Get",
8045 CallingConventions.HasThis |
8046 CallingConventions.Standard,
8052 MethodInfo FetchAddressMethod ()
8054 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8055 int arg_count = ea.Arguments.Count;
8056 Type [] args = new Type [arg_count];
8060 ret_type = TypeManager.GetReferenceType (type);
8062 for (int i = 0; i < arg_count; i++){
8063 //args [i++] = a.Type;
8064 args [i] = TypeManager.int32_type;
8067 address = mb.GetArrayMethod (
8068 ea.Expr.Type, "Address",
8069 CallingConventions.HasThis |
8070 CallingConventions.Standard,
8077 // Load the array arguments into the stack.
8079 void LoadArrayAndArguments (EmitContext ec)
8083 for (int i = 0; i < ea.Arguments.Count; ++i) {
8084 ((Argument)ea.Arguments [i]).Emit (ec);
8088 public void Emit (EmitContext ec, bool leave_copy)
8090 int rank = ea.Expr.Type.GetArrayRank ();
8091 ILGenerator ig = ec.ig;
8094 LoadFromPtr (ig, this.type);
8096 LoadArrayAndArguments (ec);
8097 EmitLoadOpcode (ig, type, rank);
8101 ig.Emit (OpCodes.Dup);
8102 temp = new LocalTemporary (this.type);
8107 public override void Emit (EmitContext ec)
8112 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8114 int rank = ea.Expr.Type.GetArrayRank ();
8115 ILGenerator ig = ec.ig;
8116 Type t = source.Type;
8117 prepared = prepare_for_load;
8120 AddressOf (ec, AddressOp.LoadStore);
8121 ec.ig.Emit (OpCodes.Dup);
8123 LoadArrayAndArguments (ec);
8127 bool is_stobj, has_type_arg;
8128 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8132 // The stobj opcode used by value types will need
8133 // an address on the stack, not really an array/array
8137 ig.Emit (OpCodes.Ldelema, t);
8142 ec.ig.Emit (OpCodes.Dup);
8143 temp = new LocalTemporary (this.type);
8148 StoreFromPtr (ig, t);
8150 ig.Emit (OpCodes.Stobj, t);
8151 else if (has_type_arg)
8158 ec.ig.Emit (OpCodes.Dup);
8159 temp = new LocalTemporary (this.type);
8164 StoreFromPtr (ig, t);
8166 int arg_count = ea.Arguments.Count;
8167 Type [] args = new Type [arg_count + 1];
8168 for (int i = 0; i < arg_count; i++) {
8169 //args [i++] = a.Type;
8170 args [i] = TypeManager.int32_type;
8172 args [arg_count] = type;
8174 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8175 ea.Expr.Type, "Set",
8176 CallingConventions.HasThis |
8177 CallingConventions.Standard,
8178 TypeManager.void_type, args);
8180 ig.Emit (OpCodes.Call, set);
8190 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8192 if (!source.Emit (ec, this)) {
8194 throw new NotImplementedException ();
8199 throw new NotImplementedException ();
8202 public void AddressOf (EmitContext ec, AddressOp mode)
8204 int rank = ea.Expr.Type.GetArrayRank ();
8205 ILGenerator ig = ec.ig;
8207 LoadArrayAndArguments (ec);
8210 ig.Emit (OpCodes.Ldelema, type);
8212 MethodInfo address = FetchAddressMethod ();
8213 ig.Emit (OpCodes.Call, address);
8217 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8219 type = storey.MutateType (type);
8220 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8225 /// Expressions that represent an indexer call.
8227 public class IndexerAccess : Expression, IAssignMethod
8229 class IndexerMethodGroupExpr : MethodGroupExpr
8231 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8234 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8237 public override string Name {
8243 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8246 // Here is the trick, decrease number of arguments by 1 when only
8247 // available property method is setter. This makes overload resolution
8248 // work correctly for indexers.
8251 if (method.Name [0] == 'g')
8252 return parameters.Count;
8254 return parameters.Count - 1;
8260 // Contains either property getter or setter
8261 public ArrayList Methods;
8262 public ArrayList Properties;
8268 void Append (Type caller_type, MemberInfo [] mi)
8273 foreach (PropertyInfo property in mi) {
8274 MethodInfo accessor = property.GetGetMethod (true);
8275 if (accessor == null)
8276 accessor = property.GetSetMethod (true);
8278 if (Methods == null) {
8279 Methods = new ArrayList ();
8280 Properties = new ArrayList ();
8283 Methods.Add (accessor);
8284 Properties.Add (property);
8288 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8290 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8292 return TypeManager.MemberLookup (
8293 caller_type, caller_type, lookup_type, MemberTypes.Property,
8294 BindingFlags.Public | BindingFlags.Instance |
8295 BindingFlags.DeclaredOnly, p_name, null);
8298 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8300 Indexers ix = new Indexers ();
8302 if (TypeManager.IsGenericParameter (lookup_type)) {
8303 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8307 if (gc.HasClassConstraint) {
8308 Type class_contraint = gc.ClassConstraint;
8309 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8310 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8311 class_contraint = class_contraint.BaseType;
8315 Type[] ifaces = gc.InterfaceConstraints;
8316 foreach (Type itype in ifaces)
8317 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8322 Type copy = lookup_type;
8323 while (copy != TypeManager.object_type && copy != null){
8324 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8325 copy = copy.BaseType;
8328 if (lookup_type.IsInterface) {
8329 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8330 if (ifaces != null) {
8331 foreach (Type itype in ifaces)
8332 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8347 // Points to our "data" repository
8349 MethodInfo get, set;
8350 bool is_base_indexer;
8352 LocalTemporary temp;
8353 LocalTemporary prepared_value;
8354 Expression set_expr;
8356 protected Type indexer_type;
8357 protected Type current_type;
8358 protected Expression instance_expr;
8359 protected ArrayList arguments;
8361 public IndexerAccess (ElementAccess ea, Location loc)
8362 : this (ea.Expr, false, loc)
8364 this.arguments = ea.Arguments;
8367 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8370 this.instance_expr = instance_expr;
8371 this.is_base_indexer = is_base_indexer;
8372 this.eclass = ExprClass.Value;
8376 static string GetAccessorName (AccessorType at)
8378 if (at == AccessorType.Set)
8381 if (at == AccessorType.Get)
8384 throw new NotImplementedException (at.ToString ());
8387 public override Expression CreateExpressionTree (EmitContext ec)
8389 ArrayList args = new ArrayList (arguments.Count + 2);
8390 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8391 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8392 foreach (Argument a in arguments)
8393 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8395 return CreateExpressionFactoryCall ("Call", args);
8398 protected virtual bool CommonResolve (EmitContext ec)
8400 indexer_type = instance_expr.Type;
8401 current_type = ec.ContainerType;
8406 public override Expression DoResolve (EmitContext ec)
8408 return ResolveAccessor (ec, AccessorType.Get);
8411 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8413 if (right_side == EmptyExpression.OutAccess) {
8414 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8415 GetSignatureForError ());
8419 // if the indexer returns a value type, and we try to set a field in it
8420 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8421 Error_CannotModifyIntermediateExpressionValue (ec);
8424 Expression e = ResolveAccessor (ec, AccessorType.Set);
8428 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8432 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8434 if (!CommonResolve (ec))
8437 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8438 if (ilist.Methods == null) {
8439 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8440 TypeManager.CSharpName (indexer_type));
8444 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8445 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8449 MethodInfo mi = (MethodInfo) mg;
8450 PropertyInfo pi = null;
8451 for (int i = 0; i < ilist.Methods.Count; ++i) {
8452 if (ilist.Methods [i] == mi) {
8453 pi = (PropertyInfo) ilist.Properties [i];
8458 type = TypeManager.TypeToCoreType (pi.PropertyType);
8459 if (type.IsPointer && !ec.InUnsafe)
8462 MethodInfo accessor;
8463 if (accessorType == AccessorType.Get) {
8464 accessor = get = pi.GetGetMethod (true);
8466 accessor = set = pi.GetSetMethod (true);
8467 if (accessor == null && pi.GetGetMethod (true) != null) {
8468 Report.SymbolRelatedToPreviousError (pi);
8469 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8470 TypeManager.GetFullNameSignature (pi));
8475 if (accessor == null) {
8476 Report.SymbolRelatedToPreviousError (pi);
8477 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8478 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8483 // Only base will allow this invocation to happen.
8485 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8486 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8489 bool must_do_cs1540_check;
8490 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8492 set = pi.GetSetMethod (true);
8494 get = pi.GetGetMethod (true);
8496 if (set != null && get != null &&
8497 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8498 Report.SymbolRelatedToPreviousError (accessor);
8499 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8500 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8502 Report.SymbolRelatedToPreviousError (pi);
8503 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8507 instance_expr.CheckMarshalByRefAccess (ec);
8508 eclass = ExprClass.IndexerAccess;
8512 public void Emit (EmitContext ec, bool leave_copy)
8515 prepared_value.Emit (ec);
8517 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8518 arguments, loc, false, false);
8522 ec.ig.Emit (OpCodes.Dup);
8523 temp = new LocalTemporary (Type);
8529 // source is ignored, because we already have a copy of it from the
8530 // LValue resolution and we have already constructed a pre-cached
8531 // version of the arguments (ea.set_arguments);
8533 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8535 prepared = prepare_for_load;
8536 Expression value = set_expr;
8539 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8540 arguments, loc, true, false);
8542 prepared_value = new LocalTemporary (type);
8543 prepared_value.Store (ec);
8545 prepared_value.Release (ec);
8548 ec.ig.Emit (OpCodes.Dup);
8549 temp = new LocalTemporary (Type);
8552 } else if (leave_copy) {
8553 temp = new LocalTemporary (Type);
8559 arguments.Add (new Argument (value, Argument.AType.Expression));
8560 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8568 public override void Emit (EmitContext ec)
8573 public override string GetSignatureForError ()
8575 return TypeManager.CSharpSignature (get != null ? get : set, false);
8578 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8581 get = storey.MutateGenericMethod (get);
8583 set = storey.MutateGenericMethod (set);
8585 instance_expr.MutateHoistedGenericType (storey);
8586 foreach (Argument a in arguments)
8587 a.Expr.MutateHoistedGenericType (storey);
8589 type = storey.MutateType (type);
8592 protected override void CloneTo (CloneContext clonectx, Expression t)
8594 IndexerAccess target = (IndexerAccess) t;
8596 if (arguments != null){
8597 target.arguments = new ArrayList ();
8598 foreach (Argument a in arguments)
8599 target.arguments.Add (a.Clone (clonectx));
8601 if (instance_expr != null)
8602 target.instance_expr = instance_expr.Clone (clonectx);
8607 /// The base operator for method names
8609 public class BaseAccess : Expression {
8610 public readonly string Identifier;
8613 public BaseAccess (string member, Location l)
8615 this.Identifier = member;
8619 public BaseAccess (string member, TypeArguments args, Location l)
8625 public override Expression CreateExpressionTree (EmitContext ec)
8627 throw new NotSupportedException ("ET");
8630 public override Expression DoResolve (EmitContext ec)
8632 Expression c = CommonResolve (ec);
8638 // MethodGroups use this opportunity to flag an error on lacking ()
8640 if (!(c is MethodGroupExpr))
8641 return c.Resolve (ec);
8645 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8647 Expression c = CommonResolve (ec);
8653 // MethodGroups use this opportunity to flag an error on lacking ()
8655 if (! (c is MethodGroupExpr))
8656 return c.DoResolveLValue (ec, right_side);
8661 Expression CommonResolve (EmitContext ec)
8663 Expression member_lookup;
8664 Type current_type = ec.ContainerType;
8665 Type base_type = current_type.BaseType;
8667 if (!This.IsThisAvailable (ec)) {
8669 Error (1511, "Keyword `base' is not available in a static method");
8671 Error (1512, "Keyword `base' is not available in the current context");
8676 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8677 AllMemberTypes, AllBindingFlags, loc);
8678 if (member_lookup == null) {
8679 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8680 null, AllMemberTypes, AllBindingFlags);
8687 left = new TypeExpression (base_type, loc);
8689 left = ec.GetThis (loc);
8691 MemberExpr me = (MemberExpr) member_lookup;
8692 me = me.ResolveMemberAccess (ec, left, loc, null);
8699 me.SetTypeArguments (args);
8705 public override void Emit (EmitContext ec)
8707 throw new Exception ("Should never be called");
8710 protected override void CloneTo (CloneContext clonectx, Expression t)
8712 BaseAccess target = (BaseAccess) t;
8715 target.args = args.Clone ();
8720 /// The base indexer operator
8722 public class BaseIndexerAccess : IndexerAccess {
8723 public BaseIndexerAccess (ArrayList args, Location loc)
8724 : base (null, true, loc)
8726 arguments = new ArrayList ();
8727 foreach (Expression tmp in args)
8728 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8731 protected override bool CommonResolve (EmitContext ec)
8733 instance_expr = ec.GetThis (loc);
8735 current_type = ec.ContainerType.BaseType;
8736 indexer_type = current_type;
8738 foreach (Argument a in arguments){
8739 if (!a.Resolve (ec, loc))
8746 public override Expression CreateExpressionTree (EmitContext ec)
8748 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8749 return base.CreateExpressionTree (ec);
8754 /// This class exists solely to pass the Type around and to be a dummy
8755 /// that can be passed to the conversion functions (this is used by
8756 /// foreach implementation to typecast the object return value from
8757 /// get_Current into the proper type. All code has been generated and
8758 /// we only care about the side effect conversions to be performed
8760 /// This is also now used as a placeholder where a no-action expression
8761 /// is needed (the `New' class).
8763 public class EmptyExpression : Expression {
8764 public static readonly Expression Null = new EmptyExpression ();
8766 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8767 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8768 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8769 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8771 static EmptyExpression temp = new EmptyExpression ();
8772 public static EmptyExpression Grab ()
8774 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8779 public static void Release (EmptyExpression e)
8786 // FIXME: Don't set to object
8787 type = TypeManager.object_type;
8788 eclass = ExprClass.Value;
8789 loc = Location.Null;
8792 public EmptyExpression (Type t)
8795 eclass = ExprClass.Value;
8796 loc = Location.Null;
8799 public override Expression CreateExpressionTree (EmitContext ec)
8801 throw new NotSupportedException ("ET");
8804 public override Expression DoResolve (EmitContext ec)
8809 public override void Emit (EmitContext ec)
8811 // nothing, as we only exist to not do anything.
8814 public override void EmitSideEffect (EmitContext ec)
8819 // This is just because we might want to reuse this bad boy
8820 // instead of creating gazillions of EmptyExpressions.
8821 // (CanImplicitConversion uses it)
8823 public void SetType (Type t)
8830 // Empty statement expression
8832 public sealed class EmptyExpressionStatement : ExpressionStatement
8834 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8836 private EmptyExpressionStatement ()
8838 eclass = ExprClass.Value;
8839 loc = Location.Null;
8842 public override Expression CreateExpressionTree (EmitContext ec)
8847 public override void EmitStatement (EmitContext ec)
8852 public override Expression DoResolve (EmitContext ec)
8854 type = TypeManager.object_type;
8858 public override void Emit (EmitContext ec)
8864 public class UserCast : Expression {
8868 public UserCast (MethodInfo method, Expression source, Location l)
8870 this.method = method;
8871 this.source = source;
8872 type = TypeManager.TypeToCoreType (method.ReturnType);
8876 public Expression Source {
8882 public override Expression CreateExpressionTree (EmitContext ec)
8884 ArrayList args = new ArrayList (3);
8885 args.Add (new Argument (source.CreateExpressionTree (ec)));
8886 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8887 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8888 return CreateExpressionFactoryCall ("Convert", args);
8891 public override Expression DoResolve (EmitContext ec)
8893 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8895 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8897 eclass = ExprClass.Value;
8901 public override void Emit (EmitContext ec)
8904 ec.ig.Emit (OpCodes.Call, method);
8907 public override string GetSignatureForError ()
8909 return TypeManager.CSharpSignature (method);
8912 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8914 source.MutateHoistedGenericType (storey);
8915 method = storey.MutateGenericMethod (method);
8920 // This class is used to "construct" the type during a typecast
8921 // operation. Since the Type.GetType class in .NET can parse
8922 // the type specification, we just use this to construct the type
8923 // one bit at a time.
8925 public class ComposedCast : TypeExpr {
8926 FullNamedExpression left;
8929 public ComposedCast (FullNamedExpression left, string dim)
8930 : this (left, dim, left.Location)
8934 public ComposedCast (FullNamedExpression left, string dim, Location l)
8941 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8943 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8947 Type ltype = lexpr.Type;
8948 if ((dim.Length > 0) && (dim [0] == '?')) {
8949 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8951 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8952 return nullable.ResolveAsTypeTerminal (ec, false);
8955 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8958 if (dim.Length != 0 && dim [0] == '[') {
8959 if (TypeManager.IsSpecialType (ltype)) {
8960 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8964 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8965 Report.SymbolRelatedToPreviousError (ltype);
8966 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8967 TypeManager.CSharpName (ltype));
8972 type = TypeManager.GetConstructedType (ltype, dim);
8977 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8979 if (type.IsPointer && !ec.IsInUnsafeScope){
8983 eclass = ExprClass.Type;
8987 public override string GetSignatureForError ()
8989 return left.GetSignatureForError () + dim;
8992 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8994 return ResolveAsBaseTerminal (ec, silent);
8998 public class FixedBufferPtr : Expression {
9001 public FixedBufferPtr (Expression array, Type array_type, Location l)
9006 type = TypeManager.GetPointerType (array_type);
9007 eclass = ExprClass.Value;
9010 public override Expression CreateExpressionTree (EmitContext ec)
9012 Error_PointerInsideExpressionTree ();
9016 public override void Emit(EmitContext ec)
9021 public override Expression DoResolve (EmitContext ec)
9024 // We are born fully resolved
9032 // This class is used to represent the address of an array, used
9033 // only by the Fixed statement, this generates "&a [0]" construct
9034 // for fixed (char *pa = a)
9036 public class ArrayPtr : FixedBufferPtr {
9039 public ArrayPtr (Expression array, Type array_type, Location l):
9040 base (array, array_type, l)
9042 this.array_type = array_type;
9045 public override void Emit (EmitContext ec)
9049 ILGenerator ig = ec.ig;
9050 IntLiteral.EmitInt (ig, 0);
9051 ig.Emit (OpCodes.Ldelema, array_type);
9056 // Encapsulates a conversion rules required for array indexes
9058 public class ArrayIndexCast : TypeCast
9060 public ArrayIndexCast (Expression expr)
9061 : base (expr, expr.Type)
9065 public override Expression CreateExpressionTree (EmitContext ec)
9067 ArrayList args = new ArrayList (2);
9068 args.Add (new Argument (child.CreateExpressionTree (ec)));
9069 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9070 return CreateExpressionFactoryCall ("ConvertChecked", args);
9073 public override void Emit (EmitContext ec)
9077 if (type == TypeManager.int32_type)
9080 if (type == TypeManager.uint32_type)
9081 ec.ig.Emit (OpCodes.Conv_U);
9082 else if (type == TypeManager.int64_type)
9083 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9084 else if (type == TypeManager.uint64_type)
9085 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9087 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9092 // Implements the `stackalloc' keyword
9094 public class StackAlloc : Expression {
9099 public StackAlloc (Expression type, Expression count, Location l)
9106 public override Expression CreateExpressionTree (EmitContext ec)
9108 throw new NotSupportedException ("ET");
9111 public override Expression DoResolve (EmitContext ec)
9113 count = count.Resolve (ec);
9117 if (count.Type != TypeManager.uint32_type){
9118 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9123 Constant c = count as Constant;
9124 if (c != null && c.IsNegative) {
9125 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9129 if (ec.InCatch || ec.InFinally) {
9130 Error (255, "Cannot use stackalloc in finally or catch");
9134 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9140 if (!TypeManager.VerifyUnManaged (otype, loc))
9143 type = TypeManager.GetPointerType (otype);
9144 eclass = ExprClass.Value;
9149 public override void Emit (EmitContext ec)
9151 int size = GetTypeSize (otype);
9152 ILGenerator ig = ec.ig;
9157 ig.Emit (OpCodes.Sizeof, otype);
9159 IntConstant.EmitInt (ig, size);
9161 ig.Emit (OpCodes.Mul_Ovf_Un);
9162 ig.Emit (OpCodes.Localloc);
9165 protected override void CloneTo (CloneContext clonectx, Expression t)
9167 StackAlloc target = (StackAlloc) t;
9168 target.count = count.Clone (clonectx);
9169 target.t = t.Clone (clonectx);
9174 // An object initializer expression
9176 public class ElementInitializer : Assign
9178 public readonly string Name;
9180 public ElementInitializer (string name, Expression initializer, Location loc)
9181 : base (null, initializer, loc)
9186 protected override void CloneTo (CloneContext clonectx, Expression t)
9188 ElementInitializer target = (ElementInitializer) t;
9189 target.source = source.Clone (clonectx);
9192 public override Expression CreateExpressionTree (EmitContext ec)
9194 ArrayList args = new ArrayList (2);
9195 FieldExpr fe = target as FieldExpr;
9197 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9199 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9201 args.Add (new Argument (source.CreateExpressionTree (ec)));
9202 return CreateExpressionFactoryCall (
9203 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9207 public override Expression DoResolve (EmitContext ec)
9210 return EmptyExpressionStatement.Instance;
9212 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9213 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9219 me.InstanceExpression = ec.CurrentInitializerVariable;
9221 if (source is CollectionOrObjectInitializers) {
9222 Expression previous = ec.CurrentInitializerVariable;
9223 ec.CurrentInitializerVariable = target;
9224 source = source.Resolve (ec);
9225 ec.CurrentInitializerVariable = previous;
9229 eclass = source.eclass;
9234 Expression expr = base.DoResolve (ec);
9239 // Ignore field initializers with default value
9241 Constant c = source as Constant;
9242 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9243 return EmptyExpressionStatement.Instance.DoResolve (ec);
9248 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9250 MemberInfo member = members [0];
9251 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9252 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9253 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9255 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9256 TypeManager.GetFullNameSignature (member));
9261 public override void EmitStatement (EmitContext ec)
9263 if (source is CollectionOrObjectInitializers)
9266 base.EmitStatement (ec);
9271 // A collection initializer expression
9273 public class CollectionElementInitializer : Invocation
9275 public class ElementInitializerArgument : Argument
9277 public ElementInitializerArgument (Expression e)
9283 sealed class AddMemberAccess : MemberAccess
9285 public AddMemberAccess (Expression expr, Location loc)
9286 : base (expr, "Add", loc)
9290 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9292 if (TypeManager.HasElementType (type))
9295 base.Error_TypeDoesNotContainDefinition (type, name);
9299 public CollectionElementInitializer (Expression argument)
9300 : base (null, new ArrayList (1), true)
9302 Arguments.Add (argument);
9303 this.loc = argument.Location;
9306 public CollectionElementInitializer (ArrayList arguments, Location loc)
9307 : base (null, arguments, true)
9312 public override Expression CreateExpressionTree (EmitContext ec)
9314 ArrayList args = new ArrayList (2);
9315 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9317 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9318 foreach (Argument a in Arguments)
9319 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9321 args.Add (new Argument (new ArrayCreation (
9322 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9323 return CreateExpressionFactoryCall ("ElementInit", args);
9326 protected override void CloneTo (CloneContext clonectx, Expression t)
9328 CollectionElementInitializer target = (CollectionElementInitializer) t;
9330 target.Arguments = new ArrayList (Arguments.Count);
9331 foreach (Expression e in Arguments)
9332 target.Arguments.Add (e.Clone (clonectx));
9335 public override Expression DoResolve (EmitContext ec)
9337 if (eclass != ExprClass.Invalid)
9340 // TODO: We could call a constructor which takes element count argument,
9341 // for known types like List<T>, Dictionary<T, U>
9343 for (int i = 0; i < Arguments.Count; ++i) {
9344 Expression expr = Arguments [i] as Expression;
9348 expr = expr.Resolve (ec);
9352 Arguments [i] = new ElementInitializerArgument (expr);
9355 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9357 return base.DoResolve (ec);
9362 // A block of object or collection initializers
9364 public class CollectionOrObjectInitializers : ExpressionStatement
9366 ArrayList initializers;
9367 bool is_collection_initialization;
9369 public static readonly CollectionOrObjectInitializers Empty =
9370 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9372 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9374 this.initializers = initializers;
9378 public bool IsEmpty {
9380 return initializers.Count == 0;
9384 public bool IsCollectionInitializer {
9386 return is_collection_initialization;
9390 protected override void CloneTo (CloneContext clonectx, Expression target)
9392 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9394 t.initializers = new ArrayList (initializers.Count);
9395 foreach (Expression e in initializers)
9396 t.initializers.Add (e.Clone (clonectx));
9399 public override Expression CreateExpressionTree (EmitContext ec)
9401 ArrayList expr_initializers = new ArrayList (initializers.Count);
9402 foreach (Expression e in initializers) {
9403 Expression expr = e.CreateExpressionTree (ec);
9405 expr_initializers.Add (expr);
9408 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9411 public override Expression DoResolve (EmitContext ec)
9413 if (eclass != ExprClass.Invalid)
9416 ArrayList element_names = null;
9417 for (int i = 0; i < initializers.Count; ++i) {
9418 Expression initializer = (Expression) initializers [i];
9419 ElementInitializer element_initializer = initializer as ElementInitializer;
9422 if (element_initializer != null) {
9423 element_names = new ArrayList (initializers.Count);
9424 element_names.Add (element_initializer.Name);
9425 } else if (initializer is CompletingExpression){
9426 initializer.Resolve (ec);
9427 throw new InternalErrorException ("This line should never be reached");
9429 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9430 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9431 "object initializer because type `{1}' does not implement `{2}' interface",
9432 ec.CurrentInitializerVariable.GetSignatureForError (),
9433 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9434 TypeManager.CSharpName (TypeManager.ienumerable_type));
9437 is_collection_initialization = true;
9440 if (is_collection_initialization != (element_initializer == null)) {
9441 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9442 is_collection_initialization ? "collection initializer" : "object initializer");
9446 if (!is_collection_initialization) {
9447 if (element_names.Contains (element_initializer.Name)) {
9448 Report.Error (1912, element_initializer.Location,
9449 "An object initializer includes more than one member `{0}' initialization",
9450 element_initializer.Name);
9452 element_names.Add (element_initializer.Name);
9457 Expression e = initializer.Resolve (ec);
9458 if (e == EmptyExpressionStatement.Instance)
9459 initializers.RemoveAt (i--);
9461 initializers [i] = e;
9464 type = ec.CurrentInitializerVariable.Type;
9465 if (is_collection_initialization) {
9466 if (TypeManager.HasElementType (type)) {
9467 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9468 TypeManager.CSharpName (type));
9472 eclass = ExprClass.Variable;
9476 public override void Emit (EmitContext ec)
9481 public override void EmitStatement (EmitContext ec)
9483 foreach (ExpressionStatement e in initializers)
9484 e.EmitStatement (ec);
9487 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9489 foreach (Expression e in initializers)
9490 e.MutateHoistedGenericType (storey);
9495 // New expression with element/object initializers
9497 public class NewInitialize : New
9500 // This class serves as a proxy for variable initializer target instances.
9501 // A real variable is assigned later when we resolve left side of an
9504 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9506 NewInitialize new_instance;
9508 public InitializerTargetExpression (NewInitialize newInstance)
9510 this.type = newInstance.type;
9511 this.loc = newInstance.loc;
9512 this.eclass = newInstance.eclass;
9513 this.new_instance = newInstance;
9516 public override Expression CreateExpressionTree (EmitContext ec)
9518 // Should not be reached
9519 throw new NotSupportedException ("ET");
9522 public override Expression DoResolve (EmitContext ec)
9527 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9532 public override void Emit (EmitContext ec)
9534 Expression e = (Expression) new_instance.instance;
9538 #region IMemoryLocation Members
9540 public void AddressOf (EmitContext ec, AddressOp mode)
9542 new_instance.instance.AddressOf (ec, mode);
9548 CollectionOrObjectInitializers initializers;
9549 IMemoryLocation instance;
9551 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9552 : base (requested_type, arguments, l)
9554 this.initializers = initializers;
9557 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9559 instance = base.EmitAddressOf (ec, Mode);
9561 if (!initializers.IsEmpty)
9562 initializers.Emit (ec);
9567 protected override void CloneTo (CloneContext clonectx, Expression t)
9569 base.CloneTo (clonectx, t);
9571 NewInitialize target = (NewInitialize) t;
9572 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9575 public override Expression CreateExpressionTree (EmitContext ec)
9577 ArrayList args = new ArrayList (2);
9578 args.Add (new Argument (base.CreateExpressionTree (ec)));
9579 if (!initializers.IsEmpty)
9580 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9582 return CreateExpressionFactoryCall (
9583 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9587 public override Expression DoResolve (EmitContext ec)
9589 if (eclass != ExprClass.Invalid)
9592 Expression e = base.DoResolve (ec);
9596 Expression previous = ec.CurrentInitializerVariable;
9597 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9598 initializers.Resolve (ec);
9599 ec.CurrentInitializerVariable = previous;
9603 public override bool Emit (EmitContext ec, IMemoryLocation target)
9605 bool left_on_stack = base.Emit (ec, target);
9607 if (initializers.IsEmpty)
9608 return left_on_stack;
9610 LocalTemporary temp = target as LocalTemporary;
9612 if (!left_on_stack) {
9613 VariableReference vr = target as VariableReference;
9615 // FIXME: This still does not work correctly for pre-set variables
9616 if (vr != null && vr.IsRef)
9617 target.AddressOf (ec, AddressOp.Load);
9619 ((Expression) target).Emit (ec);
9620 left_on_stack = true;
9623 temp = new LocalTemporary (type);
9630 initializers.Emit (ec);
9632 if (left_on_stack) {
9637 return left_on_stack;
9640 public override bool HasInitializer {
9642 return !initializers.IsEmpty;
9646 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9648 base.MutateHoistedGenericType (storey);
9649 initializers.MutateHoistedGenericType (storey);
9653 public class AnonymousTypeDeclaration : Expression
9655 ArrayList parameters;
9656 readonly TypeContainer parent;
9657 static readonly ArrayList EmptyParameters = new ArrayList (0);
9659 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9661 this.parameters = parameters;
9662 this.parent = parent;
9666 protected override void CloneTo (CloneContext clonectx, Expression target)
9668 if (parameters == null)
9671 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9672 t.parameters = new ArrayList (parameters.Count);
9673 foreach (AnonymousTypeParameter atp in parameters)
9674 t.parameters.Add (atp.Clone (clonectx));
9677 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9679 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9683 type = AnonymousTypeClass.Create (parent, parameters, loc);
9690 if (Report.Errors == 0)
9693 parent.Module.AddAnonymousType (type);
9697 public override Expression CreateExpressionTree (EmitContext ec)
9699 throw new NotSupportedException ("ET");
9702 public override Expression DoResolve (EmitContext ec)
9704 AnonymousTypeClass anonymous_type;
9706 if (!ec.IsAnonymousMethodAllowed) {
9707 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9711 if (parameters == null) {
9712 anonymous_type = CreateAnonymousType (EmptyParameters);
9713 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9714 null, loc).Resolve (ec);
9718 ArrayList arguments = new ArrayList (parameters.Count);
9719 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9720 for (int i = 0; i < parameters.Count; ++i) {
9721 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9727 arguments.Add (new Argument (e));
9728 t_args [i] = new TypeExpression (e.Type, e.Location);
9734 anonymous_type = CreateAnonymousType (parameters);
9735 if (anonymous_type == null)
9738 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9739 new TypeArguments (t_args), loc);
9741 return new New (te, arguments, loc).Resolve (ec);
9744 public override void Emit (EmitContext ec)
9746 throw new InternalErrorException ("Should not be reached");
9750 public class AnonymousTypeParameter : Expression
9752 public readonly string Name;
9753 Expression initializer;
9755 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9759 this.initializer = initializer;
9762 public AnonymousTypeParameter (Parameter parameter)
9764 this.Name = parameter.Name;
9765 this.loc = parameter.Location;
9766 this.initializer = new SimpleName (Name, loc);
9769 protected override void CloneTo (CloneContext clonectx, Expression target)
9771 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9772 t.initializer = initializer.Clone (clonectx);
9775 public override Expression CreateExpressionTree (EmitContext ec)
9777 throw new NotSupportedException ("ET");
9780 public override bool Equals (object o)
9782 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9783 return other != null && Name == other.Name;
9786 public override int GetHashCode ()
9788 return Name.GetHashCode ();
9791 public override Expression DoResolve (EmitContext ec)
9793 Expression e = initializer.Resolve (ec);
9797 if (e.eclass == ExprClass.MethodGroup) {
9798 Error_InvalidInitializer (e.ExprClassName);
9803 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9804 type == TypeManager.anonymous_method_type || type.IsPointer) {
9805 Error_InvalidInitializer (e.GetSignatureForError ());
9812 protected virtual void Error_InvalidInitializer (string initializer)
9814 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9818 public override void Emit (EmitContext ec)
9820 throw new InternalErrorException ("Should not be reached");