2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 // This is an user operator expression, automatically created during
24 public class UserOperatorCall : Expression {
25 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
27 protected readonly ArrayList arguments;
28 protected readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
34 this.arguments = args;
35 this.expr_tree = expr_tree;
37 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
38 eclass = ExprClass.Value;
42 public override Expression CreateExpressionTree (EmitContext ec)
44 if (expr_tree != null)
45 return expr_tree (ec, mg);
47 ArrayList args = new ArrayList (arguments.Count + 1);
48 args.Add (new Argument (new NullLiteral (loc)));
49 args.Add (new Argument (mg.CreateExpressionTree (ec)));
50 foreach (Argument a in arguments) {
51 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
54 return CreateExpressionFactoryCall ("Call", args);
57 protected override void CloneTo (CloneContext context, Expression target)
62 public override Expression DoResolve (EmitContext ec)
65 // We are born fully resolved
70 public override void Emit (EmitContext ec)
72 mg.EmitCall (ec, arguments);
75 public MethodGroupExpr Method {
79 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
81 foreach (Argument a in arguments)
82 a.Expr.MutateHoistedGenericType (storey);
84 mg.MutateHoistedGenericType (storey);
88 public class ParenthesizedExpression : Expression
90 public Expression Expr;
92 public ParenthesizedExpression (Expression expr)
98 public override Expression CreateExpressionTree (EmitContext ec)
100 throw new NotSupportedException ("ET");
103 public override Expression DoResolve (EmitContext ec)
105 Expr = Expr.Resolve (ec);
109 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
111 return Expr.DoResolveLValue (ec, right_side);
114 public override void Emit (EmitContext ec)
116 throw new Exception ("Should not happen");
119 protected override void CloneTo (CloneContext clonectx, Expression t)
121 ParenthesizedExpression target = (ParenthesizedExpression) t;
123 target.Expr = Expr.Clone (clonectx);
128 // Unary implements unary expressions.
130 public class Unary : Expression {
131 public enum Operator : byte {
132 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
136 static Type [] [] predefined_operators;
138 public readonly Operator Oper;
139 public Expression Expr;
140 Expression enum_conversion;
142 public Unary (Operator op, Expression expr)
150 // This routine will attempt to simplify the unary expression when the
151 // argument is a constant.
153 Constant TryReduceConstant (EmitContext ec, Constant e)
155 if (e is EmptyConstantCast)
156 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
158 if (e is SideEffectConstant) {
159 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
160 return r == null ? null : new SideEffectConstant (r, e, r.Location);
163 Type expr_type = e.Type;
166 case Operator.UnaryPlus:
167 // Unary numeric promotions
168 if (expr_type == TypeManager.byte_type)
169 return new IntConstant (((ByteConstant)e).Value, e.Location);
170 if (expr_type == TypeManager.sbyte_type)
171 return new IntConstant (((SByteConstant)e).Value, e.Location);
172 if (expr_type == TypeManager.short_type)
173 return new IntConstant (((ShortConstant)e).Value, e.Location);
174 if (expr_type == TypeManager.ushort_type)
175 return new IntConstant (((UShortConstant)e).Value, e.Location);
176 if (expr_type == TypeManager.char_type)
177 return new IntConstant (((CharConstant)e).Value, e.Location);
179 // Predefined operators
180 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
181 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
182 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
183 expr_type == TypeManager.decimal_type) {
189 case Operator.UnaryNegation:
190 // Unary numeric promotions
191 if (expr_type == TypeManager.byte_type)
192 return new IntConstant (-((ByteConstant)e).Value, e.Location);
193 if (expr_type == TypeManager.sbyte_type)
194 return new IntConstant (-((SByteConstant)e).Value, e.Location);
195 if (expr_type == TypeManager.short_type)
196 return new IntConstant (-((ShortConstant)e).Value, e.Location);
197 if (expr_type == TypeManager.ushort_type)
198 return new IntConstant (-((UShortConstant)e).Value, e.Location);
199 if (expr_type == TypeManager.char_type)
200 return new IntConstant (-((CharConstant)e).Value, e.Location);
202 // Predefined operators
203 if (expr_type == TypeManager.int32_type) {
204 int value = ((IntConstant)e).Value;
205 if (value == int.MinValue) {
206 if (ec.ConstantCheckState) {
207 ConstantFold.Error_CompileTimeOverflow (loc);
212 return new IntConstant (-value, e.Location);
214 if (expr_type == TypeManager.int64_type) {
215 long value = ((LongConstant)e).Value;
216 if (value == long.MinValue) {
217 if (ec.ConstantCheckState) {
218 ConstantFold.Error_CompileTimeOverflow (loc);
223 return new LongConstant (-value, e.Location);
226 if (expr_type == TypeManager.uint32_type) {
227 UIntLiteral uil = e as UIntLiteral;
229 if (uil.Value == 2147483648)
230 return new IntLiteral (int.MinValue, e.Location);
231 return new LongLiteral (-uil.Value, e.Location);
233 return new LongConstant (-((UIntConstant)e).Value, e.Location);
236 if (expr_type == TypeManager.uint64_type) {
237 ULongLiteral ull = e as ULongLiteral;
238 if (ull != null && ull.Value == 9223372036854775808)
239 return new LongLiteral (long.MinValue, e.Location);
243 if (expr_type == TypeManager.float_type) {
244 FloatLiteral fl = e as FloatLiteral;
245 // For better error reporting
247 fl.Value = -fl.Value;
250 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
252 if (expr_type == TypeManager.double_type) {
253 DoubleLiteral dl = e as DoubleLiteral;
254 // For better error reporting
256 dl.Value = -dl.Value;
260 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
262 if (expr_type == TypeManager.decimal_type)
263 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
267 case Operator.LogicalNot:
268 if (expr_type != TypeManager.bool_type)
271 bool b = (bool)e.GetValue ();
272 return new BoolConstant (!b, e.Location);
274 case Operator.OnesComplement:
275 // Unary numeric promotions
276 if (expr_type == TypeManager.byte_type)
277 return new IntConstant (~((ByteConstant)e).Value, e.Location);
278 if (expr_type == TypeManager.sbyte_type)
279 return new IntConstant (~((SByteConstant)e).Value, e.Location);
280 if (expr_type == TypeManager.short_type)
281 return new IntConstant (~((ShortConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.ushort_type)
283 return new IntConstant (~((UShortConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.char_type)
285 return new IntConstant (~((CharConstant)e).Value, e.Location);
287 // Predefined operators
288 if (expr_type == TypeManager.int32_type)
289 return new IntConstant (~((IntConstant)e).Value, e.Location);
290 if (expr_type == TypeManager.uint32_type)
291 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
292 if (expr_type == TypeManager.int64_type)
293 return new LongConstant (~((LongConstant)e).Value, e.Location);
294 if (expr_type == TypeManager.uint64_type){
295 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
297 if (e is EnumConstant) {
298 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
300 e = new EnumConstant (e, expr_type);
305 throw new Exception ("Can not constant fold: " + Oper.ToString());
308 protected Expression ResolveOperator (EmitContext ec, Expression expr)
310 eclass = ExprClass.Value;
312 if (predefined_operators == null)
313 CreatePredefinedOperatorsTable ();
315 Type expr_type = expr.Type;
316 Expression best_expr;
319 // Primitive types first
321 if (TypeManager.IsPrimitiveType (expr_type)) {
322 best_expr = ResolvePrimitivePredefinedType (expr);
323 if (best_expr == null)
326 type = best_expr.Type;
332 // E operator ~(E x);
334 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
335 return ResolveEnumOperator (ec, expr);
337 return ResolveUserType (ec, expr);
340 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
342 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
343 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
344 if (best_expr == null)
348 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
350 return EmptyCast.Create (this, type);
353 public override Expression CreateExpressionTree (EmitContext ec)
355 return CreateExpressionTree (ec, null);
358 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
362 case Operator.AddressOf:
363 Error_PointerInsideExpressionTree ();
365 case Operator.UnaryNegation:
366 if (ec.CheckState && user_op == null && !IsFloat (type))
367 method_name = "NegateChecked";
369 method_name = "Negate";
371 case Operator.OnesComplement:
372 case Operator.LogicalNot:
375 case Operator.UnaryPlus:
376 method_name = "UnaryPlus";
379 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
382 ArrayList args = new ArrayList (2);
383 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
385 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
386 return CreateExpressionFactoryCall (method_name, args);
389 static void CreatePredefinedOperatorsTable ()
391 predefined_operators = new Type [(int) Operator.TOP] [];
394 // 7.6.1 Unary plus operator
396 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
397 TypeManager.int32_type, TypeManager.uint32_type,
398 TypeManager.int64_type, TypeManager.uint64_type,
399 TypeManager.float_type, TypeManager.double_type,
400 TypeManager.decimal_type
404 // 7.6.2 Unary minus operator
406 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
407 TypeManager.int32_type,
408 TypeManager.int64_type,
409 TypeManager.float_type, TypeManager.double_type,
410 TypeManager.decimal_type
414 // 7.6.3 Logical negation operator
416 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
417 TypeManager.bool_type
421 // 7.6.4 Bitwise complement operator
423 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
424 TypeManager.int32_type, TypeManager.uint32_type,
425 TypeManager.int64_type, TypeManager.uint64_type
430 // Unary numeric promotions
432 static Expression DoNumericPromotion (Operator op, Expression expr)
434 Type expr_type = expr.Type;
435 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
436 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
437 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
438 expr_type == TypeManager.char_type)
439 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
441 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
442 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
447 public override Expression DoResolve (EmitContext ec)
449 if (Oper == Operator.AddressOf) {
450 return ResolveAddressOf (ec);
453 Expr = Expr.Resolve (ec);
457 if (TypeManager.IsNullableValueType (Expr.Type))
458 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
461 // Attempt to use a constant folding operation.
463 Constant cexpr = Expr as Constant;
465 cexpr = TryReduceConstant (ec, cexpr);
470 Expression expr = ResolveOperator (ec, Expr);
472 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
475 // Reduce unary operator on predefined types
477 if (expr == this && Oper == Operator.UnaryPlus)
483 public override Expression DoResolveLValue (EmitContext ec, Expression right)
488 public override void Emit (EmitContext ec)
490 EmitOperator (ec, type);
493 protected void EmitOperator (EmitContext ec, Type type)
495 ILGenerator ig = ec.ig;
498 case Operator.UnaryPlus:
502 case Operator.UnaryNegation:
503 if (ec.CheckState && !IsFloat (type)) {
504 ig.Emit (OpCodes.Ldc_I4_0);
505 if (type == TypeManager.int64_type)
506 ig.Emit (OpCodes.Conv_U8);
508 ig.Emit (OpCodes.Sub_Ovf);
511 ig.Emit (OpCodes.Neg);
516 case Operator.LogicalNot:
518 ig.Emit (OpCodes.Ldc_I4_0);
519 ig.Emit (OpCodes.Ceq);
522 case Operator.OnesComplement:
524 ig.Emit (OpCodes.Not);
527 case Operator.AddressOf:
528 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
532 throw new Exception ("This should not happen: Operator = "
537 // Same trick as in Binary expression
539 if (enum_conversion != null)
540 enum_conversion.Emit (ec);
543 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
545 if (Oper == Operator.LogicalNot)
546 Expr.EmitBranchable (ec, target, !on_true);
548 base.EmitBranchable (ec, target, on_true);
551 public override void EmitSideEffect (EmitContext ec)
553 Expr.EmitSideEffect (ec);
556 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
558 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
559 oper, TypeManager.CSharpName (t));
562 static bool IsFloat (Type t)
564 return t == TypeManager.float_type || t == TypeManager.double_type;
568 // Returns a stringified representation of the Operator
570 public static string OperName (Operator oper)
573 case Operator.UnaryPlus:
575 case Operator.UnaryNegation:
577 case Operator.LogicalNot:
579 case Operator.OnesComplement:
581 case Operator.AddressOf:
585 throw new NotImplementedException (oper.ToString ());
588 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
590 type = storey.MutateType (type);
591 Expr.MutateHoistedGenericType (storey);
594 Expression ResolveAddressOf (EmitContext ec)
599 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
600 if (Expr == null || Expr.eclass != ExprClass.Variable) {
601 Error (211, "Cannot take the address of the given expression");
605 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
609 IVariableReference vr = Expr as IVariableReference;
612 VariableInfo vi = vr.VariableInfo;
614 if (vi.LocalInfo != null)
615 vi.LocalInfo.Used = true;
618 // A variable is considered definitely assigned if you take its address.
623 is_fixed = vr.IsFixed;
624 vr.SetHasAddressTaken ();
627 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
630 IFixedExpression fe = Expr as IFixedExpression;
631 is_fixed = fe != null && fe.IsFixed;
634 if (!is_fixed && !ec.InFixedInitializer) {
635 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
638 type = TypeManager.GetPointerType (Expr.Type);
639 eclass = ExprClass.Value;
643 Expression ResolvePrimitivePredefinedType (Expression expr)
645 expr = DoNumericPromotion (Oper, expr);
646 Type expr_type = expr.Type;
647 Type[] predefined = predefined_operators [(int) Oper];
648 foreach (Type t in predefined) {
656 // Perform user-operator overload resolution
658 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
660 CSharp.Operator.OpType op_type;
662 case Operator.LogicalNot:
663 op_type = CSharp.Operator.OpType.LogicalNot; break;
664 case Operator.OnesComplement:
665 op_type = CSharp.Operator.OpType.OnesComplement; break;
666 case Operator.UnaryNegation:
667 op_type = CSharp.Operator.OpType.UnaryNegation; break;
668 case Operator.UnaryPlus:
669 op_type = CSharp.Operator.OpType.UnaryPlus; break;
671 throw new InternalErrorException (Oper.ToString ());
674 string op_name = CSharp.Operator.GetMetadataName (op_type);
675 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
679 ArrayList args = new ArrayList (1);
680 args.Add (new Argument (expr));
681 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
686 Expr = ((Argument) args [0]).Expr;
687 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
691 // Unary user type overload resolution
693 Expression ResolveUserType (EmitContext ec, Expression expr)
695 Expression best_expr = ResolveUserOperator (ec, expr);
696 if (best_expr != null)
699 Type[] predefined = predefined_operators [(int) Oper];
700 foreach (Type t in predefined) {
701 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
702 if (oper_expr == null)
706 // decimal type is predefined but has user-operators
708 if (oper_expr.Type == TypeManager.decimal_type)
709 oper_expr = ResolveUserType (ec, oper_expr);
711 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
713 if (oper_expr == null)
716 if (best_expr == null) {
717 best_expr = oper_expr;
721 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
723 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
724 OperName (Oper), TypeManager.CSharpName (expr.Type));
729 best_expr = oper_expr;
732 if (best_expr == null)
736 // HACK: Decimal user-operator is included in standard operators
738 if (best_expr.Type == TypeManager.decimal_type)
742 type = best_expr.Type;
746 protected override void CloneTo (CloneContext clonectx, Expression t)
748 Unary target = (Unary) t;
750 target.Expr = Expr.Clone (clonectx);
755 // Unary operators are turned into Indirection expressions
756 // after semantic analysis (this is so we can take the address
757 // of an indirection).
759 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
761 LocalTemporary temporary;
764 public Indirection (Expression expr, Location l)
770 public override Expression CreateExpressionTree (EmitContext ec)
772 Error_PointerInsideExpressionTree ();
776 protected override void CloneTo (CloneContext clonectx, Expression t)
778 Indirection target = (Indirection) t;
779 target.expr = expr.Clone (clonectx);
782 public override void Emit (EmitContext ec)
787 LoadFromPtr (ec.ig, Type);
790 public void Emit (EmitContext ec, bool leave_copy)
794 ec.ig.Emit (OpCodes.Dup);
795 temporary = new LocalTemporary (expr.Type);
796 temporary.Store (ec);
800 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
802 prepared = prepare_for_load;
806 if (prepare_for_load)
807 ec.ig.Emit (OpCodes.Dup);
811 ec.ig.Emit (OpCodes.Dup);
812 temporary = new LocalTemporary (expr.Type);
813 temporary.Store (ec);
816 StoreFromPtr (ec.ig, type);
818 if (temporary != null) {
820 temporary.Release (ec);
824 public void AddressOf (EmitContext ec, AddressOp Mode)
829 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
831 return DoResolve (ec);
834 public override Expression DoResolve (EmitContext ec)
836 expr = expr.Resolve (ec);
843 if (!expr.Type.IsPointer) {
844 Error (193, "The * or -> operator must be applied to a pointer");
848 if (expr.Type == TypeManager.void_ptr_type) {
849 Error (242, "The operation in question is undefined on void pointers");
853 type = TypeManager.GetElementType (expr.Type);
854 eclass = ExprClass.Variable;
858 public bool IsFixed {
862 public override string ToString ()
864 return "*(" + expr + ")";
869 /// Unary Mutator expressions (pre and post ++ and --)
873 /// UnaryMutator implements ++ and -- expressions. It derives from
874 /// ExpressionStatement becuase the pre/post increment/decrement
875 /// operators can be used in a statement context.
877 /// FIXME: Idea, we could split this up in two classes, one simpler
878 /// for the common case, and one with the extra fields for more complex
879 /// classes (indexers require temporary access; overloaded require method)
882 public class UnaryMutator : ExpressionStatement {
884 public enum Mode : byte {
891 PreDecrement = IsDecrement,
892 PostIncrement = IsPost,
893 PostDecrement = IsPost | IsDecrement
897 bool is_expr = false;
898 bool recurse = false;
903 // This is expensive for the simplest case.
905 UserOperatorCall method;
907 public UnaryMutator (Mode m, Expression e)
914 static string OperName (Mode mode)
916 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
921 /// Returns whether an object of type `t' can be incremented
922 /// or decremented with add/sub (ie, basically whether we can
923 /// use pre-post incr-decr operations on it, but it is not a
924 /// System.Decimal, which we require operator overloading to catch)
926 static bool IsIncrementableNumber (Type t)
928 return (t == TypeManager.sbyte_type) ||
929 (t == TypeManager.byte_type) ||
930 (t == TypeManager.short_type) ||
931 (t == TypeManager.ushort_type) ||
932 (t == TypeManager.int32_type) ||
933 (t == TypeManager.uint32_type) ||
934 (t == TypeManager.int64_type) ||
935 (t == TypeManager.uint64_type) ||
936 (t == TypeManager.char_type) ||
937 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
938 (t == TypeManager.float_type) ||
939 (t == TypeManager.double_type) ||
940 (t.IsPointer && t != TypeManager.void_ptr_type);
943 Expression ResolveOperator (EmitContext ec)
948 // Step 1: Perform Operator Overload location
953 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
954 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
956 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
958 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
961 ArrayList args = new ArrayList (1);
962 args.Add (new Argument (expr, Argument.AType.Expression));
963 mg = mg.OverloadResolve (ec, ref args, false, loc);
967 method = new UserOperatorCall (mg, args, null, loc);
968 Convert.ImplicitConversionRequired (ec, method, type, loc);
972 if (!IsIncrementableNumber (type)) {
973 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
974 TypeManager.CSharpName (type) + "'");
979 // The operand of the prefix/postfix increment decrement operators
980 // should be an expression that is classified as a variable,
981 // a property access or an indexer access
983 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
984 expr = expr.ResolveLValue (ec, expr, Location);
986 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
992 public override Expression CreateExpressionTree (EmitContext ec)
994 return new SimpleAssign (this, this).CreateExpressionTree (ec);
997 public override Expression DoResolve (EmitContext ec)
999 expr = expr.Resolve (ec);
1004 eclass = ExprClass.Value;
1007 if (TypeManager.IsNullableValueType (expr.Type))
1008 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1011 return ResolveOperator (ec);
1015 // Loads the proper "1" into the stack based on the type, then it emits the
1016 // opcode for the operation requested
1018 void LoadOneAndEmitOp (EmitContext ec, Type t)
1021 // Measure if getting the typecode and using that is more/less efficient
1022 // that comparing types. t.GetTypeCode() is an internal call.
1024 ILGenerator ig = ec.ig;
1026 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1027 LongConstant.EmitLong (ig, 1);
1028 else if (t == TypeManager.double_type)
1029 ig.Emit (OpCodes.Ldc_R8, 1.0);
1030 else if (t == TypeManager.float_type)
1031 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1032 else if (t.IsPointer){
1033 Type et = TypeManager.GetElementType (t);
1034 int n = GetTypeSize (et);
1037 ig.Emit (OpCodes.Sizeof, et);
1039 IntConstant.EmitInt (ig, n);
1040 ig.Emit (OpCodes.Conv_I);
1043 ig.Emit (OpCodes.Ldc_I4_1);
1046 // Now emit the operation
1049 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1050 Binary.EmitOperatorOpcode (ec, op, t);
1052 if (t == TypeManager.sbyte_type){
1054 ig.Emit (OpCodes.Conv_Ovf_I1);
1056 ig.Emit (OpCodes.Conv_I1);
1057 } else if (t == TypeManager.byte_type){
1059 ig.Emit (OpCodes.Conv_Ovf_U1);
1061 ig.Emit (OpCodes.Conv_U1);
1062 } else if (t == TypeManager.short_type){
1064 ig.Emit (OpCodes.Conv_Ovf_I2);
1066 ig.Emit (OpCodes.Conv_I2);
1067 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1069 ig.Emit (OpCodes.Conv_Ovf_U2);
1071 ig.Emit (OpCodes.Conv_U2);
1076 void EmitCode (EmitContext ec, bool is_expr)
1079 this.is_expr = is_expr;
1080 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1083 public override void Emit (EmitContext ec)
1086 // We use recurse to allow ourselfs to be the source
1087 // of an assignment. This little hack prevents us from
1088 // having to allocate another expression
1091 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1093 LoadOneAndEmitOp (ec, expr.Type);
1095 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1100 EmitCode (ec, true);
1103 public override void EmitStatement (EmitContext ec)
1105 EmitCode (ec, false);
1108 protected override void CloneTo (CloneContext clonectx, Expression t)
1110 UnaryMutator target = (UnaryMutator) t;
1112 target.expr = expr.Clone (clonectx);
1117 /// Base class for the `Is' and `As' classes.
1121 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1124 public abstract class Probe : Expression {
1125 public Expression ProbeType;
1126 protected Expression expr;
1127 protected TypeExpr probe_type_expr;
1129 public Probe (Expression expr, Expression probe_type, Location l)
1131 ProbeType = probe_type;
1136 public Expression Expr {
1142 public override Expression DoResolve (EmitContext ec)
1144 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1145 if (probe_type_expr == null)
1148 expr = expr.Resolve (ec);
1152 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1153 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1157 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1158 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1163 if (expr.Type == TypeManager.anonymous_method_type) {
1164 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1172 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1174 expr.MutateHoistedGenericType (storey);
1175 probe_type_expr.MutateHoistedGenericType (storey);
1178 protected abstract string OperatorName { get; }
1180 protected override void CloneTo (CloneContext clonectx, Expression t)
1182 Probe target = (Probe) t;
1184 target.expr = expr.Clone (clonectx);
1185 target.ProbeType = ProbeType.Clone (clonectx);
1191 /// Implementation of the `is' operator.
1193 public class Is : Probe {
1194 Nullable.Unwrap expr_unwrap;
1196 public Is (Expression expr, Expression probe_type, Location l)
1197 : base (expr, probe_type, l)
1201 public override Expression CreateExpressionTree (EmitContext ec)
1203 ArrayList args = new ArrayList (2);
1204 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1205 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1206 return CreateExpressionFactoryCall ("TypeIs", args);
1209 public override void Emit (EmitContext ec)
1211 ILGenerator ig = ec.ig;
1212 if (expr_unwrap != null) {
1213 expr_unwrap.EmitCheck (ec);
1218 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1219 ig.Emit (OpCodes.Ldnull);
1220 ig.Emit (OpCodes.Cgt_Un);
1223 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1225 ILGenerator ig = ec.ig;
1226 if (expr_unwrap != null) {
1227 expr_unwrap.EmitCheck (ec);
1230 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1232 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1235 Expression CreateConstantResult (bool result)
1238 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1239 TypeManager.CSharpName (probe_type_expr.Type));
1241 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1242 TypeManager.CSharpName (probe_type_expr.Type));
1244 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1247 public override Expression DoResolve (EmitContext ec)
1249 if (base.DoResolve (ec) == null)
1253 bool d_is_nullable = false;
1256 // If E is a method group or the null literal, or if the type of E is a reference
1257 // type or a nullable type and the value of E is null, the result is false
1259 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1260 return CreateConstantResult (false);
1262 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1263 d = TypeManager.GetTypeArguments (d) [0];
1264 d_is_nullable = true;
1267 type = TypeManager.bool_type;
1268 eclass = ExprClass.Value;
1269 Type t = probe_type_expr.Type;
1270 bool t_is_nullable = false;
1271 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1272 t = TypeManager.GetTypeArguments (t) [0];
1273 t_is_nullable = true;
1276 if (t.IsValueType) {
1279 // D and T are the same value types but D can be null
1281 if (d_is_nullable && !t_is_nullable) {
1282 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1287 // The result is true if D and T are the same value types
1289 return CreateConstantResult (true);
1292 if (TypeManager.IsGenericParameter (d))
1293 return ResolveGenericParameter (t, d);
1296 // An unboxing conversion exists
1298 if (Convert.ExplicitReferenceConversionExists (d, t))
1301 if (TypeManager.IsGenericParameter (t))
1302 return ResolveGenericParameter (d, t);
1304 if (d.IsValueType) {
1306 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1307 return CreateConstantResult (true);
1309 if (TypeManager.IsGenericParameter (d))
1310 return ResolveGenericParameter (t, d);
1312 if (TypeManager.ContainsGenericParameters (d))
1315 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1316 Convert.ExplicitReferenceConversionExists (d, t)) {
1322 return CreateConstantResult (false);
1325 Expression ResolveGenericParameter (Type d, Type t)
1328 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1329 if (constraints != null) {
1330 if (constraints.IsReferenceType && d.IsValueType)
1331 return CreateConstantResult (false);
1333 if (constraints.IsValueType && !d.IsValueType)
1334 return CreateConstantResult (TypeManager.IsEqual (d, t));
1337 if (!TypeManager.IsReferenceType (expr.Type))
1338 expr = new BoxedCast (expr, d);
1346 protected override string OperatorName {
1347 get { return "is"; }
1352 /// Implementation of the `as' operator.
1354 public class As : Probe {
1356 Expression resolved_type;
1358 public As (Expression expr, Expression probe_type, Location l)
1359 : base (expr, probe_type, l)
1363 public override Expression CreateExpressionTree (EmitContext ec)
1365 ArrayList args = new ArrayList (2);
1366 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1367 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1368 return CreateExpressionFactoryCall ("TypeAs", args);
1371 public override void Emit (EmitContext ec)
1373 ILGenerator ig = ec.ig;
1378 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1381 if (TypeManager.IsNullableType (type))
1382 ig.Emit (OpCodes.Unbox_Any, type);
1386 public override Expression DoResolve (EmitContext ec)
1388 // Because expr is modified
1389 if (eclass != ExprClass.Invalid)
1392 if (resolved_type == null) {
1393 resolved_type = base.DoResolve (ec);
1395 if (resolved_type == null)
1399 type = probe_type_expr.Type;
1400 eclass = ExprClass.Value;
1401 Type etype = expr.Type;
1403 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1404 if (probe_type_expr is TypeParameterExpr) {
1405 Report.Error (413, loc,
1406 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1407 probe_type_expr.GetSignatureForError ());
1409 Report.Error (77, loc,
1410 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1411 TypeManager.CSharpName (type));
1416 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1417 return Nullable.LiftedNull.CreateFromExpression (this);
1420 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1427 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1428 if (TypeManager.IsGenericParameter (etype))
1429 expr = new BoxedCast (expr, etype);
1435 if (TypeManager.ContainsGenericParameters (etype) ||
1436 TypeManager.ContainsGenericParameters (type)) {
1437 expr = new BoxedCast (expr, etype);
1442 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1443 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1448 protected override string OperatorName {
1449 get { return "as"; }
1452 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1454 return expr.GetAttributableValue (ec, value_type, out value);
1459 /// This represents a typecast in the source language.
1461 /// FIXME: Cast expressions have an unusual set of parsing
1462 /// rules, we need to figure those out.
1464 public class Cast : Expression {
1465 Expression target_type;
1468 public Cast (Expression cast_type, Expression expr)
1469 : this (cast_type, expr, cast_type.Location)
1473 public Cast (Expression cast_type, Expression expr, Location loc)
1475 this.target_type = cast_type;
1480 public Expression TargetType {
1481 get { return target_type; }
1484 public Expression Expr {
1485 get { return expr; }
1488 public override Expression CreateExpressionTree (EmitContext ec)
1490 throw new NotSupportedException ("ET");
1493 public override Expression DoResolve (EmitContext ec)
1495 expr = expr.Resolve (ec);
1499 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1505 if (type.IsAbstract && type.IsSealed) {
1506 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1510 eclass = ExprClass.Value;
1512 Constant c = expr as Constant;
1514 c = c.TryReduce (ec, type, loc);
1519 if (type.IsPointer && !ec.InUnsafe) {
1523 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1527 public override void Emit (EmitContext ec)
1529 throw new Exception ("Should not happen");
1532 protected override void CloneTo (CloneContext clonectx, Expression t)
1534 Cast target = (Cast) t;
1536 target.target_type = target_type.Clone (clonectx);
1537 target.expr = expr.Clone (clonectx);
1542 // C# 2.0 Default value expression
1544 public class DefaultValueExpression : Expression
1548 public DefaultValueExpression (Expression expr, Location loc)
1554 public override Expression CreateExpressionTree (EmitContext ec)
1556 ArrayList args = new ArrayList (2);
1557 args.Add (new Argument (this));
1558 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1559 return CreateExpressionFactoryCall ("Constant", args);
1562 public override Expression DoResolve (EmitContext ec)
1564 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1570 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1571 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1575 return new NullLiteral (Location).ConvertImplicitly (type);
1577 if (TypeManager.IsReferenceType (type)) {
1578 return new EmptyConstantCast (new NullLiteral (Location), type);
1581 // return ReducedExpression.Create (new NullLiteral (Location), this);
1584 Constant c = New.Constantify (type);
1588 eclass = ExprClass.Variable;
1592 public override void Emit (EmitContext ec)
1594 LocalTemporary temp_storage = new LocalTemporary(type);
1596 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1597 ec.ig.Emit(OpCodes.Initobj, type);
1598 temp_storage.Emit(ec);
1601 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1603 type = storey.MutateType (type);
1606 protected override void CloneTo (CloneContext clonectx, Expression t)
1608 DefaultValueExpression target = (DefaultValueExpression) t;
1610 target.expr = expr.Clone (clonectx);
1615 /// Binary operators
1617 public class Binary : Expression {
1619 protected class PredefinedOperator {
1620 protected readonly Type left;
1621 protected readonly Type right;
1622 public readonly Operator OperatorsMask;
1623 public Type ReturnType;
1625 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1626 : this (ltype, rtype, op_mask, ltype)
1630 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1631 : this (type, type, op_mask, return_type)
1635 public PredefinedOperator (Type type, Operator op_mask)
1636 : this (type, type, op_mask, type)
1640 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1642 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1643 throw new InternalErrorException ("Only masked values can be used");
1647 this.OperatorsMask = op_mask;
1648 this.ReturnType = return_type;
1651 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1653 b.type = ReturnType;
1655 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1656 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1659 // A user operators does not support multiple user conversions, but decimal type
1660 // is considered to be predefined type therefore we apply predefined operators rules
1661 // and then look for decimal user-operator implementation
1663 if (left == TypeManager.decimal_type)
1664 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1669 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1672 // We are dealing with primitive types only
1674 return left == ltype && ltype == rtype;
1677 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1679 if (TypeManager.IsEqual (left, lexpr.Type) &&
1680 TypeManager.IsEqual (right, rexpr.Type))
1683 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1684 Convert.ImplicitConversionExists (ec, rexpr, right);
1687 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1690 if (left != null && best_operator.left != null) {
1691 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1695 // When second arguments are same as the first one, the result is same
1697 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1698 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1701 if (result == 0 || result > 2)
1704 return result == 1 ? best_operator : this;
1708 class PredefinedStringOperator : PredefinedOperator {
1709 public PredefinedStringOperator (Type type, Operator op_mask)
1710 : base (type, op_mask, type)
1712 ReturnType = TypeManager.string_type;
1715 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1716 : base (ltype, rtype, op_mask)
1718 ReturnType = TypeManager.string_type;
1721 public override Expression ConvertResult (EmitContext ec, Binary b)
1724 // Use original expression for nullable arguments
1726 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1728 b.left = unwrap.Original;
1730 unwrap = b.right as Nullable.Unwrap;
1732 b.right = unwrap.Original;
1734 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1735 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1738 // Start a new concat expression using converted expression
1740 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1744 class PredefinedShiftOperator : PredefinedOperator {
1745 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1746 base (ltype, TypeManager.int32_type, op_mask)
1750 public override Expression ConvertResult (EmitContext ec, Binary b)
1752 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1754 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1756 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1759 // b = b.left >> b.right & (0x1f|0x3f)
1761 b.right = new Binary (Operator.BitwiseAnd,
1762 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1765 // Expression tree representation does not use & mask
1767 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1768 b.type = ReturnType;
1773 class PredefinedPointerOperator : PredefinedOperator {
1774 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1775 : base (ltype, rtype, op_mask)
1779 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1780 : base (ltype, rtype, op_mask, retType)
1784 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1785 : base (type, op_mask, return_type)
1789 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1792 if (!lexpr.Type.IsPointer)
1795 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1799 if (right == null) {
1800 if (!rexpr.Type.IsPointer)
1803 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1810 public override Expression ConvertResult (EmitContext ec, Binary b)
1813 b.left = EmptyCast.Create (b.left, left);
1814 } else if (right != null) {
1815 b.right = EmptyCast.Create (b.right, right);
1818 Type r_type = ReturnType;
1819 Expression left_arg, right_arg;
1820 if (r_type == null) {
1823 right_arg = b.right;
1824 r_type = b.left.Type;
1828 r_type = b.right.Type;
1832 right_arg = b.right;
1835 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1840 public enum Operator {
1841 Multiply = 0 | ArithmeticMask,
1842 Division = 1 | ArithmeticMask,
1843 Modulus = 2 | ArithmeticMask,
1844 Addition = 3 | ArithmeticMask | AdditionMask,
1845 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1847 LeftShift = 5 | ShiftMask,
1848 RightShift = 6 | ShiftMask,
1850 LessThan = 7 | ComparisonMask | RelationalMask,
1851 GreaterThan = 8 | ComparisonMask | RelationalMask,
1852 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1853 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1854 Equality = 11 | ComparisonMask | EqualityMask,
1855 Inequality = 12 | ComparisonMask | EqualityMask,
1857 BitwiseAnd = 13 | BitwiseMask,
1858 ExclusiveOr = 14 | BitwiseMask,
1859 BitwiseOr = 15 | BitwiseMask,
1861 LogicalAnd = 16 | LogicalMask,
1862 LogicalOr = 17 | LogicalMask,
1867 ValuesOnlyMask = ArithmeticMask - 1,
1868 ArithmeticMask = 1 << 5,
1870 ComparisonMask = 1 << 7,
1871 EqualityMask = 1 << 8,
1872 BitwiseMask = 1 << 9,
1873 LogicalMask = 1 << 10,
1874 AdditionMask = 1 << 11,
1875 SubtractionMask = 1 << 12,
1876 RelationalMask = 1 << 13
1879 readonly Operator oper;
1880 protected Expression left, right;
1881 readonly bool is_compound;
1882 Expression enum_conversion;
1884 static PredefinedOperator [] standard_operators;
1885 static PredefinedOperator [] pointer_operators;
1887 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1888 : this (oper, left, right)
1890 this.is_compound = isCompound;
1893 public Binary (Operator oper, Expression left, Expression right)
1898 this.loc = left.Location;
1901 public Operator Oper {
1908 /// Returns a stringified representation of the Operator
1910 string OperName (Operator oper)
1914 case Operator.Multiply:
1917 case Operator.Division:
1920 case Operator.Modulus:
1923 case Operator.Addition:
1926 case Operator.Subtraction:
1929 case Operator.LeftShift:
1932 case Operator.RightShift:
1935 case Operator.LessThan:
1938 case Operator.GreaterThan:
1941 case Operator.LessThanOrEqual:
1944 case Operator.GreaterThanOrEqual:
1947 case Operator.Equality:
1950 case Operator.Inequality:
1953 case Operator.BitwiseAnd:
1956 case Operator.BitwiseOr:
1959 case Operator.ExclusiveOr:
1962 case Operator.LogicalOr:
1965 case Operator.LogicalAnd:
1969 s = oper.ToString ();
1979 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1981 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1984 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1987 // TODO: This should be handled as Type of method group in CSharpName
1988 if (left.eclass == ExprClass.MethodGroup)
1989 l = left.ExprClassName;
1991 l = TypeManager.CSharpName (left.Type);
1993 if (right.eclass == ExprClass.MethodGroup)
1994 r = right.ExprClassName;
1996 r = TypeManager.CSharpName (right.Type);
1998 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2002 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2004 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2007 static string GetOperatorMetadataName (Operator op)
2009 CSharp.Operator.OpType op_type;
2011 case Operator.Addition:
2012 op_type = CSharp.Operator.OpType.Addition; break;
2013 case Operator.BitwiseAnd:
2014 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2015 case Operator.BitwiseOr:
2016 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2017 case Operator.Division:
2018 op_type = CSharp.Operator.OpType.Division; break;
2019 case Operator.Equality:
2020 op_type = CSharp.Operator.OpType.Equality; break;
2021 case Operator.ExclusiveOr:
2022 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2023 case Operator.GreaterThan:
2024 op_type = CSharp.Operator.OpType.GreaterThan; break;
2025 case Operator.GreaterThanOrEqual:
2026 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2027 case Operator.Inequality:
2028 op_type = CSharp.Operator.OpType.Inequality; break;
2029 case Operator.LeftShift:
2030 op_type = CSharp.Operator.OpType.LeftShift; break;
2031 case Operator.LessThan:
2032 op_type = CSharp.Operator.OpType.LessThan; break;
2033 case Operator.LessThanOrEqual:
2034 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2035 case Operator.Modulus:
2036 op_type = CSharp.Operator.OpType.Modulus; break;
2037 case Operator.Multiply:
2038 op_type = CSharp.Operator.OpType.Multiply; break;
2039 case Operator.RightShift:
2040 op_type = CSharp.Operator.OpType.RightShift; break;
2041 case Operator.Subtraction:
2042 op_type = CSharp.Operator.OpType.Subtraction; break;
2044 throw new InternalErrorException (op.ToString ());
2047 return CSharp.Operator.GetMetadataName (op_type);
2050 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2053 ILGenerator ig = ec.ig;
2056 case Operator.Multiply:
2058 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2059 opcode = OpCodes.Mul_Ovf;
2060 else if (!IsFloat (l))
2061 opcode = OpCodes.Mul_Ovf_Un;
2063 opcode = OpCodes.Mul;
2065 opcode = OpCodes.Mul;
2069 case Operator.Division:
2071 opcode = OpCodes.Div_Un;
2073 opcode = OpCodes.Div;
2076 case Operator.Modulus:
2078 opcode = OpCodes.Rem_Un;
2080 opcode = OpCodes.Rem;
2083 case Operator.Addition:
2085 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2086 opcode = OpCodes.Add_Ovf;
2087 else if (!IsFloat (l))
2088 opcode = OpCodes.Add_Ovf_Un;
2090 opcode = OpCodes.Add;
2092 opcode = OpCodes.Add;
2095 case Operator.Subtraction:
2097 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2098 opcode = OpCodes.Sub_Ovf;
2099 else if (!IsFloat (l))
2100 opcode = OpCodes.Sub_Ovf_Un;
2102 opcode = OpCodes.Sub;
2104 opcode = OpCodes.Sub;
2107 case Operator.RightShift:
2109 opcode = OpCodes.Shr_Un;
2111 opcode = OpCodes.Shr;
2114 case Operator.LeftShift:
2115 opcode = OpCodes.Shl;
2118 case Operator.Equality:
2119 opcode = OpCodes.Ceq;
2122 case Operator.Inequality:
2123 ig.Emit (OpCodes.Ceq);
2124 ig.Emit (OpCodes.Ldc_I4_0);
2126 opcode = OpCodes.Ceq;
2129 case Operator.LessThan:
2131 opcode = OpCodes.Clt_Un;
2133 opcode = OpCodes.Clt;
2136 case Operator.GreaterThan:
2138 opcode = OpCodes.Cgt_Un;
2140 opcode = OpCodes.Cgt;
2143 case Operator.LessThanOrEqual:
2144 if (IsUnsigned (l) || IsFloat (l))
2145 ig.Emit (OpCodes.Cgt_Un);
2147 ig.Emit (OpCodes.Cgt);
2148 ig.Emit (OpCodes.Ldc_I4_0);
2150 opcode = OpCodes.Ceq;
2153 case Operator.GreaterThanOrEqual:
2154 if (IsUnsigned (l) || IsFloat (l))
2155 ig.Emit (OpCodes.Clt_Un);
2157 ig.Emit (OpCodes.Clt);
2159 ig.Emit (OpCodes.Ldc_I4_0);
2161 opcode = OpCodes.Ceq;
2164 case Operator.BitwiseOr:
2165 opcode = OpCodes.Or;
2168 case Operator.BitwiseAnd:
2169 opcode = OpCodes.And;
2172 case Operator.ExclusiveOr:
2173 opcode = OpCodes.Xor;
2177 throw new InternalErrorException (oper.ToString ());
2183 static bool IsUnsigned (Type t)
2188 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2189 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2192 static bool IsFloat (Type t)
2194 return t == TypeManager.float_type || t == TypeManager.double_type;
2197 Expression ResolveOperator (EmitContext ec)
2200 Type r = right.Type;
2202 bool primitives_only = false;
2204 if (standard_operators == null)
2205 CreateStandardOperatorsTable ();
2208 // Handles predefined primitive types
2210 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2211 if ((oper & Operator.ShiftMask) == 0) {
2212 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2215 primitives_only = true;
2219 if (l.IsPointer || r.IsPointer)
2220 return ResolveOperatorPointer (ec, l, r);
2223 bool lenum = TypeManager.IsEnumType (l);
2224 bool renum = TypeManager.IsEnumType (r);
2225 if (lenum || renum) {
2226 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2228 // TODO: Can this be ambiguous
2234 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2235 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2237 expr = ResolveOperatorDelegate (ec, l, r);
2239 // TODO: Can this be ambiguous
2245 expr = ResolveUserOperator (ec, l, r);
2249 // Predefined reference types equality
2250 if ((oper & Operator.EqualityMask) != 0) {
2251 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2257 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2260 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2261 // if 'left' is not an enumeration constant, create one from the type of 'right'
2262 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2265 case Operator.BitwiseOr:
2266 case Operator.BitwiseAnd:
2267 case Operator.ExclusiveOr:
2268 case Operator.Equality:
2269 case Operator.Inequality:
2270 case Operator.LessThan:
2271 case Operator.LessThanOrEqual:
2272 case Operator.GreaterThan:
2273 case Operator.GreaterThanOrEqual:
2274 if (TypeManager.IsEnumType (left.Type))
2277 if (left.IsZeroInteger)
2278 return left.TryReduce (ec, right.Type, loc);
2282 case Operator.Addition:
2283 case Operator.Subtraction:
2286 case Operator.Multiply:
2287 case Operator.Division:
2288 case Operator.Modulus:
2289 case Operator.LeftShift:
2290 case Operator.RightShift:
2291 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2295 Error_OperatorCannotBeApplied (this.left, this.right);
2300 // The `|' operator used on types which were extended is dangerous
2302 void CheckBitwiseOrOnSignExtended ()
2304 OpcodeCast lcast = left as OpcodeCast;
2305 if (lcast != null) {
2306 if (IsUnsigned (lcast.UnderlyingType))
2310 OpcodeCast rcast = right as OpcodeCast;
2311 if (rcast != null) {
2312 if (IsUnsigned (rcast.UnderlyingType))
2316 if (lcast == null && rcast == null)
2319 // FIXME: consider constants
2321 Report.Warning (675, 3, loc,
2322 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2323 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2326 static void CreatePointerOperatorsTable ()
2328 ArrayList temp = new ArrayList ();
2331 // Pointer arithmetic:
2333 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2334 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2335 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2336 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2338 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2339 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2340 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2341 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2344 // T* operator + (int y, T* x);
2345 // T* operator + (uint y, T *x);
2346 // T* operator + (long y, T *x);
2347 // T* operator + (ulong y, T *x);
2349 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2350 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2351 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2352 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2355 // long operator - (T* x, T *y)
2357 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2359 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2362 static void CreateStandardOperatorsTable ()
2364 ArrayList temp = new ArrayList ();
2365 Type bool_type = TypeManager.bool_type;
2367 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2368 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2369 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2370 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2371 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2372 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2373 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2375 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2377 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2378 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2379 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2380 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2381 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2383 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2385 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2386 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2387 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2389 temp.Add (new PredefinedOperator (bool_type,
2390 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2392 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2393 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2394 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2395 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2397 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2401 // Rules used during binary numeric promotion
2403 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2408 Constant c = prim_expr as Constant;
2410 temp = c.ConvertImplicitly (type);
2417 if (type == TypeManager.uint32_type) {
2418 etype = prim_expr.Type;
2419 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2420 type = TypeManager.int64_type;
2422 if (type != second_expr.Type) {
2423 c = second_expr as Constant;
2425 temp = c.ConvertImplicitly (type);
2427 temp = Convert.ImplicitNumericConversion (second_expr, type);
2433 } else if (type == TypeManager.uint64_type) {
2435 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2437 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2438 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2442 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2451 // 7.2.6.2 Binary numeric promotions
2453 public bool DoBinaryOperatorPromotion (EmitContext ec)
2455 Type ltype = left.Type;
2456 Type rtype = right.Type;
2459 foreach (Type t in ConstantFold.binary_promotions) {
2461 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2464 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2467 Type int32 = TypeManager.int32_type;
2468 if (ltype != int32) {
2469 Constant c = left as Constant;
2471 temp = c.ConvertImplicitly (int32);
2473 temp = Convert.ImplicitNumericConversion (left, int32);
2480 if (rtype != int32) {
2481 Constant c = right as Constant;
2483 temp = c.ConvertImplicitly (int32);
2485 temp = Convert.ImplicitNumericConversion (right, int32);
2495 public override Expression DoResolve (EmitContext ec)
2500 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2501 left = ((ParenthesizedExpression) left).Expr;
2502 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2506 if (left.eclass == ExprClass.Type) {
2507 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2511 left = left.Resolve (ec);
2516 Constant lc = left as Constant;
2518 if (lc != null && lc.Type == TypeManager.bool_type &&
2519 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2520 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2522 // FIXME: resolve right expression as unreachable
2523 // right.Resolve (ec);
2525 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2529 right = right.Resolve (ec);
2533 eclass = ExprClass.Value;
2534 Constant rc = right as Constant;
2536 // The conversion rules are ignored in enum context but why
2537 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2538 left = lc = EnumLiftUp (ec, lc, rc, loc);
2542 right = rc = EnumLiftUp (ec, rc, lc, loc);
2547 if (rc != null && lc != null) {
2548 int prev_e = Report.Errors;
2549 Expression e = ConstantFold.BinaryFold (
2550 ec, oper, lc, rc, loc);
2551 if (e != null || Report.Errors != prev_e)
2554 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2555 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2557 if ((ResolveOperator (ec)) == null) {
2558 Error_OperatorCannotBeApplied (left, right);
2563 // The result is a constant with side-effect
2565 Constant side_effect = rc == null ?
2566 new SideEffectConstant (lc, right, loc) :
2567 new SideEffectConstant (rc, left, loc);
2569 return ReducedExpression.Create (side_effect, this);
2573 // Comparison warnings
2574 if ((oper & Operator.ComparisonMask) != 0) {
2575 if (left.Equals (right)) {
2576 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2578 CheckUselessComparison (lc, right.Type);
2579 CheckUselessComparison (rc, left.Type);
2582 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2583 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2584 (left.Type.IsValueType && right is NullLiteral) ||
2585 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2586 (right.Type.IsValueType && left is NullLiteral)))
2587 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2589 return DoResolveCore (ec, left, right);
2592 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2594 Expression expr = ResolveOperator (ec);
2596 Error_OperatorCannotBeApplied (left_orig, right_orig);
2598 if (left == null || right == null)
2599 throw new InternalErrorException ("Invalid conversion");
2601 if (oper == Operator.BitwiseOr)
2602 CheckBitwiseOrOnSignExtended ();
2607 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2609 left.MutateHoistedGenericType (storey);
2610 right.MutateHoistedGenericType (storey);
2614 // D operator + (D x, D y)
2615 // D operator - (D x, D y)
2616 // bool operator == (D x, D y)
2617 // bool operator != (D x, D y)
2619 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2621 bool is_equality = (oper & Operator.EqualityMask) != 0;
2622 if (!TypeManager.IsEqual (l, r)) {
2624 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2625 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2630 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2631 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2642 // Resolve delegate equality as a user operator
2645 return ResolveUserOperator (ec, l, r);
2648 ArrayList args = new ArrayList (2);
2649 args.Add (new Argument (left, Argument.AType.Expression));
2650 args.Add (new Argument (right, Argument.AType.Expression));
2652 if (oper == Operator.Addition) {
2653 if (TypeManager.delegate_combine_delegate_delegate == null) {
2654 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2655 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2658 method = TypeManager.delegate_combine_delegate_delegate;
2660 if (TypeManager.delegate_remove_delegate_delegate == null) {
2661 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2662 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2665 method = TypeManager.delegate_remove_delegate_delegate;
2668 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2669 mg = mg.OverloadResolve (ec, ref args, false, loc);
2671 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2675 // Enumeration operators
2677 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2680 // bool operator == (E x, E y);
2681 // bool operator != (E x, E y);
2682 // bool operator < (E x, E y);
2683 // bool operator > (E x, E y);
2684 // bool operator <= (E x, E y);
2685 // bool operator >= (E x, E y);
2687 // E operator & (E x, E y);
2688 // E operator | (E x, E y);
2689 // E operator ^ (E x, E y);
2691 // U operator - (E e, E f)
2692 // E operator - (E e, U x)
2694 // E operator + (U x, E e)
2695 // E operator + (E e, U x)
2697 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2698 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2701 Expression ltemp = left;
2702 Expression rtemp = right;
2703 Type underlying_type;
2706 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2708 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2714 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2722 if (TypeManager.IsEqual (ltype, rtype)) {
2723 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2725 if (left is Constant)
2726 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2728 left = EmptyCast.Create (left, underlying_type);
2730 if (right is Constant)
2731 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2733 right = EmptyCast.Create (right, underlying_type);
2735 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2737 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2738 Constant c = right as Constant;
2739 if (c == null || !c.IsDefaultValue)
2742 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2745 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2748 if (left is Constant)
2749 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2751 left = EmptyCast.Create (left, underlying_type);
2754 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2756 if (oper != Operator.Addition) {
2757 Constant c = left as Constant;
2758 if (c == null || !c.IsDefaultValue)
2761 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2764 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2767 if (right is Constant)
2768 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2770 right = EmptyCast.Create (right, underlying_type);
2777 // C# specification uses explicit cast syntax which means binary promotion
2778 // should happen, however it seems that csc does not do that
2780 if (!DoBinaryOperatorPromotion (ec)) {
2786 Type res_type = null;
2787 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2788 Type promoted_type = lenum ? left.Type : right.Type;
2789 enum_conversion = Convert.ExplicitNumericConversion (
2790 new EmptyExpression (promoted_type), underlying_type);
2792 if (oper == Operator.Subtraction && renum && lenum)
2793 res_type = underlying_type;
2794 else if (oper == Operator.Addition && renum)
2800 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2801 if (!is_compound || expr == null)
2805 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2808 if (Convert.ImplicitConversionExists (ec, left, rtype))
2811 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2814 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2819 // 7.9.6 Reference type equality operators
2821 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2824 // operator != (object a, object b)
2825 // operator == (object a, object b)
2828 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2830 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2833 type = TypeManager.bool_type;
2834 GenericConstraints constraints;
2836 bool lgen = TypeManager.IsGenericParameter (l);
2838 if (TypeManager.IsEqual (l, r)) {
2841 // Only allow to compare same reference type parameter
2843 constraints = TypeManager.GetTypeParameterConstraints (l);
2844 if (constraints != null && constraints.IsReferenceType)
2850 if (l == TypeManager.anonymous_method_type)
2853 if (TypeManager.IsValueType (l))
2859 bool rgen = TypeManager.IsGenericParameter (r);
2862 // a, Both operands are reference-type values or the value null
2863 // b, One operand is a value of type T where T is a type-parameter and
2864 // the other operand is the value null. Furthermore T does not have the
2865 // value type constrain
2867 if (left is NullLiteral || right is NullLiteral) {
2869 constraints = TypeManager.GetTypeParameterConstraints (l);
2870 if (constraints != null && constraints.HasValueTypeConstraint)
2873 left = new BoxedCast (left, TypeManager.object_type);
2878 constraints = TypeManager.GetTypeParameterConstraints (r);
2879 if (constraints != null && constraints.HasValueTypeConstraint)
2882 right = new BoxedCast (right, TypeManager.object_type);
2888 // An interface is converted to the object before the
2889 // standard conversion is applied. It's not clear from the
2890 // standard but it looks like it works like that.
2893 constraints = TypeManager.GetTypeParameterConstraints (l);
2894 if (constraints == null || constraints.IsReferenceType)
2896 } else if (l.IsInterface) {
2897 l = TypeManager.object_type;
2898 } else if (l.IsValueType) {
2903 constraints = TypeManager.GetTypeParameterConstraints (r);
2904 if (constraints == null || constraints.IsReferenceType)
2906 } else if (r.IsInterface) {
2907 r = TypeManager.object_type;
2908 } else if (r.IsValueType) {
2913 const string ref_comparison = "Possible unintended reference comparison. " +
2914 "Consider casting the {0} side of the expression to `string' to compare the values";
2917 // A standard implicit conversion exists from the type of either
2918 // operand to the type of the other operand
2920 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2921 if (l == TypeManager.string_type)
2922 Report.Warning (253, 2, loc, ref_comparison, "right");
2927 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2928 if (r == TypeManager.string_type)
2929 Report.Warning (252, 2, loc, ref_comparison, "left");
2938 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2941 // bool operator == (void* x, void* y);
2942 // bool operator != (void* x, void* y);
2943 // bool operator < (void* x, void* y);
2944 // bool operator > (void* x, void* y);
2945 // bool operator <= (void* x, void* y);
2946 // bool operator >= (void* x, void* y);
2948 if ((oper & Operator.ComparisonMask) != 0) {
2951 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2958 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2964 type = TypeManager.bool_type;
2968 if (pointer_operators == null)
2969 CreatePointerOperatorsTable ();
2971 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2975 // Build-in operators method overloading
2977 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2979 PredefinedOperator best_operator = null;
2981 Type r = right.Type;
2982 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2984 foreach (PredefinedOperator po in operators) {
2985 if ((po.OperatorsMask & oper_mask) == 0)
2988 if (primitives_only) {
2989 if (!po.IsPrimitiveApplicable (l, r))
2992 if (!po.IsApplicable (ec, left, right))
2996 if (best_operator == null) {
2998 if (primitives_only)
3004 best_operator = po.ResolveBetterOperator (ec, best_operator);
3006 if (best_operator == null) {
3007 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3008 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3015 if (best_operator == null)
3018 Expression expr = best_operator.ConvertResult (ec, this);
3019 if (enum_type == null)
3023 // HACK: required by enum_conversion
3025 expr.Type = enum_type;
3026 return EmptyCast.Create (expr, enum_type);
3030 // Performs user-operator overloading
3032 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3035 if (oper == Operator.LogicalAnd)
3036 user_oper = Operator.BitwiseAnd;
3037 else if (oper == Operator.LogicalOr)
3038 user_oper = Operator.BitwiseOr;
3042 string op = GetOperatorMetadataName (user_oper);
3044 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3045 MethodGroupExpr right_operators = null;
3047 if (!TypeManager.IsEqual (r, l)) {
3048 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3049 if (right_operators == null && left_operators == null)
3051 } else if (left_operators == null) {
3055 ArrayList args = new ArrayList (2);
3056 Argument larg = new Argument (left);
3058 Argument rarg = new Argument (right);
3061 MethodGroupExpr union;
3064 // User-defined operator implementations always take precedence
3065 // over predefined operator implementations
3067 if (left_operators != null && right_operators != null) {
3068 if (IsPredefinedUserOperator (l, user_oper)) {
3069 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3071 union = left_operators;
3072 } else if (IsPredefinedUserOperator (r, user_oper)) {
3073 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3075 union = right_operators;
3077 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3079 } else if (left_operators != null) {
3080 union = left_operators;
3082 union = right_operators;
3085 union = union.OverloadResolve (ec, ref args, true, loc);
3089 Expression oper_expr;
3091 // TODO: CreateExpressionTree is allocated every time
3092 if (user_oper != oper) {
3093 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3094 oper == Operator.LogicalAnd, loc).Resolve (ec);
3096 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3099 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3100 // and not invoke user operator
3102 if ((oper & Operator.EqualityMask) != 0) {
3103 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3104 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3105 type = TypeManager.bool_type;
3106 if (left is NullLiteral || right is NullLiteral)
3107 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3108 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3110 // Two System.Delegate(s) are never equal
3122 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3127 private void CheckUselessComparison (Constant c, Type type)
3129 if (c == null || !IsTypeIntegral (type)
3130 || c is StringConstant
3131 || c is BoolConstant
3132 || c is FloatConstant
3133 || c is DoubleConstant
3134 || c is DecimalConstant
3140 if (c is ULongConstant) {
3141 ulong uvalue = ((ULongConstant) c).Value;
3142 if (uvalue > long.MaxValue) {
3143 if (type == TypeManager.byte_type ||
3144 type == TypeManager.sbyte_type ||
3145 type == TypeManager.short_type ||
3146 type == TypeManager.ushort_type ||
3147 type == TypeManager.int32_type ||
3148 type == TypeManager.uint32_type ||
3149 type == TypeManager.int64_type ||
3150 type == TypeManager.char_type)
3151 WarnUselessComparison (type);
3154 value = (long) uvalue;
3156 else if (c is ByteConstant)
3157 value = ((ByteConstant) c).Value;
3158 else if (c is SByteConstant)
3159 value = ((SByteConstant) c).Value;
3160 else if (c is ShortConstant)
3161 value = ((ShortConstant) c).Value;
3162 else if (c is UShortConstant)
3163 value = ((UShortConstant) c).Value;
3164 else if (c is IntConstant)
3165 value = ((IntConstant) c).Value;
3166 else if (c is UIntConstant)
3167 value = ((UIntConstant) c).Value;
3168 else if (c is LongConstant)
3169 value = ((LongConstant) c).Value;
3170 else if (c is CharConstant)
3171 value = ((CharConstant)c).Value;
3176 if (IsValueOutOfRange (value, type))
3177 WarnUselessComparison (type);
3180 static bool IsValueOutOfRange (long value, Type type)
3182 if (IsTypeUnsigned (type) && value < 0)
3184 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3185 type == TypeManager.byte_type && value >= 0x100 ||
3186 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3187 type == TypeManager.ushort_type && value >= 0x10000 ||
3188 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3189 type == TypeManager.uint32_type && value >= 0x100000000;
3192 static bool IsBuildInEqualityOperator (Type t)
3194 return t == TypeManager.object_type || t == TypeManager.string_type ||
3195 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3198 static bool IsPredefinedUserOperator (Type t, Operator op)
3201 // Some predefined types have user operators
3203 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3206 private static bool IsTypeIntegral (Type type)
3208 return type == TypeManager.uint64_type ||
3209 type == TypeManager.int64_type ||
3210 type == TypeManager.uint32_type ||
3211 type == TypeManager.int32_type ||
3212 type == TypeManager.ushort_type ||
3213 type == TypeManager.short_type ||
3214 type == TypeManager.sbyte_type ||
3215 type == TypeManager.byte_type ||
3216 type == TypeManager.char_type;
3219 private static bool IsTypeUnsigned (Type type)
3221 return type == TypeManager.uint64_type ||
3222 type == TypeManager.uint32_type ||
3223 type == TypeManager.ushort_type ||
3224 type == TypeManager.byte_type ||
3225 type == TypeManager.char_type;
3228 private void WarnUselessComparison (Type type)
3230 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}'",
3231 TypeManager.CSharpName (type));
3235 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3236 /// context of a conditional bool expression. This function will return
3237 /// false if it is was possible to use EmitBranchable, or true if it was.
3239 /// The expression's code is generated, and we will generate a branch to `target'
3240 /// if the resulting expression value is equal to isTrue
3242 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3244 ILGenerator ig = ec.ig;
3247 // This is more complicated than it looks, but its just to avoid
3248 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3249 // but on top of that we want for == and != to use a special path
3250 // if we are comparing against null
3252 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3253 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3256 // put the constant on the rhs, for simplicity
3258 if (left is Constant) {
3259 Expression swap = right;
3264 if (((Constant) right).IsZeroInteger) {
3265 left.EmitBranchable (ec, target, my_on_true);
3268 if (right.Type == TypeManager.bool_type) {
3269 // right is a boolean, and it's not 'false' => it is 'true'
3270 left.EmitBranchable (ec, target, !my_on_true);
3274 } else if (oper == Operator.LogicalAnd) {
3277 Label tests_end = ig.DefineLabel ();
3279 left.EmitBranchable (ec, tests_end, false);
3280 right.EmitBranchable (ec, target, true);
3281 ig.MarkLabel (tests_end);
3284 // This optimizes code like this
3285 // if (true && i > 4)
3287 if (!(left is Constant))
3288 left.EmitBranchable (ec, target, false);
3290 if (!(right is Constant))
3291 right.EmitBranchable (ec, target, false);
3296 } else if (oper == Operator.LogicalOr){
3298 left.EmitBranchable (ec, target, true);
3299 right.EmitBranchable (ec, target, true);
3302 Label tests_end = ig.DefineLabel ();
3303 left.EmitBranchable (ec, tests_end, true);
3304 right.EmitBranchable (ec, target, false);
3305 ig.MarkLabel (tests_end);
3310 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3311 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3312 oper == Operator.Equality || oper == Operator.Inequality)) {
3313 base.EmitBranchable (ec, target, on_true);
3321 bool is_float = IsFloat (t);
3322 bool is_unsigned = is_float || IsUnsigned (t);
3325 case Operator.Equality:
3327 ig.Emit (OpCodes.Beq, target);
3329 ig.Emit (OpCodes.Bne_Un, target);
3332 case Operator.Inequality:
3334 ig.Emit (OpCodes.Bne_Un, target);
3336 ig.Emit (OpCodes.Beq, target);
3339 case Operator.LessThan:
3341 if (is_unsigned && !is_float)
3342 ig.Emit (OpCodes.Blt_Un, target);
3344 ig.Emit (OpCodes.Blt, target);
3347 ig.Emit (OpCodes.Bge_Un, target);
3349 ig.Emit (OpCodes.Bge, target);
3352 case Operator.GreaterThan:
3354 if (is_unsigned && !is_float)
3355 ig.Emit (OpCodes.Bgt_Un, target);
3357 ig.Emit (OpCodes.Bgt, target);
3360 ig.Emit (OpCodes.Ble_Un, target);
3362 ig.Emit (OpCodes.Ble, target);
3365 case Operator.LessThanOrEqual:
3367 if (is_unsigned && !is_float)
3368 ig.Emit (OpCodes.Ble_Un, target);
3370 ig.Emit (OpCodes.Ble, target);
3373 ig.Emit (OpCodes.Bgt_Un, target);
3375 ig.Emit (OpCodes.Bgt, target);
3379 case Operator.GreaterThanOrEqual:
3381 if (is_unsigned && !is_float)
3382 ig.Emit (OpCodes.Bge_Un, target);
3384 ig.Emit (OpCodes.Bge, target);
3387 ig.Emit (OpCodes.Blt_Un, target);
3389 ig.Emit (OpCodes.Blt, target);
3392 throw new InternalErrorException (oper.ToString ());
3396 public override void Emit (EmitContext ec)
3398 EmitOperator (ec, left.Type);
3401 protected virtual void EmitOperator (EmitContext ec, Type l)
3403 ILGenerator ig = ec.ig;
3406 // Handle short-circuit operators differently
3409 if ((oper & Operator.LogicalMask) != 0) {
3410 Label load_result = ig.DefineLabel ();
3411 Label end = ig.DefineLabel ();
3413 bool is_or = oper == Operator.LogicalOr;
3414 left.EmitBranchable (ec, load_result, is_or);
3416 ig.Emit (OpCodes.Br_S, end);
3418 ig.MarkLabel (load_result);
3419 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3427 // Optimize zero-based operations
3429 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3431 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3432 Constant rc = right as Constant;
3433 if (rc != null && rc.IsDefaultValue) {
3439 EmitOperatorOpcode (ec, oper, l);
3442 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3443 // expression because that would wrap lifted binary operation
3445 if (enum_conversion != null)
3446 enum_conversion.Emit (ec);
3449 public override void EmitSideEffect (EmitContext ec)
3451 if ((oper & Operator.LogicalMask) != 0 ||
3452 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3453 base.EmitSideEffect (ec);
3455 left.EmitSideEffect (ec);
3456 right.EmitSideEffect (ec);
3460 protected override void CloneTo (CloneContext clonectx, Expression t)
3462 Binary target = (Binary) t;
3464 target.left = left.Clone (clonectx);
3465 target.right = right.Clone (clonectx);
3468 public override Expression CreateExpressionTree (EmitContext ec)
3470 return CreateExpressionTree (ec, null);
3473 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3476 bool lift_arg = false;
3479 case Operator.Addition:
3480 if (method == null && ec.CheckState && !IsFloat (type))
3481 method_name = "AddChecked";
3483 method_name = "Add";
3485 case Operator.BitwiseAnd:
3486 method_name = "And";
3488 case Operator.BitwiseOr:
3491 case Operator.Division:
3492 method_name = "Divide";
3494 case Operator.Equality:
3495 method_name = "Equal";
3498 case Operator.ExclusiveOr:
3499 method_name = "ExclusiveOr";
3501 case Operator.GreaterThan:
3502 method_name = "GreaterThan";
3505 case Operator.GreaterThanOrEqual:
3506 method_name = "GreaterThanOrEqual";
3509 case Operator.Inequality:
3510 method_name = "NotEqual";
3513 case Operator.LeftShift:
3514 method_name = "LeftShift";
3516 case Operator.LessThan:
3517 method_name = "LessThan";
3520 case Operator.LessThanOrEqual:
3521 method_name = "LessThanOrEqual";
3524 case Operator.LogicalAnd:
3525 method_name = "AndAlso";
3527 case Operator.LogicalOr:
3528 method_name = "OrElse";
3530 case Operator.Modulus:
3531 method_name = "Modulo";
3533 case Operator.Multiply:
3534 if (method == null && ec.CheckState && !IsFloat (type))
3535 method_name = "MultiplyChecked";
3537 method_name = "Multiply";
3539 case Operator.RightShift:
3540 method_name = "RightShift";
3542 case Operator.Subtraction:
3543 if (method == null && ec.CheckState && !IsFloat (type))
3544 method_name = "SubtractChecked";
3546 method_name = "Subtract";
3550 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3553 ArrayList args = new ArrayList (2);
3554 args.Add (new Argument (left.CreateExpressionTree (ec)));
3555 args.Add (new Argument (right.CreateExpressionTree (ec)));
3556 if (method != null) {
3558 args.Add (new Argument (new BoolConstant (false, loc)));
3560 args.Add (new Argument (method.CreateExpressionTree (ec)));
3563 return CreateExpressionFactoryCall (method_name, args);
3568 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3569 // b, c, d... may be strings or objects.
3571 public class StringConcat : Expression {
3572 ArrayList arguments;
3574 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3577 type = TypeManager.string_type;
3578 eclass = ExprClass.Value;
3580 arguments = new ArrayList (2);
3585 public override Expression CreateExpressionTree (EmitContext ec)
3587 Argument arg = (Argument) arguments [0];
3588 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3592 // Creates nested calls tree from an array of arguments used for IL emit
3594 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3596 ArrayList concat_args = new ArrayList (2);
3597 ArrayList add_args = new ArrayList (3);
3599 concat_args.Add (left);
3600 add_args.Add (new Argument (left_etree));
3602 concat_args.Add (arguments [pos]);
3603 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3605 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3609 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3613 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3615 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3616 if (++pos == arguments.Count)
3619 left = new Argument (new EmptyExpression (method.Type));
3620 return CreateExpressionAddCall (ec, left, expr, pos);
3623 public override Expression DoResolve (EmitContext ec)
3628 public void Append (EmitContext ec, Expression operand)
3633 StringConstant sc = operand as StringConstant;
3635 if (arguments.Count != 0) {
3636 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3637 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3638 if (last_expr_constant != null) {
3639 last_argument.Expr = new StringConstant (
3640 last_expr_constant.Value + sc.Value, sc.Location);
3646 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3648 StringConcat concat_oper = operand as StringConcat;
3649 if (concat_oper != null) {
3650 arguments.AddRange (concat_oper.arguments);
3655 arguments.Add (new Argument (operand));
3658 Expression CreateConcatMemberExpression ()
3660 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3663 public override void Emit (EmitContext ec)
3665 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3666 concat = concat.Resolve (ec);
3671 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3673 foreach (Argument a in arguments)
3674 a.Expr.MutateHoistedGenericType (storey);
3679 // User-defined conditional logical operator
3681 public class ConditionalLogicalOperator : UserOperatorCall {
3682 readonly bool is_and;
3685 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3686 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3687 : base (oper_method, arguments, expr_tree, loc)
3689 this.is_and = is_and;
3692 public override Expression DoResolve (EmitContext ec)
3694 MethodInfo method = (MethodInfo)mg;
3695 type = TypeManager.TypeToCoreType (method.ReturnType);
3696 AParametersCollection pd = TypeManager.GetParameterData (method);
3697 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3698 Report.Error (217, loc,
3699 "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",
3700 TypeManager.CSharpSignature (method));
3704 Expression left_dup = new EmptyExpression (type);
3705 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3706 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3707 if (op_true == null || op_false == null) {
3708 Report.Error (218, loc,
3709 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3710 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3714 oper = is_and ? op_false : op_true;
3715 eclass = ExprClass.Value;
3719 public override void Emit (EmitContext ec)
3721 ILGenerator ig = ec.ig;
3722 Label end_target = ig.DefineLabel ();
3725 // Emit and duplicate left argument
3727 ((Argument)arguments [0]).Expr.Emit (ec);
3728 ig.Emit (OpCodes.Dup);
3729 arguments.RemoveAt (0);
3731 oper.EmitBranchable (ec, end_target, true);
3733 ig.MarkLabel (end_target);
3737 public class PointerArithmetic : Expression {
3738 Expression left, right;
3742 // We assume that `l' is always a pointer
3744 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3753 public override Expression CreateExpressionTree (EmitContext ec)
3755 Error_PointerInsideExpressionTree ();
3759 public override Expression DoResolve (EmitContext ec)
3761 eclass = ExprClass.Variable;
3763 if (left.Type == TypeManager.void_ptr_type) {
3764 Error (242, "The operation in question is undefined on void pointers");
3771 public override void Emit (EmitContext ec)
3773 Type op_type = left.Type;
3774 ILGenerator ig = ec.ig;
3776 // It must be either array or fixed buffer
3778 if (TypeManager.HasElementType (op_type)) {
3779 element = TypeManager.GetElementType (op_type);
3781 FieldExpr fe = left as FieldExpr;
3783 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3788 int size = GetTypeSize (element);
3789 Type rtype = right.Type;
3791 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3793 // handle (pointer - pointer)
3797 ig.Emit (OpCodes.Sub);
3801 ig.Emit (OpCodes.Sizeof, element);
3803 IntLiteral.EmitInt (ig, size);
3804 ig.Emit (OpCodes.Div);
3806 ig.Emit (OpCodes.Conv_I8);
3809 // handle + and - on (pointer op int)
3811 Constant left_const = left as Constant;
3812 if (left_const != null) {
3814 // Optimize ((T*)null) pointer operations
3816 if (left_const.IsDefaultValue) {
3817 left = EmptyExpression.Null;
3825 Constant right_const = right as Constant;
3826 if (right_const != null) {
3828 // Optimize 0-based arithmetic
3830 if (right_const.IsDefaultValue)
3834 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3838 ig.Emit (OpCodes.Sizeof, element);
3839 right = EmptyExpression.Null;
3844 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3845 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3846 ig.Emit (OpCodes.Conv_I);
3847 } else if (rtype == TypeManager.uint32_type) {
3848 ig.Emit (OpCodes.Conv_U);
3851 if (right_const == null && size != 1){
3853 ig.Emit (OpCodes.Sizeof, element);
3855 IntLiteral.EmitInt (ig, size);
3856 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3857 ig.Emit (OpCodes.Conv_I8);
3859 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3862 if (left_const == null) {
3863 if (rtype == TypeManager.int64_type)
3864 ig.Emit (OpCodes.Conv_I);
3865 else if (rtype == TypeManager.uint64_type)
3866 ig.Emit (OpCodes.Conv_U);
3868 Binary.EmitOperatorOpcode (ec, op, op_type);
3875 /// Implements the ternary conditional operator (?:)
3877 public class Conditional : Expression {
3878 Expression expr, true_expr, false_expr;
3880 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3883 this.true_expr = true_expr;
3884 this.false_expr = false_expr;
3885 this.loc = expr.Location;
3888 public Expression Expr {
3894 public Expression TrueExpr {
3900 public Expression FalseExpr {
3906 public override Expression CreateExpressionTree (EmitContext ec)
3908 ArrayList args = new ArrayList (3);
3909 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3910 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3911 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3912 return CreateExpressionFactoryCall ("Condition", args);
3915 public override Expression DoResolve (EmitContext ec)
3917 expr = expr.Resolve (ec);
3922 if (expr.Type != TypeManager.bool_type){
3923 expr = Expression.ResolveBoolean (
3930 Assign ass = expr as Assign;
3931 if (ass != null && ass.Source is Constant) {
3932 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3935 true_expr = true_expr.Resolve (ec);
3936 false_expr = false_expr.Resolve (ec);
3938 if (true_expr == null || false_expr == null)
3941 eclass = ExprClass.Value;
3942 Type true_type = true_expr.Type;
3943 Type false_type = false_expr.Type;
3947 // First, if an implicit conversion exists from true_expr
3948 // to false_expr, then the result type is of type false_expr.Type
3950 if (!TypeManager.IsEqual (true_type, false_type)) {
3951 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3954 // Check if both can convert implicitl to each other's type
3956 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3958 "Can not compute type of conditional expression " +
3959 "as `" + TypeManager.CSharpName (true_expr.Type) +
3960 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3961 "' convert implicitly to each other");
3966 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3969 Report.Error (173, loc,
3970 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3971 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3976 // Dead code optimalization
3977 Constant c = expr as Constant;
3979 bool is_false = c.IsDefaultValue;
3980 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3981 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3987 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3989 expr.MutateHoistedGenericType (storey);
3990 true_expr.MutateHoistedGenericType (storey);
3991 false_expr.MutateHoistedGenericType (storey);
3992 type = storey.MutateType (type);
3995 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
4000 public override void Emit (EmitContext ec)
4002 ILGenerator ig = ec.ig;
4003 Label false_target = ig.DefineLabel ();
4004 Label end_target = ig.DefineLabel ();
4006 expr.EmitBranchable (ec, false_target, false);
4007 true_expr.Emit (ec);
4009 if (type.IsInterface) {
4010 LocalBuilder temp = ec.GetTemporaryLocal (type);
4011 ig.Emit (OpCodes.Stloc, temp);
4012 ig.Emit (OpCodes.Ldloc, temp);
4013 ec.FreeTemporaryLocal (temp, type);
4016 ig.Emit (OpCodes.Br, end_target);
4017 ig.MarkLabel (false_target);
4018 false_expr.Emit (ec);
4019 ig.MarkLabel (end_target);
4022 protected override void CloneTo (CloneContext clonectx, Expression t)
4024 Conditional target = (Conditional) t;
4026 target.expr = expr.Clone (clonectx);
4027 target.true_expr = true_expr.Clone (clonectx);
4028 target.false_expr = false_expr.Clone (clonectx);
4032 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4033 LocalTemporary temp;
4036 public abstract HoistedVariable HoistedVariable { get; }
4037 public abstract bool IsFixed { get; }
4038 public abstract bool IsRef { get; }
4039 public abstract string Name { get; }
4040 public abstract void SetHasAddressTaken ();
4043 // Variable IL data, it has to be protected to encapsulate hoisted variables
4045 protected abstract ILocalVariable Variable { get; }
4048 // Variable flow-analysis data
4050 public abstract VariableInfo VariableInfo { get; }
4053 public void AddressOf (EmitContext ec, AddressOp mode)
4055 if (IsHoistedEmitRequired (ec)) {
4056 HoistedVariable.AddressOf (ec, mode);
4060 Variable.EmitAddressOf (ec);
4063 public override void Emit (EmitContext ec)
4068 public override void EmitSideEffect (EmitContext ec)
4074 // This method is used by parameters that are references, that are
4075 // being passed as references: we only want to pass the pointer (that
4076 // is already stored in the parameter, not the address of the pointer,
4077 // and not the value of the variable).
4079 public void EmitLoad (EmitContext ec)
4084 public void Emit (EmitContext ec, bool leave_copy)
4086 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4088 if (IsHoistedEmitRequired (ec)) {
4089 HoistedVariable.Emit (ec, leave_copy);
4097 // If we are a reference, we loaded on the stack a pointer
4098 // Now lets load the real value
4100 LoadFromPtr (ec.ig, type);
4104 ec.ig.Emit (OpCodes.Dup);
4107 temp = new LocalTemporary (Type);
4113 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4114 bool prepare_for_load)
4116 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4119 if (IsHoistedEmitRequired (ec)) {
4120 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4129 // HACK: variable is already emitted when source is an initializer
4130 if (source is NewInitialize) {
4138 ec.ig.Emit (OpCodes.Dup);
4140 temp = new LocalTemporary (Type);
4146 StoreFromPtr (ec.ig, type);
4148 Variable.EmitAssign (ec);
4156 public bool IsHoisted {
4157 get { return HoistedVariable != null; }
4160 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4163 // Default implementation return true when there is a hosted variable
4165 return HoistedVariable != null;
4168 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4170 type = storey.MutateType (type);
4177 public class LocalVariableReference : VariableReference {
4178 readonly string name;
4180 public LocalInfo local_info;
4183 public LocalVariableReference (Block block, string name, Location l)
4188 eclass = ExprClass.Variable;
4192 // Setting `is_readonly' to false will allow you to create a writable
4193 // reference to a read-only variable. This is used by foreach and using.
4195 public LocalVariableReference (Block block, string name, Location l,
4196 LocalInfo local_info, bool is_readonly)
4197 : this (block, name, l)
4199 this.local_info = local_info;
4200 this.is_readonly = is_readonly;
4203 public override VariableInfo VariableInfo {
4204 get { return local_info.VariableInfo; }
4207 public override HoistedVariable HoistedVariable {
4208 get { return local_info.HoistedVariableReference; }
4212 // A local variable is always fixed
4214 public override bool IsFixed {
4215 get { return true; }
4218 public override bool IsRef {
4219 get { return false; }
4222 public bool IsReadOnly {
4223 get { return is_readonly; }
4226 public override string Name {
4227 get { return name; }
4230 public bool VerifyAssigned (EmitContext ec)
4232 VariableInfo variable_info = local_info.VariableInfo;
4233 return variable_info == null || variable_info.IsAssigned (ec, loc);
4236 void ResolveLocalInfo ()
4238 if (local_info == null) {
4239 local_info = Block.GetLocalInfo (Name);
4240 type = local_info.VariableType;
4241 is_readonly = local_info.ReadOnly;
4245 public override void SetHasAddressTaken ()
4247 local_info.AddressTaken = true;
4250 public override Expression CreateExpressionTree (EmitContext ec)
4252 ArrayList arg = new ArrayList (1);
4253 arg.Add (new Argument (this));
4254 return CreateExpressionFactoryCall ("Constant", arg);
4257 Expression DoResolveBase (EmitContext ec)
4259 type = local_info.VariableType;
4261 Expression e = Block.GetConstantExpression (Name);
4263 return e.Resolve (ec);
4265 VerifyAssigned (ec);
4268 // If we are referencing a variable from the external block
4269 // flag it for capturing
4271 if (ec.MustCaptureVariable (local_info)) {
4272 if (local_info.AddressTaken)
4273 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4275 if (ec.IsVariableCapturingRequired) {
4276 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4277 storey.CaptureLocalVariable (ec, local_info);
4284 public override Expression DoResolve (EmitContext ec)
4286 ResolveLocalInfo ();
4287 local_info.Used = true;
4289 if (type == null && local_info.Type is VarExpr) {
4290 local_info.VariableType = TypeManager.object_type;
4291 Error_VariableIsUsedBeforeItIsDeclared (Name);
4295 return DoResolveBase (ec);
4298 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4300 ResolveLocalInfo ();
4303 if (right_side == EmptyExpression.OutAccess)
4304 local_info.Used = true;
4306 // Infer implicitly typed local variable
4308 VarExpr ve = local_info.Type as VarExpr;
4310 if (!ve.InferType (ec, right_side))
4312 type = local_info.VariableType = ve.Type;
4319 if (right_side == EmptyExpression.OutAccess) {
4320 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4321 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4322 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4323 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4324 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4325 } else if (right_side == EmptyExpression.UnaryAddress) {
4326 code = 459; msg = "Cannot take the address of {1} `{0}'";
4328 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4330 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4331 } else if (VariableInfo != null) {
4332 VariableInfo.SetAssigned (ec);
4335 return DoResolveBase (ec);
4338 public override int GetHashCode ()
4340 return Name.GetHashCode ();
4343 public override bool Equals (object obj)
4345 LocalVariableReference lvr = obj as LocalVariableReference;
4349 return Name == lvr.Name && Block == lvr.Block;
4352 protected override ILocalVariable Variable {
4353 get { return local_info; }
4356 public override string ToString ()
4358 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4361 protected override void CloneTo (CloneContext clonectx, Expression t)
4363 LocalVariableReference target = (LocalVariableReference) t;
4365 target.Block = clonectx.LookupBlock (Block);
4366 if (local_info != null)
4367 target.local_info = clonectx.LookupVariable (local_info);
4372 /// This represents a reference to a parameter in the intermediate
4375 public class ParameterReference : VariableReference {
4376 readonly ToplevelParameterInfo pi;
4377 readonly ToplevelBlock referenced;
4379 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4382 this.referenced = referenced;
4386 public override bool IsRef {
4387 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4390 bool HasOutModifier {
4391 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4394 public override HoistedVariable HoistedVariable {
4395 get { return pi.Parameter.HoistedVariableReference; }
4399 // A ref or out parameter is classified as a moveable variable, even
4400 // if the argument given for the parameter is a fixed variable
4402 public override bool IsFixed {
4403 get { return !IsRef; }
4406 public override string Name {
4407 get { return Parameter.Name; }
4410 public Parameter Parameter {
4411 get { return pi.Parameter; }
4414 public override VariableInfo VariableInfo {
4415 get { return pi.VariableInfo; }
4418 protected override ILocalVariable Variable {
4419 get { return Parameter; }
4422 public bool IsAssigned (EmitContext ec, Location loc)
4424 // HACK: Variables are not captured in probing mode
4425 if (ec.IsInProbingMode)
4428 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4431 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4435 public override void SetHasAddressTaken ()
4437 Parameter.HasAddressTaken = true;
4440 void SetAssigned (EmitContext ec)
4442 if (HasOutModifier && ec.DoFlowAnalysis)
4443 ec.CurrentBranching.SetAssigned (VariableInfo);
4446 bool DoResolveBase (EmitContext ec)
4448 type = pi.ParameterType;
4449 eclass = ExprClass.Variable;
4451 AnonymousExpression am = ec.CurrentAnonymousMethod;
4455 ToplevelBlock declared = pi.Block;
4456 if (declared != referenced) {
4458 Report.Error (1628, loc,
4459 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4460 Name, am.ContainerType);
4468 if (ec.IsVariableCapturingRequired) {
4469 if (pi.Parameter.HasAddressTaken)
4470 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4472 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4473 storey.CaptureParameter (ec, this);
4479 public override int GetHashCode ()
4481 return Name.GetHashCode ();
4484 public override bool Equals (object obj)
4486 ParameterReference pr = obj as ParameterReference;
4490 return Name == pr.Name && referenced == pr.referenced;
4493 protected override void CloneTo (CloneContext clonectx, Expression target)
4498 public override Expression CreateExpressionTree (EmitContext ec)
4500 if (IsHoistedEmitRequired (ec))
4501 return HoistedVariable.CreateExpressionTree (ec);
4503 return Parameter.ExpressionTreeVariableReference ();
4507 // Notice that for ref/out parameters, the type exposed is not the
4508 // same type exposed externally.
4511 // externally we expose "int&"
4512 // here we expose "int".
4514 // We record this in "is_ref". This means that the type system can treat
4515 // the type as it is expected, but when we generate the code, we generate
4516 // the alternate kind of code.
4518 public override Expression DoResolve (EmitContext ec)
4520 if (!DoResolveBase (ec))
4523 if (HasOutModifier && ec.DoFlowAnalysis &&
4524 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4530 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4532 if (!DoResolveBase (ec))
4535 // HACK: parameters are not captured when probing is on
4536 if (!ec.IsInProbingMode)
4542 static public void EmitLdArg (ILGenerator ig, int x)
4546 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4547 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4548 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4549 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4550 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4553 ig.Emit (OpCodes.Ldarg, x);
4558 /// Used for arguments to New(), Invocation()
4560 public class Argument {
4561 public enum AType : byte {
4568 public static readonly Argument[] Empty = new Argument [0];
4570 public readonly AType ArgType;
4571 public Expression Expr;
4573 public Argument (Expression expr, AType type)
4576 this.ArgType = type;
4579 public Argument (Expression expr)
4582 this.ArgType = AType.Expression;
4586 get { return Expr.Type; }
4589 public Parameter.Modifier Modifier
4594 return Parameter.Modifier.OUT;
4597 return Parameter.Modifier.REF;
4600 return Parameter.Modifier.NONE;
4605 public string GetSignatureForError ()
4607 if (Expr.eclass == ExprClass.MethodGroup)
4608 return Expr.ExprClassName;
4610 return TypeManager.CSharpName (Expr.Type);
4613 public bool ResolveMethodGroup (EmitContext ec)
4615 SimpleName sn = Expr as SimpleName;
4617 Expr = sn.GetMethodGroup ();
4619 // FIXME: csc doesn't report any error if you try to use `ref' or
4620 // `out' in a delegate creation expression.
4621 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4628 public bool Resolve (EmitContext ec, Location loc)
4633 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4634 // Verify that the argument is readable
4635 if (ArgType != AType.Out)
4636 Expr = Expr.Resolve (ec);
4638 // Verify that the argument is writeable
4639 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4640 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4642 return Expr != null;
4646 public void Emit (EmitContext ec)
4648 if (ArgType != AType.Ref && ArgType != AType.Out) {
4653 AddressOp mode = AddressOp.Store;
4654 if (ArgType == AType.Ref)
4655 mode |= AddressOp.Load;
4657 IMemoryLocation ml = (IMemoryLocation) Expr;
4658 ParameterReference pr = ml as ParameterReference;
4661 // ParameterReferences might already be references, so we want
4662 // to pass just the value
4664 if (pr != null && pr.IsRef)
4667 ml.AddressOf (ec, mode);
4670 public Argument Clone (CloneContext clonectx)
4672 return new Argument (Expr.Clone (clonectx), ArgType);
4677 /// Invocation of methods or delegates.
4679 public class Invocation : ExpressionStatement {
4680 protected ArrayList Arguments;
4681 protected Expression expr;
4682 protected MethodGroupExpr mg;
4683 bool arguments_resolved;
4686 // arguments is an ArrayList, but we do not want to typecast,
4687 // as it might be null.
4689 public Invocation (Expression expr, ArrayList arguments)
4691 SimpleName sn = expr as SimpleName;
4693 this.expr = sn.GetMethodGroup ();
4697 Arguments = arguments;
4699 loc = expr.Location;
4702 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4703 : this (expr, arguments)
4705 this.arguments_resolved = arguments_resolved;
4708 public override Expression CreateExpressionTree (EmitContext ec)
4713 // Special conversion for nested expression trees
4715 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4716 args = new ArrayList (1);
4717 args.Add (new Argument (this));
4718 return CreateExpressionFactoryCall ("Quote", args);
4721 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4723 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4726 args = new ArrayList (arg_count);
4729 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4731 args.Add (new Argument (new NullLiteral (loc)));
4733 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4736 // Use extension argument when exists
4739 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4741 args.Add (new Argument (e));
4744 if (Arguments != null) {
4745 foreach (Argument a in Arguments) {
4746 Expression e = a.Expr.CreateExpressionTree (ec);
4748 args.Add (new Argument (e));
4753 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4755 return CreateExpressionFactoryCall ("Call", args);
4758 public override Expression DoResolve (EmitContext ec)
4760 // Don't resolve already resolved expression
4761 if (eclass != ExprClass.Invalid)
4764 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4765 if (expr_resolved == null)
4768 mg = expr_resolved as MethodGroupExpr;
4770 Type expr_type = expr_resolved.Type;
4772 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4773 return (new DelegateInvocation (
4774 expr_resolved, Arguments, loc)).Resolve (ec);
4777 MemberExpr me = expr_resolved as MemberExpr;
4779 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4783 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4785 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4786 expr_resolved.GetSignatureForError ());
4790 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4794 // Next, evaluate all the expressions in the argument list
4796 if (Arguments != null && !arguments_resolved) {
4797 for (int i = 0; i < Arguments.Count; ++i)
4799 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4804 mg = DoResolveOverload (ec);
4808 MethodInfo method = (MethodInfo)mg;
4809 if (method != null) {
4810 type = TypeManager.TypeToCoreType (method.ReturnType);
4812 // TODO: this is a copy of mg.ResolveMemberAccess method
4813 Expression iexpr = mg.InstanceExpression;
4814 if (method.IsStatic) {
4815 if (iexpr == null ||
4816 iexpr is This || iexpr is EmptyExpression ||
4817 mg.IdenticalTypeName) {
4818 mg.InstanceExpression = null;
4820 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4824 if (iexpr == null) {
4825 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4830 if (type.IsPointer){
4838 // Only base will allow this invocation to happen.
4840 if (mg.IsBase && method.IsAbstract){
4841 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4845 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4847 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4849 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4853 IsSpecialMethodInvocation (method, loc);
4855 if (mg.InstanceExpression != null)
4856 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4858 eclass = ExprClass.Value;
4862 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4864 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4867 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4869 if (!TypeManager.IsSpecialMethod (method))
4872 Report.SymbolRelatedToPreviousError (method);
4873 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4874 TypeManager.CSharpSignature (method, true));
4880 /// Emits a list of resolved Arguments that are in the arguments
4883 /// The MethodBase argument might be null if the
4884 /// emission of the arguments is known not to contain
4885 /// a `params' field (for example in constructors or other routines
4886 /// that keep their arguments in this structure)
4888 /// if `dup_args' is true, a copy of the arguments will be left
4889 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4890 /// which will be duplicated before any other args. Only EmitCall
4891 /// should be using this interface.
4893 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4895 if (arguments == null)
4898 int top = arguments.Count;
4899 LocalTemporary [] temps = null;
4901 if (dup_args && top != 0)
4902 temps = new LocalTemporary [top];
4904 int argument_index = 0;
4906 for (int i = 0; i < top; i++) {
4907 a = (Argument) arguments [argument_index++];
4910 ec.ig.Emit (OpCodes.Dup);
4911 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4916 if (this_arg != null)
4919 for (int i = 0; i < top; i ++) {
4920 temps [i].Emit (ec);
4921 temps [i].Release (ec);
4926 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4928 AParametersCollection pd = TypeManager.GetParameterData (mb);
4930 Argument a = (Argument) arguments [pd.Count - 1];
4931 Arglist list = (Arglist) a.Expr;
4933 return list.ArgumentTypes;
4937 /// This checks the ConditionalAttribute on the method
4939 public static bool IsMethodExcluded (MethodBase method, Location loc)
4941 if (method.IsConstructor)
4944 method = TypeManager.DropGenericMethodArguments (method);
4945 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4946 IMethodData md = TypeManager.GetMethod (method);
4948 return md.IsExcluded ();
4950 // For some methods (generated by delegate class) GetMethod returns null
4951 // because they are not included in builder_to_method table
4955 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4959 /// is_base tells whether we want to force the use of the `call'
4960 /// opcode instead of using callvirt. Call is required to call
4961 /// a specific method, while callvirt will always use the most
4962 /// recent method in the vtable.
4964 /// is_static tells whether this is an invocation on a static method
4966 /// instance_expr is an expression that represents the instance
4967 /// it must be non-null if is_static is false.
4969 /// method is the method to invoke.
4971 /// Arguments is the list of arguments to pass to the method or constructor.
4973 public static void EmitCall (EmitContext ec, bool is_base,
4974 Expression instance_expr,
4975 MethodBase method, ArrayList Arguments, Location loc)
4977 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4980 // `dup_args' leaves an extra copy of the arguments on the stack
4981 // `omit_args' does not leave any arguments at all.
4982 // So, basically, you could make one call with `dup_args' set to true,
4983 // and then another with `omit_args' set to true, and the two calls
4984 // would have the same set of arguments. However, each argument would
4985 // only have been evaluated once.
4986 public static void EmitCall (EmitContext ec, bool is_base,
4987 Expression instance_expr,
4988 MethodBase method, ArrayList Arguments, Location loc,
4989 bool dup_args, bool omit_args)
4991 ILGenerator ig = ec.ig;
4992 bool struct_call = false;
4993 bool this_call = false;
4994 LocalTemporary this_arg = null;
4996 Type decl_type = method.DeclaringType;
4998 if (IsMethodExcluded (method, loc))
5001 bool is_static = method.IsStatic;
5003 this_call = instance_expr is This;
5004 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5008 // If this is ourselves, push "this"
5012 Type iexpr_type = instance_expr.Type;
5015 // Push the instance expression
5017 if (TypeManager.IsValueType (iexpr_type)) {
5019 // Special case: calls to a function declared in a
5020 // reference-type with a value-type argument need
5021 // to have their value boxed.
5022 if (decl_type.IsValueType ||
5023 TypeManager.IsGenericParameter (iexpr_type)) {
5025 // If the expression implements IMemoryLocation, then
5026 // we can optimize and use AddressOf on the
5029 // If not we have to use some temporary storage for
5031 if (instance_expr is IMemoryLocation) {
5032 ((IMemoryLocation)instance_expr).
5033 AddressOf (ec, AddressOp.LoadStore);
5035 LocalTemporary temp = new LocalTemporary (iexpr_type);
5036 instance_expr.Emit (ec);
5038 temp.AddressOf (ec, AddressOp.Load);
5041 // avoid the overhead of doing this all the time.
5043 t = TypeManager.GetReferenceType (iexpr_type);
5045 instance_expr.Emit (ec);
5046 ig.Emit (OpCodes.Box, instance_expr.Type);
5047 t = TypeManager.object_type;
5050 instance_expr.Emit (ec);
5051 t = instance_expr.Type;
5055 ig.Emit (OpCodes.Dup);
5056 if (Arguments != null && Arguments.Count != 0) {
5057 this_arg = new LocalTemporary (t);
5058 this_arg.Store (ec);
5065 EmitArguments (ec, Arguments, dup_args, this_arg);
5068 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5069 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5073 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5074 call_op = OpCodes.Call;
5076 call_op = OpCodes.Callvirt;
5078 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5079 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5080 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5087 // and DoFoo is not virtual, you can omit the callvirt,
5088 // because you don't need the null checking behavior.
5090 if (method is MethodInfo)
5091 ig.Emit (call_op, (MethodInfo) method);
5093 ig.Emit (call_op, (ConstructorInfo) method);
5096 public override void Emit (EmitContext ec)
5098 mg.EmitCall (ec, Arguments);
5101 public override void EmitStatement (EmitContext ec)
5106 // Pop the return value if there is one
5108 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5109 ec.ig.Emit (OpCodes.Pop);
5112 protected override void CloneTo (CloneContext clonectx, Expression t)
5114 Invocation target = (Invocation) t;
5116 if (Arguments != null) {
5117 target.Arguments = new ArrayList (Arguments.Count);
5118 foreach (Argument a in Arguments)
5119 target.Arguments.Add (a.Clone (clonectx));
5122 target.expr = expr.Clone (clonectx);
5125 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5127 mg.MutateHoistedGenericType (storey);
5128 if (Arguments != null) {
5129 foreach (Argument a in Arguments)
5130 a.Expr.MutateHoistedGenericType (storey);
5136 // It's either a cast or delegate invocation
5138 public class InvocationOrCast : ExpressionStatement
5141 Expression argument;
5143 public InvocationOrCast (Expression expr, Expression argument)
5146 this.argument = argument;
5147 this.loc = expr.Location;
5150 public override Expression CreateExpressionTree (EmitContext ec)
5152 throw new NotSupportedException ("ET");
5155 public override Expression DoResolve (EmitContext ec)
5157 Expression e = ResolveCore (ec);
5161 return e.Resolve (ec);
5164 Expression ResolveCore (EmitContext ec)
5167 // First try to resolve it as a cast.
5169 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
5171 return new Cast (te, argument, loc);
5175 // This can either be a type or a delegate invocation.
5176 // Let's just resolve it and see what we'll get.
5178 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5183 // Ok, so it's a Cast.
5185 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5186 return new Cast (expr, argument, loc);
5189 if (expr.eclass == ExprClass.Namespace) {
5190 expr.Error_UnexpectedKind (null, "type", loc);
5195 // It's a delegate invocation.
5197 if (!TypeManager.IsDelegateType (expr.Type)) {
5198 Error (149, "Method name expected");
5202 ArrayList args = new ArrayList (1);
5203 args.Add (new Argument (argument, Argument.AType.Expression));
5204 return new DelegateInvocation (expr, args, loc);
5207 public override ExpressionStatement ResolveStatement (EmitContext ec)
5209 Expression e = ResolveCore (ec);
5213 ExpressionStatement s = e as ExpressionStatement;
5215 Error_InvalidExpressionStatement ();
5219 return s.ResolveStatement (ec);
5222 public override void Emit (EmitContext ec)
5224 throw new Exception ("Cannot happen");
5227 public override void EmitStatement (EmitContext ec)
5229 throw new Exception ("Cannot happen");
5232 protected override void CloneTo (CloneContext clonectx, Expression t)
5234 InvocationOrCast target = (InvocationOrCast) t;
5236 target.expr = expr.Clone (clonectx);
5237 target.argument = argument.Clone (clonectx);
5243 // This class is used to "disable" the code generation for the
5244 // temporary variable when initializing value types.
5246 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5247 public void AddressOf (EmitContext ec, AddressOp Mode)
5254 /// Implements the new expression
5256 public class New : ExpressionStatement, IMemoryLocation {
5257 ArrayList Arguments;
5260 // During bootstrap, it contains the RequestedType,
5261 // but if `type' is not null, it *might* contain a NewDelegate
5262 // (because of field multi-initialization)
5264 public Expression RequestedType;
5266 MethodGroupExpr method;
5269 // If set, the new expression is for a value_target, and
5270 // we will not leave anything on the stack.
5272 protected Expression value_target;
5273 protected bool value_target_set;
5274 bool is_type_parameter = false;
5276 public New (Expression requested_type, ArrayList arguments, Location l)
5278 RequestedType = requested_type;
5279 Arguments = arguments;
5283 public bool SetTargetVariable (Expression value)
5285 value_target = value;
5286 value_target_set = true;
5287 if (!(value_target is IMemoryLocation)){
5288 Error_UnexpectedKind (null, "variable", loc);
5295 // This function is used to disable the following code sequence for
5296 // value type initialization:
5298 // AddressOf (temporary)
5302 // Instead the provide will have provided us with the address on the
5303 // stack to store the results.
5305 static Expression MyEmptyExpression;
5307 public void DisableTemporaryValueType ()
5309 if (MyEmptyExpression == null)
5310 MyEmptyExpression = new EmptyAddressOf ();
5313 // To enable this, look into:
5314 // test-34 and test-89 and self bootstrapping.
5316 // For instance, we can avoid a copy by using `newobj'
5317 // instead of Call + Push-temp on value types.
5318 // value_target = MyEmptyExpression;
5323 /// Converts complex core type syntax like 'new int ()' to simple constant
5325 public static Constant Constantify (Type t)
5327 if (t == TypeManager.int32_type)
5328 return new IntConstant (0, Location.Null);
5329 if (t == TypeManager.uint32_type)
5330 return new UIntConstant (0, Location.Null);
5331 if (t == TypeManager.int64_type)
5332 return new LongConstant (0, Location.Null);
5333 if (t == TypeManager.uint64_type)
5334 return new ULongConstant (0, Location.Null);
5335 if (t == TypeManager.float_type)
5336 return new FloatConstant (0, Location.Null);
5337 if (t == TypeManager.double_type)
5338 return new DoubleConstant (0, Location.Null);
5339 if (t == TypeManager.short_type)
5340 return new ShortConstant (0, Location.Null);
5341 if (t == TypeManager.ushort_type)
5342 return new UShortConstant (0, Location.Null);
5343 if (t == TypeManager.sbyte_type)
5344 return new SByteConstant (0, Location.Null);
5345 if (t == TypeManager.byte_type)
5346 return new ByteConstant (0, Location.Null);
5347 if (t == TypeManager.char_type)
5348 return new CharConstant ('\0', Location.Null);
5349 if (t == TypeManager.bool_type)
5350 return new BoolConstant (false, Location.Null);
5351 if (t == TypeManager.decimal_type)
5352 return new DecimalConstant (0, Location.Null);
5353 if (TypeManager.IsEnumType (t))
5354 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5360 // Checks whether the type is an interface that has the
5361 // [ComImport, CoClass] attributes and must be treated
5364 public Expression CheckComImport (EmitContext ec)
5366 if (!type.IsInterface)
5370 // Turn the call into:
5371 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5373 Type real_class = AttributeTester.GetCoClassAttribute (type);
5374 if (real_class == null)
5377 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5378 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5379 return cast.Resolve (ec);
5382 public override Expression CreateExpressionTree (EmitContext ec)
5384 ArrayList args = Arguments == null ?
5385 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5387 if (method == null) {
5388 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5390 args.Add (new Argument (method.CreateExpressionTree (ec)));
5391 if (Arguments != null) {
5393 foreach (Argument a in Arguments) {
5394 expr = a.Expr.CreateExpressionTree (ec);
5396 args.Add (new Argument (expr));
5401 return CreateExpressionFactoryCall ("New", args);
5404 public override Expression DoResolve (EmitContext ec)
5407 // The New DoResolve might be called twice when initializing field
5408 // expressions (see EmitFieldInitializers, the call to
5409 // GetInitializerExpression will perform a resolve on the expression,
5410 // and later the assign will trigger another resolution
5412 // This leads to bugs (#37014)
5415 if (RequestedType is NewDelegate)
5416 return RequestedType;
5420 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5426 if (type.IsPointer) {
5427 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5428 TypeManager.CSharpName (type));
5432 if (Arguments == null) {
5433 Constant c = Constantify (type);
5435 return ReducedExpression.Create (c, this);
5438 if (TypeManager.IsDelegateType (type)) {
5439 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5443 if (type.IsGenericParameter) {
5444 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5446 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5447 Error (304, String.Format (
5448 "Cannot create an instance of the " +
5449 "variable type '{0}' because it " +
5450 "doesn't have the new() constraint",
5455 if ((Arguments != null) && (Arguments.Count != 0)) {
5456 Error (417, String.Format (
5457 "`{0}': cannot provide arguments " +
5458 "when creating an instance of a " +
5459 "variable type.", type));
5463 if (TypeManager.activator_create_instance == null) {
5464 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5465 if (activator_type != null) {
5466 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5467 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5471 is_type_parameter = true;
5472 eclass = ExprClass.Value;
5477 if (type.IsAbstract && type.IsSealed) {
5478 Report.SymbolRelatedToPreviousError (type);
5479 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5483 if (type.IsInterface || type.IsAbstract){
5484 if (!TypeManager.IsGenericType (type)) {
5485 RequestedType = CheckComImport (ec);
5486 if (RequestedType != null)
5487 return RequestedType;
5490 Report.SymbolRelatedToPreviousError (type);
5491 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5495 bool is_struct = type.IsValueType;
5496 eclass = ExprClass.Value;
5499 // SRE returns a match for .ctor () on structs (the object constructor),
5500 // so we have to manually ignore it.
5502 if (is_struct && Arguments == null)
5505 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5506 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5507 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5509 if (Arguments != null){
5510 foreach (Argument a in Arguments){
5511 if (!a.Resolve (ec, loc))
5519 method = ml as MethodGroupExpr;
5520 if (method == null) {
5521 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5525 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5532 bool DoEmitTypeParameter (EmitContext ec)
5535 ILGenerator ig = ec.ig;
5536 // IMemoryLocation ml;
5538 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5539 new Type [] { type });
5541 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5542 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5543 ig.Emit (OpCodes.Call, ci);
5547 // Allow DoEmit() to be called multiple times.
5548 // We need to create a new LocalTemporary each time since
5549 // you can't share LocalBuilders among ILGeneators.
5550 LocalTemporary temp = new LocalTemporary (type);
5552 Label label_activator = ig.DefineLabel ();
5553 Label label_end = ig.DefineLabel ();
5555 temp.AddressOf (ec, AddressOp.Store);
5556 ig.Emit (OpCodes.Initobj, type);
5559 ig.Emit (OpCodes.Box, type);
5560 ig.Emit (OpCodes.Brfalse, label_activator);
5562 temp.AddressOf (ec, AddressOp.Store);
5563 ig.Emit (OpCodes.Initobj, type);
5565 ig.Emit (OpCodes.Br, label_end);
5567 ig.MarkLabel (label_activator);
5569 ig.Emit (OpCodes.Call, ci);
5570 ig.MarkLabel (label_end);
5573 throw new InternalErrorException ();
5578 // This DoEmit can be invoked in two contexts:
5579 // * As a mechanism that will leave a value on the stack (new object)
5580 // * As one that wont (init struct)
5582 // You can control whether a value is required on the stack by passing
5583 // need_value_on_stack. The code *might* leave a value on the stack
5584 // so it must be popped manually
5586 // If we are dealing with a ValueType, we have a few
5587 // situations to deal with:
5589 // * The target is a ValueType, and we have been provided
5590 // the instance (this is easy, we are being assigned).
5592 // * The target of New is being passed as an argument,
5593 // to a boxing operation or a function that takes a
5596 // In this case, we need to create a temporary variable
5597 // that is the argument of New.
5599 // Returns whether a value is left on the stack
5601 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5603 bool is_value_type = TypeManager.IsValueType (type);
5604 ILGenerator ig = ec.ig;
5609 // Allow DoEmit() to be called multiple times.
5610 // We need to create a new LocalTemporary each time since
5611 // you can't share LocalBuilders among ILGeneators.
5612 if (!value_target_set)
5613 value_target = new LocalTemporary (type);
5615 ml = (IMemoryLocation) value_target;
5616 ml.AddressOf (ec, AddressOp.Store);
5620 method.EmitArguments (ec, Arguments);
5624 ig.Emit (OpCodes.Initobj, type);
5626 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5627 if (need_value_on_stack){
5628 value_target.Emit (ec);
5633 ConstructorInfo ci = (ConstructorInfo) method;
5635 if (TypeManager.IsGenericType (type))
5636 ci = TypeBuilder.GetConstructor (type, ci);
5638 ig.Emit (OpCodes.Newobj, ci);
5643 public override void Emit (EmitContext ec)
5645 if (is_type_parameter)
5646 DoEmitTypeParameter (ec);
5651 public override void EmitStatement (EmitContext ec)
5653 bool value_on_stack;
5655 if (is_type_parameter)
5656 value_on_stack = DoEmitTypeParameter (ec);
5658 value_on_stack = DoEmit (ec, false);
5661 ec.ig.Emit (OpCodes.Pop);
5665 public virtual bool HasInitializer {
5671 public void AddressOf (EmitContext ec, AddressOp Mode)
5673 if (is_type_parameter) {
5674 LocalTemporary temp = new LocalTemporary (type);
5675 DoEmitTypeParameter (ec);
5677 temp.AddressOf (ec, Mode);
5681 if (!type.IsValueType){
5683 // We throw an exception. So far, I believe we only need to support
5685 // foreach (int j in new StructType ())
5688 throw new Exception ("AddressOf should not be used for classes");
5691 if (!value_target_set)
5692 value_target = new LocalTemporary (type);
5693 IMemoryLocation ml = (IMemoryLocation) value_target;
5695 ml.AddressOf (ec, AddressOp.Store);
5696 if (method == null) {
5697 ec.ig.Emit (OpCodes.Initobj, type);
5699 method.EmitArguments (ec, Arguments);
5700 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5703 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5706 protected override void CloneTo (CloneContext clonectx, Expression t)
5708 New target = (New) t;
5710 target.RequestedType = RequestedType.Clone (clonectx);
5711 if (Arguments != null){
5712 target.Arguments = new ArrayList ();
5713 foreach (Argument a in Arguments){
5714 target.Arguments.Add (a.Clone (clonectx));
5719 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5721 if (method != null) {
5722 method.MutateHoistedGenericType (storey);
5723 if (Arguments != null) {
5724 foreach (Argument a in Arguments)
5725 a.Expr.MutateHoistedGenericType (storey);
5729 type = storey.MutateType (type);
5734 /// 14.5.10.2: Represents an array creation expression.
5738 /// There are two possible scenarios here: one is an array creation
5739 /// expression that specifies the dimensions and optionally the
5740 /// initialization data and the other which does not need dimensions
5741 /// specified but where initialization data is mandatory.
5743 public class ArrayCreation : Expression {
5744 FullNamedExpression requested_base_type;
5745 ArrayList initializers;
5748 // The list of Argument types.
5749 // This is used to construct the `newarray' or constructor signature
5751 protected ArrayList arguments;
5753 protected Type array_element_type;
5754 bool expect_initializers = false;
5755 int num_arguments = 0;
5756 protected int dimensions;
5757 protected readonly string rank;
5759 protected ArrayList array_data;
5763 // The number of constants in array initializers
5764 int const_initializers_count;
5765 bool only_constant_initializers;
5767 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5769 this.requested_base_type = requested_base_type;
5770 this.initializers = initializers;
5774 arguments = new ArrayList (exprs.Count);
5776 foreach (Expression e in exprs) {
5777 arguments.Add (new Argument (e, Argument.AType.Expression));
5782 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5784 this.requested_base_type = requested_base_type;
5785 this.initializers = initializers;
5789 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5791 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5793 //dimensions = tmp.Length - 1;
5794 expect_initializers = true;
5797 public static void Error_IncorrectArrayInitializer (Location loc)
5799 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5802 protected override void Error_NegativeArrayIndex (Location loc)
5804 Report.Error (248, loc, "Cannot create an array with a negative size");
5807 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5809 if (specified_dims) {
5810 Argument a = (Argument) arguments [idx];
5812 if (!a.Resolve (ec, loc))
5815 Constant c = a.Expr as Constant;
5817 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5821 Report.Error (150, a.Expr.Location, "A constant value is expected");
5825 int value = (int) c.GetValue ();
5827 if (value != probe.Count) {
5828 Error_IncorrectArrayInitializer (loc);
5832 bounds [idx] = value;
5835 int child_bounds = -1;
5836 only_constant_initializers = true;
5837 for (int i = 0; i < probe.Count; ++i) {
5838 object o = probe [i];
5839 if (o is ArrayList) {
5840 ArrayList sub_probe = o as ArrayList;
5841 int current_bounds = sub_probe.Count;
5843 if (child_bounds == -1)
5844 child_bounds = current_bounds;
5846 else if (child_bounds != current_bounds){
5847 Error_IncorrectArrayInitializer (loc);
5850 if (idx + 1 >= dimensions){
5851 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5855 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5859 if (child_bounds != -1){
5860 Error_IncorrectArrayInitializer (loc);
5864 Expression element = ResolveArrayElement (ec, (Expression) o);
5865 if (element == null)
5868 // Initializers with the default values can be ignored
5869 Constant c = element as Constant;
5871 if (c.IsDefaultInitializer (array_element_type)) {
5875 ++const_initializers_count;
5878 only_constant_initializers = false;
5881 array_data.Add (element);
5888 public override Expression CreateExpressionTree (EmitContext ec)
5892 if (array_data == null) {
5893 args = new ArrayList (arguments.Count + 1);
5894 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5895 foreach (Argument a in arguments) {
5896 if (arguments.Count == 1) {
5897 Constant c = a.Expr as Constant;
5898 if (c.IsDefaultValue)
5899 return CreateExpressionFactoryCall ("NewArrayInit", args);
5901 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5904 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5907 if (dimensions > 1) {
5908 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5912 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5913 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5914 if (array_data != null) {
5915 for (int i = 0; i < array_data.Count; ++i) {
5916 Expression e = (Expression) array_data [i];
5918 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5920 args.Add (new Argument (e.CreateExpressionTree (ec)));
5924 return CreateExpressionFactoryCall ("NewArrayInit", args);
5927 public void UpdateIndices ()
5930 for (ArrayList probe = initializers; probe != null;) {
5931 if (probe.Count > 0 && probe [0] is ArrayList) {
5932 Expression e = new IntConstant (probe.Count, Location.Null);
5933 arguments.Add (new Argument (e, Argument.AType.Expression));
5935 bounds [i++] = probe.Count;
5937 probe = (ArrayList) probe [0];
5940 Expression e = new IntConstant (probe.Count, Location.Null);
5941 arguments.Add (new Argument (e, Argument.AType.Expression));
5943 bounds [i++] = probe.Count;
5950 Expression first_emit;
5951 LocalTemporary first_emit_temp;
5953 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5955 element = element.Resolve (ec);
5956 if (element == null)
5959 if (element is CompoundAssign.TargetExpression) {
5960 if (first_emit != null)
5961 throw new InternalErrorException ("Can only handle one mutator at a time");
5962 first_emit = element;
5963 element = first_emit_temp = new LocalTemporary (element.Type);
5966 return Convert.ImplicitConversionRequired (
5967 ec, element, array_element_type, loc);
5970 protected bool ResolveInitializers (EmitContext ec)
5972 if (initializers == null) {
5973 return !expect_initializers;
5977 // We use this to store all the date values in the order in which we
5978 // will need to store them in the byte blob later
5980 array_data = new ArrayList ();
5981 bounds = new System.Collections.Specialized.HybridDictionary ();
5983 if (arguments != null)
5984 return CheckIndices (ec, initializers, 0, true);
5986 arguments = new ArrayList ();
5988 if (!CheckIndices (ec, initializers, 0, false))
5997 // Resolved the type of the array
5999 bool ResolveArrayType (EmitContext ec)
6001 if (requested_base_type == null) {
6002 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6006 if (requested_base_type is VarExpr) {
6007 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
6011 StringBuilder array_qualifier = new StringBuilder (rank);
6014 // `In the first form allocates an array instace of the type that results
6015 // from deleting each of the individual expression from the expression list'
6017 if (num_arguments > 0) {
6018 array_qualifier.Append ("[");
6019 for (int i = num_arguments-1; i > 0; i--)
6020 array_qualifier.Append (",");
6021 array_qualifier.Append ("]");
6027 TypeExpr array_type_expr;
6028 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6029 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6030 if (array_type_expr == null)
6033 type = array_type_expr.Type;
6034 array_element_type = TypeManager.GetElementType (type);
6035 dimensions = type.GetArrayRank ();
6040 public override Expression DoResolve (EmitContext ec)
6045 if (!ResolveArrayType (ec))
6049 // First step is to validate the initializers and fill
6050 // in any missing bits
6052 if (!ResolveInitializers (ec))
6055 if (arguments.Count != dimensions) {
6056 Error_IncorrectArrayInitializer (loc);
6059 foreach (Argument a in arguments){
6060 if (!a.Resolve (ec, loc))
6063 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6066 eclass = ExprClass.Value;
6070 MethodInfo GetArrayMethod (int arguments)
6072 ModuleBuilder mb = CodeGen.Module.Builder;
6074 Type[] arg_types = new Type[arguments];
6075 for (int i = 0; i < arguments; i++)
6076 arg_types[i] = TypeManager.int32_type;
6078 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6082 Report.Error (-6, "New invocation: Can not find a constructor for " +
6083 "this argument list");
6090 byte [] MakeByteBlob ()
6095 int count = array_data.Count;
6097 if (TypeManager.IsEnumType (array_element_type))
6098 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6100 factor = GetTypeSize (array_element_type);
6102 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6104 data = new byte [(count * factor + 3) & ~3];
6107 for (int i = 0; i < count; ++i) {
6108 object v = array_data [i];
6110 if (v is EnumConstant)
6111 v = ((EnumConstant) v).Child;
6113 if (v is Constant && !(v is StringConstant))
6114 v = ((Constant) v).GetValue ();
6120 if (array_element_type == TypeManager.int64_type){
6121 if (!(v is Expression)){
6122 long val = (long) v;
6124 for (int j = 0; j < factor; ++j) {
6125 data [idx + j] = (byte) (val & 0xFF);
6129 } else if (array_element_type == TypeManager.uint64_type){
6130 if (!(v is Expression)){
6131 ulong val = (ulong) v;
6133 for (int j = 0; j < factor; ++j) {
6134 data [idx + j] = (byte) (val & 0xFF);
6138 } else if (array_element_type == TypeManager.float_type) {
6139 if (!(v is Expression)){
6140 element = BitConverter.GetBytes ((float) v);
6142 for (int j = 0; j < factor; ++j)
6143 data [idx + j] = element [j];
6144 if (!BitConverter.IsLittleEndian)
6145 System.Array.Reverse (data, idx, 4);
6147 } else if (array_element_type == TypeManager.double_type) {
6148 if (!(v is Expression)){
6149 element = BitConverter.GetBytes ((double) v);
6151 for (int j = 0; j < factor; ++j)
6152 data [idx + j] = element [j];
6154 // FIXME: Handle the ARM float format.
6155 if (!BitConverter.IsLittleEndian)
6156 System.Array.Reverse (data, idx, 8);
6158 } else if (array_element_type == TypeManager.char_type){
6159 if (!(v is Expression)){
6160 int val = (int) ((char) v);
6162 data [idx] = (byte) (val & 0xff);
6163 data [idx+1] = (byte) (val >> 8);
6165 } else if (array_element_type == TypeManager.short_type){
6166 if (!(v is Expression)){
6167 int val = (int) ((short) v);
6169 data [idx] = (byte) (val & 0xff);
6170 data [idx+1] = (byte) (val >> 8);
6172 } else if (array_element_type == TypeManager.ushort_type){
6173 if (!(v is Expression)){
6174 int val = (int) ((ushort) v);
6176 data [idx] = (byte) (val & 0xff);
6177 data [idx+1] = (byte) (val >> 8);
6179 } else if (array_element_type == TypeManager.int32_type) {
6180 if (!(v is Expression)){
6183 data [idx] = (byte) (val & 0xff);
6184 data [idx+1] = (byte) ((val >> 8) & 0xff);
6185 data [idx+2] = (byte) ((val >> 16) & 0xff);
6186 data [idx+3] = (byte) (val >> 24);
6188 } else if (array_element_type == TypeManager.uint32_type) {
6189 if (!(v is Expression)){
6190 uint val = (uint) v;
6192 data [idx] = (byte) (val & 0xff);
6193 data [idx+1] = (byte) ((val >> 8) & 0xff);
6194 data [idx+2] = (byte) ((val >> 16) & 0xff);
6195 data [idx+3] = (byte) (val >> 24);
6197 } else if (array_element_type == TypeManager.sbyte_type) {
6198 if (!(v is Expression)){
6199 sbyte val = (sbyte) v;
6200 data [idx] = (byte) val;
6202 } else if (array_element_type == TypeManager.byte_type) {
6203 if (!(v is Expression)){
6204 byte val = (byte) v;
6205 data [idx] = (byte) val;
6207 } else if (array_element_type == TypeManager.bool_type) {
6208 if (!(v is Expression)){
6209 bool val = (bool) v;
6210 data [idx] = (byte) (val ? 1 : 0);
6212 } else if (array_element_type == TypeManager.decimal_type){
6213 if (!(v is Expression)){
6214 int [] bits = Decimal.GetBits ((decimal) v);
6217 // FIXME: For some reason, this doesn't work on the MS runtime.
6218 int [] nbits = new int [4];
6219 nbits [0] = bits [3];
6220 nbits [1] = bits [2];
6221 nbits [2] = bits [0];
6222 nbits [3] = bits [1];
6224 for (int j = 0; j < 4; j++){
6225 data [p++] = (byte) (nbits [j] & 0xff);
6226 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6227 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6228 data [p++] = (byte) (nbits [j] >> 24);
6232 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6240 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6242 array_element_type = storey.MutateType (array_element_type);
6243 type = storey.MutateType (type);
6244 if (arguments != null) {
6245 foreach (Argument a in arguments)
6246 a.Expr.MutateHoistedGenericType (storey);
6249 if (array_data != null) {
6250 foreach (Expression e in array_data)
6251 e.MutateHoistedGenericType (storey);
6256 // Emits the initializers for the array
6258 void EmitStaticInitializers (EmitContext ec)
6260 // FIXME: This should go to Resolve !
6261 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6262 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6263 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6264 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6265 if (TypeManager.void_initializearray_array_fieldhandle == null)
6270 // First, the static data
6273 ILGenerator ig = ec.ig;
6275 byte [] data = MakeByteBlob ();
6277 fb = RootContext.MakeStaticData (data);
6279 ig.Emit (OpCodes.Dup);
6280 ig.Emit (OpCodes.Ldtoken, fb);
6281 ig.Emit (OpCodes.Call,
6282 TypeManager.void_initializearray_array_fieldhandle);
6286 // Emits pieces of the array that can not be computed at compile
6287 // time (variables and string locations).
6289 // This always expect the top value on the stack to be the array
6291 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6293 ILGenerator ig = ec.ig;
6294 int dims = bounds.Count;
6295 int [] current_pos = new int [dims];
6297 MethodInfo set = null;
6300 Type [] args = new Type [dims + 1];
6302 for (int j = 0; j < dims; j++)
6303 args [j] = TypeManager.int32_type;
6304 args [dims] = array_element_type;
6306 set = CodeGen.Module.Builder.GetArrayMethod (
6308 CallingConventions.HasThis | CallingConventions.Standard,
6309 TypeManager.void_type, args);
6312 for (int i = 0; i < array_data.Count; i++){
6314 Expression e = (Expression)array_data [i];
6316 // Constant can be initialized via StaticInitializer
6317 if (e != null && !(!emitConstants && e is Constant)) {
6318 Type etype = e.Type;
6320 ig.Emit (OpCodes.Dup);
6322 for (int idx = 0; idx < dims; idx++)
6323 IntConstant.EmitInt (ig, current_pos [idx]);
6326 // If we are dealing with a struct, get the
6327 // address of it, so we can store it.
6329 if ((dims == 1) && etype.IsValueType &&
6330 (!TypeManager.IsBuiltinOrEnum (etype) ||
6331 etype == TypeManager.decimal_type)) {
6336 // Let new know that we are providing
6337 // the address where to store the results
6339 n.DisableTemporaryValueType ();
6342 ig.Emit (OpCodes.Ldelema, etype);
6348 bool is_stobj, has_type_arg;
6349 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6351 ig.Emit (OpCodes.Stobj, etype);
6352 else if (has_type_arg)
6353 ig.Emit (op, etype);
6357 ig.Emit (OpCodes.Call, set);
6364 for (int j = dims - 1; j >= 0; j--){
6366 if (current_pos [j] < (int) bounds [j])
6368 current_pos [j] = 0;
6373 public override void Emit (EmitContext ec)
6375 ILGenerator ig = ec.ig;
6377 if (first_emit != null) {
6378 first_emit.Emit (ec);
6379 first_emit_temp.Store (ec);
6382 foreach (Argument a in arguments)
6385 if (arguments.Count == 1)
6386 ig.Emit (OpCodes.Newarr, array_element_type);
6388 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6391 if (initializers == null)
6394 // Emit static initializer for arrays which have contain more than 4 items and
6395 // the static initializer will initialize at least 25% of array values.
6396 // NOTE: const_initializers_count does not contain default constant values.
6397 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6398 TypeManager.IsPrimitiveType (array_element_type)) {
6399 EmitStaticInitializers (ec);
6401 if (!only_constant_initializers)
6402 EmitDynamicInitializers (ec, false);
6404 EmitDynamicInitializers (ec, true);
6407 if (first_emit_temp != null)
6408 first_emit_temp.Release (ec);
6411 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6413 if (arguments.Count != 1) {
6414 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6415 return base.GetAttributableValue (ec, null, out value);
6418 if (array_data == null) {
6419 Constant c = (Constant)((Argument)arguments [0]).Expr;
6420 if (c.IsDefaultValue) {
6421 value = Array.CreateInstance (array_element_type, 0);
6424 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6425 return base.GetAttributableValue (ec, null, out value);
6428 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6429 object element_value;
6430 for (int i = 0; i < ret.Length; ++i)
6432 Expression e = (Expression)array_data [i];
6434 // Is null when an initializer is optimized (value == predefined value)
6438 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6442 ret.SetValue (element_value, i);
6448 protected override void CloneTo (CloneContext clonectx, Expression t)
6450 ArrayCreation target = (ArrayCreation) t;
6452 if (requested_base_type != null)
6453 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6455 if (arguments != null){
6456 target.arguments = new ArrayList (arguments.Count);
6457 foreach (Argument a in arguments)
6458 target.arguments.Add (a.Clone (clonectx));
6461 if (initializers != null){
6462 target.initializers = new ArrayList (initializers.Count);
6463 foreach (object initializer in initializers)
6464 if (initializer is ArrayList) {
6465 ArrayList this_al = (ArrayList)initializer;
6466 ArrayList al = new ArrayList (this_al.Count);
6467 target.initializers.Add (al);
6468 foreach (Expression e in this_al)
6469 al.Add (e.Clone (clonectx));
6471 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6478 // Represents an implicitly typed array epxression
6480 public class ImplicitlyTypedArrayCreation : ArrayCreation
6482 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6483 : base (null, rank, initializers, loc)
6485 if (RootContext.Version <= LanguageVersion.ISO_2)
6486 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6488 if (rank.Length > 2) {
6489 while (rank [++dimensions] == ',');
6495 public override Expression DoResolve (EmitContext ec)
6500 if (!ResolveInitializers (ec))
6503 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6504 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6505 arguments.Count != dimensions) {
6506 Error_NoBestType ();
6511 // At this point we found common base type for all initializer elements
6512 // but we have to be sure that all static initializer elements are of
6515 UnifyInitializerElement (ec);
6517 type = TypeManager.GetConstructedType (array_element_type, rank);
6518 eclass = ExprClass.Value;
6522 void Error_NoBestType ()
6524 Report.Error (826, loc,
6525 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6529 // Converts static initializer only
6531 void UnifyInitializerElement (EmitContext ec)
6533 for (int i = 0; i < array_data.Count; ++i) {
6534 Expression e = (Expression)array_data[i];
6536 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6540 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6542 element = element.Resolve (ec);
6543 if (element == null)
6546 if (array_element_type == null) {
6547 array_element_type = element.Type;
6551 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6555 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6556 array_element_type = element.Type;
6560 Error_NoBestType ();
6565 public sealed class CompilerGeneratedThis : This
6567 public static This Instance = new CompilerGeneratedThis ();
6569 private CompilerGeneratedThis ()
6570 : base (Location.Null)
6574 public CompilerGeneratedThis (Type type, Location loc)
6580 public override Expression DoResolve (EmitContext ec)
6582 eclass = ExprClass.Variable;
6584 type = ec.ContainerType;
6588 public override HoistedVariable HoistedVariable {
6589 get { return null; }
6594 /// Represents the `this' construct
6597 public class This : VariableReference
6599 sealed class ThisVariable : ILocalVariable
6601 public static readonly ILocalVariable Instance = new ThisVariable ();
6603 public void Emit (EmitContext ec)
6605 ec.ig.Emit (OpCodes.Ldarg_0);
6608 public void EmitAssign (EmitContext ec)
6610 throw new InvalidOperationException ();
6613 public void EmitAddressOf (EmitContext ec)
6615 ec.ig.Emit (OpCodes.Ldarg_0);
6620 VariableInfo variable_info;
6623 public This (Block block, Location loc)
6629 public This (Location loc)
6634 public override VariableInfo VariableInfo {
6635 get { return variable_info; }
6638 public override bool IsFixed {
6639 get { return false; }
6642 protected override bool IsHoistedEmitRequired (EmitContext ec)
6645 // Handle 'this' differently, it cannot be assigned hence
6646 // when we are not inside anonymous method we can emit direct access
6648 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6651 public override HoistedVariable HoistedVariable {
6652 get { return TopToplevelBlock.HoistedThisVariable; }
6655 public override bool IsRef {
6656 get { return is_struct; }
6659 protected override ILocalVariable Variable {
6660 get { return ThisVariable.Instance; }
6663 // TODO: Move to ToplevelBlock
6664 ToplevelBlock TopToplevelBlock {
6666 ToplevelBlock tl = block.Toplevel;
6667 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6672 public static bool IsThisAvailable (EmitContext ec)
6674 if (ec.IsStatic || ec.IsInFieldInitializer)
6677 if (ec.CurrentAnonymousMethod == null)
6680 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6686 public bool ResolveBase (EmitContext ec)
6688 if (eclass != ExprClass.Invalid)
6691 eclass = ExprClass.Variable;
6693 if (ec.TypeContainer.CurrentType != null)
6694 type = ec.TypeContainer.CurrentType;
6696 type = ec.ContainerType;
6698 if (!IsThisAvailable (ec)) {
6700 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6702 Report.Error (1673, loc,
6703 "Anonymous methods inside structs cannot access instance members of `this'. " +
6704 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6708 is_struct = ec.TypeContainer is Struct;
6710 if (block != null) {
6711 if (block.Toplevel.ThisVariable != null)
6712 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6714 AnonymousExpression am = ec.CurrentAnonymousMethod;
6717 // this is hoisted to very top level block
6719 if (ec.IsVariableCapturingRequired) {
6721 // TODO: it should be optimized, see test-anon-75.cs
6723 // `this' variable has its own scope which is mostly empty
6724 // and causes creation of extraneous storey references.
6725 // Also it's hard to remove `this' dependencies when we Undo
6728 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6729 if (HoistedVariable == null) {
6730 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6740 // Called from Invocation to check if the invocation is correct
6742 public override void CheckMarshalByRefAccess (EmitContext ec)
6744 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6745 !variable_info.IsAssigned (ec)) {
6746 Error (188, "The `this' object cannot be used before all of its " +
6747 "fields are assigned to");
6748 variable_info.SetAssigned (ec);
6752 public override Expression CreateExpressionTree (EmitContext ec)
6754 ArrayList args = new ArrayList (1);
6755 args.Add (new Argument (this));
6757 // Use typeless constant for ldarg.0 to save some
6758 // space and avoid problems with anonymous stories
6759 return CreateExpressionFactoryCall ("Constant", args);
6762 public override Expression DoResolve (EmitContext ec)
6764 if (!ResolveBase (ec))
6768 if (ec.IsInFieldInitializer) {
6769 Error (27, "Keyword `this' is not available in the current context");
6776 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6778 if (!ResolveBase (ec))
6781 if (variable_info != null)
6782 variable_info.SetAssigned (ec);
6784 if (ec.TypeContainer is Class){
6785 if (right_side == EmptyExpression.UnaryAddress)
6786 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6787 else if (right_side == EmptyExpression.OutAccess)
6788 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6790 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6796 public override int GetHashCode()
6798 return block.GetHashCode ();
6801 public override string Name {
6802 get { return "this"; }
6805 public override bool Equals (object obj)
6807 This t = obj as This;
6811 return block == t.block;
6814 protected override void CloneTo (CloneContext clonectx, Expression t)
6816 This target = (This) t;
6818 target.block = clonectx.LookupBlock (block);
6821 public void RemoveHoisting ()
6823 TopToplevelBlock.HoistedThisVariable = null;
6826 public override void SetHasAddressTaken ()
6833 /// Represents the `__arglist' construct
6835 public class ArglistAccess : Expression
6837 public ArglistAccess (Location loc)
6842 public override Expression CreateExpressionTree (EmitContext ec)
6844 throw new NotSupportedException ("ET");
6847 public override Expression DoResolve (EmitContext ec)
6849 eclass = ExprClass.Variable;
6850 type = TypeManager.runtime_argument_handle_type;
6852 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6854 Error (190, "The __arglist construct is valid only within " +
6855 "a variable argument method");
6862 public override void Emit (EmitContext ec)
6864 ec.ig.Emit (OpCodes.Arglist);
6867 protected override void CloneTo (CloneContext clonectx, Expression target)
6874 /// Represents the `__arglist (....)' construct
6876 public class Arglist : Expression
6878 Argument[] Arguments;
6880 public Arglist (Location loc)
6881 : this (Argument.Empty, loc)
6885 public Arglist (Argument[] args, Location l)
6891 public Type[] ArgumentTypes {
6893 Type[] retval = new Type [Arguments.Length];
6894 for (int i = 0; i < Arguments.Length; i++)
6895 retval [i] = Arguments [i].Type;
6900 public override Expression CreateExpressionTree (EmitContext ec)
6902 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6906 public override Expression DoResolve (EmitContext ec)
6908 eclass = ExprClass.Variable;
6909 type = TypeManager.runtime_argument_handle_type;
6911 foreach (Argument arg in Arguments) {
6912 if (!arg.Resolve (ec, loc))
6919 public override void Emit (EmitContext ec)
6921 foreach (Argument arg in Arguments)
6925 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6927 foreach (Argument arg in Arguments)
6928 arg.Expr.MutateHoistedGenericType (storey);
6931 protected override void CloneTo (CloneContext clonectx, Expression t)
6933 Arglist target = (Arglist) t;
6935 target.Arguments = new Argument [Arguments.Length];
6936 for (int i = 0; i < Arguments.Length; i++)
6937 target.Arguments [i] = Arguments [i].Clone (clonectx);
6942 /// Implements the typeof operator
6944 public class TypeOf : Expression {
6945 Expression QueriedType;
6946 protected Type typearg;
6948 public TypeOf (Expression queried_type, Location l)
6950 QueriedType = queried_type;
6954 public override Expression CreateExpressionTree (EmitContext ec)
6956 ArrayList args = new ArrayList (2);
6957 args.Add (new Argument (this));
6958 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6959 return CreateExpressionFactoryCall ("Constant", args);
6962 public override Expression DoResolve (EmitContext ec)
6964 if (eclass != ExprClass.Invalid)
6967 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6971 typearg = texpr.Type;
6973 if (typearg == TypeManager.void_type) {
6974 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6978 if (typearg.IsPointer && !ec.InUnsafe){
6983 type = TypeManager.type_type;
6985 return DoResolveBase ();
6988 protected Expression DoResolveBase ()
6990 if (TypeManager.system_type_get_type_from_handle == null) {
6991 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6992 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6995 // Even though what is returned is a type object, it's treated as a value by the compiler.
6996 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6997 eclass = ExprClass.Value;
7001 public override void Emit (EmitContext ec)
7003 ec.ig.Emit (OpCodes.Ldtoken, typearg);
7004 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7007 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
7009 if (TypeManager.ContainsGenericParameters (typearg) &&
7010 !TypeManager.IsGenericTypeDefinition (typearg)) {
7011 Report.SymbolRelatedToPreviousError (typearg);
7012 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
7013 TypeManager.CSharpName (typearg));
7018 if (value_type == TypeManager.object_type) {
7019 value = (object)typearg;
7026 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7028 typearg = storey.MutateType (typearg);
7031 public Type TypeArgument {
7037 protected override void CloneTo (CloneContext clonectx, Expression t)
7039 TypeOf target = (TypeOf) t;
7040 if (QueriedType != null)
7041 target.QueriedType = QueriedType.Clone (clonectx);
7046 /// Implements the `typeof (void)' operator
7048 public class TypeOfVoid : TypeOf {
7049 public TypeOfVoid (Location l) : base (null, l)
7054 public override Expression DoResolve (EmitContext ec)
7056 type = TypeManager.type_type;
7057 typearg = TypeManager.void_type;
7059 return DoResolveBase ();
7063 class TypeOfMethodInfo : TypeOfMethod
7065 public TypeOfMethodInfo (MethodBase method, Location loc)
7066 : base (method, loc)
7070 public override Expression DoResolve (EmitContext ec)
7072 type = typeof (MethodInfo);
7073 return base.DoResolve (ec);
7076 public override void Emit (EmitContext ec)
7078 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7080 ec.ig.Emit (OpCodes.Castclass, type);
7084 class TypeOfConstructorInfo : TypeOfMethod
7086 public TypeOfConstructorInfo (MethodBase method, Location loc)
7087 : base (method, loc)
7091 public override Expression DoResolve (EmitContext ec)
7093 type = typeof (ConstructorInfo);
7094 return base.DoResolve (ec);
7097 public override void Emit (EmitContext ec)
7099 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7101 ec.ig.Emit (OpCodes.Castclass, type);
7105 abstract class TypeOfMethod : Expression
7107 protected readonly MethodBase method;
7109 protected TypeOfMethod (MethodBase method, Location loc)
7111 this.method = method;
7115 public override Expression CreateExpressionTree (EmitContext ec)
7117 ArrayList args = new ArrayList (2);
7118 args.Add (new Argument (this));
7119 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7120 return CreateExpressionFactoryCall ("Constant", args);
7123 public override Expression DoResolve (EmitContext ec)
7125 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7126 MethodInfo mi = is_generic ?
7127 TypeManager.methodbase_get_type_from_handle_generic :
7128 TypeManager.methodbase_get_type_from_handle;
7131 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7132 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7134 if (t == null || handle_type == null)
7137 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7139 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7140 new Type[] { handle_type } );
7143 TypeManager.methodbase_get_type_from_handle_generic = mi;
7145 TypeManager.methodbase_get_type_from_handle = mi;
7148 eclass = ExprClass.Value;
7152 public override void Emit (EmitContext ec)
7154 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7157 mi = TypeManager.methodbase_get_type_from_handle_generic;
7158 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7160 mi = TypeManager.methodbase_get_type_from_handle;
7163 ec.ig.Emit (OpCodes.Call, mi);
7167 internal class TypeOfField : Expression
7169 readonly FieldInfo field;
7171 public TypeOfField (FieldInfo field, Location loc)
7177 public override Expression CreateExpressionTree (EmitContext ec)
7179 throw new NotSupportedException ("ET");
7182 public override Expression DoResolve (EmitContext ec)
7184 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7185 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7186 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7188 if (t != null && handle_type != null)
7189 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7190 "GetFieldFromHandle", loc, handle_type);
7193 type = typeof (FieldInfo);
7194 eclass = ExprClass.Value;
7198 public override void Emit (EmitContext ec)
7200 ec.ig.Emit (OpCodes.Ldtoken, field);
7201 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7206 /// Implements the sizeof expression
7208 public class SizeOf : Expression {
7209 readonly Expression QueriedType;
7212 public SizeOf (Expression queried_type, Location l)
7214 this.QueriedType = queried_type;
7218 public override Expression CreateExpressionTree (EmitContext ec)
7220 Error_PointerInsideExpressionTree ();
7224 public override Expression DoResolve (EmitContext ec)
7226 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7230 type_queried = texpr.Type;
7231 if (TypeManager.IsEnumType (type_queried))
7232 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7234 int size_of = GetTypeSize (type_queried);
7236 return new IntConstant (size_of, loc);
7239 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7244 Report.Error (233, loc,
7245 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7246 TypeManager.CSharpName (type_queried));
7249 type = TypeManager.int32_type;
7250 eclass = ExprClass.Value;
7254 public override void Emit (EmitContext ec)
7256 int size = GetTypeSize (type_queried);
7259 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7261 IntConstant.EmitInt (ec.ig, size);
7264 protected override void CloneTo (CloneContext clonectx, Expression t)
7270 /// Implements the qualified-alias-member (::) expression.
7272 public class QualifiedAliasMember : MemberAccess
7274 readonly string alias;
7275 public static readonly string GlobalAlias = "global";
7277 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7278 : base (null, identifier, targs, l)
7283 public QualifiedAliasMember (string alias, string identifier, Location l)
7284 : base (null, identifier, l)
7289 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7291 if (alias == GlobalAlias) {
7292 expr = RootNamespace.Global;
7293 return base.ResolveAsTypeStep (ec, silent);
7296 int errors = Report.Errors;
7297 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7299 if (errors == Report.Errors)
7300 Report.Error (432, loc, "Alias `{0}' not found", alias);
7304 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7308 if (expr.eclass == ExprClass.Type) {
7310 Report.Error (431, loc,
7311 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7319 public override Expression DoResolve (EmitContext ec)
7321 return ResolveAsTypeStep (ec, false);
7324 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7326 Report.Error (687, loc,
7327 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7328 GetSignatureForError ());
7331 public override string GetSignatureForError ()
7334 if (targs != null) {
7335 name = TypeManager.RemoveGenericArity (Name) + "<" +
7336 targs.GetSignatureForError () + ">";
7339 return alias + "::" + name;
7342 protected override void CloneTo (CloneContext clonectx, Expression t)
7349 /// Implements the member access expression
7351 public class MemberAccess : ATypeNameExpression {
7352 protected Expression expr;
7354 public MemberAccess (Expression expr, string id)
7355 : base (id, expr.Location)
7360 public MemberAccess (Expression expr, string identifier, Location loc)
7361 : base (identifier, loc)
7366 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7367 : base (identifier, args, loc)
7372 // TODO: this method has very poor performace for Enum fields and
7373 // probably for other constants as well
7374 Expression DoResolve (EmitContext ec, Expression right_side)
7377 throw new Exception ();
7380 // Resolve the expression with flow analysis turned off, we'll do the definite
7381 // assignment checks later. This is because we don't know yet what the expression
7382 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7383 // definite assignment check on the actual field and not on the whole struct.
7386 SimpleName original = expr as SimpleName;
7387 Expression expr_resolved = expr.Resolve (ec,
7388 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7389 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7391 if (expr_resolved == null)
7394 string LookupIdentifier = MemberName.MakeName (Name, targs);
7396 if (expr_resolved is Namespace) {
7397 Namespace ns = (Namespace) expr_resolved;
7398 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7400 if ((retval != null) && (targs != null))
7401 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7405 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7409 Type expr_type = expr_resolved.Type;
7410 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7411 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7412 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7416 Constant c = expr_resolved as Constant;
7417 if (c != null && c.GetValue () == null) {
7418 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7419 "System.NullReferenceException");
7422 if (targs != null) {
7423 if (!targs.Resolve (ec))
7427 Expression member_lookup;
7428 member_lookup = MemberLookup (
7429 ec.ContainerType, expr_type, expr_type, Name, loc);
7431 if ((member_lookup == null) && (targs != null)) {
7432 member_lookup = MemberLookup (
7433 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7436 if (member_lookup == null) {
7437 ExprClass expr_eclass = expr_resolved.eclass;
7440 // Extension methods are not allowed on all expression types
7442 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7443 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7444 expr_eclass == ExprClass.EventAccess) {
7445 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7446 if (ex_method_lookup != null) {
7447 ex_method_lookup.ExtensionExpression = expr_resolved;
7449 if (targs != null) {
7450 ex_method_lookup.SetTypeArguments (targs);
7453 return ex_method_lookup.DoResolve (ec);
7457 expr = expr_resolved;
7458 Error_MemberLookupFailed (
7459 ec.ContainerType, expr_type, expr_type, Name, null,
7460 AllMemberTypes, AllBindingFlags);
7464 TypeExpr texpr = member_lookup as TypeExpr;
7465 if (texpr != null) {
7466 if (!(expr_resolved is TypeExpr) &&
7467 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7468 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7469 Name, member_lookup.GetSignatureForError ());
7473 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7474 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7475 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7480 ConstructedType ct = expr_resolved as ConstructedType;
7483 // When looking up a nested type in a generic instance
7484 // via reflection, we always get a generic type definition
7485 // and not a generic instance - so we have to do this here.
7487 // See gtest-172-lib.cs and gtest-172.cs for an example.
7489 ct = new ConstructedType (
7490 member_lookup.Type, ct.TypeArguments, loc);
7492 return ct.ResolveAsTypeStep (ec, false);
7495 return member_lookup;
7498 MemberExpr me = (MemberExpr) member_lookup;
7499 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7503 if (targs != null) {
7504 me.SetTypeArguments (targs);
7507 if (original != null && !TypeManager.IsValueType (expr_type)) {
7508 if (me.IsInstance) {
7509 LocalVariableReference var = expr_resolved as LocalVariableReference;
7510 if (var != null && !var.VerifyAssigned (ec))
7515 // The following DoResolve/DoResolveLValue will do the definite assignment
7518 if (right_side != null)
7519 return me.DoResolveLValue (ec, right_side);
7521 return me.DoResolve (ec);
7524 public override Expression DoResolve (EmitContext ec)
7526 return DoResolve (ec, null);
7529 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7531 return DoResolve (ec, right_side);
7534 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7536 return ResolveNamespaceOrType (ec, silent);
7539 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7541 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7543 if (new_expr == null)
7546 string LookupIdentifier = MemberName.MakeName (Name, targs);
7548 if (new_expr is Namespace) {
7549 Namespace ns = (Namespace) new_expr;
7550 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7552 if ((retval != null) && (targs != null))
7553 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7555 if (!silent && retval == null)
7556 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7560 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7561 if (tnew_expr == null)
7564 if (tnew_expr is TypeParameterExpr) {
7565 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7566 tnew_expr.GetSignatureForError ());
7570 Type expr_type = tnew_expr.Type;
7571 Expression member_lookup = MemberLookup (
7572 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7573 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7574 if (member_lookup == null) {
7578 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7582 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7587 TypeArguments the_args = targs;
7588 Type declaring_type = texpr.Type.DeclaringType;
7589 if (TypeManager.HasGenericArguments (declaring_type)) {
7590 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7591 expr_type = expr_type.BaseType;
7594 TypeArguments new_args = new TypeArguments (loc);
7595 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7596 new_args.Add (new TypeExpression (decl, loc));
7599 new_args.Add (targs);
7601 the_args = new_args;
7604 if (the_args != null) {
7605 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7606 return ctype.ResolveAsTypeStep (rc, false);
7613 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7615 Expression member_lookup = MemberLookup (
7616 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7617 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7619 if (member_lookup != null) {
7620 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7621 if (expr_type == null)
7624 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7628 member_lookup = MemberLookup (
7629 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7630 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7632 if (member_lookup == null) {
7633 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7634 Name, expr_type.GetSignatureForError ());
7636 // TODO: Report.SymbolRelatedToPreviousError
7637 member_lookup.Error_UnexpectedKind (null, "type", loc);
7641 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7643 if (RootContext.Version > LanguageVersion.ISO_2 &&
7644 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7645 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7646 "extension method `{1}' of type `{0}' could be found " +
7647 "(are you missing a using directive or an assembly reference?)",
7648 TypeManager.CSharpName (type), name);
7652 base.Error_TypeDoesNotContainDefinition (type, name);
7655 public override string GetSignatureForError ()
7657 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7660 protected override void CloneTo (CloneContext clonectx, Expression t)
7662 MemberAccess target = (MemberAccess) t;
7664 target.expr = expr.Clone (clonectx);
7669 /// Implements checked expressions
7671 public class CheckedExpr : Expression {
7673 public Expression Expr;
7675 public CheckedExpr (Expression e, Location l)
7681 public override Expression CreateExpressionTree (EmitContext ec)
7683 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7684 return Expr.CreateExpressionTree (ec);
7687 public override Expression DoResolve (EmitContext ec)
7689 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7690 Expr = Expr.Resolve (ec);
7695 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7698 eclass = Expr.eclass;
7703 public override void Emit (EmitContext ec)
7705 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7709 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7711 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7712 Expr.EmitBranchable (ec, target, on_true);
7715 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7717 Expr.MutateHoistedGenericType (storey);
7720 protected override void CloneTo (CloneContext clonectx, Expression t)
7722 CheckedExpr target = (CheckedExpr) t;
7724 target.Expr = Expr.Clone (clonectx);
7729 /// Implements the unchecked expression
7731 public class UnCheckedExpr : Expression {
7733 public Expression Expr;
7735 public UnCheckedExpr (Expression e, Location l)
7741 public override Expression CreateExpressionTree (EmitContext ec)
7743 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7744 return Expr.CreateExpressionTree (ec);
7747 public override Expression DoResolve (EmitContext ec)
7749 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7750 Expr = Expr.Resolve (ec);
7755 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
7758 eclass = Expr.eclass;
7763 public override void Emit (EmitContext ec)
7765 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7769 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7771 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7772 Expr.EmitBranchable (ec, target, on_true);
7775 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7777 Expr.MutateHoistedGenericType (storey);
7780 protected override void CloneTo (CloneContext clonectx, Expression t)
7782 UnCheckedExpr target = (UnCheckedExpr) t;
7784 target.Expr = Expr.Clone (clonectx);
7789 /// An Element Access expression.
7791 /// During semantic analysis these are transformed into
7792 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7794 public class ElementAccess : Expression {
7795 public ArrayList Arguments;
7796 public Expression Expr;
7798 public ElementAccess (Expression e, ArrayList e_list)
7806 Arguments = new ArrayList (e_list.Count);
7807 foreach (Expression tmp in e_list)
7808 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7811 bool CommonResolve (EmitContext ec)
7813 Expr = Expr.Resolve (ec);
7815 if (Arguments == null)
7818 foreach (Argument a in Arguments){
7819 if (!a.Resolve (ec, loc))
7823 return Expr != null;
7826 public override Expression CreateExpressionTree (EmitContext ec)
7828 ArrayList args = new ArrayList (Arguments.Count + 1);
7829 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7830 foreach (Argument a in Arguments)
7831 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7833 return CreateExpressionFactoryCall ("ArrayIndex", args);
7836 Expression MakePointerAccess (EmitContext ec, Type t)
7838 if (Arguments.Count != 1){
7839 Error (196, "A pointer must be indexed by only one value");
7843 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7846 return new Indirection (p, loc).Resolve (ec);
7849 public override Expression DoResolve (EmitContext ec)
7851 if (!CommonResolve (ec))
7855 // We perform some simple tests, and then to "split" the emit and store
7856 // code we create an instance of a different class, and return that.
7858 // I am experimenting with this pattern.
7862 if (t == TypeManager.array_type){
7863 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7868 return (new ArrayAccess (this, loc)).Resolve (ec);
7870 return MakePointerAccess (ec, t);
7872 FieldExpr fe = Expr as FieldExpr;
7874 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7876 return MakePointerAccess (ec, ff.ElementType);
7879 return (new IndexerAccess (this, loc)).Resolve (ec);
7882 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7884 if (!CommonResolve (ec))
7889 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7892 return MakePointerAccess (ec, type);
7894 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7895 Error_CannotModifyIntermediateExpressionValue (ec);
7897 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7900 public override void Emit (EmitContext ec)
7902 throw new Exception ("Should never be reached");
7905 public override string GetSignatureForError ()
7907 return Expr.GetSignatureForError ();
7910 protected override void CloneTo (CloneContext clonectx, Expression t)
7912 ElementAccess target = (ElementAccess) t;
7914 target.Expr = Expr.Clone (clonectx);
7915 target.Arguments = new ArrayList (Arguments.Count);
7916 foreach (Argument a in Arguments)
7917 target.Arguments.Add (a.Clone (clonectx));
7922 /// Implements array access
7924 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7926 // Points to our "data" repository
7930 LocalTemporary temp;
7934 public ArrayAccess (ElementAccess ea_data, Location l)
7940 public override Expression CreateExpressionTree (EmitContext ec)
7942 return ea.CreateExpressionTree (ec);
7945 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7947 return DoResolve (ec);
7950 public override Expression DoResolve (EmitContext ec)
7953 ExprClass eclass = ea.Expr.eclass;
7955 // As long as the type is valid
7956 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7957 eclass == ExprClass.Value)) {
7958 ea.Expr.Error_UnexpectedKind ("variable or value");
7963 if (eclass != ExprClass.Invalid)
7966 Type t = ea.Expr.Type;
7967 int rank = ea.Arguments.Count;
7968 if (t.GetArrayRank () != rank) {
7969 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7970 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7974 type = TypeManager.GetElementType (t);
7975 if (type.IsPointer && !ec.InUnsafe) {
7976 UnsafeError (ea.Location);
7980 foreach (Argument a in ea.Arguments) {
7981 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7984 eclass = ExprClass.Variable;
7990 /// Emits the right opcode to load an object of Type `t'
7991 /// from an array of T
7993 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7996 MethodInfo get = FetchGetMethod ();
7997 ig.Emit (OpCodes.Call, get);
8001 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8002 ig.Emit (OpCodes.Ldelem_U1);
8003 else if (type == TypeManager.sbyte_type)
8004 ig.Emit (OpCodes.Ldelem_I1);
8005 else if (type == TypeManager.short_type)
8006 ig.Emit (OpCodes.Ldelem_I2);
8007 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8008 ig.Emit (OpCodes.Ldelem_U2);
8009 else if (type == TypeManager.int32_type)
8010 ig.Emit (OpCodes.Ldelem_I4);
8011 else if (type == TypeManager.uint32_type)
8012 ig.Emit (OpCodes.Ldelem_U4);
8013 else if (type == TypeManager.uint64_type)
8014 ig.Emit (OpCodes.Ldelem_I8);
8015 else if (type == TypeManager.int64_type)
8016 ig.Emit (OpCodes.Ldelem_I8);
8017 else if (type == TypeManager.float_type)
8018 ig.Emit (OpCodes.Ldelem_R4);
8019 else if (type == TypeManager.double_type)
8020 ig.Emit (OpCodes.Ldelem_R8);
8021 else if (type == TypeManager.intptr_type)
8022 ig.Emit (OpCodes.Ldelem_I);
8023 else if (TypeManager.IsEnumType (type)){
8024 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8025 } else if (type.IsValueType){
8026 ig.Emit (OpCodes.Ldelema, type);
8027 ig.Emit (OpCodes.Ldobj, type);
8029 } else if (type.IsGenericParameter) {
8030 ig.Emit (OpCodes.Ldelem, type);
8032 } else if (type.IsPointer)
8033 ig.Emit (OpCodes.Ldelem_I);
8035 ig.Emit (OpCodes.Ldelem_Ref);
8038 protected override void Error_NegativeArrayIndex (Location loc)
8040 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8044 /// Returns the right opcode to store an object of Type `t'
8045 /// from an array of T.
8047 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8049 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8050 has_type_arg = false; is_stobj = false;
8051 t = TypeManager.TypeToCoreType (t);
8052 if (TypeManager.IsEnumType (t))
8053 t = TypeManager.GetEnumUnderlyingType (t);
8054 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8055 t == TypeManager.bool_type)
8056 return OpCodes.Stelem_I1;
8057 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8058 t == TypeManager.char_type)
8059 return OpCodes.Stelem_I2;
8060 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8061 return OpCodes.Stelem_I4;
8062 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8063 return OpCodes.Stelem_I8;
8064 else if (t == TypeManager.float_type)
8065 return OpCodes.Stelem_R4;
8066 else if (t == TypeManager.double_type)
8067 return OpCodes.Stelem_R8;
8068 else if (t == TypeManager.intptr_type) {
8069 has_type_arg = true;
8071 return OpCodes.Stobj;
8072 } else if (t.IsValueType) {
8073 has_type_arg = true;
8075 return OpCodes.Stobj;
8077 } else if (t.IsGenericParameter) {
8078 has_type_arg = true;
8079 return OpCodes.Stelem;
8082 } else if (t.IsPointer)
8083 return OpCodes.Stelem_I;
8085 return OpCodes.Stelem_Ref;
8088 MethodInfo FetchGetMethod ()
8090 ModuleBuilder mb = CodeGen.Module.Builder;
8091 int arg_count = ea.Arguments.Count;
8092 Type [] args = new Type [arg_count];
8095 for (int i = 0; i < arg_count; i++){
8096 //args [i++] = a.Type;
8097 args [i] = TypeManager.int32_type;
8100 get = mb.GetArrayMethod (
8101 ea.Expr.Type, "Get",
8102 CallingConventions.HasThis |
8103 CallingConventions.Standard,
8109 MethodInfo FetchAddressMethod ()
8111 ModuleBuilder mb = CodeGen.Module.Builder;
8112 int arg_count = ea.Arguments.Count;
8113 Type [] args = new Type [arg_count];
8117 ret_type = TypeManager.GetReferenceType (type);
8119 for (int i = 0; i < arg_count; i++){
8120 //args [i++] = a.Type;
8121 args [i] = TypeManager.int32_type;
8124 address = mb.GetArrayMethod (
8125 ea.Expr.Type, "Address",
8126 CallingConventions.HasThis |
8127 CallingConventions.Standard,
8134 // Load the array arguments into the stack.
8136 void LoadArrayAndArguments (EmitContext ec)
8140 for (int i = 0; i < ea.Arguments.Count; ++i) {
8141 ((Argument)ea.Arguments [i]).Emit (ec);
8145 public void Emit (EmitContext ec, bool leave_copy)
8147 int rank = ea.Expr.Type.GetArrayRank ();
8148 ILGenerator ig = ec.ig;
8151 LoadFromPtr (ig, this.type);
8153 LoadArrayAndArguments (ec);
8154 EmitLoadOpcode (ig, type, rank);
8158 ig.Emit (OpCodes.Dup);
8159 temp = new LocalTemporary (this.type);
8164 public override void Emit (EmitContext ec)
8169 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8171 int rank = ea.Expr.Type.GetArrayRank ();
8172 ILGenerator ig = ec.ig;
8173 Type t = source.Type;
8174 prepared = prepare_for_load;
8177 AddressOf (ec, AddressOp.LoadStore);
8178 ec.ig.Emit (OpCodes.Dup);
8180 LoadArrayAndArguments (ec);
8184 bool is_stobj, has_type_arg;
8185 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8189 // The stobj opcode used by value types will need
8190 // an address on the stack, not really an array/array
8194 ig.Emit (OpCodes.Ldelema, t);
8199 ec.ig.Emit (OpCodes.Dup);
8200 temp = new LocalTemporary (this.type);
8205 StoreFromPtr (ig, t);
8207 ig.Emit (OpCodes.Stobj, t);
8208 else if (has_type_arg)
8215 ec.ig.Emit (OpCodes.Dup);
8216 temp = new LocalTemporary (this.type);
8221 StoreFromPtr (ig, t);
8223 int arg_count = ea.Arguments.Count;
8224 Type [] args = new Type [arg_count + 1];
8225 for (int i = 0; i < arg_count; i++) {
8226 //args [i++] = a.Type;
8227 args [i] = TypeManager.int32_type;
8229 args [arg_count] = type;
8231 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8232 ea.Expr.Type, "Set",
8233 CallingConventions.HasThis |
8234 CallingConventions.Standard,
8235 TypeManager.void_type, args);
8237 ig.Emit (OpCodes.Call, set);
8247 public void AddressOf (EmitContext ec, AddressOp mode)
8249 int rank = ea.Expr.Type.GetArrayRank ();
8250 ILGenerator ig = ec.ig;
8252 LoadArrayAndArguments (ec);
8255 ig.Emit (OpCodes.Ldelema, type);
8257 MethodInfo address = FetchAddressMethod ();
8258 ig.Emit (OpCodes.Call, address);
8262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8264 type = storey.MutateType (type);
8265 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8270 /// Expressions that represent an indexer call.
8272 public class IndexerAccess : Expression, IAssignMethod
8274 class IndexerMethodGroupExpr : MethodGroupExpr
8276 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8279 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8282 public override string Name {
8288 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8291 // Here is the trick, decrease number of arguments by 1 when only
8292 // available property method is setter. This makes overload resolution
8293 // work correctly for indexers.
8296 if (method.Name [0] == 'g')
8297 return parameters.Count;
8299 return parameters.Count - 1;
8305 // Contains either property getter or setter
8306 public ArrayList Methods;
8307 public ArrayList Properties;
8313 void Append (Type caller_type, MemberInfo [] mi)
8318 foreach (PropertyInfo property in mi) {
8319 MethodInfo accessor = property.GetGetMethod (true);
8320 if (accessor == null)
8321 accessor = property.GetSetMethod (true);
8323 if (Methods == null) {
8324 Methods = new ArrayList ();
8325 Properties = new ArrayList ();
8328 Methods.Add (accessor);
8329 Properties.Add (property);
8333 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8335 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8337 return TypeManager.MemberLookup (
8338 caller_type, caller_type, lookup_type, MemberTypes.Property,
8339 BindingFlags.Public | BindingFlags.Instance |
8340 BindingFlags.DeclaredOnly, p_name, null);
8343 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8345 Indexers ix = new Indexers ();
8348 if (lookup_type.IsGenericParameter) {
8349 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8353 if (gc.HasClassConstraint)
8354 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8356 Type[] ifaces = gc.InterfaceConstraints;
8357 foreach (Type itype in ifaces)
8358 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8364 Type copy = lookup_type;
8365 while (copy != TypeManager.object_type && copy != null){
8366 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8367 copy = copy.BaseType;
8370 if (lookup_type.IsInterface) {
8371 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8372 if (ifaces != null) {
8373 foreach (Type itype in ifaces)
8374 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8389 // Points to our "data" repository
8391 MethodInfo get, set;
8392 bool is_base_indexer;
8394 LocalTemporary temp;
8395 LocalTemporary prepared_value;
8396 Expression set_expr;
8398 protected Type indexer_type;
8399 protected Type current_type;
8400 protected Expression instance_expr;
8401 protected ArrayList arguments;
8403 public IndexerAccess (ElementAccess ea, Location loc)
8404 : this (ea.Expr, false, loc)
8406 this.arguments = ea.Arguments;
8409 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8412 this.instance_expr = instance_expr;
8413 this.is_base_indexer = is_base_indexer;
8414 this.eclass = ExprClass.Value;
8418 static string GetAccessorName (AccessorType at)
8420 if (at == AccessorType.Set)
8423 if (at == AccessorType.Get)
8426 throw new NotImplementedException (at.ToString ());
8429 public override Expression CreateExpressionTree (EmitContext ec)
8431 ArrayList args = new ArrayList (arguments.Count + 2);
8432 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8433 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8434 foreach (Argument a in arguments)
8435 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8437 return CreateExpressionFactoryCall ("Call", args);
8440 protected virtual bool CommonResolve (EmitContext ec)
8442 indexer_type = instance_expr.Type;
8443 current_type = ec.ContainerType;
8448 public override Expression DoResolve (EmitContext ec)
8450 return ResolveAccessor (ec, AccessorType.Get);
8453 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8455 if (right_side == EmptyExpression.OutAccess) {
8456 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8457 GetSignatureForError ());
8461 // if the indexer returns a value type, and we try to set a field in it
8462 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8463 Error_CannotModifyIntermediateExpressionValue (ec);
8466 Expression e = ResolveAccessor (ec, AccessorType.Set);
8470 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8474 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8476 if (!CommonResolve (ec))
8479 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8480 if (ilist.Methods == null) {
8481 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8482 TypeManager.CSharpName (indexer_type));
8486 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8487 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8491 MethodInfo mi = (MethodInfo) mg;
8492 PropertyInfo pi = null;
8493 for (int i = 0; i < ilist.Methods.Count; ++i) {
8494 if (ilist.Methods [i] == mi) {
8495 pi = (PropertyInfo) ilist.Properties [i];
8500 type = TypeManager.TypeToCoreType (pi.PropertyType);
8501 if (type.IsPointer && !ec.InUnsafe)
8504 MethodInfo accessor;
8505 if (accessorType == AccessorType.Get) {
8506 accessor = get = pi.GetGetMethod (true);
8508 accessor = set = pi.GetSetMethod (true);
8509 if (accessor == null && pi.GetGetMethod (true) != null) {
8510 Report.SymbolRelatedToPreviousError (pi);
8511 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8512 TypeManager.GetFullNameSignature (pi));
8517 if (accessor == null) {
8518 Report.SymbolRelatedToPreviousError (pi);
8519 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8520 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8525 // Only base will allow this invocation to happen.
8527 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8528 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8531 bool must_do_cs1540_check;
8532 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8534 set = pi.GetSetMethod (true);
8536 get = pi.GetGetMethod (true);
8538 if (set != null && get != null &&
8539 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8540 Report.SymbolRelatedToPreviousError (accessor);
8541 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8542 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8544 Report.SymbolRelatedToPreviousError (pi);
8545 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8549 instance_expr.CheckMarshalByRefAccess (ec);
8550 eclass = ExprClass.IndexerAccess;
8554 public void Emit (EmitContext ec, bool leave_copy)
8557 prepared_value.Emit (ec);
8559 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8560 arguments, loc, false, false);
8564 ec.ig.Emit (OpCodes.Dup);
8565 temp = new LocalTemporary (Type);
8571 // source is ignored, because we already have a copy of it from the
8572 // LValue resolution and we have already constructed a pre-cached
8573 // version of the arguments (ea.set_arguments);
8575 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8577 prepared = prepare_for_load;
8578 Expression value = set_expr;
8581 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8582 arguments, loc, true, false);
8584 prepared_value = new LocalTemporary (type);
8585 prepared_value.Store (ec);
8587 prepared_value.Release (ec);
8590 ec.ig.Emit (OpCodes.Dup);
8591 temp = new LocalTemporary (Type);
8594 } else if (leave_copy) {
8595 temp = new LocalTemporary (Type);
8601 arguments.Add (new Argument (value, Argument.AType.Expression));
8602 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8610 public override void Emit (EmitContext ec)
8615 public override string GetSignatureForError ()
8617 return TypeManager.CSharpSignature (get != null ? get : set, false);
8620 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8623 get = storey.MutateGenericMethod (get);
8625 set = storey.MutateGenericMethod (set);
8627 instance_expr.MutateHoistedGenericType (storey);
8628 foreach (Argument a in arguments)
8629 a.Expr.MutateHoistedGenericType (storey);
8631 type = storey.MutateType (type);
8634 protected override void CloneTo (CloneContext clonectx, Expression t)
8636 IndexerAccess target = (IndexerAccess) t;
8638 if (arguments != null){
8639 target.arguments = new ArrayList ();
8640 foreach (Argument a in arguments)
8641 target.arguments.Add (a.Clone (clonectx));
8643 if (instance_expr != null)
8644 target.instance_expr = instance_expr.Clone (clonectx);
8649 /// The base operator for method names
8651 public class BaseAccess : Expression {
8652 public readonly string Identifier;
8655 public BaseAccess (string member, Location l)
8657 this.Identifier = member;
8661 public BaseAccess (string member, TypeArguments args, Location l)
8667 public override Expression CreateExpressionTree (EmitContext ec)
8669 throw new NotSupportedException ("ET");
8672 public override Expression DoResolve (EmitContext ec)
8674 Expression c = CommonResolve (ec);
8680 // MethodGroups use this opportunity to flag an error on lacking ()
8682 if (!(c is MethodGroupExpr))
8683 return c.Resolve (ec);
8687 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8689 Expression c = CommonResolve (ec);
8695 // MethodGroups use this opportunity to flag an error on lacking ()
8697 if (! (c is MethodGroupExpr))
8698 return c.DoResolveLValue (ec, right_side);
8703 Expression CommonResolve (EmitContext ec)
8705 Expression member_lookup;
8706 Type current_type = ec.ContainerType;
8707 Type base_type = current_type.BaseType;
8709 if (!This.IsThisAvailable (ec)) {
8711 Error (1511, "Keyword `base' is not available in a static method");
8713 Error (1512, "Keyword `base' is not available in the current context");
8718 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8719 AllMemberTypes, AllBindingFlags, loc);
8720 if (member_lookup == null) {
8721 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8722 null, AllMemberTypes, AllBindingFlags);
8729 left = new TypeExpression (base_type, loc);
8731 left = ec.GetThis (loc);
8733 MemberExpr me = (MemberExpr) member_lookup;
8734 me = me.ResolveMemberAccess (ec, left, loc, null);
8741 me.SetTypeArguments (args);
8747 public override void Emit (EmitContext ec)
8749 throw new Exception ("Should never be called");
8752 protected override void CloneTo (CloneContext clonectx, Expression t)
8754 BaseAccess target = (BaseAccess) t;
8757 target.args = args.Clone ();
8762 /// The base indexer operator
8764 public class BaseIndexerAccess : IndexerAccess {
8765 public BaseIndexerAccess (ArrayList args, Location loc)
8766 : base (null, true, loc)
8768 arguments = new ArrayList ();
8769 foreach (Expression tmp in args)
8770 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8773 protected override bool CommonResolve (EmitContext ec)
8775 instance_expr = ec.GetThis (loc);
8777 current_type = ec.ContainerType.BaseType;
8778 indexer_type = current_type;
8780 foreach (Argument a in arguments){
8781 if (!a.Resolve (ec, loc))
8788 public override Expression CreateExpressionTree (EmitContext ec)
8790 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8791 return base.CreateExpressionTree (ec);
8796 /// This class exists solely to pass the Type around and to be a dummy
8797 /// that can be passed to the conversion functions (this is used by
8798 /// foreach implementation to typecast the object return value from
8799 /// get_Current into the proper type. All code has been generated and
8800 /// we only care about the side effect conversions to be performed
8802 /// This is also now used as a placeholder where a no-action expression
8803 /// is needed (the `New' class).
8805 public class EmptyExpression : Expression {
8806 public static readonly Expression Null = new EmptyExpression ();
8808 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8809 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8810 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8811 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8813 static EmptyExpression temp = new EmptyExpression ();
8814 public static EmptyExpression Grab ()
8816 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8821 public static void Release (EmptyExpression e)
8826 // TODO: should be protected
8827 public EmptyExpression ()
8829 type = TypeManager.object_type;
8830 eclass = ExprClass.Value;
8831 loc = Location.Null;
8834 public EmptyExpression (Type t)
8837 eclass = ExprClass.Value;
8838 loc = Location.Null;
8841 public override Expression CreateExpressionTree (EmitContext ec)
8843 throw new NotSupportedException ("ET");
8846 public override Expression DoResolve (EmitContext ec)
8851 public override void Emit (EmitContext ec)
8853 // nothing, as we only exist to not do anything.
8856 public override void EmitSideEffect (EmitContext ec)
8861 // This is just because we might want to reuse this bad boy
8862 // instead of creating gazillions of EmptyExpressions.
8863 // (CanImplicitConversion uses it)
8865 public void SetType (Type t)
8872 // Empty statement expression
8874 public sealed class EmptyExpressionStatement : ExpressionStatement
8876 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8878 private EmptyExpressionStatement ()
8880 type = TypeManager.object_type;
8881 eclass = ExprClass.Value;
8882 loc = Location.Null;
8885 public override Expression CreateExpressionTree (EmitContext ec)
8890 public override void EmitStatement (EmitContext ec)
8895 public override Expression DoResolve (EmitContext ec)
8900 public override void Emit (EmitContext ec)
8906 public class UserCast : Expression {
8910 public UserCast (MethodInfo method, Expression source, Location l)
8912 this.method = method;
8913 this.source = source;
8914 type = TypeManager.TypeToCoreType (method.ReturnType);
8918 public Expression Source {
8924 public override Expression CreateExpressionTree (EmitContext ec)
8926 ArrayList args = new ArrayList (3);
8927 args.Add (new Argument (source.CreateExpressionTree (ec)));
8928 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8929 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8930 return CreateExpressionFactoryCall ("Convert", args);
8933 public override Expression DoResolve (EmitContext ec)
8935 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8937 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8939 eclass = ExprClass.Value;
8943 public override void Emit (EmitContext ec)
8946 ec.ig.Emit (OpCodes.Call, method);
8949 public override string GetSignatureForError ()
8951 return TypeManager.CSharpSignature (method);
8954 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8956 source.MutateHoistedGenericType (storey);
8957 method = storey.MutateGenericMethod (method);
8962 // This class is used to "construct" the type during a typecast
8963 // operation. Since the Type.GetType class in .NET can parse
8964 // the type specification, we just use this to construct the type
8965 // one bit at a time.
8967 public class ComposedCast : TypeExpr {
8968 FullNamedExpression left;
8971 public ComposedCast (FullNamedExpression left, string dim)
8972 : this (left, dim, left.Location)
8976 public ComposedCast (FullNamedExpression left, string dim, Location l)
8983 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8985 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8989 Type ltype = lexpr.Type;
8991 if ((dim.Length > 0) && (dim [0] == '?')) {
8992 TypeExpr nullable = new Nullable.NullableType (left, loc);
8994 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8995 return nullable.ResolveAsTypeTerminal (ec, false);
8999 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
9002 if (dim.Length != 0 && dim [0] == '[') {
9003 if (TypeManager.IsSpecialType (ltype)) {
9004 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9008 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9009 Report.SymbolRelatedToPreviousError (ltype);
9010 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9011 TypeManager.CSharpName (ltype));
9016 type = TypeManager.GetConstructedType (ltype, dim);
9021 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9023 if (type.IsPointer && !ec.IsInUnsafeScope){
9027 eclass = ExprClass.Type;
9031 public override string GetSignatureForError ()
9033 return left.GetSignatureForError () + dim;
9036 protected override void CloneTo (CloneContext clonectx, Expression t)
9038 ComposedCast target = (ComposedCast) t;
9040 target.left = (FullNamedExpression)left.Clone (clonectx);
9043 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
9045 return ResolveAsBaseTerminal (ec, silent);
9049 public class FixedBufferPtr : Expression {
9052 public FixedBufferPtr (Expression array, Type array_type, Location l)
9057 type = TypeManager.GetPointerType (array_type);
9058 eclass = ExprClass.Value;
9061 public override Expression CreateExpressionTree (EmitContext ec)
9063 Error_PointerInsideExpressionTree ();
9067 public override void Emit(EmitContext ec)
9072 public override Expression DoResolve (EmitContext ec)
9075 // We are born fully resolved
9083 // This class is used to represent the address of an array, used
9084 // only by the Fixed statement, this generates "&a [0]" construct
9085 // for fixed (char *pa = a)
9087 public class ArrayPtr : FixedBufferPtr {
9090 public ArrayPtr (Expression array, Type array_type, Location l):
9091 base (array, array_type, l)
9093 this.array_type = array_type;
9096 public override void Emit (EmitContext ec)
9100 ILGenerator ig = ec.ig;
9101 IntLiteral.EmitInt (ig, 0);
9102 ig.Emit (OpCodes.Ldelema, array_type);
9107 // Encapsulates a conversion rules required for array indexes
9109 public class ArrayIndexCast : TypeCast
9111 public ArrayIndexCast (Expression expr)
9112 : base (expr, expr.Type)
9116 public override Expression CreateExpressionTree (EmitContext ec)
9118 ArrayList args = new ArrayList (2);
9119 args.Add (new Argument (child.CreateExpressionTree (ec)));
9120 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9121 return CreateExpressionFactoryCall ("ConvertChecked", args);
9124 public override void Emit (EmitContext ec)
9128 if (type == TypeManager.int32_type)
9131 if (type == TypeManager.uint32_type)
9132 ec.ig.Emit (OpCodes.Conv_U);
9133 else if (type == TypeManager.int64_type)
9134 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9135 else if (type == TypeManager.uint64_type)
9136 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9138 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9143 // Implements the `stackalloc' keyword
9145 public class StackAlloc : Expression {
9150 public StackAlloc (Expression type, Expression count, Location l)
9157 public override Expression CreateExpressionTree (EmitContext ec)
9159 throw new NotSupportedException ("ET");
9162 public override Expression DoResolve (EmitContext ec)
9164 count = count.Resolve (ec);
9168 if (count.Type != TypeManager.uint32_type){
9169 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9174 Constant c = count as Constant;
9175 if (c != null && c.IsNegative) {
9176 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9180 if (ec.InCatch || ec.InFinally) {
9181 Error (255, "Cannot use stackalloc in finally or catch");
9185 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9191 if (!TypeManager.VerifyUnManaged (otype, loc))
9194 type = TypeManager.GetPointerType (otype);
9195 eclass = ExprClass.Value;
9200 public override void Emit (EmitContext ec)
9202 int size = GetTypeSize (otype);
9203 ILGenerator ig = ec.ig;
9208 ig.Emit (OpCodes.Sizeof, otype);
9210 IntConstant.EmitInt (ig, size);
9212 ig.Emit (OpCodes.Mul_Ovf_Un);
9213 ig.Emit (OpCodes.Localloc);
9216 protected override void CloneTo (CloneContext clonectx, Expression t)
9218 StackAlloc target = (StackAlloc) t;
9219 target.count = count.Clone (clonectx);
9220 target.t = t.Clone (clonectx);
9225 // An object initializer expression
9227 public class ElementInitializer : Assign
9229 public readonly string Name;
9231 public ElementInitializer (string name, Expression initializer, Location loc)
9232 : base (null, initializer, loc)
9237 protected override void CloneTo (CloneContext clonectx, Expression t)
9239 ElementInitializer target = (ElementInitializer) t;
9240 target.source = source.Clone (clonectx);
9243 public override Expression CreateExpressionTree (EmitContext ec)
9245 ArrayList args = new ArrayList (2);
9246 FieldExpr fe = target as FieldExpr;
9248 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9250 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9252 args.Add (new Argument (source.CreateExpressionTree (ec)));
9253 return CreateExpressionFactoryCall (
9254 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9258 public override Expression DoResolve (EmitContext ec)
9261 return EmptyExpressionStatement.Instance;
9263 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9264 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9270 me.InstanceExpression = ec.CurrentInitializerVariable;
9272 if (source is CollectionOrObjectInitializers) {
9273 Expression previous = ec.CurrentInitializerVariable;
9274 ec.CurrentInitializerVariable = target;
9275 source = source.Resolve (ec);
9276 ec.CurrentInitializerVariable = previous;
9280 eclass = source.eclass;
9285 Expression expr = base.DoResolve (ec);
9290 // Ignore field initializers with default value
9292 Constant c = source as Constant;
9293 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9294 return EmptyExpressionStatement.Instance;
9299 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9301 MemberInfo member = members [0];
9302 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9303 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9304 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9306 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9307 TypeManager.GetFullNameSignature (member));
9312 public override void EmitStatement (EmitContext ec)
9314 if (source is CollectionOrObjectInitializers)
9317 base.EmitStatement (ec);
9322 // A collection initializer expression
9324 public class CollectionElementInitializer : Invocation
9326 public class ElementInitializerArgument : Argument
9328 public ElementInitializerArgument (Expression e)
9334 sealed class AddMemberAccess : MemberAccess
9336 public AddMemberAccess (Expression expr, Location loc)
9337 : base (expr, "Add", loc)
9341 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9343 if (TypeManager.HasElementType (type))
9346 base.Error_TypeDoesNotContainDefinition (type, name);
9350 public CollectionElementInitializer (Expression argument)
9351 : base (null, new ArrayList (1), true)
9353 Arguments.Add (argument);
9354 this.loc = argument.Location;
9357 public CollectionElementInitializer (ArrayList arguments, Location loc)
9358 : base (null, arguments, true)
9363 public override Expression CreateExpressionTree (EmitContext ec)
9365 ArrayList args = new ArrayList (2);
9366 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9368 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9369 foreach (Argument a in Arguments)
9370 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9372 args.Add (new Argument (new ArrayCreation (
9373 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9374 return CreateExpressionFactoryCall ("ElementInit", args);
9377 protected override void CloneTo (CloneContext clonectx, Expression t)
9379 CollectionElementInitializer target = (CollectionElementInitializer) t;
9381 target.Arguments = new ArrayList (Arguments.Count);
9382 foreach (Expression e in Arguments)
9383 target.Arguments.Add (e.Clone (clonectx));
9386 public override Expression DoResolve (EmitContext ec)
9388 if (eclass != ExprClass.Invalid)
9391 // TODO: We could call a constructor which takes element count argument,
9392 // for known types like List<T>, Dictionary<T, U>
9394 for (int i = 0; i < Arguments.Count; ++i) {
9395 Expression expr = Arguments [i] as Expression;
9399 expr = expr.Resolve (ec);
9403 Arguments [i] = new ElementInitializerArgument (expr);
9406 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9408 return base.DoResolve (ec);
9413 // A block of object or collection initializers
9415 public class CollectionOrObjectInitializers : ExpressionStatement
9417 ArrayList initializers;
9419 public static readonly CollectionOrObjectInitializers Empty =
9420 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9422 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9424 this.initializers = initializers;
9428 public bool IsEmpty {
9430 return initializers.Count == 0;
9434 public bool IsCollectionInitializer {
9436 return type == typeof (CollectionOrObjectInitializers);
9440 protected override void CloneTo (CloneContext clonectx, Expression target)
9442 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9444 t.initializers = new ArrayList (initializers.Count);
9445 foreach (Expression e in initializers)
9446 t.initializers.Add (e.Clone (clonectx));
9449 public override Expression CreateExpressionTree (EmitContext ec)
9451 ArrayList expr_initializers = new ArrayList (initializers.Count);
9452 foreach (Expression e in initializers) {
9453 Expression expr = e.CreateExpressionTree (ec);
9455 expr_initializers.Add (expr);
9458 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9461 public override Expression DoResolve (EmitContext ec)
9463 if (eclass != ExprClass.Invalid)
9466 bool is_collection_initialization = false;
9467 ArrayList element_names = null;
9468 for (int i = 0; i < initializers.Count; ++i) {
9469 Expression initializer = (Expression) initializers [i];
9470 ElementInitializer element_initializer = initializer as ElementInitializer;
9473 if (element_initializer != null) {
9474 element_names = new ArrayList (initializers.Count);
9475 element_names.Add (element_initializer.Name);
9477 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9478 TypeManager.ienumerable_type)) {
9479 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9480 "object initializer because type `{1}' does not implement `{2}' interface",
9481 ec.CurrentInitializerVariable.GetSignatureForError (),
9482 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9483 TypeManager.CSharpName (TypeManager.ienumerable_type));
9486 is_collection_initialization = true;
9489 if (is_collection_initialization != (element_initializer == null)) {
9490 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9491 is_collection_initialization ? "collection initializer" : "object initializer");
9495 if (!is_collection_initialization) {
9496 if (element_names.Contains (element_initializer.Name)) {
9497 Report.Error (1912, element_initializer.Location,
9498 "An object initializer includes more than one member `{0}' initialization",
9499 element_initializer.Name);
9501 element_names.Add (element_initializer.Name);
9506 Expression e = initializer.Resolve (ec);
9507 if (e == EmptyExpressionStatement.Instance)
9508 initializers.RemoveAt (i--);
9510 initializers [i] = e;
9513 if (is_collection_initialization) {
9514 if (TypeManager.HasElementType (ec.CurrentInitializerVariable.Type)) {
9515 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9516 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type));
9519 type = typeof (CollectionOrObjectInitializers);
9521 type = typeof (ElementInitializer);
9524 eclass = ExprClass.Variable;
9528 public override void Emit (EmitContext ec)
9533 public override void EmitStatement (EmitContext ec)
9535 foreach (ExpressionStatement e in initializers)
9536 e.EmitStatement (ec);
9539 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9541 foreach (Expression e in initializers)
9542 e.MutateHoistedGenericType (storey);
9547 // New expression with element/object initializers
9549 public class NewInitialize : New
9552 // This class serves as a proxy for variable initializer target instances.
9553 // A real variable is assigned later when we resolve left side of an
9556 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9558 NewInitialize new_instance;
9560 public InitializerTargetExpression (NewInitialize newInstance)
9562 this.type = newInstance.type;
9563 this.loc = newInstance.loc;
9564 this.eclass = newInstance.eclass;
9565 this.new_instance = newInstance;
9568 public override Expression CreateExpressionTree (EmitContext ec)
9570 // Should not be reached
9571 throw new NotSupportedException ("ET");
9574 public override Expression DoResolve (EmitContext ec)
9579 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9584 public override void Emit (EmitContext ec)
9586 new_instance.value_target.Emit (ec);
9589 #region IMemoryLocation Members
9591 public void AddressOf (EmitContext ec, AddressOp mode)
9593 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9599 CollectionOrObjectInitializers initializers;
9601 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9602 : base (requested_type, arguments, l)
9604 this.initializers = initializers;
9607 protected override void CloneTo (CloneContext clonectx, Expression t)
9609 base.CloneTo (clonectx, t);
9611 NewInitialize target = (NewInitialize) t;
9612 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9615 public override Expression CreateExpressionTree (EmitContext ec)
9617 ArrayList args = new ArrayList (2);
9618 args.Add (new Argument (base.CreateExpressionTree (ec)));
9619 if (!initializers.IsEmpty)
9620 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9622 return CreateExpressionFactoryCall (
9623 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9627 public override Expression DoResolve (EmitContext ec)
9629 if (eclass != ExprClass.Invalid)
9632 Expression e = base.DoResolve (ec);
9636 // Empty initializer can be optimized to simple new
9637 if (initializers.IsEmpty) {
9638 initializers.Resolve (ec);
9639 return ReducedExpression.Create (e, this).Resolve (ec);
9642 Expression previous = ec.CurrentInitializerVariable;
9643 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9644 initializers.Resolve (ec);
9645 ec.CurrentInitializerVariable = previous;
9649 public override void Emit (EmitContext ec)
9654 // If target is non-hoisted variable, let's use it
9656 VariableReference variable = value_target as VariableReference;
9657 if (variable != null && variable.HoistedVariable == null) {
9659 StoreFromPtr (ec.ig, type);
9661 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9664 if (value_target == null || value_target_set)
9665 value_target = new LocalTemporary (type);
9667 ((LocalTemporary) value_target).Store (ec);
9670 initializers.Emit (ec);
9672 if (variable == null) {
9673 value_target.Emit (ec);
9674 value_target = null;
9678 public override void EmitStatement (EmitContext ec)
9680 if (initializers.IsEmpty) {
9681 base.EmitStatement (ec);
9687 if (value_target == null) {
9688 LocalTemporary variable = new LocalTemporary (type);
9689 variable.Store (ec);
9690 value_target = variable;
9693 initializers.EmitStatement (ec);
9696 public override bool HasInitializer {
9698 return !initializers.IsEmpty;
9702 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9704 base.MutateHoistedGenericType (storey);
9705 initializers.MutateHoistedGenericType (storey);
9709 public class AnonymousTypeDeclaration : Expression
9711 ArrayList parameters;
9712 readonly TypeContainer parent;
9713 static readonly ArrayList EmptyParameters = new ArrayList (0);
9715 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9717 this.parameters = parameters;
9718 this.parent = parent;
9722 protected override void CloneTo (CloneContext clonectx, Expression target)
9724 if (parameters == null)
9727 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9728 t.parameters = new ArrayList (parameters.Count);
9729 foreach (AnonymousTypeParameter atp in parameters)
9730 t.parameters.Add (atp.Clone (clonectx));
9733 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9735 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9739 type = AnonymousTypeClass.Create (parent, parameters, loc);
9746 if (Report.Errors == 0)
9749 RootContext.ToplevelTypes.AddAnonymousType (type);
9753 public override Expression CreateExpressionTree (EmitContext ec)
9755 throw new NotSupportedException ("ET");
9758 public override Expression DoResolve (EmitContext ec)
9760 AnonymousTypeClass anonymous_type;
9762 if (!ec.IsAnonymousMethodAllowed) {
9763 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9767 if (parameters == null) {
9768 anonymous_type = CreateAnonymousType (EmptyParameters);
9769 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9770 null, loc).Resolve (ec);
9774 ArrayList arguments = new ArrayList (parameters.Count);
9775 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9776 for (int i = 0; i < parameters.Count; ++i) {
9777 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9783 arguments.Add (new Argument (e));
9784 t_args [i] = new TypeExpression (e.Type, e.Location);
9790 anonymous_type = CreateAnonymousType (parameters);
9791 if (anonymous_type == null)
9794 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9795 new TypeArguments (loc, t_args), loc);
9797 return new New (te, arguments, loc).Resolve (ec);
9800 public override void Emit (EmitContext ec)
9802 throw new InternalErrorException ("Should not be reached");
9806 public class AnonymousTypeParameter : Expression
9808 public readonly string Name;
9809 Expression initializer;
9811 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9815 this.initializer = initializer;
9818 public AnonymousTypeParameter (Parameter parameter)
9820 this.Name = parameter.Name;
9821 this.loc = parameter.Location;
9822 this.initializer = new SimpleName (Name, loc);
9825 protected override void CloneTo (CloneContext clonectx, Expression target)
9827 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9828 t.initializer = initializer.Clone (clonectx);
9831 public override Expression CreateExpressionTree (EmitContext ec)
9833 throw new NotSupportedException ("ET");
9836 public override bool Equals (object o)
9838 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9839 return other != null && Name == other.Name;
9842 public override int GetHashCode ()
9844 return Name.GetHashCode ();
9847 public override Expression DoResolve (EmitContext ec)
9849 Expression e = initializer.Resolve (ec);
9853 if (e.eclass == ExprClass.MethodGroup) {
9854 Error_InvalidInitializer (e.ExprClassName);
9859 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9860 type == TypeManager.anonymous_method_type || type.IsPointer) {
9861 Error_InvalidInitializer (e.GetSignatureForError ());
9868 protected virtual void Error_InvalidInitializer (string initializer)
9870 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9874 public override void Emit (EmitContext ec)
9876 throw new InternalErrorException ("Should not be reached");