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 Arguments arguments;
28 protected readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, Arguments 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 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
48 new NullLiteral (loc),
49 mg.CreateExpressionTree (ec));
51 return CreateExpressionFactoryCall ("Call", args);
54 protected override void CloneTo (CloneContext context, Expression target)
59 public override Expression DoResolve (EmitContext ec)
62 // We are born fully resolved
67 public override void Emit (EmitContext ec)
69 mg.EmitCall (ec, arguments);
72 public MethodGroupExpr Method {
76 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
78 arguments.MutateHoistedGenericType (storey);
79 mg.MutateHoistedGenericType (storey);
83 public class ParenthesizedExpression : Expression
85 public Expression Expr;
87 public ParenthesizedExpression (Expression expr)
93 public override Expression CreateExpressionTree (EmitContext ec)
95 throw new NotSupportedException ("ET");
98 public override Expression DoResolve (EmitContext ec)
100 Expr = Expr.Resolve (ec);
104 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
106 return Expr.DoResolveLValue (ec, right_side);
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
127 public enum Operator : byte {
128 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
132 static Type [] [] predefined_operators;
134 public readonly Operator Oper;
135 public Expression Expr;
136 Expression enum_conversion;
138 public Unary (Operator op, Expression expr)
146 // This routine will attempt to simplify the unary expression when the
147 // argument is a constant.
149 Constant TryReduceConstant (EmitContext ec, Constant e)
151 if (e is EmptyConstantCast)
152 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
154 if (e is SideEffectConstant) {
155 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
156 return r == null ? null : new SideEffectConstant (r, e, r.Location);
159 Type expr_type = e.Type;
162 case Operator.UnaryPlus:
163 // Unary numeric promotions
164 if (expr_type == TypeManager.byte_type)
165 return new IntConstant (((ByteConstant)e).Value, e.Location);
166 if (expr_type == TypeManager.sbyte_type)
167 return new IntConstant (((SByteConstant)e).Value, e.Location);
168 if (expr_type == TypeManager.short_type)
169 return new IntConstant (((ShortConstant)e).Value, e.Location);
170 if (expr_type == TypeManager.ushort_type)
171 return new IntConstant (((UShortConstant)e).Value, e.Location);
172 if (expr_type == TypeManager.char_type)
173 return new IntConstant (((CharConstant)e).Value, e.Location);
175 // Predefined operators
176 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
177 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
178 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
179 expr_type == TypeManager.decimal_type) {
185 case Operator.UnaryNegation:
186 // Unary numeric promotions
187 if (expr_type == TypeManager.byte_type)
188 return new IntConstant (-((ByteConstant)e).Value, e.Location);
189 if (expr_type == TypeManager.sbyte_type)
190 return new IntConstant (-((SByteConstant)e).Value, e.Location);
191 if (expr_type == TypeManager.short_type)
192 return new IntConstant (-((ShortConstant)e).Value, e.Location);
193 if (expr_type == TypeManager.ushort_type)
194 return new IntConstant (-((UShortConstant)e).Value, e.Location);
195 if (expr_type == TypeManager.char_type)
196 return new IntConstant (-((CharConstant)e).Value, e.Location);
198 // Predefined operators
199 if (expr_type == TypeManager.int32_type) {
200 int value = ((IntConstant)e).Value;
201 if (value == int.MinValue) {
202 if (ec.ConstantCheckState) {
203 ConstantFold.Error_CompileTimeOverflow (loc);
208 return new IntConstant (-value, e.Location);
210 if (expr_type == TypeManager.int64_type) {
211 long value = ((LongConstant)e).Value;
212 if (value == long.MinValue) {
213 if (ec.ConstantCheckState) {
214 ConstantFold.Error_CompileTimeOverflow (loc);
219 return new LongConstant (-value, e.Location);
222 if (expr_type == TypeManager.uint32_type) {
223 UIntLiteral uil = e as UIntLiteral;
225 if (uil.Value == 2147483648)
226 return new IntLiteral (int.MinValue, e.Location);
227 return new LongLiteral (-uil.Value, e.Location);
229 return new LongConstant (-((UIntConstant)e).Value, e.Location);
232 if (expr_type == TypeManager.uint64_type) {
233 ULongLiteral ull = e as ULongLiteral;
234 if (ull != null && ull.Value == 9223372036854775808)
235 return new LongLiteral (long.MinValue, e.Location);
239 if (expr_type == TypeManager.float_type) {
240 FloatLiteral fl = e as FloatLiteral;
241 // For better error reporting
243 return new FloatLiteral (-fl.Value, e.Location);
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 return new DoubleLiteral (-dl.Value, e.Location);
253 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
255 if (expr_type == TypeManager.decimal_type)
256 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
260 case Operator.LogicalNot:
261 if (expr_type != TypeManager.bool_type)
264 bool b = (bool)e.GetValue ();
265 return new BoolConstant (!b, e.Location);
267 case Operator.OnesComplement:
268 // Unary numeric promotions
269 if (expr_type == TypeManager.byte_type)
270 return new IntConstant (~((ByteConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.sbyte_type)
272 return new IntConstant (~((SByteConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.short_type)
274 return new IntConstant (~((ShortConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.ushort_type)
276 return new IntConstant (~((UShortConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.char_type)
278 return new IntConstant (~((CharConstant)e).Value, e.Location);
280 // Predefined operators
281 if (expr_type == TypeManager.int32_type)
282 return new IntConstant (~((IntConstant)e).Value, e.Location);
283 if (expr_type == TypeManager.uint32_type)
284 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
285 if (expr_type == TypeManager.int64_type)
286 return new LongConstant (~((LongConstant)e).Value, e.Location);
287 if (expr_type == TypeManager.uint64_type){
288 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
290 if (e is EnumConstant) {
291 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
293 e = new EnumConstant (e, expr_type);
298 throw new Exception ("Can not constant fold: " + Oper.ToString());
301 protected Expression ResolveOperator (EmitContext ec, Expression expr)
303 eclass = ExprClass.Value;
305 if (predefined_operators == null)
306 CreatePredefinedOperatorsTable ();
308 Type expr_type = expr.Type;
309 Expression best_expr;
312 // Primitive types first
314 if (TypeManager.IsPrimitiveType (expr_type)) {
315 best_expr = ResolvePrimitivePredefinedType (expr);
316 if (best_expr == null)
319 type = best_expr.Type;
325 // E operator ~(E x);
327 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
328 return ResolveEnumOperator (ec, expr);
330 return ResolveUserType (ec, expr);
333 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
335 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
336 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
337 if (best_expr == null)
341 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
343 return EmptyCast.Create (this, type);
346 public override Expression CreateExpressionTree (EmitContext ec)
348 return CreateExpressionTree (ec, null);
351 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
355 case Operator.AddressOf:
356 Error_PointerInsideExpressionTree ();
358 case Operator.UnaryNegation:
359 if (ec.HasSet (EmitContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
360 method_name = "NegateChecked";
362 method_name = "Negate";
364 case Operator.OnesComplement:
365 case Operator.LogicalNot:
368 case Operator.UnaryPlus:
369 method_name = "UnaryPlus";
372 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375 Arguments args = new Arguments (2);
376 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
378 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
379 return CreateExpressionFactoryCall (method_name, args);
382 static void CreatePredefinedOperatorsTable ()
384 predefined_operators = new Type [(int) Operator.TOP] [];
387 // 7.6.1 Unary plus operator
389 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
390 TypeManager.int32_type, TypeManager.uint32_type,
391 TypeManager.int64_type, TypeManager.uint64_type,
392 TypeManager.float_type, TypeManager.double_type,
393 TypeManager.decimal_type
397 // 7.6.2 Unary minus operator
399 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
400 TypeManager.int32_type,
401 TypeManager.int64_type,
402 TypeManager.float_type, TypeManager.double_type,
403 TypeManager.decimal_type
407 // 7.6.3 Logical negation operator
409 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
410 TypeManager.bool_type
414 // 7.6.4 Bitwise complement operator
416 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
417 TypeManager.int32_type, TypeManager.uint32_type,
418 TypeManager.int64_type, TypeManager.uint64_type
423 // Unary numeric promotions
425 static Expression DoNumericPromotion (Operator op, Expression expr)
427 Type expr_type = expr.Type;
428 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
429 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
430 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
431 expr_type == TypeManager.char_type)
432 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
434 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
435 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
440 public override Expression DoResolve (EmitContext ec)
442 if (Oper == Operator.AddressOf) {
443 return ResolveAddressOf (ec);
446 Expr = Expr.Resolve (ec);
450 if (TypeManager.IsDynamicType (Expr.Type)) {
451 Arguments args = new Arguments (1);
452 args.Add (new Argument (Expr));
453 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).DoResolve (ec);
456 if (TypeManager.IsNullableType (Expr.Type))
457 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
460 // Attempt to use a constant folding operation.
462 Constant cexpr = Expr as Constant;
464 cexpr = TryReduceConstant (ec, cexpr);
469 Expression expr = ResolveOperator (ec, Expr);
471 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
474 // Reduce unary operator on predefined types
476 if (expr == this && Oper == Operator.UnaryPlus)
482 public override Expression DoResolveLValue (EmitContext ec, Expression right)
487 public override void Emit (EmitContext ec)
489 EmitOperator (ec, type);
492 protected void EmitOperator (EmitContext ec, Type type)
494 ILGenerator ig = ec.ig;
497 case Operator.UnaryPlus:
501 case Operator.UnaryNegation:
502 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
503 ig.Emit (OpCodes.Ldc_I4_0);
504 if (type == TypeManager.int64_type)
505 ig.Emit (OpCodes.Conv_U8);
507 ig.Emit (OpCodes.Sub_Ovf);
510 ig.Emit (OpCodes.Neg);
515 case Operator.LogicalNot:
517 ig.Emit (OpCodes.Ldc_I4_0);
518 ig.Emit (OpCodes.Ceq);
521 case Operator.OnesComplement:
523 ig.Emit (OpCodes.Not);
526 case Operator.AddressOf:
527 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
531 throw new Exception ("This should not happen: Operator = "
536 // Same trick as in Binary expression
538 if (enum_conversion != null)
539 enum_conversion.Emit (ec);
542 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
544 if (Oper == Operator.LogicalNot)
545 Expr.EmitBranchable (ec, target, !on_true);
547 base.EmitBranchable (ec, target, on_true);
550 public override void EmitSideEffect (EmitContext ec)
552 Expr.EmitSideEffect (ec);
555 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
557 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
558 oper, TypeManager.CSharpName (t));
562 // Converts operator to System.Linq.Expressions.ExpressionType enum name
564 string GetOperatorExpressionTypeName ()
567 case Operator.OnesComplement:
568 return "OnesComplement";
569 case Operator.LogicalNot:
571 case Operator.UnaryNegation:
573 case Operator.UnaryPlus:
576 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
580 static bool IsFloat (Type t)
582 return t == TypeManager.float_type || t == TypeManager.double_type;
586 // Returns a stringified representation of the Operator
588 public static string OperName (Operator oper)
591 case Operator.UnaryPlus:
593 case Operator.UnaryNegation:
595 case Operator.LogicalNot:
597 case Operator.OnesComplement:
599 case Operator.AddressOf:
603 throw new NotImplementedException (oper.ToString ());
606 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
608 type = storey.MutateType (type);
609 Expr.MutateHoistedGenericType (storey);
612 Expression ResolveAddressOf (EmitContext ec)
617 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
618 if (Expr == null || Expr.eclass != ExprClass.Variable) {
619 Error (211, "Cannot take the address of the given expression");
623 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
627 IVariableReference vr = Expr as IVariableReference;
630 VariableInfo vi = vr.VariableInfo;
632 if (vi.LocalInfo != null)
633 vi.LocalInfo.Used = true;
636 // A variable is considered definitely assigned if you take its address.
641 is_fixed = vr.IsFixed;
642 vr.SetHasAddressTaken ();
645 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
648 IFixedExpression fe = Expr as IFixedExpression;
649 is_fixed = fe != null && fe.IsFixed;
652 if (!is_fixed && !ec.HasSet (EmitContext.Options.FixedInitializerScope)) {
653 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
656 type = TypeManager.GetPointerType (Expr.Type);
657 eclass = ExprClass.Value;
661 Expression ResolvePrimitivePredefinedType (Expression expr)
663 expr = DoNumericPromotion (Oper, expr);
664 Type expr_type = expr.Type;
665 Type[] predefined = predefined_operators [(int) Oper];
666 foreach (Type t in predefined) {
674 // Perform user-operator overload resolution
676 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
678 CSharp.Operator.OpType op_type;
680 case Operator.LogicalNot:
681 op_type = CSharp.Operator.OpType.LogicalNot; break;
682 case Operator.OnesComplement:
683 op_type = CSharp.Operator.OpType.OnesComplement; break;
684 case Operator.UnaryNegation:
685 op_type = CSharp.Operator.OpType.UnaryNegation; break;
686 case Operator.UnaryPlus:
687 op_type = CSharp.Operator.OpType.UnaryPlus; break;
689 throw new InternalErrorException (Oper.ToString ());
692 string op_name = CSharp.Operator.GetMetadataName (op_type);
693 MethodGroupExpr user_op = MemberLookup (ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
697 Arguments args = new Arguments (1);
698 args.Add (new Argument (expr));
699 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
704 Expr = args [0].Expr;
705 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
709 // Unary user type overload resolution
711 Expression ResolveUserType (EmitContext ec, Expression expr)
713 Expression best_expr = ResolveUserOperator (ec, expr);
714 if (best_expr != null)
717 Type[] predefined = predefined_operators [(int) Oper];
718 foreach (Type t in predefined) {
719 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
720 if (oper_expr == null)
724 // decimal type is predefined but has user-operators
726 if (oper_expr.Type == TypeManager.decimal_type)
727 oper_expr = ResolveUserType (ec, oper_expr);
729 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
731 if (oper_expr == null)
734 if (best_expr == null) {
735 best_expr = oper_expr;
739 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
741 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
742 OperName (Oper), TypeManager.CSharpName (expr.Type));
747 best_expr = oper_expr;
750 if (best_expr == null)
754 // HACK: Decimal user-operator is included in standard operators
756 if (best_expr.Type == TypeManager.decimal_type)
760 type = best_expr.Type;
764 protected override void CloneTo (CloneContext clonectx, Expression t)
766 Unary target = (Unary) t;
768 target.Expr = Expr.Clone (clonectx);
773 // Unary operators are turned into Indirection expressions
774 // after semantic analysis (this is so we can take the address
775 // of an indirection).
777 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
779 LocalTemporary temporary;
782 public Indirection (Expression expr, Location l)
788 public override Expression CreateExpressionTree (EmitContext ec)
790 Error_PointerInsideExpressionTree ();
794 protected override void CloneTo (CloneContext clonectx, Expression t)
796 Indirection target = (Indirection) t;
797 target.expr = expr.Clone (clonectx);
800 public override void Emit (EmitContext ec)
805 LoadFromPtr (ec.ig, Type);
808 public void Emit (EmitContext ec, bool leave_copy)
812 ec.ig.Emit (OpCodes.Dup);
813 temporary = new LocalTemporary (expr.Type);
814 temporary.Store (ec);
818 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
820 prepared = prepare_for_load;
824 if (prepare_for_load)
825 ec.ig.Emit (OpCodes.Dup);
829 ec.ig.Emit (OpCodes.Dup);
830 temporary = new LocalTemporary (expr.Type);
831 temporary.Store (ec);
834 StoreFromPtr (ec.ig, type);
836 if (temporary != null) {
838 temporary.Release (ec);
842 public void AddressOf (EmitContext ec, AddressOp Mode)
847 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
849 return DoResolve (ec);
852 public override Expression DoResolve (EmitContext ec)
854 expr = expr.Resolve (ec);
861 if (!expr.Type.IsPointer) {
862 Error (193, "The * or -> operator must be applied to a pointer");
866 if (expr.Type == TypeManager.void_ptr_type) {
867 Error (242, "The operation in question is undefined on void pointers");
871 type = TypeManager.GetElementType (expr.Type);
872 eclass = ExprClass.Variable;
876 public bool IsFixed {
880 public override string ToString ()
882 return "*(" + expr + ")";
887 /// Unary Mutator expressions (pre and post ++ and --)
891 /// UnaryMutator implements ++ and -- expressions. It derives from
892 /// ExpressionStatement becuase the pre/post increment/decrement
893 /// operators can be used in a statement context.
895 /// FIXME: Idea, we could split this up in two classes, one simpler
896 /// for the common case, and one with the extra fields for more complex
897 /// classes (indexers require temporary access; overloaded require method)
900 public class UnaryMutator : ExpressionStatement {
902 public enum Mode : byte {
909 PreDecrement = IsDecrement,
910 PostIncrement = IsPost,
911 PostDecrement = IsPost | IsDecrement
915 bool is_expr = false;
916 bool recurse = false;
921 // This is expensive for the simplest case.
923 UserOperatorCall method;
925 public UnaryMutator (Mode m, Expression e)
932 static string OperName (Mode mode)
934 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
939 /// Returns whether an object of type `t' can be incremented
940 /// or decremented with add/sub (ie, basically whether we can
941 /// use pre-post incr-decr operations on it, but it is not a
942 /// System.Decimal, which we require operator overloading to catch)
944 static bool IsIncrementableNumber (Type t)
946 return (t == TypeManager.sbyte_type) ||
947 (t == TypeManager.byte_type) ||
948 (t == TypeManager.short_type) ||
949 (t == TypeManager.ushort_type) ||
950 (t == TypeManager.int32_type) ||
951 (t == TypeManager.uint32_type) ||
952 (t == TypeManager.int64_type) ||
953 (t == TypeManager.uint64_type) ||
954 (t == TypeManager.char_type) ||
955 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
956 (t == TypeManager.float_type) ||
957 (t == TypeManager.double_type) ||
958 (t.IsPointer && t != TypeManager.void_ptr_type);
961 Expression ResolveOperator (EmitContext ec)
966 // The operand of the prefix/postfix increment decrement operators
967 // should be an expression that is classified as a variable,
968 // a property access or an indexer access
970 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
971 expr = expr.ResolveLValue (ec, expr);
973 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
977 // Step 1: Perform Operator Overload location
982 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
983 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
985 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
987 mg = MemberLookup (ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
990 Arguments args = new Arguments (1);
991 args.Add (new Argument (expr));
992 mg = mg.OverloadResolve (ec, ref args, false, loc);
996 method = new UserOperatorCall (mg, args, null, loc);
997 Convert.ImplicitConversionRequired (ec, method, type, loc);
1001 if (!IsIncrementableNumber (type)) {
1002 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
1003 TypeManager.CSharpName (type) + "'");
1010 public override Expression CreateExpressionTree (EmitContext ec)
1012 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1015 public override Expression DoResolve (EmitContext ec)
1017 expr = expr.Resolve (ec);
1022 if (TypeManager.IsDynamicType (expr.Type)) {
1023 Arguments args = new Arguments (1);
1024 args.Add (new Argument (expr));
1025 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).DoResolve (ec);
1028 eclass = ExprClass.Value;
1030 if (TypeManager.IsNullableType (expr.Type))
1031 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1033 return ResolveOperator (ec);
1037 // Loads the proper "1" into the stack based on the type, then it emits the
1038 // opcode for the operation requested
1040 void LoadOneAndEmitOp (EmitContext ec, Type t)
1043 // Measure if getting the typecode and using that is more/less efficient
1044 // that comparing types. t.GetTypeCode() is an internal call.
1046 ILGenerator ig = ec.ig;
1048 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1049 LongConstant.EmitLong (ig, 1);
1050 else if (t == TypeManager.double_type)
1051 ig.Emit (OpCodes.Ldc_R8, 1.0);
1052 else if (t == TypeManager.float_type)
1053 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1054 else if (t.IsPointer){
1055 Type et = TypeManager.GetElementType (t);
1056 int n = GetTypeSize (et);
1059 ig.Emit (OpCodes.Sizeof, et);
1061 IntConstant.EmitInt (ig, n);
1062 ig.Emit (OpCodes.Conv_I);
1065 ig.Emit (OpCodes.Ldc_I4_1);
1068 // Now emit the operation
1071 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1072 Binary.EmitOperatorOpcode (ec, op, t);
1074 if (t == TypeManager.sbyte_type){
1075 if (ec.HasSet (EmitContext.Options.CheckedScope))
1076 ig.Emit (OpCodes.Conv_Ovf_I1);
1078 ig.Emit (OpCodes.Conv_I1);
1079 } else if (t == TypeManager.byte_type){
1080 if (ec.HasSet (EmitContext.Options.CheckedScope))
1081 ig.Emit (OpCodes.Conv_Ovf_U1);
1083 ig.Emit (OpCodes.Conv_U1);
1084 } else if (t == TypeManager.short_type){
1085 if (ec.HasSet (EmitContext.Options.CheckedScope))
1086 ig.Emit (OpCodes.Conv_Ovf_I2);
1088 ig.Emit (OpCodes.Conv_I2);
1089 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1090 if (ec.HasSet (EmitContext.Options.CheckedScope))
1091 ig.Emit (OpCodes.Conv_Ovf_U2);
1093 ig.Emit (OpCodes.Conv_U2);
1098 void EmitCode (EmitContext ec, bool is_expr)
1101 this.is_expr = is_expr;
1102 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1105 public override void Emit (EmitContext ec)
1108 // We use recurse to allow ourselfs to be the source
1109 // of an assignment. This little hack prevents us from
1110 // having to allocate another expression
1113 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1115 LoadOneAndEmitOp (ec, expr.Type);
1117 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1122 EmitCode (ec, true);
1125 public override void EmitStatement (EmitContext ec)
1127 EmitCode (ec, false);
1131 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1133 string GetOperatorExpressionTypeName ()
1135 if ((mode & Mode.IsDecrement) != 0)
1141 protected override void CloneTo (CloneContext clonectx, Expression t)
1143 UnaryMutator target = (UnaryMutator) t;
1145 target.expr = expr.Clone (clonectx);
1150 /// Base class for the `Is' and `As' classes.
1154 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1157 public abstract class Probe : Expression {
1158 public Expression ProbeType;
1159 protected Expression expr;
1160 protected TypeExpr probe_type_expr;
1162 public Probe (Expression expr, Expression probe_type, Location l)
1164 ProbeType = probe_type;
1169 public Expression Expr {
1175 public override Expression DoResolve (EmitContext ec)
1177 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1178 if (probe_type_expr == null)
1181 expr = expr.Resolve (ec);
1185 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1186 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1190 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1191 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1196 if (expr.Type == InternalType.AnonymousMethod) {
1197 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1205 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1207 expr.MutateHoistedGenericType (storey);
1208 probe_type_expr.MutateHoistedGenericType (storey);
1211 protected abstract string OperatorName { get; }
1213 protected override void CloneTo (CloneContext clonectx, Expression t)
1215 Probe target = (Probe) t;
1217 target.expr = expr.Clone (clonectx);
1218 target.ProbeType = ProbeType.Clone (clonectx);
1224 /// Implementation of the `is' operator.
1226 public class Is : Probe {
1227 Nullable.Unwrap expr_unwrap;
1229 public Is (Expression expr, Expression probe_type, Location l)
1230 : base (expr, probe_type, l)
1234 public override Expression CreateExpressionTree (EmitContext ec)
1236 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1237 expr.CreateExpressionTree (ec),
1238 new TypeOf (probe_type_expr, loc));
1240 return CreateExpressionFactoryCall ("TypeIs", args);
1243 public override void Emit (EmitContext ec)
1245 ILGenerator ig = ec.ig;
1246 if (expr_unwrap != null) {
1247 expr_unwrap.EmitCheck (ec);
1252 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1253 ig.Emit (OpCodes.Ldnull);
1254 ig.Emit (OpCodes.Cgt_Un);
1257 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1259 ILGenerator ig = ec.ig;
1260 if (expr_unwrap != null) {
1261 expr_unwrap.EmitCheck (ec);
1264 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1266 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1269 Expression CreateConstantResult (bool result)
1272 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1273 TypeManager.CSharpName (probe_type_expr.Type));
1275 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1276 TypeManager.CSharpName (probe_type_expr.Type));
1278 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1281 public override Expression DoResolve (EmitContext ec)
1283 if (base.DoResolve (ec) == null)
1287 bool d_is_nullable = false;
1290 // If E is a method group or the null literal, or if the type of E is a reference
1291 // type or a nullable type and the value of E is null, the result is false
1293 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1294 return CreateConstantResult (false);
1296 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1297 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1298 d_is_nullable = true;
1301 type = TypeManager.bool_type;
1302 eclass = ExprClass.Value;
1303 Type t = probe_type_expr.Type;
1304 bool t_is_nullable = false;
1305 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1306 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1307 t_is_nullable = true;
1310 if (TypeManager.IsStruct (t)) {
1313 // D and T are the same value types but D can be null
1315 if (d_is_nullable && !t_is_nullable) {
1316 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1321 // The result is true if D and T are the same value types
1323 return CreateConstantResult (true);
1326 if (TypeManager.IsGenericParameter (d))
1327 return ResolveGenericParameter (t, d);
1330 // An unboxing conversion exists
1332 if (Convert.ExplicitReferenceConversionExists (d, t))
1335 if (TypeManager.IsGenericParameter (t))
1336 return ResolveGenericParameter (d, t);
1338 if (TypeManager.IsStruct (d)) {
1340 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1341 return CreateConstantResult (true);
1343 if (TypeManager.IsGenericParameter (d))
1344 return ResolveGenericParameter (t, d);
1346 if (TypeManager.ContainsGenericParameters (d))
1349 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1350 Convert.ExplicitReferenceConversionExists (d, t)) {
1356 return CreateConstantResult (false);
1359 Expression ResolveGenericParameter (Type d, Type t)
1361 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1362 if (constraints != null) {
1363 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1364 return CreateConstantResult (false);
1366 if (constraints.IsValueType && !TypeManager.IsStruct (d))
1367 return CreateConstantResult (TypeManager.IsEqual (d, t));
1370 if (TypeManager.IsGenericParameter (expr.Type))
1371 expr = new BoxedCast (expr, d);
1376 protected override string OperatorName {
1377 get { return "is"; }
1382 /// Implementation of the `as' operator.
1384 public class As : Probe {
1386 Expression resolved_type;
1388 public As (Expression expr, Expression probe_type, Location l)
1389 : base (expr, probe_type, l)
1393 public override Expression CreateExpressionTree (EmitContext ec)
1395 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1396 expr.CreateExpressionTree (ec),
1397 new TypeOf (probe_type_expr, loc));
1399 return CreateExpressionFactoryCall ("TypeAs", args);
1402 public override void Emit (EmitContext ec)
1404 ILGenerator ig = ec.ig;
1409 ig.Emit (OpCodes.Isinst, type);
1412 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1413 ig.Emit (OpCodes.Unbox_Any, type);
1417 public override Expression DoResolve (EmitContext ec)
1419 // Because expr is modified
1420 if (eclass != ExprClass.Invalid)
1423 if (resolved_type == null) {
1424 resolved_type = base.DoResolve (ec);
1426 if (resolved_type == null)
1430 type = probe_type_expr.Type;
1431 eclass = ExprClass.Value;
1432 Type etype = expr.Type;
1434 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1435 if (TypeManager.IsGenericParameter (type)) {
1436 Report.Error (413, loc,
1437 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1438 probe_type_expr.GetSignatureForError ());
1440 Report.Error (77, loc,
1441 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1442 TypeManager.CSharpName (type));
1447 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1448 return Nullable.LiftedNull.CreateFromExpression (this);
1451 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1458 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1459 if (TypeManager.IsGenericParameter (etype))
1460 expr = new BoxedCast (expr, etype);
1466 if (TypeManager.ContainsGenericParameters (etype) ||
1467 TypeManager.ContainsGenericParameters (type)) {
1468 expr = new BoxedCast (expr, etype);
1473 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1474 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1479 protected override string OperatorName {
1480 get { return "as"; }
1483 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1485 type = storey.MutateType (type);
1486 base.MutateHoistedGenericType (storey);
1489 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1491 return expr.GetAttributableValue (ec, value_type, out value);
1496 /// This represents a typecast in the source language.
1498 /// FIXME: Cast expressions have an unusual set of parsing
1499 /// rules, we need to figure those out.
1501 public class Cast : Expression {
1502 Expression target_type;
1505 public Cast (Expression cast_type, Expression expr)
1506 : this (cast_type, expr, cast_type.Location)
1510 public Cast (Expression cast_type, Expression expr, Location loc)
1512 this.target_type = cast_type;
1517 public Expression TargetType {
1518 get { return target_type; }
1521 public Expression Expr {
1522 get { return expr; }
1525 public override Expression CreateExpressionTree (EmitContext ec)
1527 throw new NotSupportedException ("ET");
1530 public override Expression DoResolve (EmitContext ec)
1532 expr = expr.Resolve (ec);
1536 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1542 if (type.IsAbstract && type.IsSealed) {
1543 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1547 eclass = ExprClass.Value;
1549 Constant c = expr as Constant;
1551 c = c.TryReduce (ec, type, loc);
1556 if (type.IsPointer && !ec.InUnsafe) {
1558 } else if (TypeManager.IsDynamicType (expr.Type)) {
1559 Arguments arg = new Arguments (1);
1560 arg.Add (new Argument (expr));
1561 return new DynamicConversion (type, true, arg, loc).Resolve (ec);
1564 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1568 public override void Emit (EmitContext ec)
1570 throw new Exception ("Should not happen");
1573 protected override void CloneTo (CloneContext clonectx, Expression t)
1575 Cast target = (Cast) t;
1577 target.target_type = target_type.Clone (clonectx);
1578 target.expr = expr.Clone (clonectx);
1583 // C# 2.0 Default value expression
1585 public class DefaultValueExpression : Expression
1587 sealed class DefaultValueNullLiteral : NullLiteral
1589 public DefaultValueNullLiteral (DefaultValueExpression expr)
1590 : base (expr.type, expr.loc)
1594 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
1596 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1603 public DefaultValueExpression (Expression expr, Location loc)
1609 public override Expression CreateExpressionTree (EmitContext ec)
1611 Arguments args = new Arguments (2);
1612 args.Add (new Argument (this));
1613 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1614 return CreateExpressionFactoryCall ("Constant", args);
1617 public override Expression DoResolve (EmitContext ec)
1619 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1625 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1626 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1630 return new NullLiteral (Location).ConvertImplicitly (type);
1632 if (TypeManager.IsReferenceType (type))
1633 return new DefaultValueNullLiteral (this);
1635 Constant c = New.Constantify (type);
1639 eclass = ExprClass.Variable;
1643 public override void Emit (EmitContext ec)
1645 LocalTemporary temp_storage = new LocalTemporary(type);
1647 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1648 ec.ig.Emit(OpCodes.Initobj, type);
1649 temp_storage.Emit(ec);
1652 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1654 type = storey.MutateType (type);
1657 protected override void CloneTo (CloneContext clonectx, Expression t)
1659 DefaultValueExpression target = (DefaultValueExpression) t;
1661 target.expr = expr.Clone (clonectx);
1666 /// Binary operators
1668 public class Binary : Expression, IDynamicBinder
1671 protected class PredefinedOperator {
1672 protected readonly Type left;
1673 protected readonly Type right;
1674 public readonly Operator OperatorsMask;
1675 public Type ReturnType;
1677 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1678 : this (ltype, rtype, op_mask, ltype)
1682 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1683 : this (type, type, op_mask, return_type)
1687 public PredefinedOperator (Type type, Operator op_mask)
1688 : this (type, type, op_mask, type)
1692 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1694 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1695 throw new InternalErrorException ("Only masked values can be used");
1699 this.OperatorsMask = op_mask;
1700 this.ReturnType = return_type;
1703 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1705 b.type = ReturnType;
1707 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1708 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1711 // A user operators does not support multiple user conversions, but decimal type
1712 // is considered to be predefined type therefore we apply predefined operators rules
1713 // and then look for decimal user-operator implementation
1715 if (left == TypeManager.decimal_type)
1716 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1721 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1724 // We are dealing with primitive types only
1726 return left == ltype && ltype == rtype;
1729 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1731 if (TypeManager.IsEqual (left, lexpr.Type) &&
1732 TypeManager.IsEqual (right, rexpr.Type))
1735 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1736 Convert.ImplicitConversionExists (ec, rexpr, right);
1739 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1742 if (left != null && best_operator.left != null) {
1743 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1747 // When second arguments are same as the first one, the result is same
1749 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1750 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1753 if (result == 0 || result > 2)
1756 return result == 1 ? best_operator : this;
1760 class PredefinedStringOperator : PredefinedOperator {
1761 public PredefinedStringOperator (Type type, Operator op_mask)
1762 : base (type, op_mask, type)
1764 ReturnType = TypeManager.string_type;
1767 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1768 : base (ltype, rtype, op_mask)
1770 ReturnType = TypeManager.string_type;
1773 public override Expression ConvertResult (EmitContext ec, Binary b)
1776 // Use original expression for nullable arguments
1778 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1780 b.left = unwrap.Original;
1782 unwrap = b.right as Nullable.Unwrap;
1784 b.right = unwrap.Original;
1786 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1787 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1790 // Start a new concat expression using converted expression
1792 return new StringConcat (b.loc, b.left, b.right).Resolve (ec);
1796 class PredefinedShiftOperator : PredefinedOperator {
1797 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1798 base (ltype, TypeManager.int32_type, op_mask)
1802 public override Expression ConvertResult (EmitContext ec, Binary b)
1804 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1806 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1808 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1811 // b = b.left >> b.right & (0x1f|0x3f)
1813 b.right = new Binary (Operator.BitwiseAnd,
1814 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1817 // Expression tree representation does not use & mask
1819 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1820 b.type = ReturnType;
1825 class PredefinedPointerOperator : PredefinedOperator {
1826 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1827 : base (ltype, rtype, op_mask)
1831 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1832 : base (ltype, rtype, op_mask, retType)
1836 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1837 : base (type, op_mask, return_type)
1841 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1844 if (!lexpr.Type.IsPointer)
1847 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1851 if (right == null) {
1852 if (!rexpr.Type.IsPointer)
1855 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1862 public override Expression ConvertResult (EmitContext ec, Binary b)
1865 b.left = EmptyCast.Create (b.left, left);
1866 } else if (right != null) {
1867 b.right = EmptyCast.Create (b.right, right);
1870 Type r_type = ReturnType;
1871 Expression left_arg, right_arg;
1872 if (r_type == null) {
1875 right_arg = b.right;
1876 r_type = b.left.Type;
1880 r_type = b.right.Type;
1884 right_arg = b.right;
1887 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1892 public enum Operator {
1893 Multiply = 0 | ArithmeticMask,
1894 Division = 1 | ArithmeticMask,
1895 Modulus = 2 | ArithmeticMask,
1896 Addition = 3 | ArithmeticMask | AdditionMask,
1897 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1899 LeftShift = 5 | ShiftMask,
1900 RightShift = 6 | ShiftMask,
1902 LessThan = 7 | ComparisonMask | RelationalMask,
1903 GreaterThan = 8 | ComparisonMask | RelationalMask,
1904 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1905 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1906 Equality = 11 | ComparisonMask | EqualityMask,
1907 Inequality = 12 | ComparisonMask | EqualityMask,
1909 BitwiseAnd = 13 | BitwiseMask,
1910 ExclusiveOr = 14 | BitwiseMask,
1911 BitwiseOr = 15 | BitwiseMask,
1913 LogicalAnd = 16 | LogicalMask,
1914 LogicalOr = 17 | LogicalMask,
1919 ValuesOnlyMask = ArithmeticMask - 1,
1920 ArithmeticMask = 1 << 5,
1922 ComparisonMask = 1 << 7,
1923 EqualityMask = 1 << 8,
1924 BitwiseMask = 1 << 9,
1925 LogicalMask = 1 << 10,
1926 AdditionMask = 1 << 11,
1927 SubtractionMask = 1 << 12,
1928 RelationalMask = 1 << 13
1931 readonly Operator oper;
1932 protected Expression left, right;
1933 readonly bool is_compound;
1934 Expression enum_conversion;
1936 static PredefinedOperator [] standard_operators;
1937 static PredefinedOperator [] pointer_operators;
1939 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1940 : this (oper, left, right)
1942 this.is_compound = isCompound;
1945 public Binary (Operator oper, Expression left, Expression right)
1950 this.loc = left.Location;
1953 public Operator Oper {
1960 /// Returns a stringified representation of the Operator
1962 string OperName (Operator oper)
1966 case Operator.Multiply:
1969 case Operator.Division:
1972 case Operator.Modulus:
1975 case Operator.Addition:
1978 case Operator.Subtraction:
1981 case Operator.LeftShift:
1984 case Operator.RightShift:
1987 case Operator.LessThan:
1990 case Operator.GreaterThan:
1993 case Operator.LessThanOrEqual:
1996 case Operator.GreaterThanOrEqual:
1999 case Operator.Equality:
2002 case Operator.Inequality:
2005 case Operator.BitwiseAnd:
2008 case Operator.BitwiseOr:
2011 case Operator.ExclusiveOr:
2014 case Operator.LogicalOr:
2017 case Operator.LogicalAnd:
2021 s = oper.ToString ();
2031 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
2033 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
2036 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
2039 l = TypeManager.CSharpName (left.Type);
2040 r = TypeManager.CSharpName (right.Type);
2042 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2046 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2048 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2052 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2054 string GetOperatorExpressionTypeName ()
2057 case Operator.Addition:
2058 return is_compound ? "AddAssign" : "Add";
2059 case Operator.BitwiseAnd:
2060 return is_compound ? "AndAssign" : "And";
2061 case Operator.BitwiseOr:
2062 return is_compound ? "OrAssign" : "Or";
2063 case Operator.Division:
2064 return is_compound ? "DivideAssign" : "Divide";
2065 case Operator.ExclusiveOr:
2066 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2067 case Operator.Equality:
2069 case Operator.GreaterThan:
2070 return "GreaterThan";
2071 case Operator.GreaterThanOrEqual:
2072 return "GreaterThanOrEqual";
2073 case Operator.Inequality:
2075 case Operator.LeftShift:
2076 return is_compound ? "LeftShiftAssign" : "LeftShift";
2077 case Operator.LessThan:
2079 case Operator.LessThanOrEqual:
2080 return "LessThanOrEqual";
2081 case Operator.LogicalAnd:
2083 case Operator.LogicalOr:
2085 case Operator.Modulus:
2086 return is_compound ? "ModuloAssign" : "Modulo";
2087 case Operator.Multiply:
2088 return is_compound ? "MultiplyAssign" : "Multiply";
2089 case Operator.RightShift:
2090 return is_compound ? "RightShiftAssign" : "RightShift";
2091 case Operator.Subtraction:
2092 return is_compound ? "SubtractAssign" : "Subtract";
2094 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2098 static string GetOperatorMetadataName (Operator op)
2100 CSharp.Operator.OpType op_type;
2102 case Operator.Addition:
2103 op_type = CSharp.Operator.OpType.Addition; break;
2104 case Operator.BitwiseAnd:
2105 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2106 case Operator.BitwiseOr:
2107 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2108 case Operator.Division:
2109 op_type = CSharp.Operator.OpType.Division; break;
2110 case Operator.Equality:
2111 op_type = CSharp.Operator.OpType.Equality; break;
2112 case Operator.ExclusiveOr:
2113 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2114 case Operator.GreaterThan:
2115 op_type = CSharp.Operator.OpType.GreaterThan; break;
2116 case Operator.GreaterThanOrEqual:
2117 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2118 case Operator.Inequality:
2119 op_type = CSharp.Operator.OpType.Inequality; break;
2120 case Operator.LeftShift:
2121 op_type = CSharp.Operator.OpType.LeftShift; break;
2122 case Operator.LessThan:
2123 op_type = CSharp.Operator.OpType.LessThan; break;
2124 case Operator.LessThanOrEqual:
2125 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2126 case Operator.Modulus:
2127 op_type = CSharp.Operator.OpType.Modulus; break;
2128 case Operator.Multiply:
2129 op_type = CSharp.Operator.OpType.Multiply; break;
2130 case Operator.RightShift:
2131 op_type = CSharp.Operator.OpType.RightShift; break;
2132 case Operator.Subtraction:
2133 op_type = CSharp.Operator.OpType.Subtraction; break;
2135 throw new InternalErrorException (op.ToString ());
2138 return CSharp.Operator.GetMetadataName (op_type);
2141 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2144 ILGenerator ig = ec.ig;
2147 case Operator.Multiply:
2148 if (ec.HasSet (EmitContext.Options.CheckedScope)){
2149 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2150 opcode = OpCodes.Mul_Ovf;
2151 else if (!IsFloat (l))
2152 opcode = OpCodes.Mul_Ovf_Un;
2154 opcode = OpCodes.Mul;
2156 opcode = OpCodes.Mul;
2160 case Operator.Division:
2162 opcode = OpCodes.Div_Un;
2164 opcode = OpCodes.Div;
2167 case Operator.Modulus:
2169 opcode = OpCodes.Rem_Un;
2171 opcode = OpCodes.Rem;
2174 case Operator.Addition:
2175 if (ec.HasSet (EmitContext.Options.CheckedScope)){
2176 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2177 opcode = OpCodes.Add_Ovf;
2178 else if (!IsFloat (l))
2179 opcode = OpCodes.Add_Ovf_Un;
2181 opcode = OpCodes.Add;
2183 opcode = OpCodes.Add;
2186 case Operator.Subtraction:
2187 if (ec.HasSet (EmitContext.Options.CheckedScope)){
2188 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2189 opcode = OpCodes.Sub_Ovf;
2190 else if (!IsFloat (l))
2191 opcode = OpCodes.Sub_Ovf_Un;
2193 opcode = OpCodes.Sub;
2195 opcode = OpCodes.Sub;
2198 case Operator.RightShift:
2200 opcode = OpCodes.Shr_Un;
2202 opcode = OpCodes.Shr;
2205 case Operator.LeftShift:
2206 opcode = OpCodes.Shl;
2209 case Operator.Equality:
2210 opcode = OpCodes.Ceq;
2213 case Operator.Inequality:
2214 ig.Emit (OpCodes.Ceq);
2215 ig.Emit (OpCodes.Ldc_I4_0);
2217 opcode = OpCodes.Ceq;
2220 case Operator.LessThan:
2222 opcode = OpCodes.Clt_Un;
2224 opcode = OpCodes.Clt;
2227 case Operator.GreaterThan:
2229 opcode = OpCodes.Cgt_Un;
2231 opcode = OpCodes.Cgt;
2234 case Operator.LessThanOrEqual:
2235 if (IsUnsigned (l) || IsFloat (l))
2236 ig.Emit (OpCodes.Cgt_Un);
2238 ig.Emit (OpCodes.Cgt);
2239 ig.Emit (OpCodes.Ldc_I4_0);
2241 opcode = OpCodes.Ceq;
2244 case Operator.GreaterThanOrEqual:
2245 if (IsUnsigned (l) || IsFloat (l))
2246 ig.Emit (OpCodes.Clt_Un);
2248 ig.Emit (OpCodes.Clt);
2250 ig.Emit (OpCodes.Ldc_I4_0);
2252 opcode = OpCodes.Ceq;
2255 case Operator.BitwiseOr:
2256 opcode = OpCodes.Or;
2259 case Operator.BitwiseAnd:
2260 opcode = OpCodes.And;
2263 case Operator.ExclusiveOr:
2264 opcode = OpCodes.Xor;
2268 throw new InternalErrorException (oper.ToString ());
2274 static bool IsUnsigned (Type t)
2279 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2280 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2283 static bool IsFloat (Type t)
2285 return t == TypeManager.float_type || t == TypeManager.double_type;
2288 Expression ResolveOperator (EmitContext ec)
2291 Type r = right.Type;
2293 bool primitives_only = false;
2295 if (standard_operators == null)
2296 CreateStandardOperatorsTable ();
2299 // Handles predefined primitive types
2301 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2302 if ((oper & Operator.ShiftMask) == 0) {
2303 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2306 primitives_only = true;
2310 if (l.IsPointer || r.IsPointer)
2311 return ResolveOperatorPointer (ec, l, r);
2314 bool lenum = TypeManager.IsEnumType (l);
2315 bool renum = TypeManager.IsEnumType (r);
2316 if (lenum || renum) {
2317 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2319 // TODO: Can this be ambiguous
2325 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2326 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2328 expr = ResolveOperatorDelegate (ec, l, r);
2330 // TODO: Can this be ambiguous
2336 expr = ResolveUserOperator (ec, l, r);
2340 // Predefined reference types equality
2341 if ((oper & Operator.EqualityMask) != 0) {
2342 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2348 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2351 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2352 // if 'left' is not an enumeration constant, create one from the type of 'right'
2353 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2356 case Operator.BitwiseOr:
2357 case Operator.BitwiseAnd:
2358 case Operator.ExclusiveOr:
2359 case Operator.Equality:
2360 case Operator.Inequality:
2361 case Operator.LessThan:
2362 case Operator.LessThanOrEqual:
2363 case Operator.GreaterThan:
2364 case Operator.GreaterThanOrEqual:
2365 if (TypeManager.IsEnumType (left.Type))
2368 if (left.IsZeroInteger)
2369 return left.TryReduce (ec, right.Type, loc);
2373 case Operator.Addition:
2374 case Operator.Subtraction:
2377 case Operator.Multiply:
2378 case Operator.Division:
2379 case Operator.Modulus:
2380 case Operator.LeftShift:
2381 case Operator.RightShift:
2382 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2386 Error_OperatorCannotBeApplied (this.left, this.right);
2391 // The `|' operator used on types which were extended is dangerous
2393 void CheckBitwiseOrOnSignExtended ()
2395 OpcodeCast lcast = left as OpcodeCast;
2396 if (lcast != null) {
2397 if (IsUnsigned (lcast.UnderlyingType))
2401 OpcodeCast rcast = right as OpcodeCast;
2402 if (rcast != null) {
2403 if (IsUnsigned (rcast.UnderlyingType))
2407 if (lcast == null && rcast == null)
2410 // FIXME: consider constants
2412 Report.Warning (675, 3, loc,
2413 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2414 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2417 static void CreatePointerOperatorsTable ()
2419 ArrayList temp = new ArrayList ();
2422 // Pointer arithmetic:
2424 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2425 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2426 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2427 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2429 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2430 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2431 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2432 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2435 // T* operator + (int y, T* x);
2436 // T* operator + (uint y, T *x);
2437 // T* operator + (long y, T *x);
2438 // T* operator + (ulong y, T *x);
2440 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2441 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2442 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2443 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2446 // long operator - (T* x, T *y)
2448 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2450 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2453 static void CreateStandardOperatorsTable ()
2455 ArrayList temp = new ArrayList ();
2456 Type bool_type = TypeManager.bool_type;
2458 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2459 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2460 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2461 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2462 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2463 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2464 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2466 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2467 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2468 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2469 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2470 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2471 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2472 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2474 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2476 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2477 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2478 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2480 temp.Add (new PredefinedOperator (bool_type,
2481 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2483 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2484 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2485 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2486 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2488 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2492 // Rules used during binary numeric promotion
2494 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2499 Constant c = prim_expr as Constant;
2501 temp = c.ConvertImplicitly (type);
2508 if (type == TypeManager.uint32_type) {
2509 etype = prim_expr.Type;
2510 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2511 type = TypeManager.int64_type;
2513 if (type != second_expr.Type) {
2514 c = second_expr as Constant;
2516 temp = c.ConvertImplicitly (type);
2518 temp = Convert.ImplicitNumericConversion (second_expr, type);
2524 } else if (type == TypeManager.uint64_type) {
2526 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2528 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2529 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2533 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2542 // 7.2.6.2 Binary numeric promotions
2544 public bool DoBinaryOperatorPromotion (EmitContext ec)
2546 Type ltype = left.Type;
2547 Type rtype = right.Type;
2550 foreach (Type t in ConstantFold.binary_promotions) {
2552 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2555 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2558 Type int32 = TypeManager.int32_type;
2559 if (ltype != int32) {
2560 Constant c = left as Constant;
2562 temp = c.ConvertImplicitly (int32);
2564 temp = Convert.ImplicitNumericConversion (left, int32);
2571 if (rtype != int32) {
2572 Constant c = right as Constant;
2574 temp = c.ConvertImplicitly (int32);
2576 temp = Convert.ImplicitNumericConversion (right, int32);
2586 public override Expression DoResolve (EmitContext ec)
2591 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2592 left = ((ParenthesizedExpression) left).Expr;
2593 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2597 if (left.eclass == ExprClass.Type) {
2598 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2602 left = left.Resolve (ec);
2607 Constant lc = left as Constant;
2609 if (lc != null && lc.Type == TypeManager.bool_type &&
2610 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2611 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2613 // FIXME: resolve right expression as unreachable
2614 // right.Resolve (ec);
2616 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2620 right = right.Resolve (ec);
2624 eclass = ExprClass.Value;
2625 Constant rc = right as Constant;
2627 // The conversion rules are ignored in enum context but why
2628 if (!ec.HasSet (EmitContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2629 lc = EnumLiftUp (ec, lc, rc, loc);
2631 rc = EnumLiftUp (ec, rc, lc, loc);
2634 if (rc != null && lc != null) {
2635 int prev_e = Report.Errors;
2636 Expression e = ConstantFold.BinaryFold (
2637 ec, oper, lc, rc, loc);
2638 if (e != null || Report.Errors != prev_e)
2640 } else if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) && !TypeManager.IsDynamicType (left.Type) &&
2641 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2643 if ((ResolveOperator (ec)) == null) {
2644 Error_OperatorCannotBeApplied (left, right);
2649 // The result is a constant with side-effect
2651 Constant side_effect = rc == null ?
2652 new SideEffectConstant (lc, right, loc) :
2653 new SideEffectConstant (rc, left, loc);
2655 return ReducedExpression.Create (side_effect, this);
2658 // Comparison warnings
2659 if ((oper & Operator.ComparisonMask) != 0) {
2660 if (left.Equals (right)) {
2661 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2663 CheckUselessComparison (lc, right.Type);
2664 CheckUselessComparison (rc, left.Type);
2667 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2668 Arguments args = new Arguments (2);
2669 args.Add (new Argument (left));
2670 args.Add (new Argument (right));
2671 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2674 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2675 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2676 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2677 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2678 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2679 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2681 return DoResolveCore (ec, left, right);
2684 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2686 Expression expr = ResolveOperator (ec);
2688 Error_OperatorCannotBeApplied (left_orig, right_orig);
2690 if (left == null || right == null)
2691 throw new InternalErrorException ("Invalid conversion");
2693 if (oper == Operator.BitwiseOr)
2694 CheckBitwiseOrOnSignExtended ();
2699 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2701 left.MutateHoistedGenericType (storey);
2702 right.MutateHoistedGenericType (storey);
2706 // D operator + (D x, D y)
2707 // D operator - (D x, D y)
2708 // bool operator == (D x, D y)
2709 // bool operator != (D x, D y)
2711 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2713 bool is_equality = (oper & Operator.EqualityMask) != 0;
2714 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2716 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2717 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2722 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2723 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2734 // Resolve delegate equality as a user operator
2737 return ResolveUserOperator (ec, l, r);
2740 Arguments args = new Arguments (2);
2741 args.Add (new Argument (left));
2742 args.Add (new Argument (right));
2744 if (oper == Operator.Addition) {
2745 if (TypeManager.delegate_combine_delegate_delegate == null) {
2746 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2747 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2750 method = TypeManager.delegate_combine_delegate_delegate;
2752 if (TypeManager.delegate_remove_delegate_delegate == null) {
2753 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2754 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2757 method = TypeManager.delegate_remove_delegate_delegate;
2760 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2761 mg = mg.OverloadResolve (ec, ref args, false, loc);
2763 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2767 // Enumeration operators
2769 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2772 // bool operator == (E x, E y);
2773 // bool operator != (E x, E y);
2774 // bool operator < (E x, E y);
2775 // bool operator > (E x, E y);
2776 // bool operator <= (E x, E y);
2777 // bool operator >= (E x, E y);
2779 // E operator & (E x, E y);
2780 // E operator | (E x, E y);
2781 // E operator ^ (E x, E y);
2783 // U operator - (E e, E f)
2784 // E operator - (E e, U x)
2786 // E operator + (U x, E e)
2787 // E operator + (E e, U x)
2789 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2790 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2793 Expression ltemp = left;
2794 Expression rtemp = right;
2795 Type underlying_type;
2798 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2800 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2806 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2814 if (TypeManager.IsEqual (ltype, rtype)) {
2815 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2817 if (left is Constant)
2818 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2820 left = EmptyCast.Create (left, underlying_type);
2822 if (right is Constant)
2823 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2825 right = EmptyCast.Create (right, underlying_type);
2827 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2829 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2830 Constant c = right as Constant;
2831 if (c == null || !c.IsDefaultValue)
2834 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2837 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2840 if (left is Constant)
2841 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2843 left = EmptyCast.Create (left, underlying_type);
2846 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2848 if (oper != Operator.Addition) {
2849 Constant c = left as Constant;
2850 if (c == null || !c.IsDefaultValue)
2853 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2856 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2859 if (right is Constant)
2860 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2862 right = EmptyCast.Create (right, underlying_type);
2869 // C# specification uses explicit cast syntax which means binary promotion
2870 // should happen, however it seems that csc does not do that
2872 if (!DoBinaryOperatorPromotion (ec)) {
2878 Type res_type = null;
2879 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2880 Type promoted_type = lenum ? left.Type : right.Type;
2881 enum_conversion = Convert.ExplicitNumericConversion (
2882 new EmptyExpression (promoted_type), underlying_type);
2884 if (oper == Operator.Subtraction && renum && lenum)
2885 res_type = underlying_type;
2886 else if (oper == Operator.Addition && renum)
2892 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2893 if (!is_compound || expr == null)
2897 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2900 if (Convert.ImplicitConversionExists (ec, left, rtype))
2903 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2906 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2911 // 7.9.6 Reference type equality operators
2913 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2916 // operator != (object a, object b)
2917 // operator == (object a, object b)
2920 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2922 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2925 type = TypeManager.bool_type;
2926 GenericConstraints constraints;
2928 bool lgen = TypeManager.IsGenericParameter (l);
2930 if (TypeManager.IsEqual (l, r)) {
2933 // Only allow to compare same reference type parameter
2935 if (TypeManager.IsReferenceType (l)) {
2936 left = new BoxedCast (left, TypeManager.object_type);
2937 right = new BoxedCast (right, TypeManager.object_type);
2944 if (l == InternalType.AnonymousMethod)
2947 if (TypeManager.IsValueType (l))
2953 bool rgen = TypeManager.IsGenericParameter (r);
2956 // a, Both operands are reference-type values or the value null
2957 // b, One operand is a value of type T where T is a type-parameter and
2958 // the other operand is the value null. Furthermore T does not have the
2959 // value type constrain
2961 if (left is NullLiteral || right is NullLiteral) {
2963 constraints = TypeManager.GetTypeParameterConstraints (l);
2964 if (constraints != null && constraints.HasValueTypeConstraint)
2967 left = new BoxedCast (left, TypeManager.object_type);
2972 constraints = TypeManager.GetTypeParameterConstraints (r);
2973 if (constraints != null && constraints.HasValueTypeConstraint)
2976 right = new BoxedCast (right, TypeManager.object_type);
2982 // An interface is converted to the object before the
2983 // standard conversion is applied. It's not clear from the
2984 // standard but it looks like it works like that.
2987 if (!TypeManager.IsReferenceType (l))
2989 left = new BoxedCast (left, TypeManager.object_type);
2990 } else if (l.IsInterface) {
2991 l = TypeManager.object_type;
2992 } else if (TypeManager.IsStruct (l)) {
2997 if (!TypeManager.IsReferenceType (r))
2999 right = new BoxedCast (right, TypeManager.object_type);
3000 } else if (r.IsInterface) {
3001 r = TypeManager.object_type;
3002 } else if (TypeManager.IsStruct (r)) {
3007 const string ref_comparison = "Possible unintended reference comparison. " +
3008 "Consider casting the {0} side of the expression to `string' to compare the values";
3011 // A standard implicit conversion exists from the type of either
3012 // operand to the type of the other operand
3014 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3015 if (l == TypeManager.string_type)
3016 Report.Warning (253, 2, loc, ref_comparison, "right");
3021 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3022 if (r == TypeManager.string_type)
3023 Report.Warning (252, 2, loc, ref_comparison, "left");
3032 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
3035 // bool operator == (void* x, void* y);
3036 // bool operator != (void* x, void* y);
3037 // bool operator < (void* x, void* y);
3038 // bool operator > (void* x, void* y);
3039 // bool operator <= (void* x, void* y);
3040 // bool operator >= (void* x, void* y);
3042 if ((oper & Operator.ComparisonMask) != 0) {
3045 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3052 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3058 type = TypeManager.bool_type;
3062 if (pointer_operators == null)
3063 CreatePointerOperatorsTable ();
3065 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3069 // Build-in operators method overloading
3071 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3073 PredefinedOperator best_operator = null;
3075 Type r = right.Type;
3076 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3078 foreach (PredefinedOperator po in operators) {
3079 if ((po.OperatorsMask & oper_mask) == 0)
3082 if (primitives_only) {
3083 if (!po.IsPrimitiveApplicable (l, r))
3086 if (!po.IsApplicable (ec, left, right))
3090 if (best_operator == null) {
3092 if (primitives_only)
3098 best_operator = po.ResolveBetterOperator (ec, best_operator);
3100 if (best_operator == null) {
3101 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3102 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3109 if (best_operator == null)
3112 Expression expr = best_operator.ConvertResult (ec, this);
3113 if (enum_type == null)
3117 // HACK: required by enum_conversion
3119 expr.Type = enum_type;
3120 return EmptyCast.Create (expr, enum_type);
3124 // Performs user-operator overloading
3126 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3129 if (oper == Operator.LogicalAnd)
3130 user_oper = Operator.BitwiseAnd;
3131 else if (oper == Operator.LogicalOr)
3132 user_oper = Operator.BitwiseOr;
3136 string op = GetOperatorMetadataName (user_oper);
3138 MethodGroupExpr left_operators = MemberLookup (ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3139 MethodGroupExpr right_operators = null;
3141 if (!TypeManager.IsEqual (r, l)) {
3142 right_operators = MemberLookup (ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3143 if (right_operators == null && left_operators == null)
3145 } else if (left_operators == null) {
3149 Arguments args = new Arguments (2);
3150 Argument larg = new Argument (left);
3152 Argument rarg = new Argument (right);
3155 MethodGroupExpr union;
3158 // User-defined operator implementations always take precedence
3159 // over predefined operator implementations
3161 if (left_operators != null && right_operators != null) {
3162 if (IsPredefinedUserOperator (l, user_oper)) {
3163 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3165 union = left_operators;
3166 } else if (IsPredefinedUserOperator (r, user_oper)) {
3167 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3169 union = right_operators;
3171 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3173 } else if (left_operators != null) {
3174 union = left_operators;
3176 union = right_operators;
3179 union = union.OverloadResolve (ec, ref args, true, loc);
3183 Expression oper_expr;
3185 // TODO: CreateExpressionTree is allocated every time
3186 if (user_oper != oper) {
3187 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3188 oper == Operator.LogicalAnd, loc).Resolve (ec);
3190 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3193 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3194 // and not invoke user operator
3196 if ((oper & Operator.EqualityMask) != 0) {
3197 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3198 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3199 type = TypeManager.bool_type;
3200 if (left is NullLiteral || right is NullLiteral)
3201 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3202 } else if (l != r) {
3203 MethodInfo mi = (MethodInfo) union;
3206 // Two System.Delegate(s) are never equal
3208 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3219 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3224 private void CheckUselessComparison (Constant c, Type type)
3226 if (c == null || !IsTypeIntegral (type)
3227 || c is StringConstant
3228 || c is BoolConstant
3229 || c is FloatConstant
3230 || c is DoubleConstant
3231 || c is DecimalConstant
3237 if (c is ULongConstant) {
3238 ulong uvalue = ((ULongConstant) c).Value;
3239 if (uvalue > long.MaxValue) {
3240 if (type == TypeManager.byte_type ||
3241 type == TypeManager.sbyte_type ||
3242 type == TypeManager.short_type ||
3243 type == TypeManager.ushort_type ||
3244 type == TypeManager.int32_type ||
3245 type == TypeManager.uint32_type ||
3246 type == TypeManager.int64_type ||
3247 type == TypeManager.char_type)
3248 WarnUselessComparison (type);
3251 value = (long) uvalue;
3253 else if (c is ByteConstant)
3254 value = ((ByteConstant) c).Value;
3255 else if (c is SByteConstant)
3256 value = ((SByteConstant) c).Value;
3257 else if (c is ShortConstant)
3258 value = ((ShortConstant) c).Value;
3259 else if (c is UShortConstant)
3260 value = ((UShortConstant) c).Value;
3261 else if (c is IntConstant)
3262 value = ((IntConstant) c).Value;
3263 else if (c is UIntConstant)
3264 value = ((UIntConstant) c).Value;
3265 else if (c is LongConstant)
3266 value = ((LongConstant) c).Value;
3267 else if (c is CharConstant)
3268 value = ((CharConstant)c).Value;
3273 if (IsValueOutOfRange (value, type))
3274 WarnUselessComparison (type);
3277 static bool IsValueOutOfRange (long value, Type type)
3279 if (IsTypeUnsigned (type) && value < 0)
3281 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3282 type == TypeManager.byte_type && value >= 0x100 ||
3283 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3284 type == TypeManager.ushort_type && value >= 0x10000 ||
3285 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3286 type == TypeManager.uint32_type && value >= 0x100000000;
3289 static bool IsBuildInEqualityOperator (Type t)
3291 return t == TypeManager.object_type || t == TypeManager.string_type ||
3292 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3295 static bool IsPredefinedUserOperator (Type t, Operator op)
3298 // Some predefined types have user operators
3300 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3303 private static bool IsTypeIntegral (Type type)
3305 return type == TypeManager.uint64_type ||
3306 type == TypeManager.int64_type ||
3307 type == TypeManager.uint32_type ||
3308 type == TypeManager.int32_type ||
3309 type == TypeManager.ushort_type ||
3310 type == TypeManager.short_type ||
3311 type == TypeManager.sbyte_type ||
3312 type == TypeManager.byte_type ||
3313 type == TypeManager.char_type;
3316 private static bool IsTypeUnsigned (Type type)
3318 return type == TypeManager.uint64_type ||
3319 type == TypeManager.uint32_type ||
3320 type == TypeManager.ushort_type ||
3321 type == TypeManager.byte_type ||
3322 type == TypeManager.char_type;
3325 private void WarnUselessComparison (Type type)
3327 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}'",
3328 TypeManager.CSharpName (type));
3332 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3333 /// context of a conditional bool expression. This function will return
3334 /// false if it is was possible to use EmitBranchable, or true if it was.
3336 /// The expression's code is generated, and we will generate a branch to `target'
3337 /// if the resulting expression value is equal to isTrue
3339 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3341 ILGenerator ig = ec.ig;
3344 // This is more complicated than it looks, but its just to avoid
3345 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3346 // but on top of that we want for == and != to use a special path
3347 // if we are comparing against null
3349 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3350 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3353 // put the constant on the rhs, for simplicity
3355 if (left is Constant) {
3356 Expression swap = right;
3361 if (((Constant) right).IsZeroInteger) {
3362 left.EmitBranchable (ec, target, my_on_true);
3365 if (right.Type == TypeManager.bool_type) {
3366 // right is a boolean, and it's not 'false' => it is 'true'
3367 left.EmitBranchable (ec, target, !my_on_true);
3371 } else if (oper == Operator.LogicalAnd) {
3374 Label tests_end = ig.DefineLabel ();
3376 left.EmitBranchable (ec, tests_end, false);
3377 right.EmitBranchable (ec, target, true);
3378 ig.MarkLabel (tests_end);
3381 // This optimizes code like this
3382 // if (true && i > 4)
3384 if (!(left is Constant))
3385 left.EmitBranchable (ec, target, false);
3387 if (!(right is Constant))
3388 right.EmitBranchable (ec, target, false);
3393 } else if (oper == Operator.LogicalOr){
3395 left.EmitBranchable (ec, target, true);
3396 right.EmitBranchable (ec, target, true);
3399 Label tests_end = ig.DefineLabel ();
3400 left.EmitBranchable (ec, tests_end, true);
3401 right.EmitBranchable (ec, target, false);
3402 ig.MarkLabel (tests_end);
3407 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3408 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3409 oper == Operator.Equality || oper == Operator.Inequality)) {
3410 base.EmitBranchable (ec, target, on_true);
3418 bool is_float = IsFloat (t);
3419 bool is_unsigned = is_float || IsUnsigned (t);
3422 case Operator.Equality:
3424 ig.Emit (OpCodes.Beq, target);
3426 ig.Emit (OpCodes.Bne_Un, target);
3429 case Operator.Inequality:
3431 ig.Emit (OpCodes.Bne_Un, target);
3433 ig.Emit (OpCodes.Beq, target);
3436 case Operator.LessThan:
3438 if (is_unsigned && !is_float)
3439 ig.Emit (OpCodes.Blt_Un, target);
3441 ig.Emit (OpCodes.Blt, target);
3444 ig.Emit (OpCodes.Bge_Un, target);
3446 ig.Emit (OpCodes.Bge, target);
3449 case Operator.GreaterThan:
3451 if (is_unsigned && !is_float)
3452 ig.Emit (OpCodes.Bgt_Un, target);
3454 ig.Emit (OpCodes.Bgt, target);
3457 ig.Emit (OpCodes.Ble_Un, target);
3459 ig.Emit (OpCodes.Ble, target);
3462 case Operator.LessThanOrEqual:
3464 if (is_unsigned && !is_float)
3465 ig.Emit (OpCodes.Ble_Un, target);
3467 ig.Emit (OpCodes.Ble, target);
3470 ig.Emit (OpCodes.Bgt_Un, target);
3472 ig.Emit (OpCodes.Bgt, target);
3476 case Operator.GreaterThanOrEqual:
3478 if (is_unsigned && !is_float)
3479 ig.Emit (OpCodes.Bge_Un, target);
3481 ig.Emit (OpCodes.Bge, target);
3484 ig.Emit (OpCodes.Blt_Un, target);
3486 ig.Emit (OpCodes.Blt, target);
3489 throw new InternalErrorException (oper.ToString ());
3493 public override void Emit (EmitContext ec)
3495 EmitOperator (ec, left.Type);
3498 protected virtual void EmitOperator (EmitContext ec, Type l)
3500 ILGenerator ig = ec.ig;
3503 // Handle short-circuit operators differently
3506 if ((oper & Operator.LogicalMask) != 0) {
3507 Label load_result = ig.DefineLabel ();
3508 Label end = ig.DefineLabel ();
3510 bool is_or = oper == Operator.LogicalOr;
3511 left.EmitBranchable (ec, load_result, is_or);
3513 ig.Emit (OpCodes.Br_S, end);
3515 ig.MarkLabel (load_result);
3516 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3524 // Optimize zero-based operations
3526 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3528 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3529 Constant rc = right as Constant;
3530 if (rc != null && rc.IsDefaultValue) {
3536 EmitOperatorOpcode (ec, oper, l);
3539 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3540 // expression because that would wrap lifted binary operation
3542 if (enum_conversion != null)
3543 enum_conversion.Emit (ec);
3546 public override void EmitSideEffect (EmitContext ec)
3548 if ((oper & Operator.LogicalMask) != 0 ||
3549 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3550 base.EmitSideEffect (ec);
3552 left.EmitSideEffect (ec);
3553 right.EmitSideEffect (ec);
3557 protected override void CloneTo (CloneContext clonectx, Expression t)
3559 Binary target = (Binary) t;
3561 target.left = left.Clone (clonectx);
3562 target.right = right.Clone (clonectx);
3565 public Expression CreateCallSiteBinder (EmitContext ec, Arguments args)
3567 Arguments binder_args = new Arguments (4);
3569 MemberAccess sle = new MemberAccess (new MemberAccess (
3570 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3572 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
3574 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3575 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (EmitContext.Options.CheckedScope), loc)));
3577 bool member_access = left is DynamicMemberBinder || right is DynamicMemberBinder;
3578 binder_args.Add (new Argument (new BoolLiteral (member_access, loc)));
3579 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
3581 return new New (new MemberAccess (binder, "CSharpBinaryOperationBinder", loc), binder_args, loc);
3584 public override Expression CreateExpressionTree (EmitContext ec)
3586 return CreateExpressionTree (ec, null);
3589 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3592 bool lift_arg = false;
3595 case Operator.Addition:
3596 if (method == null && ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type))
3597 method_name = "AddChecked";
3599 method_name = "Add";
3601 case Operator.BitwiseAnd:
3602 method_name = "And";
3604 case Operator.BitwiseOr:
3607 case Operator.Division:
3608 method_name = "Divide";
3610 case Operator.Equality:
3611 method_name = "Equal";
3614 case Operator.ExclusiveOr:
3615 method_name = "ExclusiveOr";
3617 case Operator.GreaterThan:
3618 method_name = "GreaterThan";
3621 case Operator.GreaterThanOrEqual:
3622 method_name = "GreaterThanOrEqual";
3625 case Operator.Inequality:
3626 method_name = "NotEqual";
3629 case Operator.LeftShift:
3630 method_name = "LeftShift";
3632 case Operator.LessThan:
3633 method_name = "LessThan";
3636 case Operator.LessThanOrEqual:
3637 method_name = "LessThanOrEqual";
3640 case Operator.LogicalAnd:
3641 method_name = "AndAlso";
3643 case Operator.LogicalOr:
3644 method_name = "OrElse";
3646 case Operator.Modulus:
3647 method_name = "Modulo";
3649 case Operator.Multiply:
3650 if (method == null && ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type))
3651 method_name = "MultiplyChecked";
3653 method_name = "Multiply";
3655 case Operator.RightShift:
3656 method_name = "RightShift";
3658 case Operator.Subtraction:
3659 if (method == null && ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type))
3660 method_name = "SubtractChecked";
3662 method_name = "Subtract";
3666 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3669 Arguments args = new Arguments (2);
3670 args.Add (new Argument (left.CreateExpressionTree (ec)));
3671 args.Add (new Argument (right.CreateExpressionTree (ec)));
3672 if (method != null) {
3674 args.Add (new Argument (new BoolConstant (false, loc)));
3676 args.Add (new Argument (method.CreateExpressionTree (ec)));
3679 return CreateExpressionFactoryCall (method_name, args);
3684 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3685 // b, c, d... may be strings or objects.
3687 public class StringConcat : Expression {
3688 Arguments arguments;
3690 public StringConcat (Location loc, Expression left, Expression right)
3693 type = TypeManager.string_type;
3694 eclass = ExprClass.Value;
3696 arguments = new Arguments (2);
3701 public override Expression CreateExpressionTree (EmitContext ec)
3703 Argument arg = arguments [0];
3704 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3708 // Creates nested calls tree from an array of arguments used for IL emit
3710 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3712 Arguments concat_args = new Arguments (2);
3713 Arguments add_args = new Arguments (3);
3715 concat_args.Add (left);
3716 add_args.Add (new Argument (left_etree));
3718 concat_args.Add (arguments [pos]);
3719 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3721 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3725 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3729 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3731 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3732 if (++pos == arguments.Count)
3735 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3736 return CreateExpressionAddCall (ec, left, expr, pos);
3739 public override Expression DoResolve (EmitContext ec)
3744 public void Append (Expression operand)
3749 StringConstant sc = operand as StringConstant;
3751 if (arguments.Count != 0) {
3752 Argument last_argument = arguments [arguments.Count - 1];
3753 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3754 if (last_expr_constant != null) {
3755 last_argument.Expr = new StringConstant (
3756 last_expr_constant.Value + sc.Value, sc.Location);
3762 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3764 StringConcat concat_oper = operand as StringConcat;
3765 if (concat_oper != null) {
3766 arguments.AddRange (concat_oper.arguments);
3771 arguments.Add (new Argument (operand));
3774 Expression CreateConcatMemberExpression ()
3776 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3779 public override void Emit (EmitContext ec)
3781 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3782 concat = concat.Resolve (ec);
3787 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3789 arguments.MutateHoistedGenericType (storey);
3794 // User-defined conditional logical operator
3796 public class ConditionalLogicalOperator : UserOperatorCall {
3797 readonly bool is_and;
3800 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3801 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3802 : base (oper_method, arguments, expr_tree, loc)
3804 this.is_and = is_and;
3807 public override Expression DoResolve (EmitContext ec)
3809 MethodInfo method = (MethodInfo)mg;
3810 type = TypeManager.TypeToCoreType (method.ReturnType);
3811 AParametersCollection pd = TypeManager.GetParameterData (method);
3812 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3813 Report.Error (217, loc,
3814 "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",
3815 TypeManager.CSharpSignature (method));
3819 Expression left_dup = new EmptyExpression (type);
3820 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3821 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3822 if (op_true == null || op_false == null) {
3823 Report.Error (218, loc,
3824 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3825 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3829 oper = is_and ? op_false : op_true;
3830 eclass = ExprClass.Value;
3834 public override void Emit (EmitContext ec)
3836 ILGenerator ig = ec.ig;
3837 Label end_target = ig.DefineLabel ();
3840 // Emit and duplicate left argument
3842 arguments [0].Expr.Emit (ec);
3843 ig.Emit (OpCodes.Dup);
3844 arguments.RemoveAt (0);
3846 oper.EmitBranchable (ec, end_target, true);
3848 ig.MarkLabel (end_target);
3852 public class PointerArithmetic : Expression {
3853 Expression left, right;
3857 // We assume that `l' is always a pointer
3859 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3868 public override Expression CreateExpressionTree (EmitContext ec)
3870 Error_PointerInsideExpressionTree ();
3874 public override Expression DoResolve (EmitContext ec)
3876 eclass = ExprClass.Variable;
3878 if (left.Type == TypeManager.void_ptr_type) {
3879 Error (242, "The operation in question is undefined on void pointers");
3886 public override void Emit (EmitContext ec)
3888 Type op_type = left.Type;
3889 ILGenerator ig = ec.ig;
3891 // It must be either array or fixed buffer
3893 if (TypeManager.HasElementType (op_type)) {
3894 element = TypeManager.GetElementType (op_type);
3896 FieldExpr fe = left as FieldExpr;
3898 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3903 int size = GetTypeSize (element);
3904 Type rtype = right.Type;
3906 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3908 // handle (pointer - pointer)
3912 ig.Emit (OpCodes.Sub);
3916 ig.Emit (OpCodes.Sizeof, element);
3918 IntLiteral.EmitInt (ig, size);
3919 ig.Emit (OpCodes.Div);
3921 ig.Emit (OpCodes.Conv_I8);
3924 // handle + and - on (pointer op int)
3926 Constant left_const = left as Constant;
3927 if (left_const != null) {
3929 // Optimize ((T*)null) pointer operations
3931 if (left_const.IsDefaultValue) {
3932 left = EmptyExpression.Null;
3940 Constant right_const = right as Constant;
3941 if (right_const != null) {
3943 // Optimize 0-based arithmetic
3945 if (right_const.IsDefaultValue)
3949 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3953 ig.Emit (OpCodes.Sizeof, element);
3954 right = EmptyExpression.Null;
3959 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3960 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3961 ig.Emit (OpCodes.Conv_I);
3962 } else if (rtype == TypeManager.uint32_type) {
3963 ig.Emit (OpCodes.Conv_U);
3966 if (right_const == null && size != 1){
3968 ig.Emit (OpCodes.Sizeof, element);
3970 IntLiteral.EmitInt (ig, size);
3971 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3972 ig.Emit (OpCodes.Conv_I8);
3974 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3977 if (left_const == null) {
3978 if (rtype == TypeManager.int64_type)
3979 ig.Emit (OpCodes.Conv_I);
3980 else if (rtype == TypeManager.uint64_type)
3981 ig.Emit (OpCodes.Conv_U);
3983 Binary.EmitOperatorOpcode (ec, op, op_type);
3990 /// Implements the ternary conditional operator (?:)
3992 public class Conditional : Expression {
3993 Expression expr, true_expr, false_expr;
3995 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3998 this.true_expr = true_expr;
3999 this.false_expr = false_expr;
4000 this.loc = expr.Location;
4003 public Expression Expr {
4009 public Expression TrueExpr {
4015 public Expression FalseExpr {
4021 public override Expression CreateExpressionTree (EmitContext ec)
4023 Arguments args = new Arguments (3);
4024 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4025 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4026 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4027 return CreateExpressionFactoryCall ("Condition", args);
4030 public override Expression DoResolve (EmitContext ec)
4032 expr = Expression.ResolveBoolean (ec, expr, loc);
4034 Assign ass = expr as Assign;
4035 if (ass != null && ass.Source is Constant) {
4036 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
4039 true_expr = true_expr.Resolve (ec);
4040 false_expr = false_expr.Resolve (ec);
4042 if (true_expr == null || false_expr == null || expr == null)
4045 eclass = ExprClass.Value;
4046 Type true_type = true_expr.Type;
4047 Type false_type = false_expr.Type;
4051 // First, if an implicit conversion exists from true_expr
4052 // to false_expr, then the result type is of type false_expr.Type
4054 if (!TypeManager.IsEqual (true_type, false_type)) {
4055 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4058 // Check if both can convert implicitl to each other's type
4060 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4062 "Can not compute type of conditional expression " +
4063 "as `" + TypeManager.CSharpName (true_expr.Type) +
4064 "' and `" + TypeManager.CSharpName (false_expr.Type) +
4065 "' convert implicitly to each other");
4070 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4073 Report.Error (173, loc,
4074 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4075 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
4080 // Dead code optimalization
4081 Constant c = expr as Constant;
4083 bool is_false = c.IsDefaultValue;
4084 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4085 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
4091 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4093 expr.MutateHoistedGenericType (storey);
4094 true_expr.MutateHoistedGenericType (storey);
4095 false_expr.MutateHoistedGenericType (storey);
4096 type = storey.MutateType (type);
4099 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
4104 public override void Emit (EmitContext ec)
4106 ILGenerator ig = ec.ig;
4107 Label false_target = ig.DefineLabel ();
4108 Label end_target = ig.DefineLabel ();
4110 expr.EmitBranchable (ec, false_target, false);
4111 true_expr.Emit (ec);
4113 if (type.IsInterface) {
4114 LocalBuilder temp = ec.GetTemporaryLocal (type);
4115 ig.Emit (OpCodes.Stloc, temp);
4116 ig.Emit (OpCodes.Ldloc, temp);
4117 ec.FreeTemporaryLocal (temp, type);
4120 ig.Emit (OpCodes.Br, end_target);
4121 ig.MarkLabel (false_target);
4122 false_expr.Emit (ec);
4123 ig.MarkLabel (end_target);
4126 protected override void CloneTo (CloneContext clonectx, Expression t)
4128 Conditional target = (Conditional) t;
4130 target.expr = expr.Clone (clonectx);
4131 target.true_expr = true_expr.Clone (clonectx);
4132 target.false_expr = false_expr.Clone (clonectx);
4136 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4137 LocalTemporary temp;
4140 public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
4141 public abstract bool IsFixed { get; }
4142 public abstract bool IsRef { get; }
4143 public abstract string Name { get; }
4144 public abstract void SetHasAddressTaken ();
4147 // Variable IL data, it has to be protected to encapsulate hoisted variables
4149 protected abstract ILocalVariable Variable { get; }
4152 // Variable flow-analysis data
4154 public abstract VariableInfo VariableInfo { get; }
4157 public void AddressOf (EmitContext ec, AddressOp mode)
4159 HoistedVariable hv = GetHoistedVariable (ec);
4161 hv.AddressOf (ec, mode);
4165 Variable.EmitAddressOf (ec);
4168 public override void Emit (EmitContext ec)
4173 public override void EmitSideEffect (EmitContext ec)
4179 // This method is used by parameters that are references, that are
4180 // being passed as references: we only want to pass the pointer (that
4181 // is already stored in the parameter, not the address of the pointer,
4182 // and not the value of the variable).
4184 public void EmitLoad (EmitContext ec)
4189 public void Emit (EmitContext ec, bool leave_copy)
4191 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4193 HoistedVariable hv = GetHoistedVariable (ec);
4195 hv.Emit (ec, leave_copy);
4203 // If we are a reference, we loaded on the stack a pointer
4204 // Now lets load the real value
4206 LoadFromPtr (ec.ig, type);
4210 ec.ig.Emit (OpCodes.Dup);
4213 temp = new LocalTemporary (Type);
4219 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4220 bool prepare_for_load)
4222 HoistedVariable hv = GetHoistedVariable (ec);
4224 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4228 New n_source = source as New;
4229 if (n_source != null) {
4230 if (!n_source.Emit (ec, this)) {
4243 ec.ig.Emit (OpCodes.Dup);
4245 temp = new LocalTemporary (Type);
4251 StoreFromPtr (ec.ig, type);
4253 Variable.EmitAssign (ec);
4261 public bool IsHoisted {
4262 get { return GetHoistedVariable (null) != null; }
4265 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4267 type = storey.MutateType (type);
4274 public class LocalVariableReference : VariableReference {
4275 readonly string name;
4277 public LocalInfo local_info;
4279 bool resolved; // TODO: merge with eclass
4281 public LocalVariableReference (Block block, string name, Location l)
4289 // Setting `is_readonly' to false will allow you to create a writable
4290 // reference to a read-only variable. This is used by foreach and using.
4292 public LocalVariableReference (Block block, string name, Location l,
4293 LocalInfo local_info, bool is_readonly)
4294 : this (block, name, l)
4296 this.local_info = local_info;
4297 this.is_readonly = is_readonly;
4300 public override VariableInfo VariableInfo {
4301 get { return local_info.VariableInfo; }
4304 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4306 return local_info.HoistedVariableReference;
4310 // A local variable is always fixed
4312 public override bool IsFixed {
4313 get { return true; }
4316 public override bool IsRef {
4317 get { return false; }
4320 public bool IsReadOnly {
4321 get { return is_readonly; }
4324 public override string Name {
4325 get { return name; }
4328 public bool VerifyAssigned (EmitContext ec)
4330 VariableInfo variable_info = local_info.VariableInfo;
4331 return variable_info == null || variable_info.IsAssigned (ec, loc);
4334 void ResolveLocalInfo ()
4336 if (local_info == null) {
4337 local_info = Block.GetLocalInfo (Name);
4338 type = local_info.VariableType;
4339 is_readonly = local_info.ReadOnly;
4343 public override void SetHasAddressTaken ()
4345 local_info.AddressTaken = true;
4348 public override Expression CreateExpressionTree (EmitContext ec)
4350 HoistedVariable hv = GetHoistedVariable (ec);
4352 return hv.CreateExpressionTree (ec);
4354 Arguments arg = new Arguments (1);
4355 arg.Add (new Argument (this));
4356 return CreateExpressionFactoryCall ("Constant", arg);
4359 Expression DoResolveBase (EmitContext ec)
4361 type = local_info.VariableType;
4363 Expression e = Block.GetConstantExpression (Name);
4365 return e.Resolve (ec);
4367 VerifyAssigned (ec);
4370 // If we are referencing a variable from the external block
4371 // flag it for capturing
4373 if (ec.MustCaptureVariable (local_info)) {
4374 if (local_info.AddressTaken)
4375 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4377 if (ec.IsVariableCapturingRequired) {
4378 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4379 storey.CaptureLocalVariable (ec, local_info);
4383 resolved |= ec.DoFlowAnalysis;
4384 eclass = ExprClass.Variable;
4388 public override Expression DoResolve (EmitContext ec)
4393 ResolveLocalInfo ();
4394 local_info.Used = true;
4396 if (type == null && local_info.Type is VarExpr) {
4397 local_info.VariableType = TypeManager.object_type;
4398 Error_VariableIsUsedBeforeItIsDeclared (Name);
4402 return DoResolveBase (ec);
4405 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4407 ResolveLocalInfo ();
4410 if (right_side == EmptyExpression.OutAccess)
4411 local_info.Used = true;
4413 // Infer implicitly typed local variable
4415 VarExpr ve = local_info.Type as VarExpr;
4417 if (!ve.InferType (ec, right_side))
4419 type = local_info.VariableType = ve.Type;
4426 if (right_side == EmptyExpression.OutAccess) {
4427 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4428 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4429 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4430 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4431 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4432 } else if (right_side == EmptyExpression.UnaryAddress) {
4433 code = 459; msg = "Cannot take the address of {1} `{0}'";
4435 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4437 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4438 } else if (VariableInfo != null) {
4439 VariableInfo.SetAssigned (ec);
4442 return DoResolveBase (ec);
4445 public override int GetHashCode ()
4447 return Name.GetHashCode ();
4450 public override bool Equals (object obj)
4452 LocalVariableReference lvr = obj as LocalVariableReference;
4456 return Name == lvr.Name && Block == lvr.Block;
4459 protected override ILocalVariable Variable {
4460 get { return local_info; }
4463 public override string ToString ()
4465 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4468 protected override void CloneTo (CloneContext clonectx, Expression t)
4470 LocalVariableReference target = (LocalVariableReference) t;
4472 target.Block = clonectx.LookupBlock (Block);
4473 if (local_info != null)
4474 target.local_info = clonectx.LookupVariable (local_info);
4479 /// This represents a reference to a parameter in the intermediate
4482 public class ParameterReference : VariableReference {
4483 readonly ToplevelParameterInfo pi;
4485 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4491 public override bool IsRef {
4492 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4495 bool HasOutModifier {
4496 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4499 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4501 return pi.Parameter.HoistedVariableReference;
4505 // A ref or out parameter is classified as a moveable variable, even
4506 // if the argument given for the parameter is a fixed variable
4508 public override bool IsFixed {
4509 get { return !IsRef; }
4512 public override string Name {
4513 get { return Parameter.Name; }
4516 public Parameter Parameter {
4517 get { return pi.Parameter; }
4520 public override VariableInfo VariableInfo {
4521 get { return pi.VariableInfo; }
4524 protected override ILocalVariable Variable {
4525 get { return Parameter; }
4528 public bool IsAssigned (EmitContext ec, Location loc)
4530 // HACK: Variables are not captured in probing mode
4531 if (ec.IsInProbingMode)
4534 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4537 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4541 public override void SetHasAddressTaken ()
4543 Parameter.HasAddressTaken = true;
4546 void SetAssigned (EmitContext ec)
4548 if (HasOutModifier && ec.DoFlowAnalysis)
4549 ec.CurrentBranching.SetAssigned (VariableInfo);
4552 bool DoResolveBase (EmitContext ec)
4554 type = pi.ParameterType;
4555 eclass = ExprClass.Variable;
4557 AnonymousExpression am = ec.CurrentAnonymousMethod;
4561 Block b = ec.CurrentBlock;
4563 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4564 for (int i = 0; i < p.Length; ++i) {
4565 if (p [i] != Parameter)
4569 // Skip closest anonymous method parameters
4571 if (b == ec.CurrentBlock && !am.IsIterator)
4575 Report.Error (1628, loc,
4576 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4577 Name, am.ContainerType);
4585 b = b.Toplevel.Parent;
4588 if (pi.Parameter.HasAddressTaken)
4589 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4591 if (ec.IsVariableCapturingRequired) {
4592 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4593 storey.CaptureParameter (ec, this);
4599 public override int GetHashCode ()
4601 return Name.GetHashCode ();
4604 public override bool Equals (object obj)
4606 ParameterReference pr = obj as ParameterReference;
4610 return Name == pr.Name;
4613 protected override void CloneTo (CloneContext clonectx, Expression target)
4618 public override Expression CreateExpressionTree (EmitContext ec)
4620 HoistedVariable hv = GetHoistedVariable (ec);
4622 return hv.CreateExpressionTree (ec);
4624 return Parameter.ExpressionTreeVariableReference ();
4628 // Notice that for ref/out parameters, the type exposed is not the
4629 // same type exposed externally.
4632 // externally we expose "int&"
4633 // here we expose "int".
4635 // We record this in "is_ref". This means that the type system can treat
4636 // the type as it is expected, but when we generate the code, we generate
4637 // the alternate kind of code.
4639 public override Expression DoResolve (EmitContext ec)
4641 if (!DoResolveBase (ec))
4644 // HACK: Variables are not captured in probing mode
4645 if (ec.IsInProbingMode)
4648 if (HasOutModifier && ec.DoFlowAnalysis &&
4649 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4655 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4657 if (!DoResolveBase (ec))
4660 // HACK: parameters are not captured when probing is on
4661 if (!ec.IsInProbingMode)
4667 static public void EmitLdArg (ILGenerator ig, int x)
4670 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4671 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4672 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4673 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4675 if (x > byte.MaxValue)
4676 ig.Emit (OpCodes.Ldarg, x);
4678 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4685 /// Invocation of methods or delegates.
4687 public class Invocation : ExpressionStatement
4689 protected Arguments arguments;
4690 protected Expression expr;
4691 protected MethodGroupExpr mg;
4692 bool arguments_resolved;
4695 // arguments is an ArrayList, but we do not want to typecast,
4696 // as it might be null.
4698 public Invocation (Expression expr, Arguments arguments)
4700 SimpleName sn = expr as SimpleName;
4702 this.expr = sn.GetMethodGroup ();
4706 this.arguments = arguments;
4708 loc = expr.Location;
4711 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4712 : this (expr, arguments)
4714 this.arguments_resolved = arguments_resolved;
4717 public override Expression CreateExpressionTree (EmitContext ec)
4722 // Special conversion for nested expression trees
4724 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4725 args = new Arguments (1);
4726 args.Add (new Argument (this));
4727 return CreateExpressionFactoryCall ("Quote", args);
4730 Expression instance = mg.IsInstance ?
4731 mg.InstanceExpression.CreateExpressionTree (ec) :
4732 new NullLiteral (loc);
4734 args = Arguments.CreateForExpressionTree (ec, arguments,
4736 mg.CreateExpressionTree (ec));
4739 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4741 return CreateExpressionFactoryCall ("Call", args);
4744 public override Expression DoResolve (EmitContext ec)
4746 // Don't resolve already resolved expression
4747 if (eclass != ExprClass.Invalid)
4750 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4751 if (expr_resolved == null)
4755 // Next, evaluate all the expressions in the argument list
4757 bool dynamic_arg = false;
4758 if (arguments != null && !arguments_resolved)
4759 arguments.Resolve (ec, out dynamic_arg);
4761 Type expr_type = expr_resolved.Type;
4762 mg = expr_resolved as MethodGroupExpr;
4764 if (dynamic_arg || TypeManager.IsDynamicType (expr_type)) {
4766 DynamicMemberBinder dmb = expr_resolved as DynamicMemberBinder;
4768 args = dmb.Arguments;
4769 if (arguments != null)
4770 args.AddRange (arguments);
4771 } else if (mg == null) {
4772 if (arguments == null)
4773 args = new Arguments (1);
4777 args.Insert (0, new Argument (expr_resolved));
4781 Report.Error (1971, loc,
4782 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
4789 if (mg.IsStatic != mg.IsInstance) {
4791 args = new Arguments (1);
4794 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicStatic));
4796 MemberAccess ma = expr as MemberAccess;
4798 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
4800 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
4805 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
4809 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4810 return (new DelegateInvocation (
4811 expr_resolved, arguments, loc)).Resolve (ec);
4814 MemberExpr me = expr_resolved as MemberExpr;
4816 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4820 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
4822 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4823 expr_resolved.GetSignatureForError ());
4827 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4830 mg = DoResolveOverload (ec);
4834 MethodInfo method = (MethodInfo)mg;
4835 if (method != null) {
4836 type = TypeManager.TypeToCoreType (method.ReturnType);
4838 // TODO: this is a copy of mg.ResolveMemberAccess method
4839 Expression iexpr = mg.InstanceExpression;
4840 if (method.IsStatic) {
4841 if (iexpr == null ||
4842 iexpr is This || iexpr is EmptyExpression ||
4843 mg.IdenticalTypeName) {
4844 mg.InstanceExpression = null;
4846 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4850 if (iexpr == null || iexpr == EmptyExpression.Null) {
4851 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4856 if (type.IsPointer){
4864 // Only base will allow this invocation to happen.
4866 if (mg.IsBase && method.IsAbstract){
4867 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4871 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4873 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4875 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4879 IsSpecialMethodInvocation (method, loc);
4881 if (mg.InstanceExpression != null)
4882 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4884 eclass = ExprClass.Value;
4888 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4890 return mg.OverloadResolve (ec, ref arguments, false, loc);
4893 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4895 if (!TypeManager.IsSpecialMethod (method))
4898 Report.SymbolRelatedToPreviousError (method);
4899 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4900 TypeManager.CSharpSignature (method, true));
4905 static Type[] GetVarargsTypes (MethodBase mb, Arguments arguments)
4907 AParametersCollection pd = TypeManager.GetParameterData (mb);
4909 Argument a = arguments [pd.Count - 1];
4910 Arglist list = (Arglist) a.Expr;
4912 return list.ArgumentTypes;
4916 /// This checks the ConditionalAttribute on the method
4918 public static bool IsMethodExcluded (MethodBase method, Location loc)
4920 if (method.IsConstructor)
4923 method = TypeManager.DropGenericMethodArguments (method);
4924 if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
4925 IMethodData md = TypeManager.GetMethod (method);
4927 return md.IsExcluded ();
4929 // For some methods (generated by delegate class) GetMethod returns null
4930 // because they are not included in builder_to_method table
4934 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4938 /// is_base tells whether we want to force the use of the `call'
4939 /// opcode instead of using callvirt. Call is required to call
4940 /// a specific method, while callvirt will always use the most
4941 /// recent method in the vtable.
4943 /// is_static tells whether this is an invocation on a static method
4945 /// instance_expr is an expression that represents the instance
4946 /// it must be non-null if is_static is false.
4948 /// method is the method to invoke.
4950 /// Arguments is the list of arguments to pass to the method or constructor.
4952 public static void EmitCall (EmitContext ec, bool is_base,
4953 Expression instance_expr,
4954 MethodBase method, Arguments Arguments, Location loc)
4956 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4959 // `dup_args' leaves an extra copy of the arguments on the stack
4960 // `omit_args' does not leave any arguments at all.
4961 // So, basically, you could make one call with `dup_args' set to true,
4962 // and then another with `omit_args' set to true, and the two calls
4963 // would have the same set of arguments. However, each argument would
4964 // only have been evaluated once.
4965 public static void EmitCall (EmitContext ec, bool is_base,
4966 Expression instance_expr,
4967 MethodBase method, Arguments Arguments, Location loc,
4968 bool dup_args, bool omit_args)
4970 ILGenerator ig = ec.ig;
4971 bool struct_call = false;
4972 bool this_call = false;
4973 LocalTemporary this_arg = null;
4975 Type decl_type = method.DeclaringType;
4977 if (IsMethodExcluded (method, loc))
4980 bool is_static = method.IsStatic;
4982 this_call = instance_expr is This;
4983 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
4987 // If this is ourselves, push "this"
4991 Type iexpr_type = instance_expr.Type;
4994 // Push the instance expression
4996 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
4998 // Special case: calls to a function declared in a
4999 // reference-type with a value-type argument need
5000 // to have their value boxed.
5001 if (TypeManager.IsStruct (decl_type) ||
5002 TypeManager.IsGenericParameter (iexpr_type)) {
5004 // If the expression implements IMemoryLocation, then
5005 // we can optimize and use AddressOf on the
5008 // If not we have to use some temporary storage for
5010 if (instance_expr is IMemoryLocation) {
5011 ((IMemoryLocation)instance_expr).
5012 AddressOf (ec, AddressOp.LoadStore);
5014 LocalTemporary temp = new LocalTemporary (iexpr_type);
5015 instance_expr.Emit (ec);
5017 temp.AddressOf (ec, AddressOp.Load);
5020 // avoid the overhead of doing this all the time.
5022 t = TypeManager.GetReferenceType (iexpr_type);
5024 instance_expr.Emit (ec);
5026 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5027 // to help JIT to produce better code
5028 ig.Emit (OpCodes.Box, instance_expr.Type);
5029 t = TypeManager.object_type;
5032 instance_expr.Emit (ec);
5033 t = instance_expr.Type;
5037 ig.Emit (OpCodes.Dup);
5038 if (Arguments != null && Arguments.Count != 0) {
5039 this_arg = new LocalTemporary (t);
5040 this_arg.Store (ec);
5046 if (!omit_args && Arguments != null)
5047 Arguments.Emit (ec, dup_args, this_arg);
5050 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5051 call_op = OpCodes.Call;
5053 call_op = OpCodes.Callvirt;
5056 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5057 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5061 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5062 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5063 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5070 // and DoFoo is not virtual, you can omit the callvirt,
5071 // because you don't need the null checking behavior.
5073 if (method is MethodInfo)
5074 ig.Emit (call_op, (MethodInfo) method);
5076 ig.Emit (call_op, (ConstructorInfo) method);
5079 public override void Emit (EmitContext ec)
5081 mg.EmitCall (ec, arguments);
5084 public override void EmitStatement (EmitContext ec)
5089 // Pop the return value if there is one
5091 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5092 ec.ig.Emit (OpCodes.Pop);
5095 protected override void CloneTo (CloneContext clonectx, Expression t)
5097 Invocation target = (Invocation) t;
5099 if (arguments != null)
5100 target.arguments = arguments.Clone (clonectx);
5102 target.expr = expr.Clone (clonectx);
5105 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5107 mg.MutateHoistedGenericType (storey);
5108 type = storey.MutateType (type);
5109 if (arguments != null) {
5110 arguments.MutateHoistedGenericType (storey);
5116 // It's either a cast or delegate invocation
5118 public class InvocationOrCast : ExpressionStatement
5121 Expression argument;
5123 public InvocationOrCast (Expression expr, Expression argument)
5126 this.argument = argument;
5127 this.loc = expr.Location;
5130 public override Expression CreateExpressionTree (EmitContext ec)
5132 throw new NotSupportedException ("ET");
5135 public override Expression DoResolve (EmitContext ec)
5137 Expression e = ResolveCore (ec);
5141 return e.Resolve (ec);
5144 Expression ResolveCore (EmitContext ec)
5147 // First try to resolve it as a cast.
5149 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5151 return new Cast (te, argument, loc);
5155 // This can either be a type or a delegate invocation.
5156 // Let's just resolve it and see what we'll get.
5158 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5163 // Ok, so it's a Cast.
5165 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5166 return new Cast (expr, argument, loc);
5169 if (expr.eclass == ExprClass.Namespace) {
5170 expr.Error_UnexpectedKind (null, "type", loc);
5175 // It's a delegate invocation.
5177 if (!TypeManager.IsDelegateType (expr.Type)) {
5178 Error (149, "Method name expected");
5182 ArrayList args = new ArrayList (1);
5183 args.Add (new Argument (argument, Argument.AType.Expression));
5184 return new DelegateInvocation (expr, args, loc);
5187 public override ExpressionStatement ResolveStatement (EmitContext ec)
5189 Expression e = ResolveCore (ec);
5193 ExpressionStatement s = e as ExpressionStatement;
5195 Error_InvalidExpressionStatement ();
5199 return s.ResolveStatement (ec);
5202 public override void Emit (EmitContext ec)
5204 throw new Exception ("Cannot happen");
5207 public override void EmitStatement (EmitContext ec)
5209 throw new Exception ("Cannot happen");
5212 protected override void CloneTo (CloneContext clonectx, Expression t)
5214 InvocationOrCast target = (InvocationOrCast) t;
5216 target.expr = expr.Clone (clonectx);
5217 target.argument = argument.Clone (clonectx);
5223 /// Implements the new expression
5225 public class New : ExpressionStatement, IMemoryLocation {
5226 Arguments Arguments;
5229 // During bootstrap, it contains the RequestedType,
5230 // but if `type' is not null, it *might* contain a NewDelegate
5231 // (because of field multi-initialization)
5233 Expression RequestedType;
5235 MethodGroupExpr method;
5237 bool is_type_parameter;
5239 public New (Expression requested_type, Arguments arguments, Location l)
5241 RequestedType = requested_type;
5242 Arguments = arguments;
5247 /// Converts complex core type syntax like 'new int ()' to simple constant
5249 public static Constant Constantify (Type t)
5251 if (t == TypeManager.int32_type)
5252 return new IntConstant (0, Location.Null);
5253 if (t == TypeManager.uint32_type)
5254 return new UIntConstant (0, Location.Null);
5255 if (t == TypeManager.int64_type)
5256 return new LongConstant (0, Location.Null);
5257 if (t == TypeManager.uint64_type)
5258 return new ULongConstant (0, Location.Null);
5259 if (t == TypeManager.float_type)
5260 return new FloatConstant (0, Location.Null);
5261 if (t == TypeManager.double_type)
5262 return new DoubleConstant (0, Location.Null);
5263 if (t == TypeManager.short_type)
5264 return new ShortConstant (0, Location.Null);
5265 if (t == TypeManager.ushort_type)
5266 return new UShortConstant (0, Location.Null);
5267 if (t == TypeManager.sbyte_type)
5268 return new SByteConstant (0, Location.Null);
5269 if (t == TypeManager.byte_type)
5270 return new ByteConstant (0, Location.Null);
5271 if (t == TypeManager.char_type)
5272 return new CharConstant ('\0', Location.Null);
5273 if (t == TypeManager.bool_type)
5274 return new BoolConstant (false, Location.Null);
5275 if (t == TypeManager.decimal_type)
5276 return new DecimalConstant (0, Location.Null);
5277 if (TypeManager.IsEnumType (t))
5278 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5279 if (TypeManager.IsNullableType (t))
5280 return Nullable.LiftedNull.Create (t, Location.Null);
5286 // Checks whether the type is an interface that has the
5287 // [ComImport, CoClass] attributes and must be treated
5290 public Expression CheckComImport (EmitContext ec)
5292 if (!type.IsInterface)
5296 // Turn the call into:
5297 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5299 Type real_class = AttributeTester.GetCoClassAttribute (type);
5300 if (real_class == null)
5303 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5304 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5305 return cast.Resolve (ec);
5308 public override Expression CreateExpressionTree (EmitContext ec)
5311 if (method == null) {
5312 args = new Arguments (1);
5313 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5315 args = Arguments.CreateForExpressionTree (ec, Arguments,
5316 method.CreateExpressionTree (ec));
5319 return CreateExpressionFactoryCall ("New", args);
5322 public override Expression DoResolve (EmitContext ec)
5325 // The New DoResolve might be called twice when initializing field
5326 // expressions (see EmitFieldInitializers, the call to
5327 // GetInitializerExpression will perform a resolve on the expression,
5328 // and later the assign will trigger another resolution
5330 // This leads to bugs (#37014)
5333 if (RequestedType is NewDelegate)
5334 return RequestedType;
5338 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5344 if (type.IsPointer) {
5345 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5346 TypeManager.CSharpName (type));
5350 if (Arguments == null) {
5351 Constant c = Constantify (type);
5353 return ReducedExpression.Create (c, this);
5356 if (TypeManager.IsDelegateType (type)) {
5357 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5360 if (TypeManager.IsGenericParameter (type)) {
5361 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5363 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5364 Error (304, String.Format (
5365 "Cannot create an instance of the " +
5366 "variable type '{0}' because it " +
5367 "doesn't have the new() constraint",
5372 if ((Arguments != null) && (Arguments.Count != 0)) {
5373 Error (417, String.Format (
5374 "`{0}': cannot provide arguments " +
5375 "when creating an instance of a " +
5376 "variable type.", type));
5380 if (TypeManager.activator_create_instance == null) {
5381 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5382 if (activator_type != null) {
5383 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5384 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5388 is_type_parameter = true;
5389 eclass = ExprClass.Value;
5393 if (type.IsAbstract && type.IsSealed) {
5394 Report.SymbolRelatedToPreviousError (type);
5395 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5399 if (type.IsInterface || type.IsAbstract){
5400 if (!TypeManager.IsGenericType (type)) {
5401 RequestedType = CheckComImport (ec);
5402 if (RequestedType != null)
5403 return RequestedType;
5406 Report.SymbolRelatedToPreviousError (type);
5407 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5411 bool is_struct = TypeManager.IsStruct (type);
5412 eclass = ExprClass.Value;
5415 // SRE returns a match for .ctor () on structs (the object constructor),
5416 // so we have to manually ignore it.
5418 if (is_struct && Arguments == null)
5421 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5422 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5423 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5425 if (Arguments != null) {
5427 Arguments.Resolve (ec, out dynamic);
5430 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec)));
5431 return new DynamicInvocation (new SimpleName (ConstructorInfo.ConstructorName, loc), Arguments, type, loc).Resolve (ec);
5438 method = ml as MethodGroupExpr;
5439 if (method == null) {
5440 ml.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5444 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5451 bool DoEmitTypeParameter (EmitContext ec)
5454 ILGenerator ig = ec.ig;
5455 // IMemoryLocation ml;
5457 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5458 new Type [] { type });
5460 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5461 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5462 ig.Emit (OpCodes.Call, ci);
5466 // Allow DoEmit() to be called multiple times.
5467 // We need to create a new LocalTemporary each time since
5468 // you can't share LocalBuilders among ILGeneators.
5469 LocalTemporary temp = new LocalTemporary (type);
5471 Label label_activator = ig.DefineLabel ();
5472 Label label_end = ig.DefineLabel ();
5474 temp.AddressOf (ec, AddressOp.Store);
5475 ig.Emit (OpCodes.Initobj, type);
5478 ig.Emit (OpCodes.Box, type);
5479 ig.Emit (OpCodes.Brfalse, label_activator);
5481 temp.AddressOf (ec, AddressOp.Store);
5482 ig.Emit (OpCodes.Initobj, type);
5484 ig.Emit (OpCodes.Br_S, label_end);
5486 ig.MarkLabel (label_activator);
5488 ig.Emit (OpCodes.Call, ci);
5489 ig.MarkLabel (label_end);
5492 throw new InternalErrorException ();
5497 // This Emit can be invoked in two contexts:
5498 // * As a mechanism that will leave a value on the stack (new object)
5499 // * As one that wont (init struct)
5501 // If we are dealing with a ValueType, we have a few
5502 // situations to deal with:
5504 // * The target is a ValueType, and we have been provided
5505 // the instance (this is easy, we are being assigned).
5507 // * The target of New is being passed as an argument,
5508 // to a boxing operation or a function that takes a
5511 // In this case, we need to create a temporary variable
5512 // that is the argument of New.
5514 // Returns whether a value is left on the stack
5516 // *** Implementation note ***
5518 // To benefit from this optimization, each assignable expression
5519 // has to manually cast to New and call this Emit.
5521 // TODO: It's worth to implement it for arrays and fields
5523 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5525 bool is_value_type = TypeManager.IsValueType (type);
5526 ILGenerator ig = ec.ig;
5527 VariableReference vr = target as VariableReference;
5529 if (target != null && is_value_type && (vr != null || method == null)) {
5530 target.AddressOf (ec, AddressOp.Store);
5531 } else if (vr != null && vr.IsRef) {
5535 if (Arguments != null)
5536 Arguments.Emit (ec);
5538 if (is_value_type) {
5539 if (method == null) {
5540 ig.Emit (OpCodes.Initobj, type);
5545 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5550 if (is_type_parameter)
5551 return DoEmitTypeParameter (ec);
5553 ConstructorInfo ci = (ConstructorInfo) method;
5555 if (TypeManager.IsGenericType (type))
5556 ci = TypeBuilder.GetConstructor (type, ci);
5559 ig.Emit (OpCodes.Newobj, ci);
5563 public override void Emit (EmitContext ec)
5565 LocalTemporary v = null;
5566 if (method == null && TypeManager.IsValueType (type)) {
5567 // TODO: Use temporary variable from pool
5568 v = new LocalTemporary (type);
5575 public override void EmitStatement (EmitContext ec)
5577 LocalTemporary v = null;
5578 if (method == null && TypeManager.IsValueType (type)) {
5579 // TODO: Use temporary variable from pool
5580 v = new LocalTemporary (type);
5584 ec.ig.Emit (OpCodes.Pop);
5587 public bool IsDefaultValueType {
5589 return TypeManager.IsValueType (type) && !HasInitializer && Arguments == null;
5593 public virtual bool HasInitializer {
5599 public void AddressOf (EmitContext ec, AddressOp mode)
5601 EmitAddressOf (ec, mode);
5604 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5606 LocalTemporary value_target = new LocalTemporary (type);
5608 if (is_type_parameter) {
5609 DoEmitTypeParameter (ec);
5610 value_target.Store (ec);
5611 value_target.AddressOf (ec, mode);
5612 return value_target;
5615 if (!TypeManager.IsStruct (type)){
5617 // We throw an exception. So far, I believe we only need to support
5619 // foreach (int j in new StructType ())
5622 throw new Exception ("AddressOf should not be used for classes");
5625 value_target.AddressOf (ec, AddressOp.Store);
5627 if (method == null) {
5628 ec.ig.Emit (OpCodes.Initobj, type);
5630 if (Arguments != null)
5631 Arguments.Emit (ec);
5633 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5636 value_target.AddressOf (ec, mode);
5637 return value_target;
5640 protected override void CloneTo (CloneContext clonectx, Expression t)
5642 New target = (New) t;
5644 target.RequestedType = RequestedType.Clone (clonectx);
5645 if (Arguments != null){
5646 target.Arguments = Arguments.Clone (clonectx);
5650 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5652 if (method != null) {
5653 method.MutateHoistedGenericType (storey);
5654 if (Arguments != null) {
5655 Arguments.MutateHoistedGenericType (storey);
5659 type = storey.MutateType (type);
5664 /// 14.5.10.2: Represents an array creation expression.
5668 /// There are two possible scenarios here: one is an array creation
5669 /// expression that specifies the dimensions and optionally the
5670 /// initialization data and the other which does not need dimensions
5671 /// specified but where initialization data is mandatory.
5673 public class ArrayCreation : Expression {
5674 FullNamedExpression requested_base_type;
5675 ArrayList initializers;
5678 // The list of Argument types.
5679 // This is used to construct the `newarray' or constructor signature
5681 protected ArrayList arguments;
5683 protected Type array_element_type;
5684 bool expect_initializers = false;
5685 int num_arguments = 0;
5686 protected int dimensions;
5687 protected readonly string rank;
5689 protected ArrayList array_data;
5693 // The number of constants in array initializers
5694 int const_initializers_count;
5695 bool only_constant_initializers;
5697 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5699 this.requested_base_type = requested_base_type;
5700 this.initializers = initializers;
5704 arguments = new ArrayList (exprs.Count);
5706 foreach (Expression e in exprs) {
5712 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5714 this.requested_base_type = requested_base_type;
5715 this.initializers = initializers;
5719 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5721 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5723 //dimensions = tmp.Length - 1;
5724 expect_initializers = true;
5727 public static void Error_IncorrectArrayInitializer (Location loc)
5729 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5732 protected override void Error_NegativeArrayIndex (Location loc)
5734 Report.Error (248, loc, "Cannot create an array with a negative size");
5737 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims, int child_bounds)
5739 if (specified_dims) {
5740 Expression a = (Expression) arguments [idx];
5745 Constant c = a as Constant;
5747 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5751 Report.Error (150, a.Location, "A constant value is expected");
5755 int value = (int) c.GetValue ();
5757 if (value != probe.Count) {
5758 Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5762 bounds [idx] = value;
5765 only_constant_initializers = true;
5766 for (int i = 0; i < probe.Count; ++i) {
5767 object o = probe [i];
5768 if (o is ArrayList) {
5769 ArrayList sub_probe = o as ArrayList;
5770 if (idx + 1 >= dimensions){
5771 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5775 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5778 } else if (child_bounds > 1) {
5779 Report.Error (846, ((Expression) o).Location, "A nested array initializer was expected");
5781 Expression element = ResolveArrayElement (ec, (Expression) o);
5782 if (element == null)
5785 // Initializers with the default values can be ignored
5786 Constant c = element as Constant;
5788 if (c.IsDefaultInitializer (array_element_type)) {
5792 ++const_initializers_count;
5795 only_constant_initializers = false;
5798 array_data.Add (element);
5805 public override Expression CreateExpressionTree (EmitContext ec)
5809 if (array_data == null) {
5810 args = new Arguments (arguments.Count + 1);
5811 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5812 foreach (Expression a in arguments) {
5813 if (arguments.Count == 1) {
5814 Constant c = a as Constant;
5815 if (c.IsDefaultValue)
5816 return CreateExpressionFactoryCall ("NewArrayInit", args);
5818 args.Add (new Argument (a.CreateExpressionTree (ec)));
5821 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5824 if (dimensions > 1) {
5825 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5829 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5830 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5831 if (array_data != null) {
5832 for (int i = 0; i < array_data.Count; ++i) {
5833 Expression e = (Expression) array_data [i];
5835 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5837 args.Add (new Argument (e.CreateExpressionTree (ec)));
5841 return CreateExpressionFactoryCall ("NewArrayInit", args);
5844 public void UpdateIndices ()
5847 for (ArrayList probe = initializers; probe != null;) {
5848 if (probe.Count > 0 && probe [0] is ArrayList) {
5849 Expression e = new IntConstant (probe.Count, Location.Null);
5852 bounds [i++] = probe.Count;
5854 probe = (ArrayList) probe [0];
5857 Expression e = new IntConstant (probe.Count, Location.Null);
5860 bounds [i++] = probe.Count;
5867 Expression first_emit;
5868 LocalTemporary first_emit_temp;
5870 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5872 element = element.Resolve (ec);
5873 if (element == null)
5876 if (element is CompoundAssign.TargetExpression) {
5877 if (first_emit != null)
5878 throw new InternalErrorException ("Can only handle one mutator at a time");
5879 first_emit = element;
5880 element = first_emit_temp = new LocalTemporary (element.Type);
5883 return Convert.ImplicitConversionRequired (
5884 ec, element, array_element_type, loc);
5887 protected bool ResolveInitializers (EmitContext ec)
5889 if (initializers == null) {
5890 return !expect_initializers;
5894 // We use this to store all the date values in the order in which we
5895 // will need to store them in the byte blob later
5897 array_data = new ArrayList ();
5898 bounds = new System.Collections.Specialized.HybridDictionary ();
5900 if (arguments != null)
5901 return CheckIndices (ec, initializers, 0, true, dimensions);
5903 arguments = new ArrayList ();
5905 if (!CheckIndices (ec, initializers, 0, false, dimensions))
5914 // Resolved the type of the array
5916 bool ResolveArrayType (EmitContext ec)
5918 if (requested_base_type == null) {
5919 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5923 if (requested_base_type is VarExpr) {
5924 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5928 StringBuilder array_qualifier = new StringBuilder (rank);
5931 // `In the first form allocates an array instace of the type that results
5932 // from deleting each of the individual expression from the expression list'
5934 if (num_arguments > 0) {
5935 array_qualifier.Append ("[");
5936 for (int i = num_arguments-1; i > 0; i--)
5937 array_qualifier.Append (",");
5938 array_qualifier.Append ("]");
5944 TypeExpr array_type_expr;
5945 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5946 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5947 if (array_type_expr == null)
5950 type = array_type_expr.Type;
5951 array_element_type = TypeManager.GetElementType (type);
5952 dimensions = type.GetArrayRank ();
5957 public override Expression DoResolve (EmitContext ec)
5962 if (!ResolveArrayType (ec))
5966 // First step is to validate the initializers and fill
5967 // in any missing bits
5969 if (!ResolveInitializers (ec))
5972 for (int i = 0; i < arguments.Count; ++i) {
5973 Expression e = ((Expression) arguments[i]).Resolve (ec);
5977 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
5980 eclass = ExprClass.Value;
5984 MethodInfo GetArrayMethod (int arguments)
5986 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
5988 Type[] arg_types = new Type[arguments];
5989 for (int i = 0; i < arguments; i++)
5990 arg_types[i] = TypeManager.int32_type;
5992 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5996 Report.Error (-6, "New invocation: Can not find a constructor for " +
5997 "this argument list");
6004 byte [] MakeByteBlob ()
6009 int count = array_data.Count;
6011 if (TypeManager.IsEnumType (array_element_type))
6012 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6014 factor = GetTypeSize (array_element_type);
6016 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6018 data = new byte [(count * factor + 3) & ~3];
6021 for (int i = 0; i < count; ++i) {
6022 object v = array_data [i];
6024 if (v is EnumConstant)
6025 v = ((EnumConstant) v).Child;
6027 if (v is Constant && !(v is StringConstant))
6028 v = ((Constant) v).GetValue ();
6034 if (array_element_type == TypeManager.int64_type){
6035 if (!(v is Expression)){
6036 long val = (long) v;
6038 for (int j = 0; j < factor; ++j) {
6039 data [idx + j] = (byte) (val & 0xFF);
6043 } else if (array_element_type == TypeManager.uint64_type){
6044 if (!(v is Expression)){
6045 ulong val = (ulong) v;
6047 for (int j = 0; j < factor; ++j) {
6048 data [idx + j] = (byte) (val & 0xFF);
6052 } else if (array_element_type == TypeManager.float_type) {
6053 if (!(v is Expression)){
6054 element = BitConverter.GetBytes ((float) v);
6056 for (int j = 0; j < factor; ++j)
6057 data [idx + j] = element [j];
6058 if (!BitConverter.IsLittleEndian)
6059 System.Array.Reverse (data, idx, 4);
6061 } else if (array_element_type == TypeManager.double_type) {
6062 if (!(v is Expression)){
6063 element = BitConverter.GetBytes ((double) v);
6065 for (int j = 0; j < factor; ++j)
6066 data [idx + j] = element [j];
6068 // FIXME: Handle the ARM float format.
6069 if (!BitConverter.IsLittleEndian)
6070 System.Array.Reverse (data, idx, 8);
6072 } else if (array_element_type == TypeManager.char_type){
6073 if (!(v is Expression)){
6074 int val = (int) ((char) v);
6076 data [idx] = (byte) (val & 0xff);
6077 data [idx+1] = (byte) (val >> 8);
6079 } else if (array_element_type == TypeManager.short_type){
6080 if (!(v is Expression)){
6081 int val = (int) ((short) v);
6083 data [idx] = (byte) (val & 0xff);
6084 data [idx+1] = (byte) (val >> 8);
6086 } else if (array_element_type == TypeManager.ushort_type){
6087 if (!(v is Expression)){
6088 int val = (int) ((ushort) v);
6090 data [idx] = (byte) (val & 0xff);
6091 data [idx+1] = (byte) (val >> 8);
6093 } else if (array_element_type == TypeManager.int32_type) {
6094 if (!(v is Expression)){
6097 data [idx] = (byte) (val & 0xff);
6098 data [idx+1] = (byte) ((val >> 8) & 0xff);
6099 data [idx+2] = (byte) ((val >> 16) & 0xff);
6100 data [idx+3] = (byte) (val >> 24);
6102 } else if (array_element_type == TypeManager.uint32_type) {
6103 if (!(v is Expression)){
6104 uint val = (uint) v;
6106 data [idx] = (byte) (val & 0xff);
6107 data [idx+1] = (byte) ((val >> 8) & 0xff);
6108 data [idx+2] = (byte) ((val >> 16) & 0xff);
6109 data [idx+3] = (byte) (val >> 24);
6111 } else if (array_element_type == TypeManager.sbyte_type) {
6112 if (!(v is Expression)){
6113 sbyte val = (sbyte) v;
6114 data [idx] = (byte) val;
6116 } else if (array_element_type == TypeManager.byte_type) {
6117 if (!(v is Expression)){
6118 byte val = (byte) v;
6119 data [idx] = (byte) val;
6121 } else if (array_element_type == TypeManager.bool_type) {
6122 if (!(v is Expression)){
6123 bool val = (bool) v;
6124 data [idx] = (byte) (val ? 1 : 0);
6126 } else if (array_element_type == TypeManager.decimal_type){
6127 if (!(v is Expression)){
6128 int [] bits = Decimal.GetBits ((decimal) v);
6131 // FIXME: For some reason, this doesn't work on the MS runtime.
6132 int [] nbits = new int [4];
6133 nbits [0] = bits [3];
6134 nbits [1] = bits [2];
6135 nbits [2] = bits [0];
6136 nbits [3] = bits [1];
6138 for (int j = 0; j < 4; j++){
6139 data [p++] = (byte) (nbits [j] & 0xff);
6140 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6141 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6142 data [p++] = (byte) (nbits [j] >> 24);
6146 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6154 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6156 array_element_type = storey.MutateType (array_element_type);
6157 type = storey.MutateType (type);
6158 if (arguments != null) {
6159 foreach (Expression e in arguments)
6160 e.MutateHoistedGenericType (storey);
6163 if (array_data != null) {
6164 foreach (Expression e in array_data) {
6165 // Don't mutate values optimized away
6169 e.MutateHoistedGenericType (storey);
6175 // Emits the initializers for the array
6177 void EmitStaticInitializers (EmitContext ec)
6179 // FIXME: This should go to Resolve !
6180 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6181 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6182 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6183 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6184 if (TypeManager.void_initializearray_array_fieldhandle == null)
6189 // First, the static data
6192 ILGenerator ig = ec.ig;
6194 byte [] data = MakeByteBlob ();
6196 fb = RootContext.MakeStaticData (data);
6198 ig.Emit (OpCodes.Dup);
6199 ig.Emit (OpCodes.Ldtoken, fb);
6200 ig.Emit (OpCodes.Call,
6201 TypeManager.void_initializearray_array_fieldhandle);
6205 // Emits pieces of the array that can not be computed at compile
6206 // time (variables and string locations).
6208 // This always expect the top value on the stack to be the array
6210 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6212 ILGenerator ig = ec.ig;
6213 int dims = bounds.Count;
6214 int [] current_pos = new int [dims];
6216 MethodInfo set = null;
6219 Type [] args = new Type [dims + 1];
6221 for (int j = 0; j < dims; j++)
6222 args [j] = TypeManager.int32_type;
6223 args [dims] = array_element_type;
6225 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6227 CallingConventions.HasThis | CallingConventions.Standard,
6228 TypeManager.void_type, args);
6231 for (int i = 0; i < array_data.Count; i++){
6233 Expression e = (Expression)array_data [i];
6235 // Constant can be initialized via StaticInitializer
6236 if (e != null && !(!emitConstants && e is Constant)) {
6237 Type etype = e.Type;
6239 ig.Emit (OpCodes.Dup);
6241 for (int idx = 0; idx < dims; idx++)
6242 IntConstant.EmitInt (ig, current_pos [idx]);
6245 // If we are dealing with a struct, get the
6246 // address of it, so we can store it.
6248 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6249 (!TypeManager.IsBuiltinOrEnum (etype) ||
6250 etype == TypeManager.decimal_type)) {
6252 ig.Emit (OpCodes.Ldelema, etype);
6258 bool is_stobj, has_type_arg;
6259 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6261 ig.Emit (OpCodes.Stobj, etype);
6262 else if (has_type_arg)
6263 ig.Emit (op, etype);
6267 ig.Emit (OpCodes.Call, set);
6274 for (int j = dims - 1; j >= 0; j--){
6276 if (current_pos [j] < (int) bounds [j])
6278 current_pos [j] = 0;
6283 public override void Emit (EmitContext ec)
6285 ILGenerator ig = ec.ig;
6287 if (first_emit != null) {
6288 first_emit.Emit (ec);
6289 first_emit_temp.Store (ec);
6292 foreach (Expression e in arguments)
6295 if (arguments.Count == 1)
6296 ig.Emit (OpCodes.Newarr, array_element_type);
6298 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6301 if (initializers == null)
6304 // Emit static initializer for arrays which have contain more than 4 items and
6305 // the static initializer will initialize at least 25% of array values.
6306 // NOTE: const_initializers_count does not contain default constant values.
6307 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6308 TypeManager.IsPrimitiveType (array_element_type)) {
6309 EmitStaticInitializers (ec);
6311 if (!only_constant_initializers)
6312 EmitDynamicInitializers (ec, false);
6314 EmitDynamicInitializers (ec, true);
6317 if (first_emit_temp != null)
6318 first_emit_temp.Release (ec);
6321 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6323 if (arguments.Count != 1) {
6324 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6325 return base.GetAttributableValue (ec, null, out value);
6328 if (array_data == null) {
6329 Constant c = (Constant) arguments [0];
6330 if (c.IsDefaultValue) {
6331 value = Array.CreateInstance (array_element_type, 0);
6334 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6335 return base.GetAttributableValue (ec, null, out value);
6338 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6339 object element_value;
6340 for (int i = 0; i < ret.Length; ++i)
6342 Expression e = (Expression)array_data [i];
6344 // Is null when an initializer is optimized (value == predefined value)
6348 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6352 ret.SetValue (element_value, i);
6358 protected override void CloneTo (CloneContext clonectx, Expression t)
6360 ArrayCreation target = (ArrayCreation) t;
6362 if (requested_base_type != null)
6363 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6365 if (arguments != null){
6366 target.arguments = new ArrayList (arguments.Count);
6367 foreach (Expression e in arguments)
6368 target.arguments.Add (e.Clone (clonectx));
6371 if (initializers != null){
6372 target.initializers = new ArrayList (initializers.Count);
6373 foreach (object initializer in initializers)
6374 if (initializer is ArrayList) {
6375 ArrayList this_al = (ArrayList)initializer;
6376 ArrayList al = new ArrayList (this_al.Count);
6377 target.initializers.Add (al);
6378 foreach (Expression e in this_al)
6379 al.Add (e.Clone (clonectx));
6381 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6388 // Represents an implicitly typed array epxression
6390 public class ImplicitlyTypedArrayCreation : ArrayCreation
6392 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6393 : base (null, rank, initializers, loc)
6395 if (RootContext.Version <= LanguageVersion.ISO_2)
6396 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6398 if (rank.Length > 2) {
6399 while (rank [++dimensions] == ',');
6405 public override Expression DoResolve (EmitContext ec)
6410 if (!ResolveInitializers (ec))
6413 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6414 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6415 arguments.Count != dimensions) {
6416 Error_NoBestType ();
6421 // At this point we found common base type for all initializer elements
6422 // but we have to be sure that all static initializer elements are of
6425 UnifyInitializerElement (ec);
6427 type = TypeManager.GetConstructedType (array_element_type, rank);
6428 eclass = ExprClass.Value;
6432 void Error_NoBestType ()
6434 Report.Error (826, loc,
6435 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6439 // Converts static initializer only
6441 void UnifyInitializerElement (EmitContext ec)
6443 for (int i = 0; i < array_data.Count; ++i) {
6444 Expression e = (Expression)array_data[i];
6446 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6450 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6452 element = element.Resolve (ec);
6453 if (element == null)
6456 if (array_element_type == null) {
6457 if (element.Type != TypeManager.null_type)
6458 array_element_type = element.Type;
6463 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6467 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6468 array_element_type = element.Type;
6472 Error_NoBestType ();
6477 public sealed class CompilerGeneratedThis : This
6479 public static This Instance = new CompilerGeneratedThis ();
6481 private CompilerGeneratedThis ()
6482 : base (Location.Null)
6486 public CompilerGeneratedThis (Type type, Location loc)
6492 public override Expression DoResolve (EmitContext ec)
6494 eclass = ExprClass.Variable;
6496 type = ec.CurrentType;
6500 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6507 /// Represents the `this' construct
6510 public class This : VariableReference
6512 sealed class ThisVariable : ILocalVariable
6514 public static readonly ILocalVariable Instance = new ThisVariable ();
6516 public void Emit (EmitContext ec)
6518 ec.ig.Emit (OpCodes.Ldarg_0);
6521 public void EmitAssign (EmitContext ec)
6523 throw new InvalidOperationException ();
6526 public void EmitAddressOf (EmitContext ec)
6528 ec.ig.Emit (OpCodes.Ldarg_0);
6533 VariableInfo variable_info;
6536 public This (Block block, Location loc)
6542 public This (Location loc)
6547 public override VariableInfo VariableInfo {
6548 get { return variable_info; }
6551 public override bool IsFixed {
6552 get { return false; }
6555 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6557 // Is null when probing IsHoisted
6561 if (ec.CurrentAnonymousMethod == null)
6564 AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
6565 while (storey != null) {
6566 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6568 return storey.HoistedThis;
6576 public override bool IsRef {
6577 get { return is_struct; }
6580 protected override ILocalVariable Variable {
6581 get { return ThisVariable.Instance; }
6584 public static bool IsThisAvailable (EmitContext ec)
6586 if (ec.IsStatic || ec.HasAny (EmitContext.Options.FieldInitializerScope | EmitContext.Options.BaseInitializer | EmitContext.Options.ConstantScope))
6589 if (ec.CurrentAnonymousMethod == null)
6592 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6598 public bool ResolveBase (EmitContext ec)
6600 if (eclass != ExprClass.Invalid)
6603 eclass = ExprClass.Variable;
6604 type = ec.CurrentType;
6606 if (!IsThisAvailable (ec)) {
6607 if (ec.IsStatic && !ec.HasSet (EmitContext.Options.ConstantScope)) {
6608 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6609 } else if (ec.CurrentAnonymousMethod != null) {
6610 Report.Error (1673, loc,
6611 "Anonymous methods inside structs cannot access instance members of `this'. " +
6612 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6614 Error (27, "Keyword `this' is not available in the current context");
6618 is_struct = type.IsValueType;
6620 if (block != null) {
6621 if (block.Toplevel.ThisVariable != null)
6622 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6624 AnonymousExpression am = ec.CurrentAnonymousMethod;
6625 if (am != null && ec.IsVariableCapturingRequired) {
6626 am.SetHasThisAccess ();
6634 // Called from Invocation to check if the invocation is correct
6636 public override void CheckMarshalByRefAccess (EmitContext ec)
6638 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6639 !variable_info.IsAssigned (ec)) {
6640 Error (188, "The `this' object cannot be used before all of its " +
6641 "fields are assigned to");
6642 variable_info.SetAssigned (ec);
6646 public override Expression CreateExpressionTree (EmitContext ec)
6648 Arguments args = new Arguments (1);
6649 args.Add (new Argument (this));
6651 // Use typeless constant for ldarg.0 to save some
6652 // space and avoid problems with anonymous stories
6653 return CreateExpressionFactoryCall ("Constant", args);
6656 public override Expression DoResolve (EmitContext ec)
6662 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6664 if (!ResolveBase (ec))
6667 if (variable_info != null)
6668 variable_info.SetAssigned (ec);
6670 if (ec.CurrentType.IsClass){
6671 if (right_side == EmptyExpression.UnaryAddress)
6672 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6673 else if (right_side == EmptyExpression.OutAccess)
6674 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6676 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6682 public override int GetHashCode()
6684 return block.GetHashCode ();
6687 public override string Name {
6688 get { return "this"; }
6691 public override bool Equals (object obj)
6693 This t = obj as This;
6697 return block == t.block;
6700 protected override void CloneTo (CloneContext clonectx, Expression t)
6702 This target = (This) t;
6704 target.block = clonectx.LookupBlock (block);
6707 public override void SetHasAddressTaken ()
6714 /// Represents the `__arglist' construct
6716 public class ArglistAccess : Expression
6718 public ArglistAccess (Location loc)
6723 public override Expression CreateExpressionTree (EmitContext ec)
6725 throw new NotSupportedException ("ET");
6728 public override Expression DoResolve (EmitContext ec)
6730 eclass = ExprClass.Variable;
6731 type = TypeManager.runtime_argument_handle_type;
6733 if (ec.HasSet (EmitContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6734 Error (190, "The __arglist construct is valid only within " +
6735 "a variable argument method");
6741 public override void Emit (EmitContext ec)
6743 ec.ig.Emit (OpCodes.Arglist);
6746 protected override void CloneTo (CloneContext clonectx, Expression target)
6753 /// Represents the `__arglist (....)' construct
6755 class Arglist : Expression
6757 Arguments Arguments;
6759 public Arglist (Location loc)
6764 public Arglist (Arguments args, Location l)
6770 public Type[] ArgumentTypes {
6772 if (Arguments == null)
6773 return Type.EmptyTypes;
6775 Type[] retval = new Type [Arguments.Count];
6776 for (int i = 0; i < retval.Length; i++)
6777 retval [i] = Arguments [i].Expr.Type;
6783 public override Expression CreateExpressionTree (EmitContext ec)
6785 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6789 public override Expression DoResolve (EmitContext ec)
6791 eclass = ExprClass.Variable;
6792 type = InternalType.Arglist;
6793 if (Arguments != null) {
6794 bool dynamic; // Can be ignored as there is always only 1 overload
6795 Arguments.Resolve (ec, out dynamic);
6801 public override void Emit (EmitContext ec)
6803 if (Arguments != null)
6804 Arguments.Emit (ec);
6807 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6809 if (Arguments != null)
6810 Arguments.MutateHoistedGenericType (storey);
6813 protected override void CloneTo (CloneContext clonectx, Expression t)
6815 Arglist target = (Arglist) t;
6817 if (Arguments != null)
6818 target.Arguments = Arguments.Clone (clonectx);
6823 /// Implements the typeof operator
6825 public class TypeOf : Expression {
6826 Expression QueriedType;
6827 protected Type typearg;
6829 public TypeOf (Expression queried_type, Location l)
6831 QueriedType = queried_type;
6835 public override Expression CreateExpressionTree (EmitContext ec)
6837 Arguments args = new Arguments (2);
6838 args.Add (new Argument (this));
6839 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6840 return CreateExpressionFactoryCall ("Constant", args);
6843 public override Expression DoResolve (EmitContext ec)
6845 if (eclass != ExprClass.Invalid)
6848 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6852 typearg = texpr.Type;
6854 if (typearg == TypeManager.void_type) {
6855 Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6856 } else if (typearg.IsPointer && !ec.InUnsafe){
6858 } else if (texpr is DynamicTypeExpr) {
6859 Report.Error (1962, QueriedType.Location,
6860 "The typeof operator cannot be used on the dynamic type");
6863 type = TypeManager.type_type;
6865 return DoResolveBase ();
6868 protected Expression DoResolveBase ()
6870 if (TypeManager.system_type_get_type_from_handle == null) {
6871 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6872 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6875 // Even though what is returned is a type object, it's treated as a value by the compiler.
6876 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6877 eclass = ExprClass.Value;
6881 public override void Emit (EmitContext ec)
6883 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
6884 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6887 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6889 if (TypeManager.ContainsGenericParameters (typearg) &&
6890 !TypeManager.IsGenericTypeDefinition (typearg)) {
6891 Report.SymbolRelatedToPreviousError (typearg);
6892 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6893 TypeManager.CSharpName (typearg));
6898 if (value_type == TypeManager.object_type) {
6899 value = (object)typearg;
6906 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6908 typearg = storey.MutateType (typearg);
6911 public Type TypeArgument {
6917 protected override void CloneTo (CloneContext clonectx, Expression t)
6919 TypeOf target = (TypeOf) t;
6920 if (QueriedType != null)
6921 target.QueriedType = QueriedType.Clone (clonectx);
6926 /// Implements the `typeof (void)' operator
6928 public class TypeOfVoid : TypeOf {
6929 public TypeOfVoid (Location l) : base (null, l)
6934 public override Expression DoResolve (EmitContext ec)
6936 type = TypeManager.type_type;
6937 typearg = TypeManager.void_type;
6939 return DoResolveBase ();
6943 class TypeOfMethod : TypeOfMember
6945 public TypeOfMethod (MethodBase method, Location loc)
6946 : base (method, loc)
6950 public override Expression DoResolve (EmitContext ec)
6952 if (member is MethodInfo) {
6953 type = TypeManager.methodinfo_type;
6955 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType ("System.Reflection", "MethodInfo", Kind.Class, true);
6957 type = TypeManager.ctorinfo_type;
6959 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType ("System.Reflection", "ConstructorInfo", Kind.Class, true);
6962 return base.DoResolve (ec);
6965 public override void Emit (EmitContext ec)
6967 if (member is ConstructorInfo)
6968 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member);
6970 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member);
6973 ec.ig.Emit (OpCodes.Castclass, type);
6976 protected override string GetMethodName {
6977 get { return "GetMethodFromHandle"; }
6980 protected override string RuntimeHandleName {
6981 get { return "RuntimeMethodHandle"; }
6984 protected override MethodInfo TypeFromHandle {
6986 return TypeManager.methodbase_get_type_from_handle;
6989 TypeManager.methodbase_get_type_from_handle = value;
6993 protected override MethodInfo TypeFromHandleGeneric {
6995 return TypeManager.methodbase_get_type_from_handle_generic;
6998 TypeManager.methodbase_get_type_from_handle_generic = value;
7002 protected override string TypeName {
7003 get { return "MethodBase"; }
7007 abstract class TypeOfMember : Expression
7009 protected readonly MemberInfo member;
7011 protected TypeOfMember (MemberInfo member, Location loc)
7013 this.member = member;
7017 public override Expression CreateExpressionTree (EmitContext ec)
7019 Arguments args = new Arguments (2);
7020 args.Add (new Argument (this));
7021 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7022 return CreateExpressionFactoryCall ("Constant", args);
7025 public override Expression DoResolve (EmitContext ec)
7027 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7028 MethodInfo mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7031 Type t = TypeManager.CoreLookupType ("System.Reflection", TypeName, Kind.Class, true);
7032 Type handle_type = TypeManager.CoreLookupType ("System", RuntimeHandleName, Kind.Class, true);
7034 if (t == null || handle_type == null)
7037 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7039 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7040 new Type[] { handle_type } );
7043 TypeFromHandleGeneric = mi;
7045 TypeFromHandle = mi;
7048 eclass = ExprClass.Value;
7052 public override void Emit (EmitContext ec)
7054 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7057 mi = TypeFromHandleGeneric;
7058 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7060 mi = TypeFromHandle;
7063 ec.ig.Emit (OpCodes.Call, mi);
7066 protected abstract string GetMethodName { get; }
7067 protected abstract string RuntimeHandleName { get; }
7068 protected abstract MethodInfo TypeFromHandle { get; set; }
7069 protected abstract MethodInfo TypeFromHandleGeneric { get; set; }
7070 protected abstract string TypeName { get; }
7073 class TypeOfField : TypeOfMember
7075 public TypeOfField (FieldInfo field, Location loc)
7080 public override Expression DoResolve (EmitContext ec)
7082 if (TypeManager.fieldinfo_type == null)
7083 TypeManager.fieldinfo_type = TypeManager.CoreLookupType ("System.Reflection", TypeName, Kind.Class, true);
7085 type = TypeManager.fieldinfo_type;
7086 return base.DoResolve (ec);
7089 public override void Emit (EmitContext ec)
7091 ec.ig.Emit (OpCodes.Ldtoken, (FieldInfo) member);
7095 protected override string GetMethodName {
7096 get { return "GetFieldFromHandle"; }
7099 protected override string RuntimeHandleName {
7100 get { return "RuntimeFieldHandle"; }
7103 protected override MethodInfo TypeFromHandle {
7105 return TypeManager.fieldinfo_get_field_from_handle;
7108 TypeManager.fieldinfo_get_field_from_handle = value;
7112 protected override MethodInfo TypeFromHandleGeneric {
7114 return TypeManager.fieldinfo_get_field_from_handle_generic;
7117 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7121 protected override string TypeName {
7122 get { return "FieldInfo"; }
7127 /// Implements the sizeof expression
7129 public class SizeOf : Expression {
7130 readonly Expression QueriedType;
7133 public SizeOf (Expression queried_type, Location l)
7135 this.QueriedType = queried_type;
7139 public override Expression CreateExpressionTree (EmitContext ec)
7141 Error_PointerInsideExpressionTree ();
7145 public override Expression DoResolve (EmitContext ec)
7147 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7151 type_queried = texpr.Type;
7152 if (TypeManager.IsEnumType (type_queried))
7153 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7155 int size_of = GetTypeSize (type_queried);
7157 return new IntConstant (size_of, loc);
7160 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7165 Report.Error (233, loc,
7166 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7167 TypeManager.CSharpName (type_queried));
7170 type = TypeManager.int32_type;
7171 eclass = ExprClass.Value;
7175 public override void Emit (EmitContext ec)
7177 int size = GetTypeSize (type_queried);
7180 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7182 IntConstant.EmitInt (ec.ig, size);
7185 protected override void CloneTo (CloneContext clonectx, Expression t)
7191 /// Implements the qualified-alias-member (::) expression.
7193 public class QualifiedAliasMember : MemberAccess
7195 readonly string alias;
7196 public static readonly string GlobalAlias = "global";
7198 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7199 : base (null, identifier, targs, l)
7204 public QualifiedAliasMember (string alias, string identifier, Location l)
7205 : base (null, identifier, l)
7210 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7212 if (alias == GlobalAlias) {
7213 expr = GlobalRootNamespace.Instance;
7214 return base.ResolveAsTypeStep (ec, silent);
7217 int errors = Report.Errors;
7218 expr = ec.LookupNamespaceAlias (alias);
7220 if (errors == Report.Errors)
7221 Report.Error (432, loc, "Alias `{0}' not found", alias);
7225 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7229 if (expr.eclass == ExprClass.Type) {
7231 Report.Error (431, loc,
7232 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7240 public override Expression DoResolve (EmitContext ec)
7242 return ResolveAsTypeStep (ec, false);
7245 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7247 Report.Error (687, loc,
7248 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7249 GetSignatureForError ());
7252 public override string GetSignatureForError ()
7255 if (targs != null) {
7256 name = TypeManager.RemoveGenericArity (Name) + "<" +
7257 targs.GetSignatureForError () + ">";
7260 return alias + "::" + name;
7263 protected override void CloneTo (CloneContext clonectx, Expression t)
7270 /// Implements the member access expression
7272 public class MemberAccess : ATypeNameExpression {
7273 protected Expression expr;
7275 public MemberAccess (Expression expr, string id)
7276 : base (id, expr.Location)
7281 public MemberAccess (Expression expr, string identifier, Location loc)
7282 : base (identifier, loc)
7287 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7288 : base (identifier, args, loc)
7293 Expression DoResolve (EmitContext ec, Expression right_side)
7296 throw new Exception ();
7299 // Resolve the expression with flow analysis turned off, we'll do the definite
7300 // assignment checks later. This is because we don't know yet what the expression
7301 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7302 // definite assignment check on the actual field and not on the whole struct.
7305 SimpleName original = expr as SimpleName;
7306 Expression expr_resolved = expr.Resolve (ec,
7307 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7308 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7310 if (expr_resolved == null)
7313 string LookupIdentifier = MemberName.MakeName (Name, targs);
7315 Namespace ns = expr_resolved as Namespace;
7317 FullNamedExpression retval = ns.Lookup (LookupIdentifier, loc);
7320 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier);
7321 else if (targs != null)
7322 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7327 Type expr_type = expr_resolved.Type;
7328 if (TypeManager.IsDynamicType (expr_type)) {
7329 Arguments args = new Arguments (2);
7330 args.Add (new Argument (expr_resolved.Resolve (ec)));
7331 if (right_side != null)
7332 args.Add (new Argument (right_side));
7334 return new DynamicMemberBinder (right_side != null, Name, args, loc).Resolve (ec);
7337 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7338 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7339 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7343 Constant c = expr_resolved as Constant;
7344 if (c != null && c.GetValue () == null) {
7345 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7346 "System.NullReferenceException");
7349 if (targs != null) {
7350 if (!targs.Resolve (ec))
7354 Expression member_lookup;
7355 member_lookup = MemberLookup (
7356 ec.CurrentType, expr_type, expr_type, Name, loc);
7358 if (member_lookup == null && targs != null) {
7359 member_lookup = MemberLookup (
7360 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7363 if (member_lookup == null) {
7364 ExprClass expr_eclass = expr_resolved.eclass;
7367 // Extension methods are not allowed on all expression types
7369 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7370 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7371 expr_eclass == ExprClass.EventAccess) {
7372 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7373 if (ex_method_lookup != null) {
7374 ex_method_lookup.ExtensionExpression = expr_resolved;
7376 if (targs != null) {
7377 ex_method_lookup.SetTypeArguments (targs);
7380 return ex_method_lookup.DoResolve (ec);
7384 expr = expr_resolved;
7385 member_lookup = Error_MemberLookupFailed (
7386 ec.CurrentType, expr_type, expr_type, Name, null,
7387 AllMemberTypes, AllBindingFlags);
7388 if (member_lookup == null)
7392 TypeExpr texpr = member_lookup as TypeExpr;
7393 if (texpr != null) {
7394 if (!(expr_resolved is TypeExpr) &&
7395 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7396 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7397 Name, member_lookup.GetSignatureForError ());
7401 if (!texpr.CheckAccessLevel (ec.ResolveContext)) {
7402 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7403 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7407 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7410 // When looking up a nested type in a generic instance
7411 // via reflection, we always get a generic type definition
7412 // and not a generic instance - so we have to do this here.
7414 // See gtest-172-lib.cs and gtest-172.cs for an example.
7416 ct = new GenericTypeExpr (
7417 member_lookup.Type, ct.TypeArguments, loc);
7419 return ct.ResolveAsTypeStep (ec, false);
7422 return member_lookup;
7425 MemberExpr me = (MemberExpr) member_lookup;
7426 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7430 if (targs != null) {
7431 me.SetTypeArguments (targs);
7434 if (original != null && !TypeManager.IsValueType (expr_type)) {
7435 if (me.IsInstance) {
7436 LocalVariableReference var = expr_resolved as LocalVariableReference;
7437 if (var != null && !var.VerifyAssigned (ec))
7442 // The following DoResolve/DoResolveLValue will do the definite assignment
7445 if (right_side != null)
7446 return me.DoResolveLValue (ec, right_side);
7448 return me.DoResolve (ec);
7451 public override Expression DoResolve (EmitContext ec)
7453 return DoResolve (ec, null);
7456 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7458 return DoResolve (ec, right_side);
7461 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7463 return ResolveNamespaceOrType (ec, silent);
7466 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7468 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7470 if (expr_resolved == null)
7473 string LookupIdentifier = MemberName.MakeName (Name, targs);
7475 Namespace ns = expr_resolved as Namespace;
7477 FullNamedExpression retval = ns.Lookup (LookupIdentifier, loc);
7479 if (retval == null && !silent)
7480 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier);
7481 else if (targs != null)
7482 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7487 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7488 if (tnew_expr == null)
7491 Type expr_type = tnew_expr.Type;
7492 if (TypeManager.IsGenericParameter (expr_type)) {
7493 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7494 tnew_expr.GetSignatureForError ());
7498 Expression member_lookup = MemberLookup (
7499 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7500 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7501 if (member_lookup == null) {
7505 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7509 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7513 TypeArguments the_args = targs;
7514 Type declaring_type = texpr.Type.DeclaringType;
7515 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7516 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7517 expr_type = expr_type.BaseType;
7520 TypeArguments new_args = new TypeArguments ();
7521 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7522 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7525 new_args.Add (targs);
7527 the_args = new_args;
7530 if (the_args != null) {
7531 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7532 return ctype.ResolveAsTypeStep (rc, false);
7538 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7540 Expression member_lookup = MemberLookup (
7541 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7542 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7544 if (member_lookup != null) {
7545 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7546 if (expr_type == null)
7549 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7553 member_lookup = MemberLookup (
7554 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7555 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7557 if (member_lookup == null) {
7558 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7559 Name, expr_type.GetSignatureForError ());
7561 // TODO: Report.SymbolRelatedToPreviousError
7562 member_lookup.Error_UnexpectedKind (null, "type", loc);
7566 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7568 if (RootContext.Version > LanguageVersion.ISO_2 &&
7569 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7570 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7571 "extension method `{1}' of type `{0}' could be found " +
7572 "(are you missing a using directive or an assembly reference?)",
7573 TypeManager.CSharpName (type), name);
7577 base.Error_TypeDoesNotContainDefinition (type, name);
7580 public override string GetSignatureForError ()
7582 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7585 public Expression Left {
7591 protected override void CloneTo (CloneContext clonectx, Expression t)
7593 MemberAccess target = (MemberAccess) t;
7595 target.expr = expr.Clone (clonectx);
7600 /// Implements checked expressions
7602 public class CheckedExpr : Expression {
7604 public Expression Expr;
7606 public CheckedExpr (Expression e, Location l)
7612 public override Expression CreateExpressionTree (EmitContext ec)
7614 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7615 return Expr.CreateExpressionTree (ec);
7618 public override Expression DoResolve (EmitContext ec)
7620 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7621 Expr = Expr.Resolve (ec);
7626 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7629 eclass = Expr.eclass;
7634 public override void Emit (EmitContext ec)
7636 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7640 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7642 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7643 Expr.EmitBranchable (ec, target, on_true);
7646 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7648 Expr.MutateHoistedGenericType (storey);
7651 protected override void CloneTo (CloneContext clonectx, Expression t)
7653 CheckedExpr target = (CheckedExpr) t;
7655 target.Expr = Expr.Clone (clonectx);
7660 /// Implements the unchecked expression
7662 public class UnCheckedExpr : Expression {
7664 public Expression Expr;
7666 public UnCheckedExpr (Expression e, Location l)
7672 public override Expression CreateExpressionTree (EmitContext ec)
7674 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7675 return Expr.CreateExpressionTree (ec);
7678 public override Expression DoResolve (EmitContext ec)
7680 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7681 Expr = Expr.Resolve (ec);
7686 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7689 eclass = Expr.eclass;
7694 public override void Emit (EmitContext ec)
7696 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7700 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7702 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7703 Expr.EmitBranchable (ec, target, on_true);
7706 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7708 Expr.MutateHoistedGenericType (storey);
7711 protected override void CloneTo (CloneContext clonectx, Expression t)
7713 UnCheckedExpr target = (UnCheckedExpr) t;
7715 target.Expr = Expr.Clone (clonectx);
7720 /// An Element Access expression.
7722 /// During semantic analysis these are transformed into
7723 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7725 public class ElementAccess : Expression {
7726 public Arguments Arguments;
7727 public Expression Expr;
7729 public ElementAccess (Expression e, Arguments args)
7733 this.Arguments = args;
7736 public override Expression CreateExpressionTree (EmitContext ec)
7738 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7739 Expr.CreateExpressionTree (ec));
7741 return CreateExpressionFactoryCall ("ArrayIndex", args);
7744 Expression MakePointerAccess (EmitContext ec, Type t)
7746 if (Arguments.Count != 1){
7747 Error (196, "A pointer must be indexed by only one value");
7751 if (Arguments [0] is NamedArgument)
7752 Error_NamedArgument ((NamedArgument) Arguments[0]);
7754 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7755 return new Indirection (p, loc).Resolve (ec);
7758 public override Expression DoResolve (EmitContext ec)
7760 Expr = Expr.Resolve (ec);
7765 // We perform some simple tests, and then to "split" the emit and store
7766 // code we create an instance of a different class, and return that.
7768 // I am experimenting with this pattern.
7772 if (t == TypeManager.array_type){
7773 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7778 return (new ArrayAccess (this, loc)).Resolve (ec);
7780 return MakePointerAccess (ec, t);
7782 FieldExpr fe = Expr as FieldExpr;
7784 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7786 return MakePointerAccess (ec, ff.ElementType);
7789 return (new IndexerAccess (this, loc)).Resolve (ec);
7792 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7794 Expr = Expr.Resolve (ec);
7800 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7803 return MakePointerAccess (ec, type);
7805 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7806 Error_CannotModifyIntermediateExpressionValue (ec);
7808 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7811 public override void Emit (EmitContext ec)
7813 throw new Exception ("Should never be reached");
7816 public static void Error_NamedArgument (NamedArgument na)
7818 Report.Error (1742, na.Name.Location, "An element access expression cannot use named argument");
7821 public override string GetSignatureForError ()
7823 return Expr.GetSignatureForError ();
7826 protected override void CloneTo (CloneContext clonectx, Expression t)
7828 ElementAccess target = (ElementAccess) t;
7830 target.Expr = Expr.Clone (clonectx);
7831 if (Arguments != null)
7832 target.Arguments = Arguments.Clone (clonectx);
7837 /// Implements array access
7839 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7841 // Points to our "data" repository
7845 LocalTemporary temp;
7849 public ArrayAccess (ElementAccess ea_data, Location l)
7855 public override Expression CreateExpressionTree (EmitContext ec)
7857 return ea.CreateExpressionTree (ec);
7860 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7862 return DoResolve (ec);
7865 public override Expression DoResolve (EmitContext ec)
7868 ExprClass eclass = ea.Expr.eclass;
7870 // As long as the type is valid
7871 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7872 eclass == ExprClass.Value)) {
7873 ea.Expr.Error_UnexpectedKind ("variable or value");
7878 if (eclass != ExprClass.Invalid)
7881 // dynamic is used per argument in ConvertExpressionToArrayIndex case
7883 ea.Arguments.Resolve (ec, out dynamic);
7885 Type t = ea.Expr.Type;
7886 int rank = ea.Arguments.Count;
7887 if (t.GetArrayRank () != rank) {
7888 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7889 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7893 type = TypeManager.GetElementType (t);
7894 if (type.IsPointer && !ec.InUnsafe) {
7895 UnsafeError (ea.Location);
7898 foreach (Argument a in ea.Arguments) {
7899 if (a is NamedArgument)
7900 ElementAccess.Error_NamedArgument ((NamedArgument) a);
7902 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7905 eclass = ExprClass.Variable;
7911 /// Emits the right opcode to load an object of Type `t'
7912 /// from an array of T
7914 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7917 MethodInfo get = FetchGetMethod ();
7918 ig.Emit (OpCodes.Call, get);
7922 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7923 ig.Emit (OpCodes.Ldelem_U1);
7924 else if (type == TypeManager.sbyte_type)
7925 ig.Emit (OpCodes.Ldelem_I1);
7926 else if (type == TypeManager.short_type)
7927 ig.Emit (OpCodes.Ldelem_I2);
7928 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7929 ig.Emit (OpCodes.Ldelem_U2);
7930 else if (type == TypeManager.int32_type)
7931 ig.Emit (OpCodes.Ldelem_I4);
7932 else if (type == TypeManager.uint32_type)
7933 ig.Emit (OpCodes.Ldelem_U4);
7934 else if (type == TypeManager.uint64_type)
7935 ig.Emit (OpCodes.Ldelem_I8);
7936 else if (type == TypeManager.int64_type)
7937 ig.Emit (OpCodes.Ldelem_I8);
7938 else if (type == TypeManager.float_type)
7939 ig.Emit (OpCodes.Ldelem_R4);
7940 else if (type == TypeManager.double_type)
7941 ig.Emit (OpCodes.Ldelem_R8);
7942 else if (type == TypeManager.intptr_type)
7943 ig.Emit (OpCodes.Ldelem_I);
7944 else if (TypeManager.IsEnumType (type)){
7945 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7946 } else if (TypeManager.IsStruct (type)){
7947 ig.Emit (OpCodes.Ldelema, type);
7948 ig.Emit (OpCodes.Ldobj, type);
7950 } else if (type.IsGenericParameter) {
7951 ig.Emit (OpCodes.Ldelem, type);
7953 } else if (type.IsPointer)
7954 ig.Emit (OpCodes.Ldelem_I);
7956 ig.Emit (OpCodes.Ldelem_Ref);
7959 protected override void Error_NegativeArrayIndex (Location loc)
7961 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7965 /// Returns the right opcode to store an object of Type `t'
7966 /// from an array of T.
7968 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7970 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7971 has_type_arg = false; is_stobj = false;
7972 t = TypeManager.TypeToCoreType (t);
7973 if (TypeManager.IsEnumType (t))
7974 t = TypeManager.GetEnumUnderlyingType (t);
7975 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7976 t == TypeManager.bool_type)
7977 return OpCodes.Stelem_I1;
7978 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7979 t == TypeManager.char_type)
7980 return OpCodes.Stelem_I2;
7981 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7982 return OpCodes.Stelem_I4;
7983 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7984 return OpCodes.Stelem_I8;
7985 else if (t == TypeManager.float_type)
7986 return OpCodes.Stelem_R4;
7987 else if (t == TypeManager.double_type)
7988 return OpCodes.Stelem_R8;
7989 else if (t == TypeManager.intptr_type) {
7990 has_type_arg = true;
7992 return OpCodes.Stobj;
7993 } else if (TypeManager.IsStruct (t)) {
7994 has_type_arg = true;
7996 return OpCodes.Stobj;
7998 } else if (t.IsGenericParameter) {
7999 has_type_arg = true;
8000 return OpCodes.Stelem;
8003 } else if (t.IsPointer)
8004 return OpCodes.Stelem_I;
8006 return OpCodes.Stelem_Ref;
8009 MethodInfo FetchGetMethod ()
8011 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8012 int arg_count = ea.Arguments.Count;
8013 Type [] args = new Type [arg_count];
8016 for (int i = 0; i < arg_count; i++){
8017 //args [i++] = a.Type;
8018 args [i] = TypeManager.int32_type;
8021 get = mb.GetArrayMethod (
8022 ea.Expr.Type, "Get",
8023 CallingConventions.HasThis |
8024 CallingConventions.Standard,
8030 MethodInfo FetchAddressMethod ()
8032 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8033 int arg_count = ea.Arguments.Count;
8034 Type [] args = new Type [arg_count];
8038 ret_type = TypeManager.GetReferenceType (type);
8040 for (int i = 0; i < arg_count; i++){
8041 //args [i++] = a.Type;
8042 args [i] = TypeManager.int32_type;
8045 address = mb.GetArrayMethod (
8046 ea.Expr.Type, "Address",
8047 CallingConventions.HasThis |
8048 CallingConventions.Standard,
8055 // Load the array arguments into the stack.
8057 void LoadArrayAndArguments (EmitContext ec)
8061 for (int i = 0; i < ea.Arguments.Count; ++i) {
8062 ea.Arguments [i].Emit (ec);
8066 public void Emit (EmitContext ec, bool leave_copy)
8068 int rank = ea.Expr.Type.GetArrayRank ();
8069 ILGenerator ig = ec.ig;
8072 LoadFromPtr (ig, this.type);
8074 LoadArrayAndArguments (ec);
8075 EmitLoadOpcode (ig, type, rank);
8079 ig.Emit (OpCodes.Dup);
8080 temp = new LocalTemporary (this.type);
8085 public override void Emit (EmitContext ec)
8090 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8092 int rank = ea.Expr.Type.GetArrayRank ();
8093 ILGenerator ig = ec.ig;
8094 Type t = source.Type;
8095 prepared = prepare_for_load;
8098 AddressOf (ec, AddressOp.LoadStore);
8099 ec.ig.Emit (OpCodes.Dup);
8101 LoadArrayAndArguments (ec);
8105 bool is_stobj, has_type_arg;
8106 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8110 // The stobj opcode used by value types will need
8111 // an address on the stack, not really an array/array
8115 ig.Emit (OpCodes.Ldelema, t);
8120 ec.ig.Emit (OpCodes.Dup);
8121 temp = new LocalTemporary (this.type);
8126 StoreFromPtr (ig, t);
8128 ig.Emit (OpCodes.Stobj, t);
8129 else if (has_type_arg)
8136 ec.ig.Emit (OpCodes.Dup);
8137 temp = new LocalTemporary (this.type);
8142 StoreFromPtr (ig, t);
8144 int arg_count = ea.Arguments.Count;
8145 Type [] args = new Type [arg_count + 1];
8146 for (int i = 0; i < arg_count; i++) {
8147 //args [i++] = a.Type;
8148 args [i] = TypeManager.int32_type;
8150 args [arg_count] = type;
8152 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8153 ea.Expr.Type, "Set",
8154 CallingConventions.HasThis |
8155 CallingConventions.Standard,
8156 TypeManager.void_type, args);
8158 ig.Emit (OpCodes.Call, set);
8168 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8170 if (!source.Emit (ec, this)) {
8172 throw new NotImplementedException ();
8177 throw new NotImplementedException ();
8180 public void AddressOf (EmitContext ec, AddressOp mode)
8182 int rank = ea.Expr.Type.GetArrayRank ();
8183 ILGenerator ig = ec.ig;
8185 LoadArrayAndArguments (ec);
8188 ig.Emit (OpCodes.Ldelema, type);
8190 MethodInfo address = FetchAddressMethod ();
8191 ig.Emit (OpCodes.Call, address);
8195 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8197 type = storey.MutateType (type);
8198 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8203 /// Expressions that represent an indexer call.
8205 public class IndexerAccess : Expression, IAssignMethod
8207 class IndexerMethodGroupExpr : MethodGroupExpr
8209 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8212 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8215 public override string Name {
8221 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8224 // Here is the trick, decrease number of arguments by 1 when only
8225 // available property method is setter. This makes overload resolution
8226 // work correctly for indexers.
8229 if (method.Name [0] == 'g')
8230 return parameters.Count;
8232 return parameters.Count - 1;
8238 // Contains either property getter or setter
8239 public ArrayList Methods;
8240 public ArrayList Properties;
8246 void Append (Type caller_type, MemberInfo [] mi)
8251 foreach (PropertyInfo property in mi) {
8252 MethodInfo accessor = property.GetGetMethod (true);
8253 if (accessor == null)
8254 accessor = property.GetSetMethod (true);
8256 if (Methods == null) {
8257 Methods = new ArrayList ();
8258 Properties = new ArrayList ();
8261 Methods.Add (accessor);
8262 Properties.Add (property);
8266 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8268 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8270 return TypeManager.MemberLookup (
8271 caller_type, caller_type, lookup_type, MemberTypes.Property,
8272 BindingFlags.Public | BindingFlags.Instance |
8273 BindingFlags.DeclaredOnly, p_name, null);
8276 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8278 Indexers ix = new Indexers ();
8280 if (TypeManager.IsGenericParameter (lookup_type)) {
8281 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8285 if (gc.HasClassConstraint) {
8286 Type class_contraint = gc.ClassConstraint;
8287 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8288 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8289 class_contraint = class_contraint.BaseType;
8293 Type[] ifaces = gc.InterfaceConstraints;
8294 foreach (Type itype in ifaces)
8295 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8300 Type copy = lookup_type;
8301 while (copy != TypeManager.object_type && copy != null){
8302 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8303 copy = copy.BaseType;
8306 if (lookup_type.IsInterface) {
8307 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8308 if (ifaces != null) {
8309 foreach (Type itype in ifaces)
8310 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8319 // Points to our "data" repository
8321 MethodInfo get, set;
8322 bool is_base_indexer;
8324 LocalTemporary temp;
8325 LocalTemporary prepared_value;
8326 Expression set_expr;
8328 protected Type indexer_type;
8329 protected Type current_type;
8330 protected Expression instance_expr;
8331 protected Arguments arguments;
8333 public IndexerAccess (ElementAccess ea, Location loc)
8334 : this (ea.Expr, false, loc)
8336 this.arguments = ea.Arguments;
8339 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8342 this.instance_expr = instance_expr;
8343 this.is_base_indexer = is_base_indexer;
8344 this.eclass = ExprClass.Value;
8348 static string GetAccessorName (bool isSet)
8350 return isSet ? "set" : "get";
8353 public override Expression CreateExpressionTree (EmitContext ec)
8355 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8356 instance_expr.CreateExpressionTree (ec),
8357 new TypeOfMethod (get, loc));
8359 return CreateExpressionFactoryCall ("Call", args);
8362 protected virtual void CommonResolve (EmitContext ec)
8364 indexer_type = instance_expr.Type;
8365 current_type = ec.CurrentType;
8368 public override Expression DoResolve (EmitContext ec)
8370 return ResolveAccessor (ec, null);
8373 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8375 if (right_side == EmptyExpression.OutAccess) {
8376 Report.Error (206, loc,
8377 "A property or indexer may not be passed as an out or ref parameter");
8381 // if the indexer returns a value type, and we try to set a field in it
8382 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8383 Error_CannotModifyIntermediateExpressionValue (ec);
8386 return ResolveAccessor (ec, right_side);
8389 Expression ResolveAccessor (EmitContext ec, Expression right_side)
8394 arguments.Resolve (ec, out dynamic);
8395 if (dynamic || TypeManager.IsDynamicType (indexer_type)) {
8396 int additional = right_side == null ? 1 : 2;
8397 Arguments args = new Arguments (arguments.Count + additional);
8398 if (is_base_indexer) {
8399 Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8401 args.Add (new Argument (instance_expr));
8403 args.AddRange (arguments);
8404 if (right_side != null)
8405 args.Add (new Argument (right_side));
8407 return new DynamicIndexBinder (right_side != null, args, loc).Resolve (ec);
8410 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8411 if (ilist.Methods == null) {
8412 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8413 TypeManager.CSharpName (indexer_type));
8417 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8418 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8422 MethodInfo mi = (MethodInfo) mg;
8423 PropertyInfo pi = null;
8424 for (int i = 0; i < ilist.Methods.Count; ++i) {
8425 if (ilist.Methods [i] == mi) {
8426 pi = (PropertyInfo) ilist.Properties [i];
8431 type = TypeManager.TypeToCoreType (pi.PropertyType);
8432 if (type.IsPointer && !ec.InUnsafe)
8435 MethodInfo accessor;
8436 if (right_side == null) {
8437 accessor = get = pi.GetGetMethod (true);
8439 accessor = set = pi.GetSetMethod (true);
8440 if (accessor == null && pi.GetGetMethod (true) != null) {
8441 Report.SymbolRelatedToPreviousError (pi);
8442 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8443 TypeManager.GetFullNameSignature (pi));
8447 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8450 if (accessor == null) {
8451 Report.SymbolRelatedToPreviousError (pi);
8452 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8453 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8458 // Only base will allow this invocation to happen.
8460 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8461 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8464 bool must_do_cs1540_check;
8465 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8467 set = pi.GetSetMethod (true);
8469 get = pi.GetGetMethod (true);
8471 if (set != null && get != null &&
8472 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8473 Report.SymbolRelatedToPreviousError (accessor);
8474 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8475 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8477 Report.SymbolRelatedToPreviousError (pi);
8478 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8482 instance_expr.CheckMarshalByRefAccess (ec);
8483 eclass = ExprClass.IndexerAccess;
8487 public void Emit (EmitContext ec, bool leave_copy)
8490 prepared_value.Emit (ec);
8492 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8493 arguments, loc, false, false);
8497 ec.ig.Emit (OpCodes.Dup);
8498 temp = new LocalTemporary (Type);
8504 // source is ignored, because we already have a copy of it from the
8505 // LValue resolution and we have already constructed a pre-cached
8506 // version of the arguments (ea.set_arguments);
8508 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8510 prepared = prepare_for_load;
8511 Expression value = set_expr;
8514 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8515 arguments, loc, true, false);
8517 prepared_value = new LocalTemporary (type);
8518 prepared_value.Store (ec);
8520 prepared_value.Release (ec);
8523 ec.ig.Emit (OpCodes.Dup);
8524 temp = new LocalTemporary (Type);
8527 } else if (leave_copy) {
8528 temp = new LocalTemporary (Type);
8535 arguments.Add (new Argument (value));
8537 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8545 public override void Emit (EmitContext ec)
8550 public override string GetSignatureForError ()
8552 return TypeManager.CSharpSignature (get != null ? get : set, false);
8555 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8558 get = storey.MutateGenericMethod (get);
8560 set = storey.MutateGenericMethod (set);
8562 instance_expr.MutateHoistedGenericType (storey);
8563 if (arguments != null)
8564 arguments.MutateHoistedGenericType (storey);
8566 type = storey.MutateType (type);
8569 protected override void CloneTo (CloneContext clonectx, Expression t)
8571 IndexerAccess target = (IndexerAccess) t;
8573 if (arguments != null)
8574 target.arguments = arguments.Clone (clonectx);
8576 if (instance_expr != null)
8577 target.instance_expr = instance_expr.Clone (clonectx);
8582 /// The base operator for method names
8584 public class BaseAccess : Expression {
8585 public readonly string Identifier;
8588 public BaseAccess (string member, Location l)
8590 this.Identifier = member;
8594 public BaseAccess (string member, TypeArguments args, Location l)
8600 public override Expression CreateExpressionTree (EmitContext ec)
8602 throw new NotSupportedException ("ET");
8605 public override Expression DoResolve (EmitContext ec)
8607 Expression c = CommonResolve (ec);
8613 // MethodGroups use this opportunity to flag an error on lacking ()
8615 if (!(c is MethodGroupExpr))
8616 return c.Resolve (ec);
8620 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8622 Expression c = CommonResolve (ec);
8628 // MethodGroups use this opportunity to flag an error on lacking ()
8630 if (! (c is MethodGroupExpr))
8631 return c.DoResolveLValue (ec, right_side);
8636 Expression CommonResolve (EmitContext ec)
8638 Expression member_lookup;
8639 Type current_type = ec.CurrentType;
8640 Type base_type = current_type.BaseType;
8642 if (!This.IsThisAvailable (ec)) {
8644 Error (1511, "Keyword `base' is not available in a static method");
8646 Error (1512, "Keyword `base' is not available in the current context");
8651 member_lookup = MemberLookup (ec.CurrentType, null, base_type, Identifier,
8652 AllMemberTypes, AllBindingFlags, loc);
8653 if (member_lookup == null) {
8654 Error_MemberLookupFailed (ec.CurrentType, base_type, base_type, Identifier,
8655 null, AllMemberTypes, AllBindingFlags);
8662 left = new TypeExpression (base_type, loc);
8664 left = ec.GetThis (loc);
8666 MemberExpr me = (MemberExpr) member_lookup;
8667 me = me.ResolveMemberAccess (ec, left, loc, null);
8674 me.SetTypeArguments (args);
8680 public override void Emit (EmitContext ec)
8682 throw new Exception ("Should never be called");
8685 protected override void CloneTo (CloneContext clonectx, Expression t)
8687 BaseAccess target = (BaseAccess) t;
8690 target.args = args.Clone ();
8695 /// The base indexer operator
8697 public class BaseIndexerAccess : IndexerAccess {
8698 public BaseIndexerAccess (Arguments args, Location loc)
8699 : base (null, true, loc)
8701 this.arguments = args;
8704 protected override void CommonResolve (EmitContext ec)
8706 instance_expr = ec.GetThis (loc);
8708 current_type = ec.CurrentType.BaseType;
8709 indexer_type = current_type;
8712 public override Expression CreateExpressionTree (EmitContext ec)
8714 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8715 return base.CreateExpressionTree (ec);
8720 /// This class exists solely to pass the Type around and to be a dummy
8721 /// that can be passed to the conversion functions (this is used by
8722 /// foreach implementation to typecast the object return value from
8723 /// get_Current into the proper type. All code has been generated and
8724 /// we only care about the side effect conversions to be performed
8726 /// This is also now used as a placeholder where a no-action expression
8727 /// is needed (the `New' class).
8729 public class EmptyExpression : Expression {
8730 public static readonly Expression Null = new EmptyExpression ();
8732 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8733 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8734 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8735 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8737 static EmptyExpression temp = new EmptyExpression ();
8738 public static EmptyExpression Grab ()
8740 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8745 public static void Release (EmptyExpression e)
8752 // FIXME: Don't set to object
8753 type = TypeManager.object_type;
8754 eclass = ExprClass.Value;
8755 loc = Location.Null;
8758 public EmptyExpression (Type t)
8761 eclass = ExprClass.Value;
8762 loc = Location.Null;
8765 public override Expression CreateExpressionTree (EmitContext ec)
8767 throw new NotSupportedException ("ET");
8770 public override Expression DoResolve (EmitContext ec)
8775 public override void Emit (EmitContext ec)
8777 // nothing, as we only exist to not do anything.
8780 public override void EmitSideEffect (EmitContext ec)
8785 // This is just because we might want to reuse this bad boy
8786 // instead of creating gazillions of EmptyExpressions.
8787 // (CanImplicitConversion uses it)
8789 public void SetType (Type t)
8796 // Empty statement expression
8798 public sealed class EmptyExpressionStatement : ExpressionStatement
8800 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8802 private EmptyExpressionStatement ()
8804 eclass = ExprClass.Value;
8805 loc = Location.Null;
8808 public override Expression CreateExpressionTree (EmitContext ec)
8813 public override void EmitStatement (EmitContext ec)
8818 public override Expression DoResolve (EmitContext ec)
8820 type = TypeManager.object_type;
8824 public override void Emit (EmitContext ec)
8830 public class UserCast : Expression {
8834 public UserCast (MethodInfo method, Expression source, Location l)
8836 this.method = method;
8837 this.source = source;
8838 type = TypeManager.TypeToCoreType (method.ReturnType);
8842 public Expression Source {
8848 public override Expression CreateExpressionTree (EmitContext ec)
8850 Arguments args = new Arguments (3);
8851 args.Add (new Argument (source.CreateExpressionTree (ec)));
8852 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8853 args.Add (new Argument (new TypeOfMethod (method, loc)));
8854 return CreateExpressionFactoryCall ("Convert", args);
8857 public override Expression DoResolve (EmitContext ec)
8859 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8861 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8863 eclass = ExprClass.Value;
8867 public override void Emit (EmitContext ec)
8870 ec.ig.Emit (OpCodes.Call, method);
8873 public override string GetSignatureForError ()
8875 return TypeManager.CSharpSignature (method);
8878 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8880 source.MutateHoistedGenericType (storey);
8881 method = storey.MutateGenericMethod (method);
8886 // This class is used to "construct" the type during a typecast
8887 // operation. Since the Type.GetType class in .NET can parse
8888 // the type specification, we just use this to construct the type
8889 // one bit at a time.
8891 public class ComposedCast : TypeExpr {
8892 FullNamedExpression left;
8895 public ComposedCast (FullNamedExpression left, string dim)
8896 : this (left, dim, left.Location)
8900 public ComposedCast (FullNamedExpression left, string dim, Location l)
8907 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8909 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8913 Type ltype = lexpr.Type;
8914 if ((dim.Length > 0) && (dim [0] == '?')) {
8915 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8917 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8918 return nullable.ResolveAsTypeTerminal (ec, false);
8921 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8924 if (dim.Length != 0 && dim [0] == '[') {
8925 if (TypeManager.IsSpecialType (ltype)) {
8926 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8930 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8931 Report.SymbolRelatedToPreviousError (ltype);
8932 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8933 TypeManager.CSharpName (ltype));
8938 type = TypeManager.GetConstructedType (ltype, dim);
8943 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8945 if (type.IsPointer && !ec.IsInUnsafeScope){
8949 eclass = ExprClass.Type;
8953 public override string GetSignatureForError ()
8955 return left.GetSignatureForError () + dim;
8958 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8960 return ResolveAsBaseTerminal (ec, silent);
8964 public class FixedBufferPtr : Expression {
8967 public FixedBufferPtr (Expression array, Type array_type, Location l)
8972 type = TypeManager.GetPointerType (array_type);
8973 eclass = ExprClass.Value;
8976 public override Expression CreateExpressionTree (EmitContext ec)
8978 Error_PointerInsideExpressionTree ();
8982 public override void Emit(EmitContext ec)
8987 public override Expression DoResolve (EmitContext ec)
8990 // We are born fully resolved
8998 // This class is used to represent the address of an array, used
8999 // only by the Fixed statement, this generates "&a [0]" construct
9000 // for fixed (char *pa = a)
9002 public class ArrayPtr : FixedBufferPtr {
9005 public ArrayPtr (Expression array, Type array_type, Location l):
9006 base (array, array_type, l)
9008 this.array_type = array_type;
9011 public override void Emit (EmitContext ec)
9015 ILGenerator ig = ec.ig;
9016 IntLiteral.EmitInt (ig, 0);
9017 ig.Emit (OpCodes.Ldelema, array_type);
9022 // Encapsulates a conversion rules required for array indexes
9024 public class ArrayIndexCast : TypeCast
9026 public ArrayIndexCast (Expression expr)
9027 : base (expr, expr.Type)
9031 public override Expression CreateExpressionTree (EmitContext ec)
9033 Arguments args = new Arguments (2);
9034 args.Add (new Argument (child.CreateExpressionTree (ec)));
9035 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9036 return CreateExpressionFactoryCall ("ConvertChecked", args);
9039 public override void Emit (EmitContext ec)
9043 if (type == TypeManager.int32_type)
9046 if (type == TypeManager.uint32_type)
9047 ec.ig.Emit (OpCodes.Conv_U);
9048 else if (type == TypeManager.int64_type)
9049 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9050 else if (type == TypeManager.uint64_type)
9051 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9053 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9058 // Implements the `stackalloc' keyword
9060 public class StackAlloc : Expression {
9065 public StackAlloc (Expression type, Expression count, Location l)
9072 public override Expression CreateExpressionTree (EmitContext ec)
9074 throw new NotSupportedException ("ET");
9077 public override Expression DoResolve (EmitContext ec)
9079 count = count.Resolve (ec);
9083 if (count.Type != TypeManager.uint32_type){
9084 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9089 Constant c = count as Constant;
9090 if (c != null && c.IsNegative) {
9091 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9095 if (ec.HasAny (EmitContext.Options.CatchScope | EmitContext.Options.FinallyScope)) {
9096 Error (255, "Cannot use stackalloc in finally or catch");
9100 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9106 if (!TypeManager.VerifyUnManaged (otype, loc))
9109 type = TypeManager.GetPointerType (otype);
9110 eclass = ExprClass.Value;
9115 public override void Emit (EmitContext ec)
9117 int size = GetTypeSize (otype);
9118 ILGenerator ig = ec.ig;
9123 ig.Emit (OpCodes.Sizeof, otype);
9125 IntConstant.EmitInt (ig, size);
9127 ig.Emit (OpCodes.Mul_Ovf_Un);
9128 ig.Emit (OpCodes.Localloc);
9131 protected override void CloneTo (CloneContext clonectx, Expression t)
9133 StackAlloc target = (StackAlloc) t;
9134 target.count = count.Clone (clonectx);
9135 target.t = t.Clone (clonectx);
9140 // An object initializer expression
9142 public class ElementInitializer : Assign
9144 public readonly string Name;
9146 public ElementInitializer (string name, Expression initializer, Location loc)
9147 : base (null, initializer, loc)
9152 protected override void CloneTo (CloneContext clonectx, Expression t)
9154 ElementInitializer target = (ElementInitializer) t;
9155 target.source = source.Clone (clonectx);
9158 public override Expression CreateExpressionTree (EmitContext ec)
9160 Arguments args = new Arguments (2);
9161 FieldExpr fe = target as FieldExpr;
9163 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9165 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9167 args.Add (new Argument (source.CreateExpressionTree (ec)));
9168 return CreateExpressionFactoryCall (
9169 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9173 public override Expression DoResolve (EmitContext ec)
9176 return EmptyExpressionStatement.Instance;
9178 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9179 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9185 me.InstanceExpression = ec.CurrentInitializerVariable;
9187 if (source is CollectionOrObjectInitializers) {
9188 Expression previous = ec.CurrentInitializerVariable;
9189 ec.CurrentInitializerVariable = target;
9190 source = source.Resolve (ec);
9191 ec.CurrentInitializerVariable = previous;
9195 eclass = source.eclass;
9200 Expression expr = base.DoResolve (ec);
9205 // Ignore field initializers with default value
9207 Constant c = source as Constant;
9208 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9209 return EmptyExpressionStatement.Instance.DoResolve (ec);
9214 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9216 MemberInfo member = members [0];
9217 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9218 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9219 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9221 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9222 TypeManager.GetFullNameSignature (member));
9227 public override void EmitStatement (EmitContext ec)
9229 if (source is CollectionOrObjectInitializers)
9232 base.EmitStatement (ec);
9237 // A collection initializer expression
9239 class CollectionElementInitializer : Invocation
9241 public class ElementInitializerArgument : Argument
9243 public ElementInitializerArgument (Expression e)
9249 sealed class AddMemberAccess : MemberAccess
9251 public AddMemberAccess (Expression expr, Location loc)
9252 : base (expr, "Add", loc)
9256 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9258 if (TypeManager.HasElementType (type))
9261 base.Error_TypeDoesNotContainDefinition (type, name);
9265 public CollectionElementInitializer (Expression argument)
9266 : base (null, new Arguments (1))
9268 base.arguments.Add (new ElementInitializerArgument (argument));
9269 this.loc = argument.Location;
9272 public CollectionElementInitializer (ArrayList arguments, Location loc)
9273 : base (null, new Arguments (arguments.Count))
9275 foreach (Expression e in arguments)
9276 base.arguments.Add (new ElementInitializerArgument (e));
9281 public override Expression CreateExpressionTree (EmitContext ec)
9283 Arguments args = new Arguments (2);
9284 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9286 ArrayList expr_initializers = new ArrayList (arguments.Count);
9287 foreach (Argument a in arguments)
9288 expr_initializers.Add (a.CreateExpressionTree (ec));
9290 args.Add (new Argument (new ArrayCreation (
9291 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9292 return CreateExpressionFactoryCall ("ElementInit", args);
9295 protected override void CloneTo (CloneContext clonectx, Expression t)
9297 CollectionElementInitializer target = (CollectionElementInitializer) t;
9298 if (arguments != null)
9299 target.arguments = arguments.Clone (clonectx);
9302 public override Expression DoResolve (EmitContext ec)
9304 if (eclass != ExprClass.Invalid)
9307 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9309 return base.DoResolve (ec);
9314 // A block of object or collection initializers
9316 public class CollectionOrObjectInitializers : ExpressionStatement
9318 ArrayList initializers;
9319 bool is_collection_initialization;
9321 public static readonly CollectionOrObjectInitializers Empty =
9322 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9324 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9326 this.initializers = initializers;
9330 public bool IsEmpty {
9332 return initializers.Count == 0;
9336 public bool IsCollectionInitializer {
9338 return is_collection_initialization;
9342 protected override void CloneTo (CloneContext clonectx, Expression target)
9344 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9346 t.initializers = new ArrayList (initializers.Count);
9347 foreach (Expression e in initializers)
9348 t.initializers.Add (e.Clone (clonectx));
9351 public override Expression CreateExpressionTree (EmitContext ec)
9353 ArrayList expr_initializers = new ArrayList (initializers.Count);
9354 foreach (Expression e in initializers) {
9355 Expression expr = e.CreateExpressionTree (ec);
9357 expr_initializers.Add (expr);
9360 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9363 public override Expression DoResolve (EmitContext ec)
9365 if (eclass != ExprClass.Invalid)
9368 ArrayList element_names = null;
9369 for (int i = 0; i < initializers.Count; ++i) {
9370 Expression initializer = (Expression) initializers [i];
9371 ElementInitializer element_initializer = initializer as ElementInitializer;
9374 if (element_initializer != null) {
9375 element_names = new ArrayList (initializers.Count);
9376 element_names.Add (element_initializer.Name);
9377 } else if (initializer is CompletingExpression){
9378 initializer.Resolve (ec);
9379 throw new InternalErrorException ("This line should never be reached");
9381 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9382 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9383 "object initializer because type `{1}' does not implement `{2}' interface",
9384 ec.CurrentInitializerVariable.GetSignatureForError (),
9385 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9386 TypeManager.CSharpName (TypeManager.ienumerable_type));
9389 is_collection_initialization = true;
9392 if (is_collection_initialization != (element_initializer == null)) {
9393 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9394 is_collection_initialization ? "collection initializer" : "object initializer");
9398 if (!is_collection_initialization) {
9399 if (element_names.Contains (element_initializer.Name)) {
9400 Report.Error (1912, element_initializer.Location,
9401 "An object initializer includes more than one member `{0}' initialization",
9402 element_initializer.Name);
9404 element_names.Add (element_initializer.Name);
9409 Expression e = initializer.Resolve (ec);
9410 if (e == EmptyExpressionStatement.Instance)
9411 initializers.RemoveAt (i--);
9413 initializers [i] = e;
9416 type = ec.CurrentInitializerVariable.Type;
9417 if (is_collection_initialization) {
9418 if (TypeManager.HasElementType (type)) {
9419 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9420 TypeManager.CSharpName (type));
9424 eclass = ExprClass.Variable;
9428 public override void Emit (EmitContext ec)
9433 public override void EmitStatement (EmitContext ec)
9435 foreach (ExpressionStatement e in initializers)
9436 e.EmitStatement (ec);
9439 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9441 foreach (Expression e in initializers)
9442 e.MutateHoistedGenericType (storey);
9447 // New expression with element/object initializers
9449 public class NewInitialize : New
9452 // This class serves as a proxy for variable initializer target instances.
9453 // A real variable is assigned later when we resolve left side of an
9456 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9458 NewInitialize new_instance;
9460 public InitializerTargetExpression (NewInitialize newInstance)
9462 this.type = newInstance.type;
9463 this.loc = newInstance.loc;
9464 this.eclass = newInstance.eclass;
9465 this.new_instance = newInstance;
9468 public override Expression CreateExpressionTree (EmitContext ec)
9470 // Should not be reached
9471 throw new NotSupportedException ("ET");
9474 public override Expression DoResolve (EmitContext ec)
9479 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9484 public override void Emit (EmitContext ec)
9486 Expression e = (Expression) new_instance.instance;
9490 #region IMemoryLocation Members
9492 public void AddressOf (EmitContext ec, AddressOp mode)
9494 new_instance.instance.AddressOf (ec, mode);
9500 CollectionOrObjectInitializers initializers;
9501 IMemoryLocation instance;
9503 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9504 : base (requested_type, arguments, l)
9506 this.initializers = initializers;
9509 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9511 instance = base.EmitAddressOf (ec, Mode);
9513 if (!initializers.IsEmpty)
9514 initializers.Emit (ec);
9519 protected override void CloneTo (CloneContext clonectx, Expression t)
9521 base.CloneTo (clonectx, t);
9523 NewInitialize target = (NewInitialize) t;
9524 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9527 public override Expression CreateExpressionTree (EmitContext ec)
9529 Arguments args = new Arguments (2);
9530 args.Add (new Argument (base.CreateExpressionTree (ec)));
9531 if (!initializers.IsEmpty)
9532 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9534 return CreateExpressionFactoryCall (
9535 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9539 public override Expression DoResolve (EmitContext ec)
9541 if (eclass != ExprClass.Invalid)
9544 Expression e = base.DoResolve (ec);
9548 Expression previous = ec.CurrentInitializerVariable;
9549 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9550 initializers.Resolve (ec);
9551 ec.CurrentInitializerVariable = previous;
9555 public override bool Emit (EmitContext ec, IMemoryLocation target)
9557 bool left_on_stack = base.Emit (ec, target);
9559 if (initializers.IsEmpty)
9560 return left_on_stack;
9562 LocalTemporary temp = target as LocalTemporary;
9564 if (!left_on_stack) {
9565 VariableReference vr = target as VariableReference;
9567 // FIXME: This still does not work correctly for pre-set variables
9568 if (vr != null && vr.IsRef)
9569 target.AddressOf (ec, AddressOp.Load);
9571 ((Expression) target).Emit (ec);
9572 left_on_stack = true;
9575 temp = new LocalTemporary (type);
9582 initializers.Emit (ec);
9584 if (left_on_stack) {
9589 return left_on_stack;
9592 public override bool HasInitializer {
9594 return !initializers.IsEmpty;
9598 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9600 base.MutateHoistedGenericType (storey);
9601 initializers.MutateHoistedGenericType (storey);
9605 public class AnonymousTypeDeclaration : Expression
9607 ArrayList parameters;
9608 readonly TypeContainer parent;
9609 static readonly ArrayList EmptyParameters = new ArrayList (0);
9611 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9613 this.parameters = parameters;
9614 this.parent = parent;
9618 protected override void CloneTo (CloneContext clonectx, Expression target)
9620 if (parameters == null)
9623 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9624 t.parameters = new ArrayList (parameters.Count);
9625 foreach (AnonymousTypeParameter atp in parameters)
9626 t.parameters.Add (atp.Clone (clonectx));
9629 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9631 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9635 type = AnonymousTypeClass.Create (parent, parameters, loc);
9642 if (Report.Errors == 0)
9645 parent.Module.AddAnonymousType (type);
9649 public override Expression CreateExpressionTree (EmitContext ec)
9651 throw new NotSupportedException ("ET");
9654 public override Expression DoResolve (EmitContext ec)
9656 AnonymousTypeClass anonymous_type;
9658 if (ec.HasSet (EmitContext.Options.ConstantScope)) {
9659 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9663 if (parameters == null) {
9664 anonymous_type = CreateAnonymousType (EmptyParameters);
9665 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9666 null, loc).Resolve (ec);
9670 Arguments arguments = new Arguments (parameters.Count);
9671 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9672 for (int i = 0; i < parameters.Count; ++i) {
9673 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9679 arguments.Add (new Argument (e));
9680 t_args [i] = new TypeExpression (e.Type, e.Location);
9686 anonymous_type = CreateAnonymousType (parameters);
9687 if (anonymous_type == null)
9690 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9691 new TypeArguments (t_args), loc);
9693 return new New (te, arguments, loc).Resolve (ec);
9696 public override void Emit (EmitContext ec)
9698 throw new InternalErrorException ("Should not be reached");
9702 public class AnonymousTypeParameter : Expression
9704 public readonly string Name;
9705 Expression initializer;
9707 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9711 this.initializer = initializer;
9714 public AnonymousTypeParameter (Parameter parameter)
9716 this.Name = parameter.Name;
9717 this.loc = parameter.Location;
9718 this.initializer = new SimpleName (Name, loc);
9721 protected override void CloneTo (CloneContext clonectx, Expression target)
9723 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9724 t.initializer = initializer.Clone (clonectx);
9727 public override Expression CreateExpressionTree (EmitContext ec)
9729 throw new NotSupportedException ("ET");
9732 public override bool Equals (object o)
9734 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9735 return other != null && Name == other.Name;
9738 public override int GetHashCode ()
9740 return Name.GetHashCode ();
9743 public override Expression DoResolve (EmitContext ec)
9745 Expression e = initializer.Resolve (ec);
9749 if (e.eclass == ExprClass.MethodGroup) {
9750 Error_InvalidInitializer (e.ExprClassName);
9755 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9756 type == InternalType.AnonymousMethod || type.IsPointer) {
9757 Error_InvalidInitializer (e.GetSignatureForError ());
9764 protected virtual void Error_InvalidInitializer (string initializer)
9766 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9770 public override void Emit (EmitContext ec)
9772 throw new InternalErrorException ("Should not be reached");