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 void Emit (EmitContext ec)
111 throw new Exception ("Should not happen");
114 protected override void CloneTo (CloneContext clonectx, Expression t)
116 ParenthesizedExpression target = (ParenthesizedExpression) t;
118 target.Expr = Expr.Clone (clonectx);
123 // Unary implements unary expressions.
125 public class Unary : Expression {
126 public enum Operator : byte {
127 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 static Type [] [] predefined_operators;
133 public readonly Operator Oper;
134 public Expression Expr;
135 Expression enum_conversion;
137 public Unary (Operator op, Expression expr, Location loc)
145 // This routine will attempt to simplify the unary expression when the
146 // argument is a constant.
148 Constant TryReduceConstant (EmitContext ec, Constant e)
150 if (e is EmptyConstantCast)
151 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
153 if (e is SideEffectConstant) {
154 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
155 return r == null ? null : new SideEffectConstant (r, e, r.Location);
158 Type expr_type = e.Type;
161 case Operator.UnaryPlus:
162 // Unary numeric promotions
163 if (expr_type == TypeManager.byte_type)
164 return new IntConstant (((ByteConstant)e).Value, e.Location);
165 if (expr_type == TypeManager.sbyte_type)
166 return new IntConstant (((SByteConstant)e).Value, e.Location);
167 if (expr_type == TypeManager.short_type)
168 return new IntConstant (((ShortConstant)e).Value, e.Location);
169 if (expr_type == TypeManager.ushort_type)
170 return new IntConstant (((UShortConstant)e).Value, e.Location);
171 if (expr_type == TypeManager.char_type)
172 return new IntConstant (((CharConstant)e).Value, e.Location);
174 // Predefined operators
175 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
176 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
177 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
178 expr_type == TypeManager.decimal_type) {
184 case Operator.UnaryNegation:
185 // Unary numeric promotions
186 if (expr_type == TypeManager.byte_type)
187 return new IntConstant (-((ByteConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.sbyte_type)
189 return new IntConstant (-((SByteConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.short_type)
191 return new IntConstant (-((ShortConstant)e).Value, e.Location);
192 if (expr_type == TypeManager.ushort_type)
193 return new IntConstant (-((UShortConstant)e).Value, e.Location);
194 if (expr_type == TypeManager.char_type)
195 return new IntConstant (-((CharConstant)e).Value, e.Location);
197 // Predefined operators
198 if (expr_type == TypeManager.int32_type) {
199 int value = ((IntConstant)e).Value;
200 if (value == int.MinValue) {
201 if (ec.ConstantCheckState) {
202 ConstantFold.Error_CompileTimeOverflow (loc);
207 return new IntConstant (-value, e.Location);
209 if (expr_type == TypeManager.int64_type) {
210 long value = ((LongConstant)e).Value;
211 if (value == long.MinValue) {
212 if (ec.ConstantCheckState) {
213 ConstantFold.Error_CompileTimeOverflow (loc);
218 return new LongConstant (-value, e.Location);
221 if (expr_type == TypeManager.uint32_type) {
222 UIntLiteral uil = e as UIntLiteral;
224 if (uil.Value == 2147483648)
225 return new IntLiteral (int.MinValue, e.Location);
226 return new LongLiteral (-uil.Value, e.Location);
228 return new LongConstant (-((UIntConstant)e).Value, e.Location);
231 if (expr_type == TypeManager.uint64_type) {
232 ULongLiteral ull = e as ULongLiteral;
233 if (ull != null && ull.Value == 9223372036854775808)
234 return new LongLiteral (long.MinValue, e.Location);
238 if (expr_type == TypeManager.float_type) {
239 FloatLiteral fl = e as FloatLiteral;
240 // For better error reporting
242 fl.Value = -fl.Value;
245 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
247 if (expr_type == TypeManager.double_type) {
248 DoubleLiteral dl = e as DoubleLiteral;
249 // For better error reporting
251 dl.Value = -dl.Value;
255 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
257 if (expr_type == TypeManager.decimal_type)
258 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
262 case Operator.LogicalNot:
263 if (expr_type != TypeManager.bool_type)
266 bool b = (bool)e.GetValue ();
267 return new BoolConstant (!b, e.Location);
269 case Operator.OnesComplement:
270 // Unary numeric promotions
271 if (expr_type == TypeManager.byte_type)
272 return new IntConstant (~((ByteConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.sbyte_type)
274 return new IntConstant (~((SByteConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.short_type)
276 return new IntConstant (~((ShortConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.ushort_type)
278 return new IntConstant (~((UShortConstant)e).Value, e.Location);
279 if (expr_type == TypeManager.char_type)
280 return new IntConstant (~((CharConstant)e).Value, e.Location);
282 // Predefined operators
283 if (expr_type == TypeManager.int32_type)
284 return new IntConstant (~((IntConstant)e).Value, e.Location);
285 if (expr_type == TypeManager.uint32_type)
286 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
287 if (expr_type == TypeManager.int64_type)
288 return new LongConstant (~((LongConstant)e).Value, e.Location);
289 if (expr_type == TypeManager.uint64_type){
290 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
292 if (e is EnumConstant) {
293 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
295 e = new EnumConstant (e, expr_type);
300 throw new Exception ("Can not constant fold: " + Oper.ToString());
303 protected Expression ResolveOperator (EmitContext ec, Expression expr)
305 eclass = ExprClass.Value;
307 if (predefined_operators == null)
308 CreatePredefinedOperatorsTable ();
310 Type expr_type = expr.Type;
311 Expression best_expr;
314 // Primitive types first
316 if (TypeManager.IsPrimitiveType (expr_type)) {
317 best_expr = ResolvePrimitivePredefinedType (expr);
318 if (best_expr == null)
321 type = best_expr.Type;
327 // E operator ~(E x);
329 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
330 return ResolveEnumOperator (ec, expr);
332 return ResolveUserType (ec, expr);
335 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
337 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
338 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
339 if (best_expr == null)
343 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
345 return EmptyCast.Create (this, type);
348 public override Expression CreateExpressionTree (EmitContext ec)
350 return CreateExpressionTree (ec, null);
353 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
357 case Operator.AddressOf:
358 Error_PointerInsideExpressionTree ();
360 case Operator.UnaryNegation:
361 if (ec.CheckState && user_op == null && !IsFloat (type))
362 method_name = "NegateChecked";
364 method_name = "Negate";
366 case Operator.OnesComplement:
367 case Operator.LogicalNot:
370 case Operator.UnaryPlus:
371 method_name = "UnaryPlus";
374 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
377 ArrayList args = new ArrayList (2);
378 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
380 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
381 return CreateExpressionFactoryCall (method_name, args);
384 static void CreatePredefinedOperatorsTable ()
386 predefined_operators = new Type [(int) Operator.TOP] [];
389 // 7.6.1 Unary plus operator
391 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
392 TypeManager.int32_type, TypeManager.uint32_type,
393 TypeManager.int64_type, TypeManager.uint64_type,
394 TypeManager.float_type, TypeManager.double_type,
395 TypeManager.decimal_type
399 // 7.6.2 Unary minus operator
401 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
402 TypeManager.int32_type,
403 TypeManager.int64_type,
404 TypeManager.float_type, TypeManager.double_type,
405 TypeManager.decimal_type
409 // 7.6.3 Logical negation operator
411 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
412 TypeManager.bool_type
416 // 7.6.4 Bitwise complement operator
418 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
419 TypeManager.int32_type, TypeManager.uint32_type,
420 TypeManager.int64_type, TypeManager.uint64_type
425 // Unary numeric promotions
427 static Expression DoNumericPromotion (Operator op, Expression expr)
429 Type expr_type = expr.Type;
430 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
431 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
432 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
433 expr_type == TypeManager.char_type)
434 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
436 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
437 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
442 public override Expression DoResolve (EmitContext ec)
444 if (Oper == Operator.AddressOf) {
445 return ResolveAddressOf (ec);
448 Expr = Expr.Resolve (ec);
452 if (TypeManager.IsNullableValueType (Expr.Type))
453 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
456 // Attempt to use a constant folding operation.
458 Constant cexpr = Expr as Constant;
460 cexpr = TryReduceConstant (ec, cexpr);
465 Expression expr = ResolveOperator (ec, Expr);
467 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
470 // Reduce unary operator on predefined types
472 if (expr == this && Oper == Operator.UnaryPlus)
478 public override Expression DoResolveLValue (EmitContext ec, Expression right)
483 public override void Emit (EmitContext ec)
485 EmitOperator (ec, type);
488 protected void EmitOperator (EmitContext ec, Type type)
490 ILGenerator ig = ec.ig;
493 case Operator.UnaryPlus:
497 case Operator.UnaryNegation:
498 if (ec.CheckState && !IsFloat (type)) {
499 ig.Emit (OpCodes.Ldc_I4_0);
500 if (type == TypeManager.int64_type)
501 ig.Emit (OpCodes.Conv_U8);
503 ig.Emit (OpCodes.Sub_Ovf);
506 ig.Emit (OpCodes.Neg);
511 case Operator.LogicalNot:
513 ig.Emit (OpCodes.Ldc_I4_0);
514 ig.Emit (OpCodes.Ceq);
517 case Operator.OnesComplement:
519 ig.Emit (OpCodes.Not);
522 case Operator.AddressOf:
523 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
527 throw new Exception ("This should not happen: Operator = "
532 // Same trick as in Binary expression
534 if (enum_conversion != null)
535 enum_conversion.Emit (ec);
538 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
540 if (Oper == Operator.LogicalNot)
541 Expr.EmitBranchable (ec, target, !on_true);
543 base.EmitBranchable (ec, target, on_true);
546 public override void EmitSideEffect (EmitContext ec)
548 Expr.EmitSideEffect (ec);
551 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
553 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
554 oper, TypeManager.CSharpName (t));
557 static bool IsFloat (Type t)
559 return t == TypeManager.float_type || t == TypeManager.double_type;
563 // Returns a stringified representation of the Operator
565 public static string OperName (Operator oper)
568 case Operator.UnaryPlus:
570 case Operator.UnaryNegation:
572 case Operator.LogicalNot:
574 case Operator.OnesComplement:
576 case Operator.AddressOf:
580 throw new NotImplementedException (oper.ToString ());
583 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
585 type = storey.MutateType (type);
586 Expr.MutateHoistedGenericType (storey);
589 Expression ResolveAddressOf (EmitContext ec)
594 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
595 if (Expr == null || Expr.eclass != ExprClass.Variable) {
596 Error (211, "Cannot take the address of the given expression");
600 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
604 IVariableReference vr = Expr as IVariableReference;
607 VariableInfo vi = vr.VariableInfo;
609 if (vi.LocalInfo != null)
610 vi.LocalInfo.Used = true;
613 // A variable is considered definitely assigned if you take its address.
618 is_fixed = vr.IsFixed;
619 vr.SetHasAddressTaken ();
622 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
626 // A pointer-indirection is always fixed
628 is_fixed = Expr is Indirection;
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, Location l)
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 // Step 1: Perform Operator Overload location
950 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
951 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
953 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
955 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
958 ArrayList args = new ArrayList (1);
959 args.Add (new Argument (expr, Argument.AType.Expression));
960 mg = mg.OverloadResolve (ec, ref args, false, loc);
964 method = new UserOperatorCall (mg, args, null, loc);
965 Convert.ImplicitConversionRequired (ec, method, type, loc);
969 if (!IsIncrementableNumber (type)) {
970 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
971 TypeManager.CSharpName (type) + "'");
976 // The operand of the prefix/postfix increment decrement operators
977 // should be an expression that is classified as a variable,
978 // a property access or an indexer access
980 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
981 expr = expr.ResolveLValue (ec, expr, Location);
983 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
989 public override Expression CreateExpressionTree (EmitContext ec)
991 return new SimpleAssign (this, this).CreateExpressionTree (ec);
994 public override Expression DoResolve (EmitContext ec)
996 expr = expr.Resolve (ec);
1001 eclass = ExprClass.Value;
1004 if (TypeManager.IsNullableValueType (expr.Type))
1005 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1008 return ResolveOperator (ec);
1012 // Loads the proper "1" into the stack based on the type, then it emits the
1013 // opcode for the operation requested
1015 void LoadOneAndEmitOp (EmitContext ec, Type t)
1018 // Measure if getting the typecode and using that is more/less efficient
1019 // that comparing types. t.GetTypeCode() is an internal call.
1021 ILGenerator ig = ec.ig;
1023 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1024 LongConstant.EmitLong (ig, 1);
1025 else if (t == TypeManager.double_type)
1026 ig.Emit (OpCodes.Ldc_R8, 1.0);
1027 else if (t == TypeManager.float_type)
1028 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1029 else if (t.IsPointer){
1030 Type et = TypeManager.GetElementType (t);
1031 int n = GetTypeSize (et);
1034 ig.Emit (OpCodes.Sizeof, et);
1036 IntConstant.EmitInt (ig, n);
1037 ig.Emit (OpCodes.Conv_I);
1040 ig.Emit (OpCodes.Ldc_I4_1);
1043 // Now emit the operation
1046 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1047 Binary.EmitOperatorOpcode (ec, op, t);
1049 if (t == TypeManager.sbyte_type){
1051 ig.Emit (OpCodes.Conv_Ovf_I1);
1053 ig.Emit (OpCodes.Conv_I1);
1054 } else if (t == TypeManager.byte_type){
1056 ig.Emit (OpCodes.Conv_Ovf_U1);
1058 ig.Emit (OpCodes.Conv_U1);
1059 } else if (t == TypeManager.short_type){
1061 ig.Emit (OpCodes.Conv_Ovf_I2);
1063 ig.Emit (OpCodes.Conv_I2);
1064 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1066 ig.Emit (OpCodes.Conv_Ovf_U2);
1068 ig.Emit (OpCodes.Conv_U2);
1073 void EmitCode (EmitContext ec, bool is_expr)
1076 this.is_expr = is_expr;
1077 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1080 public override void Emit (EmitContext ec)
1083 // We use recurse to allow ourselfs to be the source
1084 // of an assignment. This little hack prevents us from
1085 // having to allocate another expression
1088 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1090 LoadOneAndEmitOp (ec, expr.Type);
1092 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1097 EmitCode (ec, true);
1100 public override void EmitStatement (EmitContext ec)
1102 EmitCode (ec, false);
1105 protected override void CloneTo (CloneContext clonectx, Expression t)
1107 UnaryMutator target = (UnaryMutator) t;
1109 target.expr = expr.Clone (clonectx);
1114 /// Base class for the `Is' and `As' classes.
1118 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1121 public abstract class Probe : Expression {
1122 public Expression ProbeType;
1123 protected Expression expr;
1124 protected TypeExpr probe_type_expr;
1126 public Probe (Expression expr, Expression probe_type, Location l)
1128 ProbeType = probe_type;
1133 public Expression Expr {
1139 public override Expression DoResolve (EmitContext ec)
1141 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1142 if (probe_type_expr == null)
1145 expr = expr.Resolve (ec);
1149 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1150 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1154 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1155 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1160 if (expr.Type == TypeManager.anonymous_method_type) {
1161 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1169 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1171 expr.MutateHoistedGenericType (storey);
1172 probe_type_expr.MutateHoistedGenericType (storey);
1175 protected abstract string OperatorName { get; }
1177 protected override void CloneTo (CloneContext clonectx, Expression t)
1179 Probe target = (Probe) t;
1181 target.expr = expr.Clone (clonectx);
1182 target.ProbeType = ProbeType.Clone (clonectx);
1188 /// Implementation of the `is' operator.
1190 public class Is : Probe {
1191 Nullable.Unwrap expr_unwrap;
1193 public Is (Expression expr, Expression probe_type, Location l)
1194 : base (expr, probe_type, l)
1198 public override Expression CreateExpressionTree (EmitContext ec)
1200 ArrayList args = new ArrayList (2);
1201 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1202 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1203 return CreateExpressionFactoryCall ("TypeIs", args);
1206 public override void Emit (EmitContext ec)
1208 ILGenerator ig = ec.ig;
1209 if (expr_unwrap != null) {
1210 expr_unwrap.EmitCheck (ec);
1215 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1216 ig.Emit (OpCodes.Ldnull);
1217 ig.Emit (OpCodes.Cgt_Un);
1220 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1222 ILGenerator ig = ec.ig;
1223 if (expr_unwrap != null) {
1224 expr_unwrap.EmitCheck (ec);
1227 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1229 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1232 Expression CreateConstantResult (bool result)
1235 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1236 TypeManager.CSharpName (probe_type_expr.Type));
1238 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1244 public override Expression DoResolve (EmitContext ec)
1246 if (base.DoResolve (ec) == null)
1250 bool d_is_nullable = false;
1253 // If E is a method group or the null literal, or if the type of E is a reference
1254 // type or a nullable type and the value of E is null, the result is false
1256 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1257 return CreateConstantResult (false);
1259 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1260 d = TypeManager.GetTypeArguments (d) [0];
1261 d_is_nullable = true;
1264 type = TypeManager.bool_type;
1265 eclass = ExprClass.Value;
1266 Type t = probe_type_expr.Type;
1267 bool t_is_nullable = false;
1268 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1269 t = TypeManager.GetTypeArguments (t) [0];
1270 t_is_nullable = true;
1273 if (t.IsValueType) {
1276 // D and T are the same value types but D can be null
1278 if (d_is_nullable && !t_is_nullable) {
1279 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1284 // The result is true if D and T are the same value types
1286 return CreateConstantResult (true);
1289 if (TypeManager.IsGenericParameter (d))
1290 return ResolveGenericParameter (t, d);
1293 // An unboxing conversion exists
1295 if (Convert.ExplicitReferenceConversionExists (d, t))
1298 if (TypeManager.IsGenericParameter (t))
1299 return ResolveGenericParameter (d, t);
1301 if (d.IsValueType) {
1303 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1304 return CreateConstantResult (true);
1306 if (TypeManager.IsGenericParameter (d))
1307 return ResolveGenericParameter (t, d);
1309 if (TypeManager.ContainsGenericParameters (d))
1312 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1313 Convert.ExplicitReferenceConversionExists (d, t)) {
1319 return CreateConstantResult (false);
1322 Expression ResolveGenericParameter (Type d, Type t)
1325 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1326 if (constraints != null) {
1327 if (constraints.IsReferenceType && d.IsValueType)
1328 return CreateConstantResult (false);
1330 if (constraints.IsValueType && !d.IsValueType)
1331 return CreateConstantResult (TypeManager.IsEqual (d, t));
1334 if (!TypeManager.IsReferenceType (expr.Type))
1335 expr = new BoxedCast (expr, d);
1343 protected override string OperatorName {
1344 get { return "is"; }
1349 /// Implementation of the `as' operator.
1351 public class As : Probe {
1353 Expression resolved_type;
1355 public As (Expression expr, Expression probe_type, Location l)
1356 : base (expr, probe_type, l)
1360 public override Expression CreateExpressionTree (EmitContext ec)
1362 ArrayList args = new ArrayList (2);
1363 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1364 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1365 return CreateExpressionFactoryCall ("TypeAs", args);
1368 public override void Emit (EmitContext ec)
1370 ILGenerator ig = ec.ig;
1375 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1378 if (TypeManager.IsNullableType (type))
1379 ig.Emit (OpCodes.Unbox_Any, type);
1383 public override Expression DoResolve (EmitContext ec)
1385 if (resolved_type == null) {
1386 resolved_type = base.DoResolve (ec);
1388 if (resolved_type == null)
1392 type = probe_type_expr.Type;
1393 eclass = ExprClass.Value;
1394 Type etype = expr.Type;
1396 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1397 if (probe_type_expr is TypeParameterExpr) {
1398 Report.Error (413, loc,
1399 "The `as' operator cannot be used with a non-reference type parameter `{0}'",
1400 probe_type_expr.GetSignatureForError ());
1402 Report.Error (77, loc,
1403 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1404 TypeManager.CSharpName (type));
1409 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1410 return Nullable.LiftedNull.CreateFromExpression (this);
1413 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1420 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1421 if (TypeManager.IsGenericParameter (etype))
1422 expr = new BoxedCast (expr, etype);
1428 if (TypeManager.ContainsGenericParameters (etype) ||
1429 TypeManager.ContainsGenericParameters (type)) {
1430 expr = new BoxedCast (expr, etype);
1435 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1436 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1441 protected override string OperatorName {
1442 get { return "as"; }
1445 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1447 return expr.GetAttributableValue (ec, value_type, out value);
1452 /// This represents a typecast in the source language.
1454 /// FIXME: Cast expressions have an unusual set of parsing
1455 /// rules, we need to figure those out.
1457 public class Cast : Expression {
1458 Expression target_type;
1461 public Cast (Expression cast_type, Expression expr)
1462 : this (cast_type, expr, cast_type.Location)
1466 public Cast (Expression cast_type, Expression expr, Location loc)
1468 this.target_type = cast_type;
1473 public Expression TargetType {
1474 get { return target_type; }
1477 public Expression Expr {
1478 get { return expr; }
1481 public override Expression CreateExpressionTree (EmitContext ec)
1483 throw new NotSupportedException ("ET");
1486 public override Expression DoResolve (EmitContext ec)
1488 expr = expr.Resolve (ec);
1492 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1498 if (type.IsAbstract && type.IsSealed) {
1499 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1503 eclass = ExprClass.Value;
1505 Constant c = expr as Constant;
1507 c = c.TryReduce (ec, type, loc);
1512 if (type.IsPointer && !ec.InUnsafe) {
1516 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1520 public override void Emit (EmitContext ec)
1522 throw new Exception ("Should not happen");
1525 protected override void CloneTo (CloneContext clonectx, Expression t)
1527 Cast target = (Cast) t;
1529 target.target_type = target_type.Clone (clonectx);
1530 target.expr = expr.Clone (clonectx);
1535 // C# 2.0 Default value expression
1537 public class DefaultValueExpression : Expression
1541 public DefaultValueExpression (Expression expr, Location loc)
1547 public override Expression CreateExpressionTree (EmitContext ec)
1549 ArrayList args = new ArrayList (2);
1550 args.Add (new Argument (this));
1551 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1552 return CreateExpressionFactoryCall ("Constant", args);
1555 public override Expression DoResolve (EmitContext ec)
1557 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1563 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1564 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1568 return new NullLiteral (Location).ConvertImplicitly (type);
1570 if (TypeManager.IsReferenceType (type)) {
1571 return new EmptyConstantCast (new NullLiteral (Location), type);
1574 // return ReducedExpression.Create (new NullLiteral (Location), this);
1577 Constant c = New.Constantify (type);
1581 eclass = ExprClass.Variable;
1585 public override void Emit (EmitContext ec)
1587 LocalTemporary temp_storage = new LocalTemporary(type);
1589 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1590 ec.ig.Emit(OpCodes.Initobj, type);
1591 temp_storage.Emit(ec);
1594 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1596 type = storey.MutateType (type);
1599 protected override void CloneTo (CloneContext clonectx, Expression t)
1601 DefaultValueExpression target = (DefaultValueExpression) t;
1603 target.expr = expr.Clone (clonectx);
1608 /// Binary operators
1610 public class Binary : Expression {
1612 protected class PredefinedOperator {
1613 protected readonly Type left;
1614 protected readonly Type right;
1615 public readonly Operator OperatorsMask;
1616 public Type ReturnType;
1618 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1619 : this (ltype, rtype, op_mask, ltype)
1623 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1624 : this (type, type, op_mask, return_type)
1628 public PredefinedOperator (Type type, Operator op_mask)
1629 : this (type, type, op_mask, type)
1633 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1635 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1636 throw new InternalErrorException ("Only masked values can be used");
1640 this.OperatorsMask = op_mask;
1641 this.ReturnType = return_type;
1644 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1646 b.type = ReturnType;
1648 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1649 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1652 // A user operators does not support multiple user conversions, but decimal type
1653 // is considered to be predefined type therefore we apply predefined operators rules
1654 // and then look for decimal user-operator implementation
1656 if (left == TypeManager.decimal_type)
1657 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1662 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1665 // We are dealing with primitive types only
1667 return left == ltype && ltype == rtype;
1670 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1672 if (TypeManager.IsEqual (left, lexpr.Type) &&
1673 TypeManager.IsEqual (right, rexpr.Type))
1676 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1677 Convert.ImplicitConversionExists (ec, rexpr, right);
1680 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1683 if (left != null && best_operator.left != null) {
1684 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1688 // When second arguments are same as the first one, the result is same
1690 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1691 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1694 if (result == 0 || result > 2)
1697 return result == 1 ? best_operator : this;
1701 class PredefinedStringOperator : PredefinedOperator {
1702 public PredefinedStringOperator (Type type, Operator op_mask)
1703 : base (type, op_mask, type)
1705 ReturnType = TypeManager.string_type;
1708 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1709 : base (ltype, rtype, op_mask)
1711 ReturnType = TypeManager.string_type;
1714 public override Expression ConvertResult (EmitContext ec, Binary b)
1717 // Use original expression for nullable arguments
1719 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1721 b.left = unwrap.Original;
1723 unwrap = b.right as Nullable.Unwrap;
1725 b.right = unwrap.Original;
1727 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1728 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1731 // Start a new concat expression using converted expression
1733 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1737 class PredefinedShiftOperator : PredefinedOperator {
1738 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1739 base (ltype, TypeManager.int32_type, op_mask)
1743 public override Expression ConvertResult (EmitContext ec, Binary b)
1745 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1747 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1749 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1752 // b = b.left >> b.right & (0x1f|0x3f)
1754 b.right = new Binary (Operator.BitwiseAnd,
1755 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1758 // Expression tree representation does not use & mask
1760 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1761 b.type = ReturnType;
1766 class PredefinedPointerOperator : PredefinedOperator {
1767 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1768 : base (ltype, rtype, op_mask)
1772 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1773 : base (ltype, rtype, op_mask, retType)
1777 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1778 : base (type, op_mask, return_type)
1782 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1785 if (!lexpr.Type.IsPointer)
1788 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1792 if (right == null) {
1793 if (!rexpr.Type.IsPointer)
1796 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1803 public override Expression ConvertResult (EmitContext ec, Binary b)
1806 b.left = EmptyCast.Create (b.left, left);
1807 } else if (right != null) {
1808 b.right = EmptyCast.Create (b.right, right);
1811 Type r_type = ReturnType;
1812 if (r_type == null) {
1814 r_type = b.left.Type;
1816 r_type = b.right.Type;
1819 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1824 public enum Operator {
1825 Multiply = 0 | ArithmeticMask,
1826 Division = 1 | ArithmeticMask,
1827 Modulus = 2 | ArithmeticMask,
1828 Addition = 3 | ArithmeticMask | AdditionMask,
1829 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1831 LeftShift = 5 | ShiftMask,
1832 RightShift = 6 | ShiftMask,
1834 LessThan = 7 | ComparisonMask | RelationalMask,
1835 GreaterThan = 8 | ComparisonMask | RelationalMask,
1836 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1837 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1838 Equality = 11 | ComparisonMask | EqualityMask,
1839 Inequality = 12 | ComparisonMask | EqualityMask,
1841 BitwiseAnd = 13 | BitwiseMask,
1842 ExclusiveOr = 14 | BitwiseMask,
1843 BitwiseOr = 15 | BitwiseMask,
1845 LogicalAnd = 16 | LogicalMask,
1846 LogicalOr = 17 | LogicalMask,
1851 ValuesOnlyMask = ArithmeticMask - 1,
1852 ArithmeticMask = 1 << 5,
1854 ComparisonMask = 1 << 7,
1855 EqualityMask = 1 << 8,
1856 BitwiseMask = 1 << 9,
1857 LogicalMask = 1 << 10,
1858 AdditionMask = 1 << 11,
1859 SubtractionMask = 1 << 12,
1860 RelationalMask = 1 << 13
1863 readonly Operator oper;
1864 protected Expression left, right;
1865 readonly bool is_compound;
1866 Expression enum_conversion;
1868 static PredefinedOperator [] standard_operators;
1869 static PredefinedOperator [] pointer_operators;
1871 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1872 : this (oper, left, right)
1874 this.is_compound = isCompound;
1877 public Binary (Operator oper, Expression left, Expression right)
1882 this.loc = left.Location;
1885 public Operator Oper {
1892 /// Returns a stringified representation of the Operator
1894 string OperName (Operator oper)
1898 case Operator.Multiply:
1901 case Operator.Division:
1904 case Operator.Modulus:
1907 case Operator.Addition:
1910 case Operator.Subtraction:
1913 case Operator.LeftShift:
1916 case Operator.RightShift:
1919 case Operator.LessThan:
1922 case Operator.GreaterThan:
1925 case Operator.LessThanOrEqual:
1928 case Operator.GreaterThanOrEqual:
1931 case Operator.Equality:
1934 case Operator.Inequality:
1937 case Operator.BitwiseAnd:
1940 case Operator.BitwiseOr:
1943 case Operator.ExclusiveOr:
1946 case Operator.LogicalOr:
1949 case Operator.LogicalAnd:
1953 s = oper.ToString ();
1963 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1965 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1968 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1971 // TODO: This should be handled as Type of method group in CSharpName
1972 if (left.eclass == ExprClass.MethodGroup)
1973 l = left.ExprClassName;
1975 l = TypeManager.CSharpName (left.Type);
1977 if (right.eclass == ExprClass.MethodGroup)
1978 r = right.ExprClassName;
1980 r = TypeManager.CSharpName (right.Type);
1982 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1986 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1988 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
1991 static string GetOperatorMetadataName (Operator op)
1993 CSharp.Operator.OpType op_type;
1995 case Operator.Addition:
1996 op_type = CSharp.Operator.OpType.Addition; break;
1997 case Operator.BitwiseAnd:
1998 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
1999 case Operator.BitwiseOr:
2000 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2001 case Operator.Division:
2002 op_type = CSharp.Operator.OpType.Division; break;
2003 case Operator.Equality:
2004 op_type = CSharp.Operator.OpType.Equality; break;
2005 case Operator.ExclusiveOr:
2006 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2007 case Operator.GreaterThan:
2008 op_type = CSharp.Operator.OpType.GreaterThan; break;
2009 case Operator.GreaterThanOrEqual:
2010 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2011 case Operator.Inequality:
2012 op_type = CSharp.Operator.OpType.Inequality; break;
2013 case Operator.LeftShift:
2014 op_type = CSharp.Operator.OpType.LeftShift; break;
2015 case Operator.LessThan:
2016 op_type = CSharp.Operator.OpType.LessThan; break;
2017 case Operator.LessThanOrEqual:
2018 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2019 case Operator.Modulus:
2020 op_type = CSharp.Operator.OpType.Modulus; break;
2021 case Operator.Multiply:
2022 op_type = CSharp.Operator.OpType.Multiply; break;
2023 case Operator.RightShift:
2024 op_type = CSharp.Operator.OpType.RightShift; break;
2025 case Operator.Subtraction:
2026 op_type = CSharp.Operator.OpType.Subtraction; break;
2028 throw new InternalErrorException (op.ToString ());
2031 return CSharp.Operator.GetMetadataName (op_type);
2034 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2037 ILGenerator ig = ec.ig;
2040 case Operator.Multiply:
2042 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2043 opcode = OpCodes.Mul_Ovf;
2044 else if (!IsFloat (l))
2045 opcode = OpCodes.Mul_Ovf_Un;
2047 opcode = OpCodes.Mul;
2049 opcode = OpCodes.Mul;
2053 case Operator.Division:
2055 opcode = OpCodes.Div_Un;
2057 opcode = OpCodes.Div;
2060 case Operator.Modulus:
2062 opcode = OpCodes.Rem_Un;
2064 opcode = OpCodes.Rem;
2067 case Operator.Addition:
2069 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2070 opcode = OpCodes.Add_Ovf;
2071 else if (!IsFloat (l))
2072 opcode = OpCodes.Add_Ovf_Un;
2074 opcode = OpCodes.Add;
2076 opcode = OpCodes.Add;
2079 case Operator.Subtraction:
2081 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2082 opcode = OpCodes.Sub_Ovf;
2083 else if (!IsFloat (l))
2084 opcode = OpCodes.Sub_Ovf_Un;
2086 opcode = OpCodes.Sub;
2088 opcode = OpCodes.Sub;
2091 case Operator.RightShift:
2093 opcode = OpCodes.Shr_Un;
2095 opcode = OpCodes.Shr;
2098 case Operator.LeftShift:
2099 opcode = OpCodes.Shl;
2102 case Operator.Equality:
2103 opcode = OpCodes.Ceq;
2106 case Operator.Inequality:
2107 ig.Emit (OpCodes.Ceq);
2108 ig.Emit (OpCodes.Ldc_I4_0);
2110 opcode = OpCodes.Ceq;
2113 case Operator.LessThan:
2115 opcode = OpCodes.Clt_Un;
2117 opcode = OpCodes.Clt;
2120 case Operator.GreaterThan:
2122 opcode = OpCodes.Cgt_Un;
2124 opcode = OpCodes.Cgt;
2127 case Operator.LessThanOrEqual:
2128 if (IsUnsigned (l) || IsFloat (l))
2129 ig.Emit (OpCodes.Cgt_Un);
2131 ig.Emit (OpCodes.Cgt);
2132 ig.Emit (OpCodes.Ldc_I4_0);
2134 opcode = OpCodes.Ceq;
2137 case Operator.GreaterThanOrEqual:
2138 if (IsUnsigned (l) || IsFloat (l))
2139 ig.Emit (OpCodes.Clt_Un);
2141 ig.Emit (OpCodes.Clt);
2143 ig.Emit (OpCodes.Ldc_I4_0);
2145 opcode = OpCodes.Ceq;
2148 case Operator.BitwiseOr:
2149 opcode = OpCodes.Or;
2152 case Operator.BitwiseAnd:
2153 opcode = OpCodes.And;
2156 case Operator.ExclusiveOr:
2157 opcode = OpCodes.Xor;
2161 throw new InternalErrorException (oper.ToString ());
2167 static bool IsUnsigned (Type t)
2172 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2173 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2176 static bool IsFloat (Type t)
2178 return t == TypeManager.float_type || t == TypeManager.double_type;
2181 Expression ResolveOperator (EmitContext ec)
2184 Type r = right.Type;
2186 bool primitives_only = false;
2188 if (standard_operators == null)
2189 CreateStandardOperatorsTable ();
2192 // Handles predefined primitive types
2194 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2195 if ((oper & Operator.ShiftMask) == 0) {
2196 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2199 primitives_only = true;
2203 if (l.IsPointer || r.IsPointer)
2204 return ResolveOperatorPointer (ec, l, r);
2207 bool lenum = TypeManager.IsEnumType (l);
2208 bool renum = TypeManager.IsEnumType (r);
2209 if (lenum || renum) {
2210 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2212 // TODO: Can this be ambiguous
2218 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2219 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2221 expr = ResolveOperatorDelegate (ec, l, r);
2223 // TODO: Can this be ambiguous
2229 expr = ResolveUserOperator (ec, l, r);
2233 // Predefined reference types equality
2234 if ((oper & Operator.EqualityMask) != 0) {
2235 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2241 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2244 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2245 // if 'left' is not an enumeration constant, create one from the type of 'right'
2246 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2249 case Operator.BitwiseOr:
2250 case Operator.BitwiseAnd:
2251 case Operator.ExclusiveOr:
2252 case Operator.Equality:
2253 case Operator.Inequality:
2254 case Operator.LessThan:
2255 case Operator.LessThanOrEqual:
2256 case Operator.GreaterThan:
2257 case Operator.GreaterThanOrEqual:
2258 if (TypeManager.IsEnumType (left.Type))
2261 if (left.IsZeroInteger)
2262 return left.TryReduce (ec, right.Type, loc);
2266 case Operator.Addition:
2267 case Operator.Subtraction:
2270 case Operator.Multiply:
2271 case Operator.Division:
2272 case Operator.Modulus:
2273 case Operator.LeftShift:
2274 case Operator.RightShift:
2275 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2279 Error_OperatorCannotBeApplied (this.left, this.right);
2284 // The `|' operator used on types which were extended is dangerous
2286 void CheckBitwiseOrOnSignExtended ()
2288 OpcodeCast lcast = left as OpcodeCast;
2289 if (lcast != null) {
2290 if (IsUnsigned (lcast.UnderlyingType))
2294 OpcodeCast rcast = right as OpcodeCast;
2295 if (rcast != null) {
2296 if (IsUnsigned (rcast.UnderlyingType))
2300 if (lcast == null && rcast == null)
2303 // FIXME: consider constants
2305 Report.Warning (675, 3, loc,
2306 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2307 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2310 static void CreatePointerOperatorsTable ()
2312 ArrayList temp = new ArrayList ();
2315 // Pointer arithmetic:
2317 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2318 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2319 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2320 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2322 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2323 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2324 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2325 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2328 // T* operator + (int y, T* x);
2329 // T* operator + (uint y, T *x);
2330 // T* operator + (long y, T *x);
2331 // T* operator + (ulong y, T *x);
2333 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2334 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2335 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2336 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2339 // long operator - (T* x, T *y)
2341 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2343 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2346 static void CreateStandardOperatorsTable ()
2348 ArrayList temp = new ArrayList ();
2349 Type bool_type = TypeManager.bool_type;
2351 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2352 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2353 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2354 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2355 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2356 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2357 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2359 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2360 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2361 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2362 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2363 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2364 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2365 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2367 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2369 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2370 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2371 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2373 temp.Add (new PredefinedOperator (bool_type,
2374 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2376 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2377 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2378 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2379 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2381 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2385 // Rules used during binary numeric promotion
2387 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2392 Constant c = prim_expr as Constant;
2394 temp = c.ConvertImplicitly (type);
2401 if (type == TypeManager.uint32_type) {
2402 etype = prim_expr.Type;
2403 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2404 type = TypeManager.int64_type;
2406 if (type != second_expr.Type) {
2407 c = second_expr as Constant;
2409 temp = c.ConvertImplicitly (type);
2411 temp = Convert.ImplicitNumericConversion (second_expr, type);
2417 } else if (type == TypeManager.uint64_type) {
2419 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2421 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2422 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2426 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2435 // 7.2.6.2 Binary numeric promotions
2437 public bool DoBinaryOperatorPromotion (EmitContext ec)
2439 Type ltype = left.Type;
2440 Type rtype = right.Type;
2443 foreach (Type t in ConstantFold.binary_promotions) {
2445 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2448 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2451 Type int32 = TypeManager.int32_type;
2452 if (ltype != int32) {
2453 Constant c = left as Constant;
2455 temp = c.ConvertImplicitly (int32);
2457 temp = Convert.ImplicitNumericConversion (left, int32);
2464 if (rtype != int32) {
2465 Constant c = right as Constant;
2467 temp = c.ConvertImplicitly (int32);
2469 temp = Convert.ImplicitNumericConversion (right, int32);
2479 public override Expression DoResolve (EmitContext ec)
2484 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2485 left = ((ParenthesizedExpression) left).Expr;
2486 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2490 if (left.eclass == ExprClass.Type) {
2491 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2495 left = left.Resolve (ec);
2500 Constant lc = left as Constant;
2502 if (lc != null && lc.Type == TypeManager.bool_type &&
2503 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2504 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2506 // FIXME: resolve right expression as unreachable
2507 // right.Resolve (ec);
2509 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2513 right = right.Resolve (ec);
2517 eclass = ExprClass.Value;
2518 Constant rc = right as Constant;
2520 // The conversion rules are ignored in enum context but why
2521 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2522 left = lc = EnumLiftUp (ec, lc, rc, loc);
2526 right = rc = EnumLiftUp (ec, rc, lc, loc);
2531 if (rc != null && lc != null) {
2532 int prev_e = Report.Errors;
2533 Expression e = ConstantFold.BinaryFold (
2534 ec, oper, lc, rc, loc);
2535 if (e != null || Report.Errors != prev_e)
2538 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2539 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2541 if ((ResolveOperator (ec)) == null) {
2542 Error_OperatorCannotBeApplied (left, right);
2547 // The result is a constant with side-effect
2549 Constant side_effect = rc == null ?
2550 new SideEffectConstant (lc, right, loc) :
2551 new SideEffectConstant (rc, left, loc);
2553 return ReducedExpression.Create (side_effect, this);
2557 // Comparison warnings
2558 if ((oper & Operator.ComparisonMask) != 0) {
2559 if (left.Equals (right)) {
2560 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2562 CheckUselessComparison (lc, right.Type);
2563 CheckUselessComparison (rc, left.Type);
2566 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2567 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2568 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2569 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2571 return DoResolveCore (ec, left, right);
2574 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2576 Expression expr = ResolveOperator (ec);
2578 Error_OperatorCannotBeApplied (left_orig, right_orig);
2580 if (left == null || right == null)
2581 throw new InternalErrorException ("Invalid conversion");
2583 if (oper == Operator.BitwiseOr)
2584 CheckBitwiseOrOnSignExtended ();
2589 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2591 left.MutateHoistedGenericType (storey);
2592 right.MutateHoistedGenericType (storey);
2596 // D operator + (D x, D y)
2597 // D operator - (D x, D y)
2598 // bool operator == (D x, D y)
2599 // bool operator != (D x, D y)
2601 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2603 bool is_equality = (oper & Operator.EqualityMask) != 0;
2604 if (!TypeManager.IsEqual (l, r)) {
2606 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2607 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2612 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2613 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2624 // Resolve delegate equality as a user operator
2627 return ResolveUserOperator (ec, l, r);
2630 ArrayList args = new ArrayList (2);
2631 args.Add (new Argument (left, Argument.AType.Expression));
2632 args.Add (new Argument (right, Argument.AType.Expression));
2634 if (oper == Operator.Addition) {
2635 if (TypeManager.delegate_combine_delegate_delegate == null) {
2636 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2637 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2640 method = TypeManager.delegate_combine_delegate_delegate;
2642 if (TypeManager.delegate_remove_delegate_delegate == null) {
2643 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2644 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2647 method = TypeManager.delegate_remove_delegate_delegate;
2650 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2651 mg = mg.OverloadResolve (ec, ref args, false, loc);
2653 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2657 // Enumeration operators
2659 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2662 // bool operator == (E x, E y);
2663 // bool operator != (E x, E y);
2664 // bool operator < (E x, E y);
2665 // bool operator > (E x, E y);
2666 // bool operator <= (E x, E y);
2667 // bool operator >= (E x, E y);
2669 // E operator & (E x, E y);
2670 // E operator | (E x, E y);
2671 // E operator ^ (E x, E y);
2673 // U operator - (E e, E f)
2674 // E operator - (E e, U x)
2676 // E operator + (U x, E e)
2677 // E operator + (E e, U x)
2679 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2680 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2683 Expression ltemp = left;
2684 Expression rtemp = right;
2685 Type underlying_type;
2688 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2690 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2696 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2704 if (TypeManager.IsEqual (ltype, rtype)) {
2705 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2707 if (left is Constant)
2708 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2710 left = EmptyCast.Create (left, underlying_type);
2712 if (right is Constant)
2713 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2715 right = EmptyCast.Create (right, underlying_type);
2717 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2719 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2720 Constant c = right as Constant;
2721 if (c == null || !c.IsDefaultValue)
2724 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2727 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2730 if (left is Constant)
2731 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2733 left = EmptyCast.Create (left, underlying_type);
2736 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2738 if (oper != Operator.Addition) {
2739 Constant c = left as Constant;
2740 if (c == null || !c.IsDefaultValue)
2743 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2746 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2749 if (right is Constant)
2750 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2752 right = EmptyCast.Create (right, underlying_type);
2759 // C# specification uses explicit cast syntax which means binary promotion
2760 // should happen, however it seems that csc does not do that
2762 if (!DoBinaryOperatorPromotion (ec)) {
2768 Type res_type = null;
2769 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2770 Type promoted_type = lenum ? left.Type : right.Type;
2771 enum_conversion = Convert.ExplicitNumericConversion (
2772 new EmptyExpression (promoted_type), underlying_type);
2774 if (oper == Operator.Subtraction && renum && lenum)
2775 res_type = underlying_type;
2776 else if (oper == Operator.Addition && renum)
2782 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2783 if (!is_compound || expr == null)
2787 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2790 if (Convert.ImplicitConversionExists (ec, left, rtype))
2793 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2796 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2801 // 7.9.6 Reference type equality operators
2803 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2806 // operator != (object a, object b)
2807 // operator == (object a, object b)
2810 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2812 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2815 type = TypeManager.bool_type;
2816 GenericConstraints constraints;
2818 bool lgen = TypeManager.IsGenericParameter (l);
2820 if (TypeManager.IsEqual (l, r)) {
2823 // Only allow to compare same reference type parameter
2825 constraints = TypeManager.GetTypeParameterConstraints (l);
2826 if (constraints != null && constraints.IsReferenceType)
2832 if (l == TypeManager.anonymous_method_type)
2835 if (TypeManager.IsValueType (l))
2841 bool rgen = TypeManager.IsGenericParameter (r);
2844 // a, Both operands are reference-type values or the value null
2845 // b, One operand is a value of type T where T is a type-parameter and
2846 // the other operand is the value null. Furthermore T does not have the
2847 // value type constrain
2849 if (left is NullLiteral || right is NullLiteral) {
2851 constraints = TypeManager.GetTypeParameterConstraints (l);
2852 if (constraints != null && constraints.HasValueTypeConstraint)
2855 left = new BoxedCast (left, TypeManager.object_type);
2860 constraints = TypeManager.GetTypeParameterConstraints (r);
2861 if (constraints != null && constraints.HasValueTypeConstraint)
2864 right = new BoxedCast (right, TypeManager.object_type);
2870 // An interface is converted to the object before the
2871 // standard conversion is applied. It's not clear from the
2872 // standard but it looks like it works like that.
2875 constraints = TypeManager.GetTypeParameterConstraints (l);
2876 if (constraints == null || constraints.IsReferenceType)
2878 } else if (l.IsInterface) {
2879 l = TypeManager.object_type;
2880 } else if (l.IsValueType) {
2885 constraints = TypeManager.GetTypeParameterConstraints (r);
2886 if (constraints == null || constraints.IsReferenceType)
2888 } else if (r.IsInterface) {
2889 r = TypeManager.object_type;
2890 } else if (r.IsValueType) {
2895 const string ref_comparison = "Possible unintended reference comparison. " +
2896 "Consider casting the {0} side of the expression to `string' to compare the values";
2899 // A standard implicit conversion exists from the type of either
2900 // operand to the type of the other operand
2902 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2903 if (l == TypeManager.string_type)
2904 Report.Warning (253, 2, loc, ref_comparison, "right");
2909 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2910 if (r == TypeManager.string_type)
2911 Report.Warning (252, 2, loc, ref_comparison, "left");
2920 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2923 // bool operator == (void* x, void* y);
2924 // bool operator != (void* x, void* y);
2925 // bool operator < (void* x, void* y);
2926 // bool operator > (void* x, void* y);
2927 // bool operator <= (void* x, void* y);
2928 // bool operator >= (void* x, void* y);
2930 if ((oper & Operator.ComparisonMask) != 0) {
2933 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2940 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2946 type = TypeManager.bool_type;
2950 if (pointer_operators == null)
2951 CreatePointerOperatorsTable ();
2953 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2957 // Build-in operators method overloading
2959 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2961 PredefinedOperator best_operator = null;
2963 Type r = right.Type;
2964 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2966 foreach (PredefinedOperator po in operators) {
2967 if ((po.OperatorsMask & oper_mask) == 0)
2970 if (primitives_only) {
2971 if (!po.IsPrimitiveApplicable (l, r))
2974 if (!po.IsApplicable (ec, left, right))
2978 if (best_operator == null) {
2980 if (primitives_only)
2986 best_operator = po.ResolveBetterOperator (ec, best_operator);
2988 if (best_operator == null) {
2989 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2990 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2997 if (best_operator == null)
3000 Expression expr = best_operator.ConvertResult (ec, this);
3001 if (enum_type == null)
3005 // HACK: required by enum_conversion
3007 expr.Type = enum_type;
3008 return EmptyCast.Create (expr, enum_type);
3012 // Performs user-operator overloading
3014 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3017 if (oper == Operator.LogicalAnd)
3018 user_oper = Operator.BitwiseAnd;
3019 else if (oper == Operator.LogicalOr)
3020 user_oper = Operator.BitwiseOr;
3024 string op = GetOperatorMetadataName (user_oper);
3026 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3027 MethodGroupExpr right_operators = null;
3029 if (!TypeManager.IsEqual (r, l)) {
3030 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3031 if (right_operators == null && left_operators == null)
3033 } else if (left_operators == null) {
3037 ArrayList args = new ArrayList (2);
3038 Argument larg = new Argument (left);
3040 Argument rarg = new Argument (right);
3043 MethodGroupExpr union;
3046 // User-defined operator implementations always take precedence
3047 // over predefined operator implementations
3049 if (left_operators != null && right_operators != null) {
3050 if (IsPredefinedUserOperator (l, user_oper)) {
3051 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3053 union = left_operators;
3054 } else if (IsPredefinedUserOperator (r, user_oper)) {
3055 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3057 union = right_operators;
3059 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3061 } else if (left_operators != null) {
3062 union = left_operators;
3064 union = right_operators;
3067 union = union.OverloadResolve (ec, ref args, true, loc);
3071 Expression oper_expr;
3073 // TODO: CreateExpressionTree is allocated every time
3074 if (user_oper != oper) {
3075 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3076 oper == Operator.LogicalAnd, loc).Resolve (ec);
3078 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3081 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3082 // and not invoke user operator
3084 if ((oper & Operator.EqualityMask) != 0) {
3085 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3086 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3087 type = TypeManager.bool_type;
3088 if (left is NullLiteral || right is NullLiteral)
3089 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3090 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3092 // Two System.Delegate(s) are never equal
3104 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3109 private void CheckUselessComparison (Constant c, Type type)
3111 if (c == null || !IsTypeIntegral (type)
3112 || c is StringConstant
3113 || c is BoolConstant
3114 || c is FloatConstant
3115 || c is DoubleConstant
3116 || c is DecimalConstant
3122 if (c is ULongConstant) {
3123 ulong uvalue = ((ULongConstant) c).Value;
3124 if (uvalue > long.MaxValue) {
3125 if (type == TypeManager.byte_type ||
3126 type == TypeManager.sbyte_type ||
3127 type == TypeManager.short_type ||
3128 type == TypeManager.ushort_type ||
3129 type == TypeManager.int32_type ||
3130 type == TypeManager.uint32_type ||
3131 type == TypeManager.int64_type ||
3132 type == TypeManager.char_type)
3133 WarnUselessComparison (type);
3136 value = (long) uvalue;
3138 else if (c is ByteConstant)
3139 value = ((ByteConstant) c).Value;
3140 else if (c is SByteConstant)
3141 value = ((SByteConstant) c).Value;
3142 else if (c is ShortConstant)
3143 value = ((ShortConstant) c).Value;
3144 else if (c is UShortConstant)
3145 value = ((UShortConstant) c).Value;
3146 else if (c is IntConstant)
3147 value = ((IntConstant) c).Value;
3148 else if (c is UIntConstant)
3149 value = ((UIntConstant) c).Value;
3150 else if (c is LongConstant)
3151 value = ((LongConstant) c).Value;
3152 else if (c is CharConstant)
3153 value = ((CharConstant)c).Value;
3158 if (IsValueOutOfRange (value, type))
3159 WarnUselessComparison (type);
3162 static bool IsValueOutOfRange (long value, Type type)
3164 if (IsTypeUnsigned (type) && value < 0)
3166 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3167 type == TypeManager.byte_type && value >= 0x100 ||
3168 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3169 type == TypeManager.ushort_type && value >= 0x10000 ||
3170 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3171 type == TypeManager.uint32_type && value >= 0x100000000;
3174 static bool IsBuildInEqualityOperator (Type t)
3176 return t == TypeManager.object_type || t == TypeManager.string_type ||
3177 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3180 static bool IsPredefinedUserOperator (Type t, Operator op)
3183 // Some predefined types have user operators
3185 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3188 private static bool IsTypeIntegral (Type type)
3190 return type == TypeManager.uint64_type ||
3191 type == TypeManager.int64_type ||
3192 type == TypeManager.uint32_type ||
3193 type == TypeManager.int32_type ||
3194 type == TypeManager.ushort_type ||
3195 type == TypeManager.short_type ||
3196 type == TypeManager.sbyte_type ||
3197 type == TypeManager.byte_type ||
3198 type == TypeManager.char_type;
3201 private static bool IsTypeUnsigned (Type type)
3203 return type == TypeManager.uint64_type ||
3204 type == TypeManager.uint32_type ||
3205 type == TypeManager.ushort_type ||
3206 type == TypeManager.byte_type ||
3207 type == TypeManager.char_type;
3210 private void WarnUselessComparison (Type type)
3212 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}'",
3213 TypeManager.CSharpName (type));
3217 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3218 /// context of a conditional bool expression. This function will return
3219 /// false if it is was possible to use EmitBranchable, or true if it was.
3221 /// The expression's code is generated, and we will generate a branch to `target'
3222 /// if the resulting expression value is equal to isTrue
3224 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3226 ILGenerator ig = ec.ig;
3229 // This is more complicated than it looks, but its just to avoid
3230 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3231 // but on top of that we want for == and != to use a special path
3232 // if we are comparing against null
3234 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3235 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3238 // put the constant on the rhs, for simplicity
3240 if (left is Constant) {
3241 Expression swap = right;
3246 if (((Constant) right).IsZeroInteger) {
3247 left.EmitBranchable (ec, target, my_on_true);
3250 if (right.Type == TypeManager.bool_type) {
3251 // right is a boolean, and it's not 'false' => it is 'true'
3252 left.EmitBranchable (ec, target, !my_on_true);
3256 } else if (oper == Operator.LogicalAnd) {
3259 Label tests_end = ig.DefineLabel ();
3261 left.EmitBranchable (ec, tests_end, false);
3262 right.EmitBranchable (ec, target, true);
3263 ig.MarkLabel (tests_end);
3266 // This optimizes code like this
3267 // if (true && i > 4)
3269 if (!(left is Constant))
3270 left.EmitBranchable (ec, target, false);
3272 if (!(right is Constant))
3273 right.EmitBranchable (ec, target, false);
3278 } else if (oper == Operator.LogicalOr){
3280 left.EmitBranchable (ec, target, true);
3281 right.EmitBranchable (ec, target, true);
3284 Label tests_end = ig.DefineLabel ();
3285 left.EmitBranchable (ec, tests_end, true);
3286 right.EmitBranchable (ec, target, false);
3287 ig.MarkLabel (tests_end);
3292 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3293 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3294 oper == Operator.Equality || oper == Operator.Inequality)) {
3295 base.EmitBranchable (ec, target, on_true);
3303 bool is_float = IsFloat (t);
3304 bool is_unsigned = is_float || IsUnsigned (t);
3307 case Operator.Equality:
3309 ig.Emit (OpCodes.Beq, target);
3311 ig.Emit (OpCodes.Bne_Un, target);
3314 case Operator.Inequality:
3316 ig.Emit (OpCodes.Bne_Un, target);
3318 ig.Emit (OpCodes.Beq, target);
3321 case Operator.LessThan:
3323 if (is_unsigned && !is_float)
3324 ig.Emit (OpCodes.Blt_Un, target);
3326 ig.Emit (OpCodes.Blt, target);
3329 ig.Emit (OpCodes.Bge_Un, target);
3331 ig.Emit (OpCodes.Bge, target);
3334 case Operator.GreaterThan:
3336 if (is_unsigned && !is_float)
3337 ig.Emit (OpCodes.Bgt_Un, target);
3339 ig.Emit (OpCodes.Bgt, target);
3342 ig.Emit (OpCodes.Ble_Un, target);
3344 ig.Emit (OpCodes.Ble, target);
3347 case Operator.LessThanOrEqual:
3349 if (is_unsigned && !is_float)
3350 ig.Emit (OpCodes.Ble_Un, target);
3352 ig.Emit (OpCodes.Ble, target);
3355 ig.Emit (OpCodes.Bgt_Un, target);
3357 ig.Emit (OpCodes.Bgt, target);
3361 case Operator.GreaterThanOrEqual:
3363 if (is_unsigned && !is_float)
3364 ig.Emit (OpCodes.Bge_Un, target);
3366 ig.Emit (OpCodes.Bge, target);
3369 ig.Emit (OpCodes.Blt_Un, target);
3371 ig.Emit (OpCodes.Blt, target);
3374 throw new InternalErrorException (oper.ToString ());
3378 public override void Emit (EmitContext ec)
3380 EmitOperator (ec, left.Type);
3383 protected virtual void EmitOperator (EmitContext ec, Type l)
3385 ILGenerator ig = ec.ig;
3388 // Handle short-circuit operators differently
3391 if ((oper & Operator.LogicalMask) != 0) {
3392 Label load_result = ig.DefineLabel ();
3393 Label end = ig.DefineLabel ();
3395 bool is_or = oper == Operator.LogicalOr;
3396 left.EmitBranchable (ec, load_result, is_or);
3398 ig.Emit (OpCodes.Br_S, end);
3400 ig.MarkLabel (load_result);
3401 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3409 // Optimize zero-based operations
3411 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3413 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3414 Constant rc = right as Constant;
3415 if (rc != null && rc.IsDefaultValue) {
3421 EmitOperatorOpcode (ec, oper, l);
3424 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3425 // expression because that would wrap lifted binary operation
3427 if (enum_conversion != null)
3428 enum_conversion.Emit (ec);
3431 public override void EmitSideEffect (EmitContext ec)
3433 if ((oper & Operator.LogicalMask) != 0 ||
3434 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3435 base.EmitSideEffect (ec);
3437 left.EmitSideEffect (ec);
3438 right.EmitSideEffect (ec);
3442 protected override void CloneTo (CloneContext clonectx, Expression t)
3444 Binary target = (Binary) t;
3446 target.left = left.Clone (clonectx);
3447 target.right = right.Clone (clonectx);
3450 public override Expression CreateExpressionTree (EmitContext ec)
3452 return CreateExpressionTree (ec, null);
3455 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3458 bool lift_arg = false;
3461 case Operator.Addition:
3462 if (method == null && ec.CheckState && !IsFloat (type))
3463 method_name = "AddChecked";
3465 method_name = "Add";
3467 case Operator.BitwiseAnd:
3468 method_name = "And";
3470 case Operator.BitwiseOr:
3473 case Operator.Division:
3474 method_name = "Divide";
3476 case Operator.Equality:
3477 method_name = "Equal";
3480 case Operator.ExclusiveOr:
3481 method_name = "ExclusiveOr";
3483 case Operator.GreaterThan:
3484 method_name = "GreaterThan";
3487 case Operator.GreaterThanOrEqual:
3488 method_name = "GreaterThanOrEqual";
3491 case Operator.Inequality:
3492 method_name = "NotEqual";
3495 case Operator.LeftShift:
3496 method_name = "LeftShift";
3498 case Operator.LessThan:
3499 method_name = "LessThan";
3502 case Operator.LessThanOrEqual:
3503 method_name = "LessThanOrEqual";
3506 case Operator.LogicalAnd:
3507 method_name = "AndAlso";
3509 case Operator.LogicalOr:
3510 method_name = "OrElse";
3512 case Operator.Modulus:
3513 method_name = "Modulo";
3515 case Operator.Multiply:
3516 if (method == null && ec.CheckState && !IsFloat (type))
3517 method_name = "MultiplyChecked";
3519 method_name = "Multiply";
3521 case Operator.RightShift:
3522 method_name = "RightShift";
3524 case Operator.Subtraction:
3525 if (method == null && ec.CheckState && !IsFloat (type))
3526 method_name = "SubtractChecked";
3528 method_name = "Subtract";
3532 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3535 ArrayList args = new ArrayList (2);
3536 args.Add (new Argument (left.CreateExpressionTree (ec)));
3537 args.Add (new Argument (right.CreateExpressionTree (ec)));
3538 if (method != null) {
3540 args.Add (new Argument (new BoolConstant (false, loc)));
3542 args.Add (new Argument (method.CreateExpressionTree (ec)));
3545 return CreateExpressionFactoryCall (method_name, args);
3550 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3551 // b, c, d... may be strings or objects.
3553 public class StringConcat : Expression {
3554 ArrayList arguments;
3556 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3559 type = TypeManager.string_type;
3560 eclass = ExprClass.Value;
3562 arguments = new ArrayList (2);
3567 public override Expression CreateExpressionTree (EmitContext ec)
3569 Argument arg = (Argument) arguments [0];
3570 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3574 // Creates nested calls tree from an array of arguments used for IL emit
3576 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3578 ArrayList concat_args = new ArrayList (2);
3579 ArrayList add_args = new ArrayList (3);
3581 concat_args.Add (left);
3582 add_args.Add (new Argument (left_etree));
3584 concat_args.Add (arguments [pos]);
3585 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3587 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3591 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3595 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3597 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3598 if (++pos == arguments.Count)
3601 left = new Argument (new EmptyExpression (method.Type));
3602 return CreateExpressionAddCall (ec, left, expr, pos);
3605 public override Expression DoResolve (EmitContext ec)
3610 public void Append (EmitContext ec, Expression operand)
3615 StringConstant sc = operand as StringConstant;
3617 if (arguments.Count != 0) {
3618 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3619 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3620 if (last_expr_constant != null) {
3621 last_argument.Expr = new StringConstant (
3622 last_expr_constant.Value + sc.Value, sc.Location);
3628 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3630 StringConcat concat_oper = operand as StringConcat;
3631 if (concat_oper != null) {
3632 arguments.AddRange (concat_oper.arguments);
3637 arguments.Add (new Argument (operand));
3640 Expression CreateConcatMemberExpression ()
3642 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3645 public override void Emit (EmitContext ec)
3647 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3648 concat = concat.Resolve (ec);
3653 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3655 foreach (Argument a in arguments)
3656 a.Expr.MutateHoistedGenericType (storey);
3661 // User-defined conditional logical operator
3663 public class ConditionalLogicalOperator : UserOperatorCall {
3664 readonly bool is_and;
3667 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3668 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3669 : base (oper_method, arguments, expr_tree, loc)
3671 this.is_and = is_and;
3674 public override Expression DoResolve (EmitContext ec)
3676 MethodInfo method = (MethodInfo)mg;
3677 type = TypeManager.TypeToCoreType (method.ReturnType);
3678 AParametersCollection pd = TypeManager.GetParameterData (method);
3679 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3680 Report.Error (217, loc,
3681 "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",
3682 TypeManager.CSharpSignature (method));
3686 Expression left_dup = new EmptyExpression (type);
3687 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3688 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3689 if (op_true == null || op_false == null) {
3690 Report.Error (218, loc,
3691 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3692 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3696 oper = is_and ? op_false : op_true;
3697 eclass = ExprClass.Value;
3701 public override void Emit (EmitContext ec)
3703 ILGenerator ig = ec.ig;
3704 Label end_target = ig.DefineLabel ();
3707 // Emit and duplicate left argument
3709 ((Argument)arguments [0]).Expr.Emit (ec);
3710 ig.Emit (OpCodes.Dup);
3711 arguments.RemoveAt (0);
3713 oper.EmitBranchable (ec, end_target, true);
3715 ig.MarkLabel (end_target);
3719 public class PointerArithmetic : Expression {
3720 Expression left, right;
3724 // We assume that `l' is always a pointer
3726 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3735 public override Expression CreateExpressionTree (EmitContext ec)
3737 Error_PointerInsideExpressionTree ();
3741 public override Expression DoResolve (EmitContext ec)
3743 eclass = ExprClass.Variable;
3745 if (left.Type == TypeManager.void_ptr_type) {
3746 Error (242, "The operation in question is undefined on void pointers");
3753 public override void Emit (EmitContext ec)
3755 Type op_type = left.Type;
3756 ILGenerator ig = ec.ig;
3758 // It must be either array or fixed buffer
3760 if (TypeManager.HasElementType (op_type)) {
3761 element = TypeManager.GetElementType (op_type);
3763 FieldExpr fe = left as FieldExpr;
3765 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3770 int size = GetTypeSize (element);
3771 Type rtype = right.Type;
3773 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3775 // handle (pointer - pointer)
3779 ig.Emit (OpCodes.Sub);
3783 ig.Emit (OpCodes.Sizeof, element);
3785 IntLiteral.EmitInt (ig, size);
3786 ig.Emit (OpCodes.Div);
3788 ig.Emit (OpCodes.Conv_I8);
3791 // handle + and - on (pointer op int)
3795 Constant right_const = right as Constant;
3796 if (right_const != null) {
3798 // Optimize 0-based arithmetic
3800 if (right_const.IsDefaultValue)
3804 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3808 ig.Emit (OpCodes.Sizeof, element);
3809 right = EmptyExpression.Null;
3814 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3815 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3816 ig.Emit (OpCodes.Conv_I);
3817 } else if (rtype == TypeManager.uint32_type) {
3818 ig.Emit (OpCodes.Conv_U);
3821 if (right_const == null && size != 1){
3823 ig.Emit (OpCodes.Sizeof, element);
3825 IntLiteral.EmitInt (ig, size);
3826 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3827 ig.Emit (OpCodes.Conv_I8);
3829 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3832 if (rtype == TypeManager.int64_type)
3833 ig.Emit (OpCodes.Conv_I);
3834 else if (rtype == TypeManager.uint64_type)
3835 ig.Emit (OpCodes.Conv_U);
3837 Binary.EmitOperatorOpcode (ec, op, op_type);
3843 /// Implements the ternary conditional operator (?:)
3845 public class Conditional : Expression {
3846 Expression expr, true_expr, false_expr;
3848 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3851 this.true_expr = true_expr;
3852 this.false_expr = false_expr;
3853 this.loc = expr.Location;
3856 public Expression Expr {
3862 public Expression TrueExpr {
3868 public Expression FalseExpr {
3874 public override Expression CreateExpressionTree (EmitContext ec)
3876 ArrayList args = new ArrayList (3);
3877 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3878 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3879 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3880 return CreateExpressionFactoryCall ("Condition", args);
3883 public override Expression DoResolve (EmitContext ec)
3885 expr = expr.Resolve (ec);
3890 if (expr.Type != TypeManager.bool_type){
3891 expr = Expression.ResolveBoolean (
3898 Assign ass = expr as Assign;
3899 if (ass != null && ass.Source is Constant) {
3900 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3903 true_expr = true_expr.Resolve (ec);
3904 false_expr = false_expr.Resolve (ec);
3906 if (true_expr == null || false_expr == null)
3909 eclass = ExprClass.Value;
3910 Type true_type = true_expr.Type;
3911 Type false_type = false_expr.Type;
3915 // First, if an implicit conversion exists from true_expr
3916 // to false_expr, then the result type is of type false_expr.Type
3918 if (!TypeManager.IsEqual (true_type, false_type)) {
3919 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3922 // Check if both can convert implicitl to each other's type
3924 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3926 "Can not compute type of conditional expression " +
3927 "as `" + TypeManager.CSharpName (true_expr.Type) +
3928 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3929 "' convert implicitly to each other");
3934 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3937 Report.Error (173, loc,
3938 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3939 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3944 // Dead code optimalization
3945 Constant c = expr as Constant;
3947 bool is_false = c.IsDefaultValue;
3948 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3949 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3955 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3957 expr.MutateHoistedGenericType (storey);
3958 true_expr.MutateHoistedGenericType (storey);
3959 false_expr.MutateHoistedGenericType (storey);
3960 type = storey.MutateType (type);
3963 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3968 public override void Emit (EmitContext ec)
3970 ILGenerator ig = ec.ig;
3971 Label false_target = ig.DefineLabel ();
3972 Label end_target = ig.DefineLabel ();
3974 expr.EmitBranchable (ec, false_target, false);
3975 true_expr.Emit (ec);
3977 if (type.IsInterface) {
3978 LocalBuilder temp = ec.GetTemporaryLocal (type);
3979 ig.Emit (OpCodes.Stloc, temp);
3980 ig.Emit (OpCodes.Ldloc, temp);
3981 ec.FreeTemporaryLocal (temp, type);
3984 ig.Emit (OpCodes.Br, end_target);
3985 ig.MarkLabel (false_target);
3986 false_expr.Emit (ec);
3987 ig.MarkLabel (end_target);
3990 protected override void CloneTo (CloneContext clonectx, Expression t)
3992 Conditional target = (Conditional) t;
3994 target.expr = expr.Clone (clonectx);
3995 target.true_expr = true_expr.Clone (clonectx);
3996 target.false_expr = false_expr.Clone (clonectx);
4000 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4001 LocalTemporary temp;
4004 public abstract HoistedVariable HoistedVariable { get; }
4005 public abstract bool IsFixed { get; }
4006 public abstract bool IsRef { get; }
4007 public abstract string Name { get; }
4008 public abstract void SetHasAddressTaken ();
4011 // Variable IL data, it has to be protected to encapsulate hoisted variables
4013 protected abstract ILocalVariable Variable { get; }
4016 // Variable flow-analysis data
4018 public abstract VariableInfo VariableInfo { get; }
4021 public void AddressOf (EmitContext ec, AddressOp mode)
4023 if (IsHoistedEmitRequired (ec)) {
4024 HoistedVariable.AddressOf (ec, mode);
4028 Variable.EmitAddressOf (ec);
4031 public override void Emit (EmitContext ec)
4036 public override void EmitSideEffect (EmitContext ec)
4042 // This method is used by parameters that are references, that are
4043 // being passed as references: we only want to pass the pointer (that
4044 // is already stored in the parameter, not the address of the pointer,
4045 // and not the value of the variable).
4047 public void EmitLoad (EmitContext ec)
4052 public void Emit (EmitContext ec, bool leave_copy)
4054 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4056 if (IsHoistedEmitRequired (ec)) {
4057 HoistedVariable.Emit (ec, leave_copy);
4065 // If we are a reference, we loaded on the stack a pointer
4066 // Now lets load the real value
4068 LoadFromPtr (ec.ig, type);
4072 ec.ig.Emit (OpCodes.Dup);
4075 temp = new LocalTemporary (Type);
4081 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4082 bool prepare_for_load)
4084 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4087 if (IsHoistedEmitRequired (ec)) {
4088 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4097 // HACK: variable is already emitted when source is an initializer
4098 if (source is NewInitialize) {
4106 ec.ig.Emit (OpCodes.Dup);
4108 temp = new LocalTemporary (Type);
4114 StoreFromPtr (ec.ig, type);
4116 Variable.EmitAssign (ec);
4124 public bool IsHoisted {
4125 get { return HoistedVariable != null; }
4128 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4131 // Default implementation return true when there is a hosted variable
4133 return HoistedVariable != null;
4136 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4138 type = storey.MutateType (type);
4145 public class LocalVariableReference : VariableReference {
4146 readonly string name;
4148 public LocalInfo local_info;
4151 public LocalVariableReference (Block block, string name, Location l)
4156 eclass = ExprClass.Variable;
4160 // Setting `is_readonly' to false will allow you to create a writable
4161 // reference to a read-only variable. This is used by foreach and using.
4163 public LocalVariableReference (Block block, string name, Location l,
4164 LocalInfo local_info, bool is_readonly)
4165 : this (block, name, l)
4167 this.local_info = local_info;
4168 this.is_readonly = is_readonly;
4171 public override VariableInfo VariableInfo {
4172 get { return local_info.VariableInfo; }
4175 public override HoistedVariable HoistedVariable {
4176 get { return local_info.HoistedVariableReference; }
4180 // A local variable is always fixed
4182 public override bool IsFixed {
4183 get { return true; }
4186 public override bool IsRef {
4187 get { return false; }
4190 public bool IsReadOnly {
4191 get { return is_readonly; }
4194 public override string Name {
4195 get { return name; }
4198 public bool VerifyAssigned (EmitContext ec)
4200 VariableInfo variable_info = local_info.VariableInfo;
4201 return variable_info == null || variable_info.IsAssigned (ec, loc);
4204 void ResolveLocalInfo ()
4206 if (local_info == null) {
4207 local_info = Block.GetLocalInfo (Name);
4208 type = local_info.VariableType;
4209 is_readonly = local_info.ReadOnly;
4213 public override void SetHasAddressTaken ()
4215 local_info.AddressTaken = true;
4218 public override Expression CreateExpressionTree (EmitContext ec)
4220 ArrayList arg = new ArrayList (1);
4221 arg.Add (new Argument (this));
4222 return CreateExpressionFactoryCall ("Constant", arg);
4225 Expression DoResolveBase (EmitContext ec)
4227 type = local_info.VariableType;
4229 Expression e = Block.GetConstantExpression (Name);
4231 return e.Resolve (ec);
4233 VerifyAssigned (ec);
4236 // If we are referencing a variable from the external block
4237 // flag it for capturing
4239 if (ec.MustCaptureVariable (local_info)) {
4240 if (local_info.AddressTaken)
4241 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4243 if (ec.IsVariableCapturingRequired) {
4244 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4245 storey.CaptureLocalVariable (ec, local_info);
4252 public override Expression DoResolve (EmitContext ec)
4254 ResolveLocalInfo ();
4255 local_info.Used = true;
4257 if (type == null && local_info.Type is VarExpr) {
4258 local_info.VariableType = TypeManager.object_type;
4259 Error_VariableIsUsedBeforeItIsDeclared (Name);
4263 return DoResolveBase (ec);
4266 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4268 ResolveLocalInfo ();
4271 if (right_side == EmptyExpression.OutAccess)
4272 local_info.Used = true;
4274 // Infer implicitly typed local variable
4276 VarExpr ve = local_info.Type as VarExpr;
4278 if (!ve.InferType (ec, right_side))
4280 type = local_info.VariableType = ve.Type;
4287 if (right_side == EmptyExpression.OutAccess) {
4288 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4289 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4290 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4291 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4292 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4293 } else if (right_side == EmptyExpression.UnaryAddress) {
4294 code = 459; msg = "Cannot take the address of {1} `{0}'";
4296 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4298 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4299 } else if (VariableInfo != null) {
4300 VariableInfo.SetAssigned (ec);
4303 return DoResolveBase (ec);
4306 public override int GetHashCode ()
4308 return Name.GetHashCode ();
4311 public override bool Equals (object obj)
4313 LocalVariableReference lvr = obj as LocalVariableReference;
4317 return Name == lvr.Name && Block == lvr.Block;
4320 protected override ILocalVariable Variable {
4321 get { return local_info; }
4324 public override string ToString ()
4326 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4329 protected override void CloneTo (CloneContext clonectx, Expression t)
4331 LocalVariableReference target = (LocalVariableReference) t;
4333 target.Block = clonectx.LookupBlock (Block);
4334 if (local_info != null)
4335 target.local_info = clonectx.LookupVariable (local_info);
4340 /// This represents a reference to a parameter in the intermediate
4343 public class ParameterReference : VariableReference {
4344 readonly ToplevelParameterInfo pi;
4345 readonly ToplevelBlock referenced;
4347 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4350 this.referenced = referenced;
4354 public override bool IsRef {
4355 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4358 bool HasOutModifier {
4359 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4362 public override HoistedVariable HoistedVariable {
4363 get { return pi.Parameter.HoistedVariableReference; }
4367 // A ref or out parameter is classified as a moveable variable, even
4368 // if the argument given for the parameter is a fixed variable
4370 public override bool IsFixed {
4371 get { return !IsRef; }
4374 public override string Name {
4375 get { return Parameter.Name; }
4378 public Parameter Parameter {
4379 get { return pi.Parameter; }
4382 public override VariableInfo VariableInfo {
4383 get { return pi.VariableInfo; }
4386 protected override ILocalVariable Variable {
4387 get { return Parameter; }
4390 public bool IsAssigned (EmitContext ec, Location loc)
4392 // HACK: Variables are not captured in probing mode
4393 if (ec.IsInProbingMode)
4396 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4399 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4403 public override void SetHasAddressTaken ()
4405 Parameter.HasAddressTaken = true;
4408 void SetAssigned (EmitContext ec)
4410 if (HasOutModifier && ec.DoFlowAnalysis)
4411 ec.CurrentBranching.SetAssigned (VariableInfo);
4414 bool DoResolveBase (EmitContext ec)
4416 type = pi.ParameterType;
4417 eclass = ExprClass.Variable;
4419 AnonymousExpression am = ec.CurrentAnonymousMethod;
4423 ToplevelBlock declared = pi.Block;
4424 if (declared != referenced) {
4426 Report.Error (1628, loc,
4427 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4428 Name, am.ContainerType);
4436 if (ec.IsVariableCapturingRequired) {
4437 if (pi.Parameter.HasAddressTaken)
4438 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4440 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4441 storey.CaptureParameter (ec, this);
4447 public override int GetHashCode ()
4449 return Name.GetHashCode ();
4452 public override bool Equals (object obj)
4454 ParameterReference pr = obj as ParameterReference;
4458 return Name == pr.Name && referenced == pr.referenced;
4461 protected override void CloneTo (CloneContext clonectx, Expression target)
4466 public override Expression CreateExpressionTree (EmitContext ec)
4468 if (IsHoistedEmitRequired (ec))
4469 return HoistedVariable.CreateExpressionTree (ec);
4471 return Parameter.ExpressionTreeVariableReference ();
4475 // Notice that for ref/out parameters, the type exposed is not the
4476 // same type exposed externally.
4479 // externally we expose "int&"
4480 // here we expose "int".
4482 // We record this in "is_ref". This means that the type system can treat
4483 // the type as it is expected, but when we generate the code, we generate
4484 // the alternate kind of code.
4486 public override Expression DoResolve (EmitContext ec)
4488 if (!DoResolveBase (ec))
4491 if (HasOutModifier && ec.DoFlowAnalysis &&
4492 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4498 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4500 if (!DoResolveBase (ec))
4503 // HACK: parameters are not captured when probing is on
4504 if (!ec.IsInProbingMode)
4510 static public void EmitLdArg (ILGenerator ig, int x)
4514 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4515 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4516 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4517 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4518 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4521 ig.Emit (OpCodes.Ldarg, x);
4526 /// Used for arguments to New(), Invocation()
4528 public class Argument {
4529 public enum AType : byte {
4536 public static readonly Argument[] Empty = new Argument [0];
4538 public readonly AType ArgType;
4539 public Expression Expr;
4541 public Argument (Expression expr, AType type)
4544 this.ArgType = type;
4547 public Argument (Expression expr)
4550 this.ArgType = AType.Expression;
4554 get { return Expr.Type; }
4557 public Parameter.Modifier Modifier
4562 return Parameter.Modifier.OUT;
4565 return Parameter.Modifier.REF;
4568 return Parameter.Modifier.NONE;
4573 public string GetSignatureForError ()
4575 if (Expr.eclass == ExprClass.MethodGroup)
4576 return Expr.ExprClassName;
4578 return TypeManager.CSharpName (Expr.Type);
4581 public bool ResolveMethodGroup (EmitContext ec)
4583 SimpleName sn = Expr as SimpleName;
4585 Expr = sn.GetMethodGroup ();
4587 // FIXME: csc doesn't report any error if you try to use `ref' or
4588 // `out' in a delegate creation expression.
4589 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4596 public bool Resolve (EmitContext ec, Location loc)
4601 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4602 // Verify that the argument is readable
4603 if (ArgType != AType.Out)
4604 Expr = Expr.Resolve (ec);
4606 // Verify that the argument is writeable
4607 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4608 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4610 return Expr != null;
4614 public void Emit (EmitContext ec)
4616 if (ArgType != AType.Ref && ArgType != AType.Out) {
4621 AddressOp mode = AddressOp.Store;
4622 if (ArgType == AType.Ref)
4623 mode |= AddressOp.Load;
4625 IMemoryLocation ml = (IMemoryLocation) Expr;
4626 ParameterReference pr = ml as ParameterReference;
4629 // ParameterReferences might already be references, so we want
4630 // to pass just the value
4632 if (pr != null && pr.IsRef)
4635 ml.AddressOf (ec, mode);
4638 public Argument Clone (CloneContext clonectx)
4640 return new Argument (Expr.Clone (clonectx), ArgType);
4645 /// Invocation of methods or delegates.
4647 public class Invocation : ExpressionStatement {
4648 protected ArrayList Arguments;
4649 protected Expression expr;
4650 protected MethodGroupExpr mg;
4651 bool arguments_resolved;
4654 // arguments is an ArrayList, but we do not want to typecast,
4655 // as it might be null.
4657 public Invocation (Expression expr, ArrayList arguments)
4659 SimpleName sn = expr as SimpleName;
4661 this.expr = sn.GetMethodGroup ();
4665 Arguments = arguments;
4667 loc = expr.Location;
4670 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4671 : this (expr, arguments)
4673 this.arguments_resolved = arguments_resolved;
4676 public override Expression CreateExpressionTree (EmitContext ec)
4681 // Special conversion for nested expression trees
4683 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4684 args = new ArrayList (1);
4685 args.Add (new Argument (this));
4686 return CreateExpressionFactoryCall ("Quote", args);
4689 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4691 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4694 args = new ArrayList (arg_count);
4697 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4699 args.Add (new Argument (new NullLiteral (loc)));
4701 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4704 // Use extension argument when exists
4707 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4709 args.Add (new Argument (e));
4712 if (Arguments != null) {
4713 foreach (Argument a in Arguments) {
4714 Expression e = a.Expr.CreateExpressionTree (ec);
4716 args.Add (new Argument (e));
4721 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4723 return CreateExpressionFactoryCall ("Call", args);
4726 public override Expression DoResolve (EmitContext ec)
4728 // Don't resolve already resolved expression
4729 if (eclass != ExprClass.Invalid)
4732 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4733 if (expr_resolved == null)
4736 mg = expr_resolved as MethodGroupExpr;
4738 Type expr_type = expr_resolved.Type;
4740 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4741 return (new DelegateInvocation (
4742 expr_resolved, Arguments, loc)).Resolve (ec);
4745 MemberExpr me = expr_resolved as MemberExpr;
4747 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4751 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4753 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4754 expr_resolved.GetSignatureForError ());
4758 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4762 // Next, evaluate all the expressions in the argument list
4764 if (Arguments != null && !arguments_resolved) {
4765 for (int i = 0; i < Arguments.Count; ++i)
4767 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4772 mg = DoResolveOverload (ec);
4776 MethodInfo method = (MethodInfo)mg;
4777 if (method != null) {
4778 type = TypeManager.TypeToCoreType (method.ReturnType);
4780 // TODO: this is a copy of mg.ResolveMemberAccess method
4781 Expression iexpr = mg.InstanceExpression;
4782 if (method.IsStatic) {
4783 if (iexpr == null ||
4784 iexpr is This || iexpr is EmptyExpression ||
4785 mg.IdenticalTypeName) {
4786 mg.InstanceExpression = null;
4788 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4792 if (iexpr == null) {
4793 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4798 if (type.IsPointer){
4806 // Only base will allow this invocation to happen.
4808 if (mg.IsBase && method.IsAbstract){
4809 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4813 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4815 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4817 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4821 IsSpecialMethodInvocation (method, loc);
4823 if (mg.InstanceExpression != null)
4824 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4826 eclass = ExprClass.Value;
4830 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4832 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4835 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4837 if (!TypeManager.IsSpecialMethod (method))
4840 Report.SymbolRelatedToPreviousError (method);
4841 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4842 TypeManager.CSharpSignature (method, true));
4848 /// Emits a list of resolved Arguments that are in the arguments
4851 /// The MethodBase argument might be null if the
4852 /// emission of the arguments is known not to contain
4853 /// a `params' field (for example in constructors or other routines
4854 /// that keep their arguments in this structure)
4856 /// if `dup_args' is true, a copy of the arguments will be left
4857 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4858 /// which will be duplicated before any other args. Only EmitCall
4859 /// should be using this interface.
4861 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4863 if (arguments == null)
4866 int top = arguments.Count;
4867 LocalTemporary [] temps = null;
4869 if (dup_args && top != 0)
4870 temps = new LocalTemporary [top];
4872 int argument_index = 0;
4874 for (int i = 0; i < top; i++) {
4875 a = (Argument) arguments [argument_index++];
4878 ec.ig.Emit (OpCodes.Dup);
4879 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4884 if (this_arg != null)
4887 for (int i = 0; i < top; i ++) {
4888 temps [i].Emit (ec);
4889 temps [i].Release (ec);
4894 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4896 AParametersCollection pd = TypeManager.GetParameterData (mb);
4898 Argument a = (Argument) arguments [pd.Count - 1];
4899 Arglist list = (Arglist) a.Expr;
4901 return list.ArgumentTypes;
4905 /// This checks the ConditionalAttribute on the method
4907 public static bool IsMethodExcluded (MethodBase method, Location loc)
4909 if (method.IsConstructor)
4912 method = TypeManager.DropGenericMethodArguments (method);
4913 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4914 IMethodData md = TypeManager.GetMethod (method);
4916 return md.IsExcluded ();
4918 // For some methods (generated by delegate class) GetMethod returns null
4919 // because they are not included in builder_to_method table
4923 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4927 /// is_base tells whether we want to force the use of the `call'
4928 /// opcode instead of using callvirt. Call is required to call
4929 /// a specific method, while callvirt will always use the most
4930 /// recent method in the vtable.
4932 /// is_static tells whether this is an invocation on a static method
4934 /// instance_expr is an expression that represents the instance
4935 /// it must be non-null if is_static is false.
4937 /// method is the method to invoke.
4939 /// Arguments is the list of arguments to pass to the method or constructor.
4941 public static void EmitCall (EmitContext ec, bool is_base,
4942 Expression instance_expr,
4943 MethodBase method, ArrayList Arguments, Location loc)
4945 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4948 // `dup_args' leaves an extra copy of the arguments on the stack
4949 // `omit_args' does not leave any arguments at all.
4950 // So, basically, you could make one call with `dup_args' set to true,
4951 // and then another with `omit_args' set to true, and the two calls
4952 // would have the same set of arguments. However, each argument would
4953 // only have been evaluated once.
4954 public static void EmitCall (EmitContext ec, bool is_base,
4955 Expression instance_expr,
4956 MethodBase method, ArrayList Arguments, Location loc,
4957 bool dup_args, bool omit_args)
4959 ILGenerator ig = ec.ig;
4960 bool struct_call = false;
4961 bool this_call = false;
4962 LocalTemporary this_arg = null;
4964 Type decl_type = method.DeclaringType;
4966 if (IsMethodExcluded (method, loc))
4969 bool is_static = method.IsStatic;
4971 this_call = instance_expr is This;
4972 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4976 // If this is ourselves, push "this"
4980 Type iexpr_type = instance_expr.Type;
4983 // Push the instance expression
4985 if (TypeManager.IsValueType (iexpr_type)) {
4987 // Special case: calls to a function declared in a
4988 // reference-type with a value-type argument need
4989 // to have their value boxed.
4990 if (decl_type.IsValueType ||
4991 TypeManager.IsGenericParameter (iexpr_type)) {
4993 // If the expression implements IMemoryLocation, then
4994 // we can optimize and use AddressOf on the
4997 // If not we have to use some temporary storage for
4999 if (instance_expr is IMemoryLocation) {
5000 ((IMemoryLocation)instance_expr).
5001 AddressOf (ec, AddressOp.LoadStore);
5003 LocalTemporary temp = new LocalTemporary (iexpr_type);
5004 instance_expr.Emit (ec);
5006 temp.AddressOf (ec, AddressOp.Load);
5009 // avoid the overhead of doing this all the time.
5011 t = TypeManager.GetReferenceType (iexpr_type);
5013 instance_expr.Emit (ec);
5014 ig.Emit (OpCodes.Box, instance_expr.Type);
5015 t = TypeManager.object_type;
5018 instance_expr.Emit (ec);
5019 t = instance_expr.Type;
5023 ig.Emit (OpCodes.Dup);
5024 if (Arguments != null && Arguments.Count != 0) {
5025 this_arg = new LocalTemporary (t);
5026 this_arg.Store (ec);
5033 EmitArguments (ec, Arguments, dup_args, this_arg);
5036 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5037 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5041 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5042 call_op = OpCodes.Call;
5044 call_op = OpCodes.Callvirt;
5046 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5047 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5048 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5055 // and DoFoo is not virtual, you can omit the callvirt,
5056 // because you don't need the null checking behavior.
5058 if (method is MethodInfo)
5059 ig.Emit (call_op, (MethodInfo) method);
5061 ig.Emit (call_op, (ConstructorInfo) method);
5064 public override void Emit (EmitContext ec)
5066 mg.EmitCall (ec, Arguments);
5069 public override void EmitStatement (EmitContext ec)
5074 // Pop the return value if there is one
5076 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5077 ec.ig.Emit (OpCodes.Pop);
5080 protected override void CloneTo (CloneContext clonectx, Expression t)
5082 Invocation target = (Invocation) t;
5084 if (Arguments != null) {
5085 target.Arguments = new ArrayList (Arguments.Count);
5086 foreach (Argument a in Arguments)
5087 target.Arguments.Add (a.Clone (clonectx));
5090 target.expr = expr.Clone (clonectx);
5093 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5095 mg.MutateHoistedGenericType (storey);
5096 if (Arguments != null) {
5097 foreach (Argument a in Arguments)
5098 a.Expr.MutateHoistedGenericType (storey);
5104 // It's either a cast or delegate invocation
5106 public class InvocationOrCast : ExpressionStatement
5109 Expression argument;
5111 public InvocationOrCast (Expression expr, Expression argument)
5114 this.argument = argument;
5115 this.loc = expr.Location;
5118 public override Expression CreateExpressionTree (EmitContext ec)
5120 throw new NotSupportedException ("ET");
5123 public override Expression DoResolve (EmitContext ec)
5125 Expression e = ResolveCore (ec);
5129 return e.Resolve (ec);
5132 Expression ResolveCore (EmitContext ec)
5135 // First try to resolve it as a cast.
5137 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5139 return new Cast (te, argument, loc);
5143 // This can either be a type or a delegate invocation.
5144 // Let's just resolve it and see what we'll get.
5146 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5151 // Ok, so it's a Cast.
5153 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5154 return new Cast (expr, argument, loc);
5157 if (expr.eclass == ExprClass.Namespace) {
5158 expr.Error_UnexpectedKind (null, "type", loc);
5163 // It's a delegate invocation.
5165 if (!TypeManager.IsDelegateType (expr.Type)) {
5166 Error (149, "Method name expected");
5170 ArrayList args = new ArrayList (1);
5171 args.Add (new Argument (argument, Argument.AType.Expression));
5172 return new DelegateInvocation (expr, args, loc);
5175 public override ExpressionStatement ResolveStatement (EmitContext ec)
5177 Expression e = ResolveCore (ec);
5181 ExpressionStatement s = e as ExpressionStatement;
5183 Error_InvalidExpressionStatement ();
5187 return s.ResolveStatement (ec);
5190 public override void Emit (EmitContext ec)
5192 throw new Exception ("Cannot happen");
5195 public override void EmitStatement (EmitContext ec)
5197 throw new Exception ("Cannot happen");
5200 protected override void CloneTo (CloneContext clonectx, Expression t)
5202 InvocationOrCast target = (InvocationOrCast) t;
5204 target.expr = expr.Clone (clonectx);
5205 target.argument = argument.Clone (clonectx);
5210 // This class is used to "disable" the code generation for the
5211 // temporary variable when initializing value types.
5213 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5214 public void AddressOf (EmitContext ec, AddressOp Mode)
5221 /// Implements the new expression
5223 public class New : ExpressionStatement, IMemoryLocation {
5224 ArrayList Arguments;
5227 // During bootstrap, it contains the RequestedType,
5228 // but if `type' is not null, it *might* contain a NewDelegate
5229 // (because of field multi-initialization)
5231 public Expression RequestedType;
5233 MethodGroupExpr method;
5236 // If set, the new expression is for a value_target, and
5237 // we will not leave anything on the stack.
5239 protected Expression value_target;
5240 protected bool value_target_set;
5241 bool is_type_parameter = false;
5243 public New (Expression requested_type, ArrayList arguments, Location l)
5245 RequestedType = requested_type;
5246 Arguments = arguments;
5250 public bool SetTargetVariable (Expression value)
5252 value_target = value;
5253 value_target_set = true;
5254 if (!(value_target is IMemoryLocation)){
5255 Error_UnexpectedKind (null, "variable", loc);
5262 // This function is used to disable the following code sequence for
5263 // value type initialization:
5265 // AddressOf (temporary)
5269 // Instead the provide will have provided us with the address on the
5270 // stack to store the results.
5272 static Expression MyEmptyExpression;
5274 public void DisableTemporaryValueType ()
5276 if (MyEmptyExpression == null)
5277 MyEmptyExpression = new EmptyAddressOf ();
5280 // To enable this, look into:
5281 // test-34 and test-89 and self bootstrapping.
5283 // For instance, we can avoid a copy by using `newobj'
5284 // instead of Call + Push-temp on value types.
5285 // value_target = MyEmptyExpression;
5290 /// Converts complex core type syntax like 'new int ()' to simple constant
5292 public static Constant Constantify (Type t)
5294 if (t == TypeManager.int32_type)
5295 return new IntConstant (0, Location.Null);
5296 if (t == TypeManager.uint32_type)
5297 return new UIntConstant (0, Location.Null);
5298 if (t == TypeManager.int64_type)
5299 return new LongConstant (0, Location.Null);
5300 if (t == TypeManager.uint64_type)
5301 return new ULongConstant (0, Location.Null);
5302 if (t == TypeManager.float_type)
5303 return new FloatConstant (0, Location.Null);
5304 if (t == TypeManager.double_type)
5305 return new DoubleConstant (0, Location.Null);
5306 if (t == TypeManager.short_type)
5307 return new ShortConstant (0, Location.Null);
5308 if (t == TypeManager.ushort_type)
5309 return new UShortConstant (0, Location.Null);
5310 if (t == TypeManager.sbyte_type)
5311 return new SByteConstant (0, Location.Null);
5312 if (t == TypeManager.byte_type)
5313 return new ByteConstant (0, Location.Null);
5314 if (t == TypeManager.char_type)
5315 return new CharConstant ('\0', Location.Null);
5316 if (t == TypeManager.bool_type)
5317 return new BoolConstant (false, Location.Null);
5318 if (t == TypeManager.decimal_type)
5319 return new DecimalConstant (0, Location.Null);
5320 if (TypeManager.IsEnumType (t))
5321 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5327 // Checks whether the type is an interface that has the
5328 // [ComImport, CoClass] attributes and must be treated
5331 public Expression CheckComImport (EmitContext ec)
5333 if (!type.IsInterface)
5337 // Turn the call into:
5338 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5340 Type real_class = AttributeTester.GetCoClassAttribute (type);
5341 if (real_class == null)
5344 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5345 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5346 return cast.Resolve (ec);
5349 public override Expression CreateExpressionTree (EmitContext ec)
5351 ArrayList args = Arguments == null ?
5352 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5354 if (method == null) {
5355 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5357 args.Add (new Argument (method.CreateExpressionTree (ec)));
5358 if (Arguments != null) {
5360 foreach (Argument a in Arguments) {
5361 expr = a.Expr.CreateExpressionTree (ec);
5363 args.Add (new Argument (expr));
5368 return CreateExpressionFactoryCall ("New", args);
5371 public override Expression DoResolve (EmitContext ec)
5374 // The New DoResolve might be called twice when initializing field
5375 // expressions (see EmitFieldInitializers, the call to
5376 // GetInitializerExpression will perform a resolve on the expression,
5377 // and later the assign will trigger another resolution
5379 // This leads to bugs (#37014)
5382 if (RequestedType is NewDelegate)
5383 return RequestedType;
5387 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5393 if (type.IsPointer) {
5394 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5395 TypeManager.CSharpName (type));
5399 if (Arguments == null) {
5400 Constant c = Constantify (type);
5402 return ReducedExpression.Create (c, this);
5405 if (TypeManager.IsDelegateType (type)) {
5406 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5410 if (type.IsGenericParameter) {
5411 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5413 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5414 Error (304, String.Format (
5415 "Cannot create an instance of the " +
5416 "variable type '{0}' because it " +
5417 "doesn't have the new() constraint",
5422 if ((Arguments != null) && (Arguments.Count != 0)) {
5423 Error (417, String.Format (
5424 "`{0}': cannot provide arguments " +
5425 "when creating an instance of a " +
5426 "variable type.", type));
5430 if (TypeManager.activator_create_instance == null) {
5431 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5432 if (activator_type != null) {
5433 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5434 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5438 is_type_parameter = true;
5439 eclass = ExprClass.Value;
5444 if (type.IsAbstract && type.IsSealed) {
5445 Report.SymbolRelatedToPreviousError (type);
5446 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5450 if (type.IsInterface || type.IsAbstract){
5451 if (!TypeManager.IsGenericType (type)) {
5452 RequestedType = CheckComImport (ec);
5453 if (RequestedType != null)
5454 return RequestedType;
5457 Report.SymbolRelatedToPreviousError (type);
5458 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5462 bool is_struct = type.IsValueType;
5463 eclass = ExprClass.Value;
5466 // SRE returns a match for .ctor () on structs (the object constructor),
5467 // so we have to manually ignore it.
5469 if (is_struct && Arguments == null)
5472 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5473 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5474 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5476 if (Arguments != null){
5477 foreach (Argument a in Arguments){
5478 if (!a.Resolve (ec, loc))
5486 method = ml as MethodGroupExpr;
5487 if (method == null) {
5488 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5492 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5499 bool DoEmitTypeParameter (EmitContext ec)
5502 ILGenerator ig = ec.ig;
5503 // IMemoryLocation ml;
5505 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5506 new Type [] { type });
5508 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5509 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5510 ig.Emit (OpCodes.Call, ci);
5514 // Allow DoEmit() to be called multiple times.
5515 // We need to create a new LocalTemporary each time since
5516 // you can't share LocalBuilders among ILGeneators.
5517 LocalTemporary temp = new LocalTemporary (type);
5519 Label label_activator = ig.DefineLabel ();
5520 Label label_end = ig.DefineLabel ();
5522 temp.AddressOf (ec, AddressOp.Store);
5523 ig.Emit (OpCodes.Initobj, type);
5526 ig.Emit (OpCodes.Box, type);
5527 ig.Emit (OpCodes.Brfalse, label_activator);
5529 temp.AddressOf (ec, AddressOp.Store);
5530 ig.Emit (OpCodes.Initobj, type);
5532 ig.Emit (OpCodes.Br, label_end);
5534 ig.MarkLabel (label_activator);
5536 ig.Emit (OpCodes.Call, ci);
5537 ig.MarkLabel (label_end);
5540 throw new InternalErrorException ();
5545 // This DoEmit can be invoked in two contexts:
5546 // * As a mechanism that will leave a value on the stack (new object)
5547 // * As one that wont (init struct)
5549 // You can control whether a value is required on the stack by passing
5550 // need_value_on_stack. The code *might* leave a value on the stack
5551 // so it must be popped manually
5553 // If we are dealing with a ValueType, we have a few
5554 // situations to deal with:
5556 // * The target is a ValueType, and we have been provided
5557 // the instance (this is easy, we are being assigned).
5559 // * The target of New is being passed as an argument,
5560 // to a boxing operation or a function that takes a
5563 // In this case, we need to create a temporary variable
5564 // that is the argument of New.
5566 // Returns whether a value is left on the stack
5568 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5570 bool is_value_type = TypeManager.IsValueType (type);
5571 ILGenerator ig = ec.ig;
5576 // Allow DoEmit() to be called multiple times.
5577 // We need to create a new LocalTemporary each time since
5578 // you can't share LocalBuilders among ILGeneators.
5579 if (!value_target_set)
5580 value_target = new LocalTemporary (type);
5582 ml = (IMemoryLocation) value_target;
5583 ml.AddressOf (ec, AddressOp.Store);
5587 method.EmitArguments (ec, Arguments);
5591 ig.Emit (OpCodes.Initobj, type);
5593 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5594 if (need_value_on_stack){
5595 value_target.Emit (ec);
5600 ConstructorInfo ci = (ConstructorInfo) method;
5602 if (TypeManager.IsGenericType (type))
5603 ci = TypeBuilder.GetConstructor (type, ci);
5605 ig.Emit (OpCodes.Newobj, ci);
5610 public override void Emit (EmitContext ec)
5612 if (is_type_parameter)
5613 DoEmitTypeParameter (ec);
5618 public override void EmitStatement (EmitContext ec)
5620 bool value_on_stack;
5622 if (is_type_parameter)
5623 value_on_stack = DoEmitTypeParameter (ec);
5625 value_on_stack = DoEmit (ec, false);
5628 ec.ig.Emit (OpCodes.Pop);
5632 public virtual bool HasInitializer {
5638 public void AddressOf (EmitContext ec, AddressOp Mode)
5640 if (is_type_parameter) {
5641 LocalTemporary temp = new LocalTemporary (type);
5642 DoEmitTypeParameter (ec);
5644 temp.AddressOf (ec, Mode);
5648 if (!type.IsValueType){
5650 // We throw an exception. So far, I believe we only need to support
5652 // foreach (int j in new StructType ())
5655 throw new Exception ("AddressOf should not be used for classes");
5658 if (!value_target_set)
5659 value_target = new LocalTemporary (type);
5660 IMemoryLocation ml = (IMemoryLocation) value_target;
5662 ml.AddressOf (ec, AddressOp.Store);
5663 if (method == null) {
5664 ec.ig.Emit (OpCodes.Initobj, type);
5666 method.EmitArguments (ec, Arguments);
5667 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5670 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5673 protected override void CloneTo (CloneContext clonectx, Expression t)
5675 New target = (New) t;
5677 target.RequestedType = RequestedType.Clone (clonectx);
5678 if (Arguments != null){
5679 target.Arguments = new ArrayList ();
5680 foreach (Argument a in Arguments){
5681 target.Arguments.Add (a.Clone (clonectx));
5686 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5688 if (method != null) {
5689 method.MutateHoistedGenericType (storey);
5690 if (Arguments != null) {
5691 foreach (Argument a in Arguments)
5692 a.Expr.MutateHoistedGenericType (storey);
5696 type = storey.MutateType (type);
5701 /// 14.5.10.2: Represents an array creation expression.
5705 /// There are two possible scenarios here: one is an array creation
5706 /// expression that specifies the dimensions and optionally the
5707 /// initialization data and the other which does not need dimensions
5708 /// specified but where initialization data is mandatory.
5710 public class ArrayCreation : Expression {
5711 FullNamedExpression requested_base_type;
5712 ArrayList initializers;
5715 // The list of Argument types.
5716 // This is used to construct the `newarray' or constructor signature
5718 protected ArrayList arguments;
5720 protected Type array_element_type;
5721 bool expect_initializers = false;
5722 int num_arguments = 0;
5723 protected int dimensions;
5724 protected readonly string rank;
5726 protected ArrayList array_data;
5730 // The number of constants in array initializers
5731 int const_initializers_count;
5732 bool only_constant_initializers;
5734 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5736 this.requested_base_type = requested_base_type;
5737 this.initializers = initializers;
5741 arguments = new ArrayList (exprs.Count);
5743 foreach (Expression e in exprs) {
5744 arguments.Add (new Argument (e, Argument.AType.Expression));
5749 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5751 this.requested_base_type = requested_base_type;
5752 this.initializers = initializers;
5756 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5758 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5760 //dimensions = tmp.Length - 1;
5761 expect_initializers = true;
5764 void Error_IncorrectArrayInitializer ()
5766 Error (178, "Invalid rank specifier: expected `,' or `]'");
5769 protected override void Error_NegativeArrayIndex (Location loc)
5771 Report.Error (248, loc, "Cannot create an array with a negative size");
5774 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5776 if (specified_dims) {
5777 Argument a = (Argument) arguments [idx];
5779 if (!a.Resolve (ec, loc))
5782 Constant c = a.Expr as Constant;
5784 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5788 Report.Error (150, a.Expr.Location, "A constant value is expected");
5792 int value = (int) c.GetValue ();
5794 if (value != probe.Count) {
5795 Error_IncorrectArrayInitializer ();
5799 bounds [idx] = value;
5802 int child_bounds = -1;
5803 only_constant_initializers = true;
5804 for (int i = 0; i < probe.Count; ++i) {
5805 object o = probe [i];
5806 if (o is ArrayList) {
5807 ArrayList sub_probe = o as ArrayList;
5808 int current_bounds = sub_probe.Count;
5810 if (child_bounds == -1)
5811 child_bounds = current_bounds;
5813 else if (child_bounds != current_bounds){
5814 Error_IncorrectArrayInitializer ();
5817 if (idx + 1 >= dimensions){
5818 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5822 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5826 if (child_bounds != -1){
5827 Error_IncorrectArrayInitializer ();
5831 Expression element = ResolveArrayElement (ec, (Expression) o);
5832 if (element == null)
5835 // Initializers with the default values can be ignored
5836 Constant c = element as Constant;
5838 if (c.IsDefaultInitializer (array_element_type)) {
5842 ++const_initializers_count;
5845 only_constant_initializers = false;
5848 array_data.Add (element);
5855 public override Expression CreateExpressionTree (EmitContext ec)
5859 if (array_data == null) {
5860 args = new ArrayList (arguments.Count + 1);
5861 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5862 foreach (Argument a in arguments) {
5863 if (arguments.Count == 1) {
5864 Constant c = a.Expr as Constant;
5865 if (c.IsDefaultValue)
5866 return CreateExpressionFactoryCall ("NewArrayInit", args);
5868 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5871 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5874 if (dimensions > 1) {
5875 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5879 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5880 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5881 if (array_data != null) {
5882 for (int i = 0; i < array_data.Count; ++i) {
5883 Expression e = (Expression) array_data [i];
5885 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5887 args.Add (new Argument (e.CreateExpressionTree (ec)));
5891 return CreateExpressionFactoryCall ("NewArrayInit", args);
5894 public void UpdateIndices ()
5897 for (ArrayList probe = initializers; probe != null;) {
5898 if (probe.Count > 0 && probe [0] is ArrayList) {
5899 Expression e = new IntConstant (probe.Count, Location.Null);
5900 arguments.Add (new Argument (e, Argument.AType.Expression));
5902 bounds [i++] = probe.Count;
5904 probe = (ArrayList) probe [0];
5907 Expression e = new IntConstant (probe.Count, Location.Null);
5908 arguments.Add (new Argument (e, Argument.AType.Expression));
5910 bounds [i++] = probe.Count;
5917 Expression first_emit;
5918 LocalTemporary first_emit_temp;
5920 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5922 element = element.Resolve (ec);
5923 if (element == null)
5926 if (element is CompoundAssign.Helper) {
5927 if (first_emit != null)
5928 throw new InternalErrorException ("Can only handle one mutator at a time");
5929 first_emit = element;
5930 element = first_emit_temp = new LocalTemporary (element.Type);
5933 return Convert.ImplicitConversionRequired (
5934 ec, element, array_element_type, loc);
5937 protected bool ResolveInitializers (EmitContext ec)
5939 if (initializers == null) {
5940 return !expect_initializers;
5944 // We use this to store all the date values in the order in which we
5945 // will need to store them in the byte blob later
5947 array_data = new ArrayList ();
5948 bounds = new System.Collections.Specialized.HybridDictionary ();
5950 if (arguments != null)
5951 return CheckIndices (ec, initializers, 0, true);
5953 arguments = new ArrayList ();
5955 if (!CheckIndices (ec, initializers, 0, false))
5964 // Resolved the type of the array
5966 bool ResolveArrayType (EmitContext ec)
5968 if (requested_base_type == null) {
5969 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5973 if (requested_base_type is VarExpr) {
5974 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5978 StringBuilder array_qualifier = new StringBuilder (rank);
5981 // `In the first form allocates an array instace of the type that results
5982 // from deleting each of the individual expression from the expression list'
5984 if (num_arguments > 0) {
5985 array_qualifier.Append ("[");
5986 for (int i = num_arguments-1; i > 0; i--)
5987 array_qualifier.Append (",");
5988 array_qualifier.Append ("]");
5994 TypeExpr array_type_expr;
5995 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5996 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5997 if (array_type_expr == null)
6000 type = array_type_expr.Type;
6001 array_element_type = TypeManager.GetElementType (type);
6002 dimensions = type.GetArrayRank ();
6007 public override Expression DoResolve (EmitContext ec)
6012 if (!ResolveArrayType (ec))
6016 // First step is to validate the initializers and fill
6017 // in any missing bits
6019 if (!ResolveInitializers (ec))
6022 if (arguments.Count != dimensions) {
6023 Error_IncorrectArrayInitializer ();
6026 foreach (Argument a in arguments){
6027 if (!a.Resolve (ec, loc))
6030 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6033 eclass = ExprClass.Value;
6037 MethodInfo GetArrayMethod (int arguments)
6039 ModuleBuilder mb = CodeGen.Module.Builder;
6041 Type[] arg_types = new Type[arguments];
6042 for (int i = 0; i < arguments; i++)
6043 arg_types[i] = TypeManager.int32_type;
6045 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6049 Report.Error (-6, "New invocation: Can not find a constructor for " +
6050 "this argument list");
6057 byte [] MakeByteBlob ()
6062 int count = array_data.Count;
6064 if (TypeManager.IsEnumType (array_element_type))
6065 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6067 factor = GetTypeSize (array_element_type);
6069 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6071 data = new byte [(count * factor + 3) & ~3];
6074 for (int i = 0; i < count; ++i) {
6075 object v = array_data [i];
6077 if (v is EnumConstant)
6078 v = ((EnumConstant) v).Child;
6080 if (v is Constant && !(v is StringConstant))
6081 v = ((Constant) v).GetValue ();
6087 if (array_element_type == TypeManager.int64_type){
6088 if (!(v is Expression)){
6089 long val = (long) v;
6091 for (int j = 0; j < factor; ++j) {
6092 data [idx + j] = (byte) (val & 0xFF);
6096 } else if (array_element_type == TypeManager.uint64_type){
6097 if (!(v is Expression)){
6098 ulong val = (ulong) v;
6100 for (int j = 0; j < factor; ++j) {
6101 data [idx + j] = (byte) (val & 0xFF);
6105 } else if (array_element_type == TypeManager.float_type) {
6106 if (!(v is Expression)){
6107 element = BitConverter.GetBytes ((float) v);
6109 for (int j = 0; j < factor; ++j)
6110 data [idx + j] = element [j];
6111 if (!BitConverter.IsLittleEndian)
6112 System.Array.Reverse (data, idx, 4);
6114 } else if (array_element_type == TypeManager.double_type) {
6115 if (!(v is Expression)){
6116 element = BitConverter.GetBytes ((double) v);
6118 for (int j = 0; j < factor; ++j)
6119 data [idx + j] = element [j];
6121 // FIXME: Handle the ARM float format.
6122 if (!BitConverter.IsLittleEndian)
6123 System.Array.Reverse (data, idx, 8);
6125 } else if (array_element_type == TypeManager.char_type){
6126 if (!(v is Expression)){
6127 int val = (int) ((char) v);
6129 data [idx] = (byte) (val & 0xff);
6130 data [idx+1] = (byte) (val >> 8);
6132 } else if (array_element_type == TypeManager.short_type){
6133 if (!(v is Expression)){
6134 int val = (int) ((short) v);
6136 data [idx] = (byte) (val & 0xff);
6137 data [idx+1] = (byte) (val >> 8);
6139 } else if (array_element_type == TypeManager.ushort_type){
6140 if (!(v is Expression)){
6141 int val = (int) ((ushort) v);
6143 data [idx] = (byte) (val & 0xff);
6144 data [idx+1] = (byte) (val >> 8);
6146 } else if (array_element_type == TypeManager.int32_type) {
6147 if (!(v is Expression)){
6150 data [idx] = (byte) (val & 0xff);
6151 data [idx+1] = (byte) ((val >> 8) & 0xff);
6152 data [idx+2] = (byte) ((val >> 16) & 0xff);
6153 data [idx+3] = (byte) (val >> 24);
6155 } else if (array_element_type == TypeManager.uint32_type) {
6156 if (!(v is Expression)){
6157 uint val = (uint) v;
6159 data [idx] = (byte) (val & 0xff);
6160 data [idx+1] = (byte) ((val >> 8) & 0xff);
6161 data [idx+2] = (byte) ((val >> 16) & 0xff);
6162 data [idx+3] = (byte) (val >> 24);
6164 } else if (array_element_type == TypeManager.sbyte_type) {
6165 if (!(v is Expression)){
6166 sbyte val = (sbyte) v;
6167 data [idx] = (byte) val;
6169 } else if (array_element_type == TypeManager.byte_type) {
6170 if (!(v is Expression)){
6171 byte val = (byte) v;
6172 data [idx] = (byte) val;
6174 } else if (array_element_type == TypeManager.bool_type) {
6175 if (!(v is Expression)){
6176 bool val = (bool) v;
6177 data [idx] = (byte) (val ? 1 : 0);
6179 } else if (array_element_type == TypeManager.decimal_type){
6180 if (!(v is Expression)){
6181 int [] bits = Decimal.GetBits ((decimal) v);
6184 // FIXME: For some reason, this doesn't work on the MS runtime.
6185 int [] nbits = new int [4];
6186 nbits [0] = bits [3];
6187 nbits [1] = bits [2];
6188 nbits [2] = bits [0];
6189 nbits [3] = bits [1];
6191 for (int j = 0; j < 4; j++){
6192 data [p++] = (byte) (nbits [j] & 0xff);
6193 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6194 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6195 data [p++] = (byte) (nbits [j] >> 24);
6199 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6207 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6209 array_element_type = storey.MutateType (array_element_type);
6210 type = storey.MutateType (type);
6211 if (arguments != null) {
6212 foreach (Argument a in arguments)
6213 a.Expr.MutateHoistedGenericType (storey);
6216 if (array_data != null) {
6217 foreach (Expression e in array_data)
6218 e.MutateHoistedGenericType (storey);
6223 // Emits the initializers for the array
6225 void EmitStaticInitializers (EmitContext ec)
6227 // FIXME: This should go to Resolve !
6228 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6229 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6230 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6231 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6232 if (TypeManager.void_initializearray_array_fieldhandle == null)
6237 // First, the static data
6240 ILGenerator ig = ec.ig;
6242 byte [] data = MakeByteBlob ();
6244 fb = RootContext.MakeStaticData (data);
6246 ig.Emit (OpCodes.Dup);
6247 ig.Emit (OpCodes.Ldtoken, fb);
6248 ig.Emit (OpCodes.Call,
6249 TypeManager.void_initializearray_array_fieldhandle);
6253 // Emits pieces of the array that can not be computed at compile
6254 // time (variables and string locations).
6256 // This always expect the top value on the stack to be the array
6258 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6260 ILGenerator ig = ec.ig;
6261 int dims = bounds.Count;
6262 int [] current_pos = new int [dims];
6264 MethodInfo set = null;
6267 Type [] args = new Type [dims + 1];
6269 for (int j = 0; j < dims; j++)
6270 args [j] = TypeManager.int32_type;
6271 args [dims] = array_element_type;
6273 set = CodeGen.Module.Builder.GetArrayMethod (
6275 CallingConventions.HasThis | CallingConventions.Standard,
6276 TypeManager.void_type, args);
6279 for (int i = 0; i < array_data.Count; i++){
6281 Expression e = (Expression)array_data [i];
6283 // Constant can be initialized via StaticInitializer
6284 if (e != null && !(!emitConstants && e is Constant)) {
6285 Type etype = e.Type;
6287 ig.Emit (OpCodes.Dup);
6289 for (int idx = 0; idx < dims; idx++)
6290 IntConstant.EmitInt (ig, current_pos [idx]);
6293 // If we are dealing with a struct, get the
6294 // address of it, so we can store it.
6296 if ((dims == 1) && etype.IsValueType &&
6297 (!TypeManager.IsBuiltinOrEnum (etype) ||
6298 etype == TypeManager.decimal_type)) {
6303 // Let new know that we are providing
6304 // the address where to store the results
6306 n.DisableTemporaryValueType ();
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 array_element_type = element.Type;
6518 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6522 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6523 array_element_type = element.Type;
6527 Error_NoBestType ();
6532 public sealed class CompilerGeneratedThis : This
6534 public static This Instance = new CompilerGeneratedThis ();
6536 private CompilerGeneratedThis ()
6537 : base (Location.Null)
6541 public CompilerGeneratedThis (Type type, Location loc)
6547 public override Expression DoResolve (EmitContext ec)
6549 eclass = ExprClass.Variable;
6551 type = ec.ContainerType;
6555 public override HoistedVariable HoistedVariable {
6556 get { return null; }
6561 /// Represents the `this' construct
6564 public class This : VariableReference
6566 sealed class ThisVariable : ILocalVariable
6568 public static readonly ILocalVariable Instance = new ThisVariable ();
6570 public void Emit (EmitContext ec)
6572 ec.ig.Emit (OpCodes.Ldarg_0);
6575 public void EmitAssign (EmitContext ec)
6577 throw new InvalidOperationException ();
6580 public void EmitAddressOf (EmitContext ec)
6582 ec.ig.Emit (OpCodes.Ldarg_0);
6587 VariableInfo variable_info;
6590 public This (Block block, Location loc)
6596 public This (Location loc)
6601 public override VariableInfo VariableInfo {
6602 get { return variable_info; }
6605 public override bool IsFixed {
6606 get { return false; }
6609 protected override bool IsHoistedEmitRequired (EmitContext ec)
6612 // Handle 'this' differently, it cannot be assigned hence
6613 // when we are not inside anonymous method we can emit direct access
6615 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6618 public override HoistedVariable HoistedVariable {
6619 get { return TopToplevelBlock.HoistedThisVariable; }
6622 public override bool IsRef {
6623 get { return is_struct; }
6626 protected override ILocalVariable Variable {
6627 get { return ThisVariable.Instance; }
6630 // TODO: Move to ToplevelBlock
6631 ToplevelBlock TopToplevelBlock {
6633 ToplevelBlock tl = block.Toplevel;
6634 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6639 public static bool IsThisAvailable (EmitContext ec)
6641 if (ec.IsStatic || ec.IsInFieldInitializer)
6644 if (ec.CurrentAnonymousMethod == null)
6647 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6653 public bool ResolveBase (EmitContext ec)
6655 if (eclass != ExprClass.Invalid)
6658 eclass = ExprClass.Variable;
6660 if (ec.TypeContainer.CurrentType != null)
6661 type = ec.TypeContainer.CurrentType;
6663 type = ec.ContainerType;
6665 if (!IsThisAvailable (ec)) {
6667 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6669 Report.Error (1673, loc,
6670 "Anonymous methods inside structs cannot access instance members of `this'. " +
6671 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6675 is_struct = ec.TypeContainer is Struct;
6677 if (block != null) {
6678 if (block.Toplevel.ThisVariable != null)
6679 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6681 AnonymousExpression am = ec.CurrentAnonymousMethod;
6684 // this is hoisted to very top level block
6686 if (ec.IsVariableCapturingRequired) {
6687 // TODO: it could be optimized
6688 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6689 if (HoistedVariable == null) {
6690 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6700 // Called from Invocation to check if the invocation is correct
6702 public override void CheckMarshalByRefAccess (EmitContext ec)
6704 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6705 !variable_info.IsAssigned (ec)) {
6706 Error (188, "The `this' object cannot be used before all of its " +
6707 "fields are assigned to");
6708 variable_info.SetAssigned (ec);
6712 public override Expression CreateExpressionTree (EmitContext ec)
6714 ArrayList args = new ArrayList (2);
6715 args.Add (new Argument (this));
6716 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6717 return CreateExpressionFactoryCall ("Constant", args);
6720 public override Expression DoResolve (EmitContext ec)
6722 if (!ResolveBase (ec))
6726 if (ec.IsInFieldInitializer) {
6727 Error (27, "Keyword `this' is not available in the current context");
6734 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6736 if (!ResolveBase (ec))
6739 if (variable_info != null)
6740 variable_info.SetAssigned (ec);
6742 if (ec.TypeContainer is Class){
6743 if (right_side == EmptyExpression.UnaryAddress)
6744 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6745 else if (right_side == EmptyExpression.OutAccess)
6746 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6748 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6754 public override int GetHashCode()
6756 return block.GetHashCode ();
6759 public override string Name {
6760 get { return "this"; }
6763 public override bool Equals (object obj)
6765 This t = obj as This;
6769 return block == t.block;
6772 protected override void CloneTo (CloneContext clonectx, Expression t)
6774 This target = (This) t;
6776 target.block = clonectx.LookupBlock (block);
6779 public void RemoveHoisting ()
6781 TopToplevelBlock.HoistedThisVariable = null;
6784 public override void SetHasAddressTaken ()
6791 /// Represents the `__arglist' construct
6793 public class ArglistAccess : Expression
6795 public ArglistAccess (Location loc)
6800 public override Expression CreateExpressionTree (EmitContext ec)
6802 throw new NotSupportedException ("ET");
6805 public override Expression DoResolve (EmitContext ec)
6807 eclass = ExprClass.Variable;
6808 type = TypeManager.runtime_argument_handle_type;
6810 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6812 Error (190, "The __arglist construct is valid only within " +
6813 "a variable argument method");
6820 public override void Emit (EmitContext ec)
6822 ec.ig.Emit (OpCodes.Arglist);
6825 protected override void CloneTo (CloneContext clonectx, Expression target)
6832 /// Represents the `__arglist (....)' construct
6834 public class Arglist : Expression
6836 Argument[] Arguments;
6838 public Arglist (Location loc)
6839 : this (Argument.Empty, loc)
6843 public Arglist (Argument[] args, Location l)
6849 public Type[] ArgumentTypes {
6851 Type[] retval = new Type [Arguments.Length];
6852 for (int i = 0; i < Arguments.Length; i++)
6853 retval [i] = Arguments [i].Type;
6858 public override Expression CreateExpressionTree (EmitContext ec)
6860 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6864 public override Expression DoResolve (EmitContext ec)
6866 eclass = ExprClass.Variable;
6867 type = TypeManager.runtime_argument_handle_type;
6869 foreach (Argument arg in Arguments) {
6870 if (!arg.Resolve (ec, loc))
6877 public override void Emit (EmitContext ec)
6879 foreach (Argument arg in Arguments)
6883 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6885 foreach (Argument arg in Arguments)
6886 arg.Expr.MutateHoistedGenericType (storey);
6889 protected override void CloneTo (CloneContext clonectx, Expression t)
6891 Arglist target = (Arglist) t;
6893 target.Arguments = new Argument [Arguments.Length];
6894 for (int i = 0; i < Arguments.Length; i++)
6895 target.Arguments [i] = Arguments [i].Clone (clonectx);
6900 /// Implements the typeof operator
6902 public class TypeOf : Expression {
6903 Expression QueriedType;
6904 protected Type typearg;
6906 public TypeOf (Expression queried_type, Location l)
6908 QueriedType = queried_type;
6912 public override Expression CreateExpressionTree (EmitContext ec)
6914 ArrayList args = new ArrayList (2);
6915 args.Add (new Argument (this));
6916 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6917 return CreateExpressionFactoryCall ("Constant", args);
6920 public override Expression DoResolve (EmitContext ec)
6922 if (eclass != ExprClass.Invalid)
6925 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6929 typearg = texpr.Type;
6931 if (typearg == TypeManager.void_type) {
6932 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6936 if (typearg.IsPointer && !ec.InUnsafe){
6941 type = TypeManager.type_type;
6943 return DoResolveBase ();
6946 protected Expression DoResolveBase ()
6948 if (TypeManager.system_type_get_type_from_handle == null) {
6949 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6950 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6953 // Even though what is returned is a type object, it's treated as a value by the compiler.
6954 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6955 eclass = ExprClass.Value;
6959 public override void Emit (EmitContext ec)
6961 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6962 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6965 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6967 if (TypeManager.ContainsGenericParameters (typearg) &&
6968 !TypeManager.IsGenericTypeDefinition (typearg)) {
6969 Report.SymbolRelatedToPreviousError (typearg);
6970 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6971 TypeManager.CSharpName (typearg));
6976 if (value_type == TypeManager.object_type) {
6977 value = (object)typearg;
6984 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6986 typearg = storey.MutateType (typearg);
6989 public Type TypeArgument {
6995 protected override void CloneTo (CloneContext clonectx, Expression t)
6997 TypeOf target = (TypeOf) t;
6998 if (QueriedType != null)
6999 target.QueriedType = QueriedType.Clone (clonectx);
7004 /// Implements the `typeof (void)' operator
7006 public class TypeOfVoid : TypeOf {
7007 public TypeOfVoid (Location l) : base (null, l)
7012 public override Expression DoResolve (EmitContext ec)
7014 type = TypeManager.type_type;
7015 typearg = TypeManager.void_type;
7017 return DoResolveBase ();
7021 class TypeOfMethodInfo : TypeOfMethod
7023 public TypeOfMethodInfo (MethodBase method, Location loc)
7024 : base (method, loc)
7028 public override Expression DoResolve (EmitContext ec)
7030 type = typeof (MethodInfo);
7031 return base.DoResolve (ec);
7034 public override void Emit (EmitContext ec)
7036 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7038 ec.ig.Emit (OpCodes.Castclass, type);
7042 class TypeOfConstructorInfo : TypeOfMethod
7044 public TypeOfConstructorInfo (MethodBase method, Location loc)
7045 : base (method, loc)
7049 public override Expression DoResolve (EmitContext ec)
7051 type = typeof (ConstructorInfo);
7052 return base.DoResolve (ec);
7055 public override void Emit (EmitContext ec)
7057 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7059 ec.ig.Emit (OpCodes.Castclass, type);
7063 abstract class TypeOfMethod : Expression
7065 protected readonly MethodBase method;
7067 protected TypeOfMethod (MethodBase method, Location loc)
7069 this.method = method;
7073 public override Expression CreateExpressionTree (EmitContext ec)
7075 ArrayList args = new ArrayList (2);
7076 args.Add (new Argument (this));
7077 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7078 return CreateExpressionFactoryCall ("Constant", args);
7081 public override Expression DoResolve (EmitContext ec)
7083 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7084 MethodInfo mi = is_generic ?
7085 TypeManager.methodbase_get_type_from_handle_generic :
7086 TypeManager.methodbase_get_type_from_handle;
7089 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7090 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7092 if (t == null || handle_type == null)
7095 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7097 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7098 new Type[] { handle_type } );
7101 TypeManager.methodbase_get_type_from_handle_generic = mi;
7103 TypeManager.methodbase_get_type_from_handle = mi;
7106 eclass = ExprClass.Value;
7110 public override void Emit (EmitContext ec)
7112 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7115 mi = TypeManager.methodbase_get_type_from_handle_generic;
7116 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7118 mi = TypeManager.methodbase_get_type_from_handle;
7121 ec.ig.Emit (OpCodes.Call, mi);
7125 internal class TypeOfField : Expression
7127 readonly FieldInfo field;
7129 public TypeOfField (FieldInfo field, Location loc)
7135 public override Expression CreateExpressionTree (EmitContext ec)
7137 throw new NotSupportedException ("ET");
7140 public override Expression DoResolve (EmitContext ec)
7142 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7143 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7144 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7146 if (t != null && handle_type != null)
7147 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7148 "GetFieldFromHandle", loc, handle_type);
7151 type = typeof (FieldInfo);
7152 eclass = ExprClass.Value;
7156 public override void Emit (EmitContext ec)
7158 ec.ig.Emit (OpCodes.Ldtoken, field);
7159 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7164 /// Implements the sizeof expression
7166 public class SizeOf : Expression {
7167 readonly Expression QueriedType;
7170 public SizeOf (Expression queried_type, Location l)
7172 this.QueriedType = queried_type;
7176 public override Expression CreateExpressionTree (EmitContext ec)
7178 Error_PointerInsideExpressionTree ();
7182 public override Expression DoResolve (EmitContext ec)
7184 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7188 type_queried = texpr.Type;
7189 if (TypeManager.IsEnumType (type_queried))
7190 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7192 int size_of = GetTypeSize (type_queried);
7194 return new IntConstant (size_of, loc);
7197 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7202 Report.Error (233, loc,
7203 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7204 TypeManager.CSharpName (type_queried));
7207 type = TypeManager.int32_type;
7208 eclass = ExprClass.Value;
7212 public override void Emit (EmitContext ec)
7214 int size = GetTypeSize (type_queried);
7217 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7219 IntConstant.EmitInt (ec.ig, size);
7222 protected override void CloneTo (CloneContext clonectx, Expression t)
7228 /// Implements the qualified-alias-member (::) expression.
7230 public class QualifiedAliasMember : MemberAccess
7232 readonly string alias;
7233 public static readonly string GlobalAlias = "global";
7235 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7236 : base (null, identifier, targs, l)
7241 public QualifiedAliasMember (string alias, string identifier, Location l)
7242 : base (null, identifier, l)
7247 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7249 if (alias == GlobalAlias) {
7250 expr = RootNamespace.Global;
7251 return base.ResolveAsTypeStep (ec, silent);
7254 int errors = Report.Errors;
7255 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7257 if (errors == Report.Errors)
7258 Report.Error (432, loc, "Alias `{0}' not found", alias);
7262 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7266 if (expr.eclass == ExprClass.Type) {
7268 Report.Error (431, loc,
7269 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7277 public override Expression DoResolve (EmitContext ec)
7279 return ResolveAsTypeStep (ec, false);
7282 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7284 Report.Error (687, loc,
7285 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7286 GetSignatureForError ());
7289 public override string GetSignatureForError ()
7292 if (targs != null) {
7293 name = TypeManager.RemoveGenericArity (Name) + "<" +
7294 targs.GetSignatureForError () + ">";
7297 return alias + "::" + name;
7300 protected override void CloneTo (CloneContext clonectx, Expression t)
7307 /// Implements the member access expression
7309 public class MemberAccess : ATypeNameExpression {
7310 protected Expression expr;
7312 public MemberAccess (Expression expr, string id)
7313 : base (id, expr.Location)
7318 public MemberAccess (Expression expr, string identifier, Location loc)
7319 : base (identifier, loc)
7324 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7325 : base (identifier, args, loc)
7330 // TODO: this method has very poor performace for Enum fields and
7331 // probably for other constants as well
7332 Expression DoResolve (EmitContext ec, Expression right_side)
7335 throw new Exception ();
7338 // Resolve the expression with flow analysis turned off, we'll do the definite
7339 // assignment checks later. This is because we don't know yet what the expression
7340 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7341 // definite assignment check on the actual field and not on the whole struct.
7344 SimpleName original = expr as SimpleName;
7345 Expression expr_resolved = expr.Resolve (ec,
7346 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7347 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7349 if (expr_resolved == null)
7352 string LookupIdentifier = MemberName.MakeName (Name, targs);
7354 if (expr_resolved is Namespace) {
7355 Namespace ns = (Namespace) expr_resolved;
7356 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7358 if ((retval != null) && (targs != null))
7359 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7363 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7367 Type expr_type = expr_resolved.Type;
7368 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7369 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7370 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7374 Constant c = expr_resolved as Constant;
7375 if (c != null && c.GetValue () == null) {
7376 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7377 "System.NullReferenceException");
7380 if (targs != null) {
7381 if (!targs.Resolve (ec))
7385 Expression member_lookup;
7386 member_lookup = MemberLookup (
7387 ec.ContainerType, expr_type, expr_type, Name, loc);
7389 if ((member_lookup == null) && (targs != null)) {
7390 member_lookup = MemberLookup (
7391 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7394 if (member_lookup == null) {
7395 ExprClass expr_eclass = expr_resolved.eclass;
7398 // Extension methods are not allowed on all expression types
7400 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7401 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7402 expr_eclass == ExprClass.EventAccess) {
7403 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7404 if (ex_method_lookup != null) {
7405 ex_method_lookup.ExtensionExpression = expr_resolved;
7407 if (targs != null) {
7408 ex_method_lookup.SetTypeArguments (targs);
7411 return ex_method_lookup.DoResolve (ec);
7415 expr = expr_resolved;
7416 Error_MemberLookupFailed (
7417 ec.ContainerType, expr_type, expr_type, Name, null,
7418 AllMemberTypes, AllBindingFlags);
7422 TypeExpr texpr = member_lookup as TypeExpr;
7423 if (texpr != null) {
7424 if (!(expr_resolved is TypeExpr) &&
7425 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7426 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7427 Name, member_lookup.GetSignatureForError ());
7431 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7432 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7433 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7438 ConstructedType ct = expr_resolved as ConstructedType;
7441 // When looking up a nested type in a generic instance
7442 // via reflection, we always get a generic type definition
7443 // and not a generic instance - so we have to do this here.
7445 // See gtest-172-lib.cs and gtest-172.cs for an example.
7447 ct = new ConstructedType (
7448 member_lookup.Type, ct.TypeArguments, loc);
7450 return ct.ResolveAsTypeStep (ec, false);
7453 return member_lookup;
7456 MemberExpr me = (MemberExpr) member_lookup;
7457 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7461 if (targs != null) {
7462 me.SetTypeArguments (targs);
7465 if (original != null && !TypeManager.IsValueType (expr_type)) {
7466 if (me.IsInstance) {
7467 LocalVariableReference var = expr_resolved as LocalVariableReference;
7468 if (var != null && !var.VerifyAssigned (ec))
7473 // The following DoResolve/DoResolveLValue will do the definite assignment
7476 if (right_side != null)
7477 return me.DoResolveLValue (ec, right_side);
7479 return me.DoResolve (ec);
7482 public override Expression DoResolve (EmitContext ec)
7484 return DoResolve (ec, null);
7487 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7489 return DoResolve (ec, right_side);
7492 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7494 return ResolveNamespaceOrType (ec, silent);
7497 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7499 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7501 if (new_expr == null)
7504 string LookupIdentifier = MemberName.MakeName (Name, targs);
7506 if (new_expr is Namespace) {
7507 Namespace ns = (Namespace) new_expr;
7508 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7510 if ((retval != null) && (targs != null))
7511 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7513 if (!silent && retval == null)
7514 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7518 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7519 if (tnew_expr == null)
7522 if (tnew_expr is TypeParameterExpr) {
7523 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7524 tnew_expr.GetSignatureForError ());
7528 Type expr_type = tnew_expr.Type;
7529 Expression member_lookup = MemberLookup (
7530 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7531 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7532 if (member_lookup == null) {
7536 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7540 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7545 TypeArguments the_args = targs;
7546 Type declaring_type = texpr.Type.DeclaringType;
7547 if (TypeManager.HasGenericArguments (declaring_type)) {
7548 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7549 expr_type = expr_type.BaseType;
7552 TypeArguments new_args = new TypeArguments (loc);
7553 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7554 new_args.Add (new TypeExpression (decl, loc));
7557 new_args.Add (targs);
7559 the_args = new_args;
7562 if (the_args != null) {
7563 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7564 return ctype.ResolveAsTypeStep (rc, false);
7571 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7573 Expression member_lookup = MemberLookup (
7574 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7575 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7577 if (member_lookup != null) {
7578 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7579 if (expr_type == null)
7582 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7586 member_lookup = MemberLookup (
7587 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7588 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7590 if (member_lookup == null) {
7591 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7592 Name, expr_type.GetSignatureForError ());
7594 // TODO: Report.SymbolRelatedToPreviousError
7595 member_lookup.Error_UnexpectedKind (null, "type", loc);
7599 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7601 if (RootContext.Version > LanguageVersion.ISO_2 &&
7602 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7603 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7604 "extension method `{1}' of type `{0}' could be found " +
7605 "(are you missing a using directive or an assembly reference?)",
7606 TypeManager.CSharpName (type), name);
7610 base.Error_TypeDoesNotContainDefinition (type, name);
7613 public override string GetSignatureForError ()
7615 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7618 protected override void CloneTo (CloneContext clonectx, Expression t)
7620 MemberAccess target = (MemberAccess) t;
7622 target.expr = expr.Clone (clonectx);
7627 /// Implements checked expressions
7629 public class CheckedExpr : Expression {
7631 public Expression Expr;
7633 public CheckedExpr (Expression e, Location l)
7639 public override Expression CreateExpressionTree (EmitContext ec)
7641 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7642 return Expr.CreateExpressionTree (ec);
7645 public override Expression DoResolve (EmitContext ec)
7647 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7648 Expr = Expr.Resolve (ec);
7653 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7656 eclass = Expr.eclass;
7661 public override void Emit (EmitContext ec)
7663 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7667 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7669 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7670 Expr.EmitBranchable (ec, target, on_true);
7673 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7675 Expr.MutateHoistedGenericType (storey);
7678 protected override void CloneTo (CloneContext clonectx, Expression t)
7680 CheckedExpr target = (CheckedExpr) t;
7682 target.Expr = Expr.Clone (clonectx);
7687 /// Implements the unchecked expression
7689 public class UnCheckedExpr : Expression {
7691 public Expression Expr;
7693 public UnCheckedExpr (Expression e, Location l)
7699 public override Expression CreateExpressionTree (EmitContext ec)
7701 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7702 return Expr.CreateExpressionTree (ec);
7705 public override Expression DoResolve (EmitContext ec)
7707 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7708 Expr = Expr.Resolve (ec);
7713 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7716 eclass = Expr.eclass;
7721 public override void Emit (EmitContext ec)
7723 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7727 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7729 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7730 Expr.EmitBranchable (ec, target, on_true);
7733 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7735 Expr.MutateHoistedGenericType (storey);
7738 protected override void CloneTo (CloneContext clonectx, Expression t)
7740 UnCheckedExpr target = (UnCheckedExpr) t;
7742 target.Expr = Expr.Clone (clonectx);
7747 /// An Element Access expression.
7749 /// During semantic analysis these are transformed into
7750 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7752 public class ElementAccess : Expression {
7753 public ArrayList Arguments;
7754 public Expression Expr;
7756 public ElementAccess (Expression e, ArrayList e_list)
7764 Arguments = new ArrayList (e_list.Count);
7765 foreach (Expression tmp in e_list)
7766 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7769 bool CommonResolve (EmitContext ec)
7771 Expr = Expr.Resolve (ec);
7773 if (Arguments == null)
7776 foreach (Argument a in Arguments){
7777 if (!a.Resolve (ec, loc))
7781 return Expr != null;
7784 public override Expression CreateExpressionTree (EmitContext ec)
7786 ArrayList args = new ArrayList (Arguments.Count + 1);
7787 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7788 foreach (Argument a in Arguments)
7789 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7791 return CreateExpressionFactoryCall ("ArrayIndex", args);
7794 Expression MakePointerAccess (EmitContext ec, Type t)
7796 if (Arguments.Count != 1){
7797 Error (196, "A pointer must be indexed by only one value");
7801 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7804 return new Indirection (p, loc).Resolve (ec);
7807 public override Expression DoResolve (EmitContext ec)
7809 if (!CommonResolve (ec))
7813 // We perform some simple tests, and then to "split" the emit and store
7814 // code we create an instance of a different class, and return that.
7816 // I am experimenting with this pattern.
7820 if (t == TypeManager.array_type){
7821 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7826 return (new ArrayAccess (this, loc)).Resolve (ec);
7828 return MakePointerAccess (ec, t);
7830 FieldExpr fe = Expr as FieldExpr;
7832 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7834 return MakePointerAccess (ec, ff.ElementType);
7837 return (new IndexerAccess (this, loc)).Resolve (ec);
7840 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7842 if (!CommonResolve (ec))
7847 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7850 return MakePointerAccess (ec, type);
7852 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7853 Error_CannotModifyIntermediateExpressionValue (ec);
7855 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7858 public override void Emit (EmitContext ec)
7860 throw new Exception ("Should never be reached");
7863 public override string GetSignatureForError ()
7865 return Expr.GetSignatureForError ();
7868 protected override void CloneTo (CloneContext clonectx, Expression t)
7870 ElementAccess target = (ElementAccess) t;
7872 target.Expr = Expr.Clone (clonectx);
7873 target.Arguments = new ArrayList (Arguments.Count);
7874 foreach (Argument a in Arguments)
7875 target.Arguments.Add (a.Clone (clonectx));
7880 /// Implements array access
7882 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7884 // Points to our "data" repository
7888 LocalTemporary temp;
7892 public ArrayAccess (ElementAccess ea_data, Location l)
7898 public override Expression CreateExpressionTree (EmitContext ec)
7900 return ea.CreateExpressionTree (ec);
7903 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7905 return DoResolve (ec);
7908 public override Expression DoResolve (EmitContext ec)
7911 ExprClass eclass = ea.Expr.eclass;
7913 // As long as the type is valid
7914 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7915 eclass == ExprClass.Value)) {
7916 ea.Expr.Error_UnexpectedKind ("variable or value");
7921 if (eclass != ExprClass.Invalid)
7924 Type t = ea.Expr.Type;
7925 int rank = ea.Arguments.Count;
7926 if (t.GetArrayRank () != rank) {
7927 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7928 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7932 type = TypeManager.GetElementType (t);
7933 if (type.IsPointer && !ec.InUnsafe) {
7934 UnsafeError (ea.Location);
7938 foreach (Argument a in ea.Arguments) {
7939 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7942 eclass = ExprClass.Variable;
7948 /// Emits the right opcode to load an object of Type `t'
7949 /// from an array of T
7951 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7954 MethodInfo get = FetchGetMethod ();
7955 ig.Emit (OpCodes.Call, get);
7959 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7960 ig.Emit (OpCodes.Ldelem_U1);
7961 else if (type == TypeManager.sbyte_type)
7962 ig.Emit (OpCodes.Ldelem_I1);
7963 else if (type == TypeManager.short_type)
7964 ig.Emit (OpCodes.Ldelem_I2);
7965 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7966 ig.Emit (OpCodes.Ldelem_U2);
7967 else if (type == TypeManager.int32_type)
7968 ig.Emit (OpCodes.Ldelem_I4);
7969 else if (type == TypeManager.uint32_type)
7970 ig.Emit (OpCodes.Ldelem_U4);
7971 else if (type == TypeManager.uint64_type)
7972 ig.Emit (OpCodes.Ldelem_I8);
7973 else if (type == TypeManager.int64_type)
7974 ig.Emit (OpCodes.Ldelem_I8);
7975 else if (type == TypeManager.float_type)
7976 ig.Emit (OpCodes.Ldelem_R4);
7977 else if (type == TypeManager.double_type)
7978 ig.Emit (OpCodes.Ldelem_R8);
7979 else if (type == TypeManager.intptr_type)
7980 ig.Emit (OpCodes.Ldelem_I);
7981 else if (TypeManager.IsEnumType (type)){
7982 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7983 } else if (type.IsValueType){
7984 ig.Emit (OpCodes.Ldelema, type);
7985 ig.Emit (OpCodes.Ldobj, type);
7987 } else if (type.IsGenericParameter) {
7988 ig.Emit (OpCodes.Ldelem, type);
7990 } else if (type.IsPointer)
7991 ig.Emit (OpCodes.Ldelem_I);
7993 ig.Emit (OpCodes.Ldelem_Ref);
7996 protected override void Error_NegativeArrayIndex (Location loc)
7998 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8002 /// Returns the right opcode to store an object of Type `t'
8003 /// from an array of T.
8005 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8007 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8008 has_type_arg = false; is_stobj = false;
8009 t = TypeManager.TypeToCoreType (t);
8010 if (TypeManager.IsEnumType (t))
8011 t = TypeManager.GetEnumUnderlyingType (t);
8012 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8013 t == TypeManager.bool_type)
8014 return OpCodes.Stelem_I1;
8015 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8016 t == TypeManager.char_type)
8017 return OpCodes.Stelem_I2;
8018 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8019 return OpCodes.Stelem_I4;
8020 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8021 return OpCodes.Stelem_I8;
8022 else if (t == TypeManager.float_type)
8023 return OpCodes.Stelem_R4;
8024 else if (t == TypeManager.double_type)
8025 return OpCodes.Stelem_R8;
8026 else if (t == TypeManager.intptr_type) {
8027 has_type_arg = true;
8029 return OpCodes.Stobj;
8030 } else if (t.IsValueType) {
8031 has_type_arg = true;
8033 return OpCodes.Stobj;
8035 } else if (t.IsGenericParameter) {
8036 has_type_arg = true;
8037 return OpCodes.Stelem;
8040 } else if (t.IsPointer)
8041 return OpCodes.Stelem_I;
8043 return OpCodes.Stelem_Ref;
8046 MethodInfo FetchGetMethod ()
8048 ModuleBuilder mb = CodeGen.Module.Builder;
8049 int arg_count = ea.Arguments.Count;
8050 Type [] args = new Type [arg_count];
8053 for (int i = 0; i < arg_count; i++){
8054 //args [i++] = a.Type;
8055 args [i] = TypeManager.int32_type;
8058 get = mb.GetArrayMethod (
8059 ea.Expr.Type, "Get",
8060 CallingConventions.HasThis |
8061 CallingConventions.Standard,
8067 MethodInfo FetchAddressMethod ()
8069 ModuleBuilder mb = CodeGen.Module.Builder;
8070 int arg_count = ea.Arguments.Count;
8071 Type [] args = new Type [arg_count];
8075 ret_type = TypeManager.GetReferenceType (type);
8077 for (int i = 0; i < arg_count; i++){
8078 //args [i++] = a.Type;
8079 args [i] = TypeManager.int32_type;
8082 address = mb.GetArrayMethod (
8083 ea.Expr.Type, "Address",
8084 CallingConventions.HasThis |
8085 CallingConventions.Standard,
8092 // Load the array arguments into the stack.
8094 void LoadArrayAndArguments (EmitContext ec)
8098 for (int i = 0; i < ea.Arguments.Count; ++i) {
8099 ((Argument)ea.Arguments [i]).Emit (ec);
8103 public void Emit (EmitContext ec, bool leave_copy)
8105 int rank = ea.Expr.Type.GetArrayRank ();
8106 ILGenerator ig = ec.ig;
8109 LoadFromPtr (ig, this.type);
8111 LoadArrayAndArguments (ec);
8112 EmitLoadOpcode (ig, type, rank);
8116 ig.Emit (OpCodes.Dup);
8117 temp = new LocalTemporary (this.type);
8122 public override void Emit (EmitContext ec)
8127 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8129 int rank = ea.Expr.Type.GetArrayRank ();
8130 ILGenerator ig = ec.ig;
8131 Type t = source.Type;
8132 prepared = prepare_for_load;
8135 AddressOf (ec, AddressOp.LoadStore);
8136 ec.ig.Emit (OpCodes.Dup);
8138 LoadArrayAndArguments (ec);
8142 bool is_stobj, has_type_arg;
8143 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8147 // The stobj opcode used by value types will need
8148 // an address on the stack, not really an array/array
8152 ig.Emit (OpCodes.Ldelema, t);
8157 ec.ig.Emit (OpCodes.Dup);
8158 temp = new LocalTemporary (this.type);
8163 StoreFromPtr (ig, t);
8165 ig.Emit (OpCodes.Stobj, t);
8166 else if (has_type_arg)
8173 ec.ig.Emit (OpCodes.Dup);
8174 temp = new LocalTemporary (this.type);
8179 StoreFromPtr (ig, t);
8181 int arg_count = ea.Arguments.Count;
8182 Type [] args = new Type [arg_count + 1];
8183 for (int i = 0; i < arg_count; i++) {
8184 //args [i++] = a.Type;
8185 args [i] = TypeManager.int32_type;
8187 args [arg_count] = type;
8189 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8190 ea.Expr.Type, "Set",
8191 CallingConventions.HasThis |
8192 CallingConventions.Standard,
8193 TypeManager.void_type, args);
8195 ig.Emit (OpCodes.Call, set);
8205 public void AddressOf (EmitContext ec, AddressOp mode)
8207 int rank = ea.Expr.Type.GetArrayRank ();
8208 ILGenerator ig = ec.ig;
8210 LoadArrayAndArguments (ec);
8213 ig.Emit (OpCodes.Ldelema, type);
8215 MethodInfo address = FetchAddressMethod ();
8216 ig.Emit (OpCodes.Call, address);
8220 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8222 type = storey.MutateType (type);
8223 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8228 /// Expressions that represent an indexer call.
8230 public class IndexerAccess : Expression, IAssignMethod
8232 class IndexerMethodGroupExpr : MethodGroupExpr
8234 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8237 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8240 public override string Name {
8246 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8249 // Here is the trick, decrease number of arguments by 1 when only
8250 // available property method is setter. This makes overload resolution
8251 // work correctly for indexers.
8254 if (method.Name [0] == 'g')
8255 return parameters.Count;
8257 return parameters.Count - 1;
8263 // Contains either property getter or setter
8264 public ArrayList Methods;
8265 public ArrayList Properties;
8271 void Append (Type caller_type, MemberInfo [] mi)
8276 foreach (PropertyInfo property in mi) {
8277 MethodInfo accessor = property.GetGetMethod (true);
8278 if (accessor == null)
8279 accessor = property.GetSetMethod (true);
8281 if (Methods == null) {
8282 Methods = new ArrayList ();
8283 Properties = new ArrayList ();
8286 Methods.Add (accessor);
8287 Properties.Add (property);
8291 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8293 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8295 return TypeManager.MemberLookup (
8296 caller_type, caller_type, lookup_type, MemberTypes.Property,
8297 BindingFlags.Public | BindingFlags.Instance |
8298 BindingFlags.DeclaredOnly, p_name, null);
8301 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8303 Indexers ix = new Indexers ();
8306 if (lookup_type.IsGenericParameter) {
8307 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8311 if (gc.HasClassConstraint)
8312 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8314 Type[] ifaces = gc.InterfaceConstraints;
8315 foreach (Type itype in ifaces)
8316 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)
8784 // TODO: should be protected
8785 public EmptyExpression ()
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 type = TypeManager.object_type;
8839 eclass = ExprClass.Value;
8840 loc = Location.Null;
8843 public override Expression CreateExpressionTree (EmitContext ec)
8848 public override void EmitStatement (EmitContext ec)
8853 public override Expression DoResolve (EmitContext ec)
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;
8949 if ((dim.Length > 0) && (dim [0] == '?')) {
8950 TypeExpr nullable = new Nullable.NullableType (left, loc);
8952 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8953 return nullable.ResolveAsTypeTerminal (ec, false);
8957 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8960 if (dim.Length != 0 && dim [0] == '[') {
8961 if (TypeManager.IsSpecialType (ltype)) {
8962 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8966 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8967 Report.SymbolRelatedToPreviousError (ltype);
8968 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8969 TypeManager.CSharpName (ltype));
8974 type = TypeManager.GetConstructedType (ltype, dim);
8979 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8981 if (type.IsPointer && !ec.IsInUnsafeScope){
8985 eclass = ExprClass.Type;
8989 public override string GetSignatureForError ()
8991 return left.GetSignatureForError () + dim;
8994 protected override void CloneTo (CloneContext clonectx, Expression t)
8996 ComposedCast target = (ComposedCast) t;
8998 target.left = (FullNamedExpression)left.Clone (clonectx);
9001 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
9003 return ResolveAsBaseTerminal (ec, silent);
9007 public class FixedBufferPtr : Expression {
9010 public FixedBufferPtr (Expression array, Type array_type, Location l)
9015 type = TypeManager.GetPointerType (array_type);
9016 eclass = ExprClass.Value;
9019 public override Expression CreateExpressionTree (EmitContext ec)
9021 Error_PointerInsideExpressionTree ();
9025 public override void Emit(EmitContext ec)
9030 public override Expression DoResolve (EmitContext ec)
9033 // We are born fully resolved
9041 // This class is used to represent the address of an array, used
9042 // only by the Fixed statement, this generates "&a [0]" construct
9043 // for fixed (char *pa = a)
9045 public class ArrayPtr : FixedBufferPtr {
9048 public ArrayPtr (Expression array, Type array_type, Location l):
9049 base (array, array_type, l)
9051 this.array_type = array_type;
9054 public override void Emit (EmitContext ec)
9058 ILGenerator ig = ec.ig;
9059 IntLiteral.EmitInt (ig, 0);
9060 ig.Emit (OpCodes.Ldelema, array_type);
9065 // Encapsulates a conversion rules required for array indexes
9067 public class ArrayIndexCast : TypeCast
9069 public ArrayIndexCast (Expression expr)
9070 : base (expr, expr.Type)
9074 public override Expression CreateExpressionTree (EmitContext ec)
9076 ArrayList args = new ArrayList (2);
9077 args.Add (new Argument (child.CreateExpressionTree (ec)));
9078 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9079 return CreateExpressionFactoryCall ("ConvertChecked", args);
9082 public override void Emit (EmitContext ec)
9086 if (type == TypeManager.int32_type)
9089 if (type == TypeManager.uint32_type)
9090 ec.ig.Emit (OpCodes.Conv_U);
9091 else if (type == TypeManager.int64_type)
9092 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9093 else if (type == TypeManager.uint64_type)
9094 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9096 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9101 // Implements the `stackalloc' keyword
9103 public class StackAlloc : Expression {
9108 public StackAlloc (Expression type, Expression count, Location l)
9115 public override Expression CreateExpressionTree (EmitContext ec)
9117 throw new NotSupportedException ("ET");
9120 public override Expression DoResolve (EmitContext ec)
9122 count = count.Resolve (ec);
9126 if (count.Type != TypeManager.uint32_type){
9127 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9132 Constant c = count as Constant;
9133 if (c != null && c.IsNegative) {
9134 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9138 if (ec.InCatch || ec.InFinally) {
9139 Error (255, "Cannot use stackalloc in finally or catch");
9143 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9149 if (!TypeManager.VerifyUnManaged (otype, loc))
9152 type = TypeManager.GetPointerType (otype);
9153 eclass = ExprClass.Value;
9158 public override void Emit (EmitContext ec)
9160 int size = GetTypeSize (otype);
9161 ILGenerator ig = ec.ig;
9166 ig.Emit (OpCodes.Sizeof, otype);
9168 IntConstant.EmitInt (ig, size);
9170 ig.Emit (OpCodes.Mul_Ovf_Un);
9171 ig.Emit (OpCodes.Localloc);
9174 protected override void CloneTo (CloneContext clonectx, Expression t)
9176 StackAlloc target = (StackAlloc) t;
9177 target.count = count.Clone (clonectx);
9178 target.t = t.Clone (clonectx);
9183 // An object initializer expression
9185 public class ElementInitializer : Assign
9187 public readonly string Name;
9189 public ElementInitializer (string name, Expression initializer, Location loc)
9190 : base (null, initializer, loc)
9195 protected override void CloneTo (CloneContext clonectx, Expression t)
9197 ElementInitializer target = (ElementInitializer) t;
9198 target.source = source.Clone (clonectx);
9201 public override Expression CreateExpressionTree (EmitContext ec)
9203 ArrayList args = new ArrayList (2);
9204 FieldExpr fe = target as FieldExpr;
9206 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9208 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9210 args.Add (new Argument (source.CreateExpressionTree (ec)));
9211 return CreateExpressionFactoryCall (
9212 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9216 public override Expression DoResolve (EmitContext ec)
9219 return EmptyExpressionStatement.Instance;
9221 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9222 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9228 me.InstanceExpression = ec.CurrentInitializerVariable;
9230 if (source is CollectionOrObjectInitializers) {
9231 Expression previous = ec.CurrentInitializerVariable;
9232 ec.CurrentInitializerVariable = target;
9233 source = source.Resolve (ec);
9234 ec.CurrentInitializerVariable = previous;
9238 eclass = source.eclass;
9243 Expression expr = base.DoResolve (ec);
9248 // Ignore field initializers with default value
9250 Constant c = source as Constant;
9251 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9252 return EmptyExpressionStatement.Instance;
9257 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9259 MemberInfo member = members [0];
9260 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9261 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9262 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9264 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9265 TypeManager.GetFullNameSignature (member));
9270 public override void EmitStatement (EmitContext ec)
9272 if (source is CollectionOrObjectInitializers)
9275 base.EmitStatement (ec);
9280 // A collection initializer expression
9282 public class CollectionElementInitializer : Invocation
9284 public class ElementInitializerArgument : Argument
9286 public ElementInitializerArgument (Expression e)
9292 sealed class AddMemberAccess : MemberAccess
9294 public AddMemberAccess (Expression expr, Location loc)
9295 : base (expr, "Add", loc)
9299 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9301 if (TypeManager.HasElementType (type))
9304 base.Error_TypeDoesNotContainDefinition (type, name);
9308 public CollectionElementInitializer (Expression argument)
9309 : base (null, new ArrayList (1), true)
9311 Arguments.Add (argument);
9312 this.loc = argument.Location;
9315 public CollectionElementInitializer (ArrayList arguments, Location loc)
9316 : base (null, arguments, true)
9321 public override Expression CreateExpressionTree (EmitContext ec)
9323 ArrayList args = new ArrayList (2);
9324 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9326 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9327 foreach (Argument a in Arguments)
9328 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9330 args.Add (new Argument (new ArrayCreation (
9331 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9332 return CreateExpressionFactoryCall ("ElementInit", args);
9335 protected override void CloneTo (CloneContext clonectx, Expression t)
9337 CollectionElementInitializer target = (CollectionElementInitializer) t;
9339 target.Arguments = new ArrayList (Arguments.Count);
9340 foreach (Expression e in Arguments)
9341 target.Arguments.Add (e.Clone (clonectx));
9344 public override Expression DoResolve (EmitContext ec)
9346 if (eclass != ExprClass.Invalid)
9349 // TODO: We could call a constructor which takes element count argument,
9350 // for known types like List<T>, Dictionary<T, U>
9352 for (int i = 0; i < Arguments.Count; ++i) {
9353 Expression expr = Arguments [i] as Expression;
9357 expr = expr.Resolve (ec);
9361 Arguments [i] = new ElementInitializerArgument (expr);
9364 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9366 return base.DoResolve (ec);
9371 // A block of object or collection initializers
9373 public class CollectionOrObjectInitializers : ExpressionStatement
9375 ArrayList initializers;
9377 public static readonly CollectionOrObjectInitializers Empty =
9378 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9380 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9382 this.initializers = initializers;
9386 public bool IsEmpty {
9388 return initializers.Count == 0;
9392 public bool IsCollectionInitializer {
9394 return type == typeof (CollectionOrObjectInitializers);
9398 protected override void CloneTo (CloneContext clonectx, Expression target)
9400 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9402 t.initializers = new ArrayList (initializers.Count);
9403 foreach (Expression e in initializers)
9404 t.initializers.Add (e.Clone (clonectx));
9407 public override Expression CreateExpressionTree (EmitContext ec)
9409 ArrayList expr_initializers = new ArrayList (initializers.Count);
9410 foreach (Expression e in initializers) {
9411 Expression expr = e.CreateExpressionTree (ec);
9413 expr_initializers.Add (expr);
9416 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9419 public override Expression DoResolve (EmitContext ec)
9421 if (eclass != ExprClass.Invalid)
9424 bool is_collection_initialization = false;
9425 ArrayList element_names = null;
9426 for (int i = 0; i < initializers.Count; ++i) {
9427 Expression initializer = (Expression) initializers [i];
9428 ElementInitializer element_initializer = initializer as ElementInitializer;
9431 if (element_initializer != null) {
9432 element_names = new ArrayList (initializers.Count);
9433 element_names.Add (element_initializer.Name);
9435 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9436 TypeManager.ienumerable_type)) {
9437 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9438 "object initializer because type `{1}' does not implement `{2}' interface",
9439 ec.CurrentInitializerVariable.GetSignatureForError (),
9440 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9441 TypeManager.CSharpName (TypeManager.ienumerable_type));
9444 is_collection_initialization = true;
9447 if (is_collection_initialization != (element_initializer == null)) {
9448 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9449 is_collection_initialization ? "collection initializer" : "object initializer");
9453 if (!is_collection_initialization) {
9454 if (element_names.Contains (element_initializer.Name)) {
9455 Report.Error (1912, element_initializer.Location,
9456 "An object initializer includes more than one member `{0}' initialization",
9457 element_initializer.Name);
9459 element_names.Add (element_initializer.Name);
9464 Expression e = initializer.Resolve (ec);
9465 if (e == EmptyExpressionStatement.Instance)
9466 initializers.RemoveAt (i--);
9468 initializers [i] = e;
9471 if (is_collection_initialization) {
9472 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9473 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9474 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9477 type = typeof (CollectionOrObjectInitializers);
9479 type = typeof (ElementInitializer);
9482 eclass = ExprClass.Variable;
9486 public override void Emit (EmitContext ec)
9491 public override void EmitStatement (EmitContext ec)
9493 foreach (ExpressionStatement e in initializers)
9494 e.EmitStatement (ec);
9497 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9499 foreach (Expression e in initializers)
9500 e.MutateHoistedGenericType (storey);
9505 // New expression with element/object initializers
9507 public class NewInitialize : New
9510 // This class serves as a proxy for variable initializer target instances.
9511 // A real variable is assigned later when we resolve left side of an
9514 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9516 NewInitialize new_instance;
9518 public InitializerTargetExpression (NewInitialize newInstance)
9520 this.type = newInstance.type;
9521 this.loc = newInstance.loc;
9522 this.eclass = newInstance.eclass;
9523 this.new_instance = newInstance;
9526 public override Expression CreateExpressionTree (EmitContext ec)
9528 // Should not be reached
9529 throw new NotSupportedException ("ET");
9532 public override Expression DoResolve (EmitContext ec)
9537 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9542 public override void Emit (EmitContext ec)
9544 new_instance.value_target.Emit (ec);
9547 #region IMemoryLocation Members
9549 public void AddressOf (EmitContext ec, AddressOp mode)
9551 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9557 CollectionOrObjectInitializers initializers;
9559 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9560 : base (requested_type, arguments, l)
9562 this.initializers = initializers;
9565 protected override void CloneTo (CloneContext clonectx, Expression t)
9567 base.CloneTo (clonectx, t);
9569 NewInitialize target = (NewInitialize) t;
9570 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9573 public override Expression CreateExpressionTree (EmitContext ec)
9575 ArrayList args = new ArrayList (2);
9576 args.Add (new Argument (base.CreateExpressionTree (ec)));
9577 if (!initializers.IsEmpty)
9578 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9580 return CreateExpressionFactoryCall (
9581 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9585 public override Expression DoResolve (EmitContext ec)
9587 if (eclass != ExprClass.Invalid)
9590 Expression e = base.DoResolve (ec);
9594 // Empty initializer can be optimized to simple new
9595 if (initializers.IsEmpty) {
9596 initializers.Resolve (ec);
9597 return ReducedExpression.Create (e, this).Resolve (ec);
9600 Expression previous = ec.CurrentInitializerVariable;
9601 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9602 initializers.Resolve (ec);
9603 ec.CurrentInitializerVariable = previous;
9607 public override void Emit (EmitContext ec)
9612 // If target is non-hoisted variable, let's use it
9614 VariableReference variable = value_target as VariableReference;
9615 if (variable != null && variable.HoistedVariable == null) {
9617 StoreFromPtr (ec.ig, type);
9619 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9622 if (value_target == null || value_target_set)
9623 value_target = new LocalTemporary (type);
9625 ((LocalTemporary) value_target).Store (ec);
9628 initializers.Emit (ec);
9630 if (variable == null) {
9631 value_target.Emit (ec);
9632 value_target = null;
9636 public override void EmitStatement (EmitContext ec)
9638 if (initializers.IsEmpty) {
9639 base.EmitStatement (ec);
9645 if (value_target == null) {
9646 LocalTemporary variable = new LocalTemporary (type);
9647 variable.Store (ec);
9648 value_target = variable;
9651 initializers.EmitStatement (ec);
9654 public override bool HasInitializer {
9656 return !initializers.IsEmpty;
9660 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9662 base.MutateHoistedGenericType (storey);
9663 initializers.MutateHoistedGenericType (storey);
9667 public class AnonymousTypeDeclaration : Expression
9669 ArrayList parameters;
9670 readonly TypeContainer parent;
9671 static readonly ArrayList EmptyParameters = new ArrayList (0);
9673 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9675 this.parameters = parameters;
9676 this.parent = parent;
9680 protected override void CloneTo (CloneContext clonectx, Expression target)
9682 if (parameters == null)
9685 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9686 t.parameters = new ArrayList (parameters.Count);
9687 foreach (AnonymousTypeParameter atp in parameters)
9688 t.parameters.Add (atp.Clone (clonectx));
9691 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9693 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9697 type = AnonymousTypeClass.Create (parent, parameters, loc);
9704 if (Report.Errors == 0)
9707 RootContext.ToplevelTypes.AddAnonymousType (type);
9711 public override Expression CreateExpressionTree (EmitContext ec)
9713 throw new NotSupportedException ("ET");
9716 public override Expression DoResolve (EmitContext ec)
9718 AnonymousTypeClass anonymous_type;
9720 if (!ec.IsAnonymousMethodAllowed) {
9721 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9725 if (parameters == null) {
9726 anonymous_type = CreateAnonymousType (EmptyParameters);
9727 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9728 null, loc).Resolve (ec);
9732 ArrayList arguments = new ArrayList (parameters.Count);
9733 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9734 for (int i = 0; i < parameters.Count; ++i) {
9735 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9741 arguments.Add (new Argument (e));
9742 t_args [i] = new TypeExpression (e.Type, e.Location);
9748 anonymous_type = CreateAnonymousType (parameters);
9749 if (anonymous_type == null)
9752 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9753 new TypeArguments (loc, t_args), loc);
9755 return new New (te, arguments, loc).Resolve (ec);
9758 public override void Emit (EmitContext ec)
9760 throw new InternalErrorException ("Should not be reached");
9764 public class AnonymousTypeParameter : Expression
9766 public readonly string Name;
9767 Expression initializer;
9769 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9773 this.initializer = initializer;
9776 public AnonymousTypeParameter (Parameter parameter)
9778 this.Name = parameter.Name;
9779 this.loc = parameter.Location;
9780 this.initializer = new SimpleName (Name, loc);
9783 protected override void CloneTo (CloneContext clonectx, Expression target)
9785 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9786 t.initializer = initializer.Clone (clonectx);
9789 public override Expression CreateExpressionTree (EmitContext ec)
9791 throw new NotSupportedException ("ET");
9794 public override bool Equals (object o)
9796 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9797 return other != null && Name == other.Name;
9800 public override int GetHashCode ()
9802 return Name.GetHashCode ();
9805 public override Expression DoResolve (EmitContext ec)
9807 Expression e = initializer.Resolve (ec);
9811 if (e.eclass == ExprClass.MethodGroup) {
9812 Error_InvalidInitializer (e.ExprClassName);
9817 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9818 type == TypeManager.anonymous_method_type || type.IsPointer) {
9819 Error_InvalidInitializer (e.GetSignatureForError ());
9826 protected virtual void Error_InvalidInitializer (string initializer)
9828 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9832 public override void Emit (EmitContext ec)
9834 throw new InternalErrorException ("Should not be reached");