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)
95 this.loc = expr.Location;
98 public override Expression CreateExpressionTree (EmitContext ec)
100 throw new NotSupportedException ("ET");
103 public override Expression DoResolve (EmitContext ec)
105 Expr = Expr.Resolve (ec);
109 public override void Emit (EmitContext ec)
111 throw new Exception ("Should not happen");
114 protected override void CloneTo (CloneContext clonectx, Expression t)
116 ParenthesizedExpression target = (ParenthesizedExpression) t;
118 target.Expr = Expr.Clone (clonectx);
123 // Unary implements unary expressions.
125 public class Unary : Expression {
126 public enum Operator : byte {
127 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 static Type [] [] predefined_operators;
133 public readonly Operator Oper;
134 public Expression Expr;
135 Expression enum_conversion;
137 public Unary (Operator op, Expression expr, Location loc)
145 // This routine will attempt to simplify the unary expression when the
146 // argument is a constant.
148 Constant TryReduceConstant (EmitContext ec, Constant e)
150 if (e is SideEffectConstant) {
151 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
152 return r == null ? null : new SideEffectConstant (r, e, r.Location);
155 Type expr_type = e.Type;
158 case Operator.UnaryPlus:
159 // Unary numeric promotions
160 if (expr_type == TypeManager.byte_type)
161 return new IntConstant (((ByteConstant)e).Value, e.Location);
162 if (expr_type == TypeManager.sbyte_type)
163 return new IntConstant (((SByteConstant)e).Value, e.Location);
164 if (expr_type == TypeManager.short_type)
165 return new IntConstant (((ShortConstant)e).Value, e.Location);
166 if (expr_type == TypeManager.ushort_type)
167 return new IntConstant (((UShortConstant)e).Value, e.Location);
168 if (expr_type == TypeManager.char_type)
169 return new IntConstant (((CharConstant)e).Value, e.Location);
171 // Predefined operators
172 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
173 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
174 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
175 expr_type == TypeManager.decimal_type)
182 case Operator.UnaryNegation:
183 // Unary numeric promotions
184 if (expr_type == TypeManager.byte_type)
185 return new IntConstant (-((ByteConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.sbyte_type)
187 return new IntConstant (-((SByteConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.short_type)
189 return new IntConstant (-((ShortConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.ushort_type)
191 return new IntConstant (-((UShortConstant)e).Value, e.Location);
192 if (expr_type == TypeManager.char_type)
193 return new IntConstant (-((CharConstant)e).Value, e.Location);
195 // Predefined operators
196 if (expr_type == TypeManager.int32_type) {
197 int value = ((IntConstant)e).Value;
198 if (value == int.MinValue) {
199 if (ec.ConstantCheckState) {
200 ConstantFold.Error_CompileTimeOverflow (loc);
205 return new IntConstant (-value, e.Location);
207 if (expr_type == TypeManager.int64_type) {
208 long value = ((LongConstant)e).Value;
209 if (value == long.MinValue) {
210 if (ec.ConstantCheckState) {
211 ConstantFold.Error_CompileTimeOverflow (loc);
216 return new LongConstant (-value, e.Location);
219 if (expr_type == TypeManager.uint32_type) {
220 UIntLiteral uil = e as UIntLiteral;
222 if (uil.Value == 2147483648)
223 return new IntLiteral (int.MinValue, e.Location);
224 return new LongLiteral (-uil.Value, e.Location);
226 return new LongConstant (-((UIntConstant)e).Value, e.Location);
229 if (expr_type == TypeManager.uint64_type) {
230 ULongLiteral ull = e as ULongLiteral;
231 if (ull != null && ull.Value == 9223372036854775808)
232 return new LongLiteral (long.MinValue, e.Location);
236 if (expr_type == TypeManager.float_type) {
237 FloatLiteral fl = e as FloatLiteral;
238 // For better error reporting
240 fl.Value = -fl.Value;
243 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.double_type) {
246 DoubleLiteral dl = e as DoubleLiteral;
247 // For better error reporting
249 dl.Value = -dl.Value;
253 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
255 if (expr_type == TypeManager.decimal_type)
256 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
260 case Operator.LogicalNot:
261 if (expr_type != TypeManager.bool_type)
264 bool b = (bool)e.GetValue ();
265 return new BoolConstant (!b, e.Location);
267 case Operator.OnesComplement:
268 // Unary numeric promotions
269 if (expr_type == TypeManager.byte_type)
270 return new IntConstant (~((ByteConstant)e).Value, e.Location);
271 if (expr_type == TypeManager.sbyte_type)
272 return new IntConstant (~((SByteConstant)e).Value, e.Location);
273 if (expr_type == TypeManager.short_type)
274 return new IntConstant (~((ShortConstant)e).Value, e.Location);
275 if (expr_type == TypeManager.ushort_type)
276 return new IntConstant (~((UShortConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.char_type)
278 return new IntConstant (~((CharConstant)e).Value, e.Location);
280 // Predefined operators
281 if (expr_type == TypeManager.int32_type)
282 return new IntConstant (~((IntConstant)e).Value, e.Location);
283 if (expr_type == TypeManager.uint32_type)
284 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
285 if (expr_type == TypeManager.int64_type)
286 return new LongConstant (~((LongConstant)e).Value, e.Location);
287 if (expr_type == TypeManager.uint64_type){
288 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
290 if (e is EnumConstant) {
291 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
293 e = new EnumConstant (e, expr_type);
298 throw new Exception ("Can not constant fold: " + Oper.ToString());
301 protected Expression ResolveOperator (EmitContext ec, Expression expr)
303 eclass = ExprClass.Value;
305 if (predefined_operators == null)
306 CreatePredefinedOperatorsTable ();
308 Type expr_type = expr.Type;
309 Expression best_expr;
312 // Primitive types first
314 if (TypeManager.IsPrimitiveType (expr_type)) {
315 best_expr = ResolvePrimitivePredefinedType (expr);
316 if (best_expr == null)
319 type = best_expr.Type;
325 // E operator ~(E x);
327 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
328 return ResolveEnumOperator (ec, expr);
330 return ResolveUserType (ec, expr);
333 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
335 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
336 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
337 if (best_expr == null)
341 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
343 return EmptyCast.Create (this, type);
346 public override Expression CreateExpressionTree (EmitContext ec)
348 return CreateExpressionTree (ec, null);
351 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
355 case Operator.AddressOf:
356 Error_PointerInsideExpressionTree ();
358 case Operator.UnaryNegation:
359 if (ec.CheckState && user_op == null && !IsFloat (type))
360 method_name = "NegateChecked";
362 method_name = "Negate";
364 case Operator.OnesComplement:
365 case Operator.LogicalNot:
368 case Operator.UnaryPlus:
369 method_name = "UnaryPlus";
372 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
375 ArrayList args = new ArrayList (2);
376 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
378 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
379 return CreateExpressionFactoryCall (method_name, args);
382 static void CreatePredefinedOperatorsTable ()
384 predefined_operators = new Type [(int) Operator.TOP] [];
387 // 7.6.1 Unary plus operator
389 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
390 TypeManager.int32_type, TypeManager.uint32_type,
391 TypeManager.int64_type, TypeManager.uint64_type,
392 TypeManager.float_type, TypeManager.double_type,
393 TypeManager.decimal_type
397 // 7.6.2 Unary minus operator
399 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
400 TypeManager.int32_type,
401 TypeManager.int64_type,
402 TypeManager.float_type, TypeManager.double_type,
403 TypeManager.decimal_type
407 // 7.6.3 Logical negation operator
409 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
410 TypeManager.bool_type
414 // 7.6.4 Bitwise complement operator
416 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
417 TypeManager.int32_type, TypeManager.uint32_type,
418 TypeManager.int64_type, TypeManager.uint64_type
423 // Unary numeric promotions
425 static Expression DoNumericPromotion (Operator op, Expression expr)
427 Type expr_type = expr.Type;
428 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
429 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
430 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
431 expr_type == TypeManager.char_type)
432 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
434 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
435 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
440 public override Expression DoResolve (EmitContext ec)
442 if (Oper == Operator.AddressOf) {
443 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
445 if (Expr == null || Expr.eclass != ExprClass.Variable){
446 Error (211, "Cannot take the address of the given expression");
450 return ResolveAddressOf (ec);
453 Expr = Expr.Resolve (ec);
457 if (TypeManager.IsNullableValueType (Expr.Type))
458 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).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)
601 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
605 IVariable variable = Expr as IVariable;
606 if (variable != null && variable.IsFixed) {
607 if (ec.InFixedInitializer) {
608 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
612 if (!ec.InFixedInitializer) {
613 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
618 LocalVariableReference lr = Expr as LocalVariableReference;
621 AnonymousMethodBody.Error_AddressOfCapturedVar (lr.Name, loc);
624 lr.local_info.AddressTaken = true;
625 lr.local_info.Used = true;
628 ParameterReference pr = Expr as ParameterReference;
629 if ((pr != null) && pr.IsHoisted) {
630 AnonymousMethodBody.Error_AddressOfCapturedVar (pr.Name, loc);
634 // According to the specs, a variable is considered definitely assigned if you take
636 if ((variable != null) && (variable.VariableInfo != null)) {
637 variable.VariableInfo.SetAssigned (ec);
640 type = TypeManager.GetPointerType (Expr.Type);
641 eclass = ExprClass.Value;
645 Expression ResolvePrimitivePredefinedType (Expression expr)
647 expr = DoNumericPromotion (Oper, expr);
648 Type expr_type = expr.Type;
649 Type[] predefined = predefined_operators [(int) Oper];
650 foreach (Type t in predefined) {
658 // Perform user-operator overload resolution
660 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
662 CSharp.Operator.OpType op_type;
664 case Operator.LogicalNot:
665 op_type = CSharp.Operator.OpType.LogicalNot; break;
666 case Operator.OnesComplement:
667 op_type = CSharp.Operator.OpType.OnesComplement; break;
668 case Operator.UnaryNegation:
669 op_type = CSharp.Operator.OpType.UnaryNegation; break;
670 case Operator.UnaryPlus:
671 op_type = CSharp.Operator.OpType.UnaryPlus; break;
673 throw new InternalErrorException (Oper.ToString ());
676 string op_name = CSharp.Operator.GetMetadataName (op_type);
677 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
681 ArrayList args = new ArrayList (1);
682 args.Add (new Argument (expr));
683 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
688 Expr = ((Argument) args [0]).Expr;
689 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
693 // Unary user type overload resolution
695 Expression ResolveUserType (EmitContext ec, Expression expr)
697 Expression best_expr = ResolveUserOperator (ec, expr);
698 if (best_expr != null)
701 Type[] predefined = predefined_operators [(int) Oper];
702 foreach (Type t in predefined) {
703 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
704 if (oper_expr == null)
708 // decimal type is predefined but has user-operators
710 if (oper_expr.Type == TypeManager.decimal_type)
711 oper_expr = ResolveUserType (ec, oper_expr);
713 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
715 if (oper_expr == null)
718 if (best_expr == null) {
719 best_expr = oper_expr;
723 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
725 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
726 OperName (Oper), TypeManager.CSharpName (expr.Type));
731 best_expr = oper_expr;
734 if (best_expr == null)
738 // HACK: Decimal user-operator is included in standard operators
740 if (best_expr.Type == TypeManager.decimal_type)
744 type = best_expr.Type;
748 protected override void CloneTo (CloneContext clonectx, Expression t)
750 Unary target = (Unary) t;
752 target.Expr = Expr.Clone (clonectx);
757 // Unary operators are turned into Indirection expressions
758 // after semantic analysis (this is so we can take the address
759 // of an indirection).
761 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
763 LocalTemporary temporary;
766 public Indirection (Expression expr, Location l)
772 public override Expression CreateExpressionTree (EmitContext ec)
774 Error_PointerInsideExpressionTree ();
778 protected override void CloneTo (CloneContext clonectx, Expression t)
780 Indirection target = (Indirection) t;
781 target.expr = expr.Clone (clonectx);
784 public override void Emit (EmitContext ec)
789 LoadFromPtr (ec.ig, Type);
792 public void Emit (EmitContext ec, bool leave_copy)
796 ec.ig.Emit (OpCodes.Dup);
797 temporary = new LocalTemporary (expr.Type);
798 temporary.Store (ec);
802 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
804 prepared = prepare_for_load;
808 if (prepare_for_load)
809 ec.ig.Emit (OpCodes.Dup);
813 ec.ig.Emit (OpCodes.Dup);
814 temporary = new LocalTemporary (expr.Type);
815 temporary.Store (ec);
818 StoreFromPtr (ec.ig, type);
820 if (temporary != null) {
822 temporary.Release (ec);
826 public void AddressOf (EmitContext ec, AddressOp Mode)
831 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
833 return DoResolve (ec);
836 public override Expression DoResolve (EmitContext ec)
838 expr = expr.Resolve (ec);
845 if (!expr.Type.IsPointer) {
846 Error (193, "The * or -> operator must be applied to a pointer");
850 type = TypeManager.GetElementType (expr.Type);
851 eclass = ExprClass.Variable;
855 public override string ToString ()
857 return "*(" + expr + ")";
860 #region IVariable Members
862 public VariableInfo VariableInfo {
867 // A pointer-indirection is always fixed.
869 public bool IsFixed {
877 /// Unary Mutator expressions (pre and post ++ and --)
881 /// UnaryMutator implements ++ and -- expressions. It derives from
882 /// ExpressionStatement becuase the pre/post increment/decrement
883 /// operators can be used in a statement context.
885 /// FIXME: Idea, we could split this up in two classes, one simpler
886 /// for the common case, and one with the extra fields for more complex
887 /// classes (indexers require temporary access; overloaded require method)
890 public class UnaryMutator : ExpressionStatement {
892 public enum Mode : byte {
899 PreDecrement = IsDecrement,
900 PostIncrement = IsPost,
901 PostDecrement = IsPost | IsDecrement
905 bool is_expr = false;
906 bool recurse = false;
911 // This is expensive for the simplest case.
913 UserOperatorCall method;
915 public UnaryMutator (Mode m, Expression e, Location l)
922 static string OperName (Mode mode)
924 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
929 /// Returns whether an object of type `t' can be incremented
930 /// or decremented with add/sub (ie, basically whether we can
931 /// use pre-post incr-decr operations on it, but it is not a
932 /// System.Decimal, which we require operator overloading to catch)
934 static bool IsIncrementableNumber (Type t)
936 return (t == TypeManager.sbyte_type) ||
937 (t == TypeManager.byte_type) ||
938 (t == TypeManager.short_type) ||
939 (t == TypeManager.ushort_type) ||
940 (t == TypeManager.int32_type) ||
941 (t == TypeManager.uint32_type) ||
942 (t == TypeManager.int64_type) ||
943 (t == TypeManager.uint64_type) ||
944 (t == TypeManager.char_type) ||
945 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
946 (t == TypeManager.float_type) ||
947 (t == TypeManager.double_type) ||
948 (t.IsPointer && t != TypeManager.void_ptr_type);
951 Expression ResolveOperator (EmitContext ec)
956 // Step 1: Perform Operator Overload location
961 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
962 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
964 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
966 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
969 ArrayList args = new ArrayList (1);
970 args.Add (new Argument (expr, Argument.AType.Expression));
971 mg = mg.OverloadResolve (ec, ref args, false, loc);
975 method = new UserOperatorCall (mg, args, null, loc);
976 Convert.ImplicitConversionRequired (ec, method, type, loc);
980 if (!IsIncrementableNumber (type)) {
981 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
982 TypeManager.CSharpName (type) + "'");
987 // The operand of the prefix/postfix increment decrement operators
988 // should be an expression that is classified as a variable,
989 // a property access or an indexer access
991 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
992 expr = expr.ResolveLValue (ec, expr, Location);
994 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1000 public override Expression CreateExpressionTree (EmitContext ec)
1002 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1005 public override Expression DoResolve (EmitContext ec)
1007 expr = expr.Resolve (ec);
1012 eclass = ExprClass.Value;
1015 if (TypeManager.IsNullableValueType (expr.Type))
1016 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1019 return ResolveOperator (ec);
1023 // Loads the proper "1" into the stack based on the type, then it emits the
1024 // opcode for the operation requested
1026 void LoadOneAndEmitOp (EmitContext ec, Type t)
1029 // Measure if getting the typecode and using that is more/less efficient
1030 // that comparing types. t.GetTypeCode() is an internal call.
1032 ILGenerator ig = ec.ig;
1034 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1035 LongConstant.EmitLong (ig, 1);
1036 else if (t == TypeManager.double_type)
1037 ig.Emit (OpCodes.Ldc_R8, 1.0);
1038 else if (t == TypeManager.float_type)
1039 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1040 else if (t.IsPointer){
1041 Type et = TypeManager.GetElementType (t);
1042 int n = GetTypeSize (et);
1045 ig.Emit (OpCodes.Sizeof, et);
1047 IntConstant.EmitInt (ig, n);
1048 ig.Emit (OpCodes.Conv_I);
1051 ig.Emit (OpCodes.Ldc_I4_1);
1054 // Now emit the operation
1057 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1058 Binary.EmitOperatorOpcode (ec, op, t);
1060 if (t == TypeManager.sbyte_type){
1062 ig.Emit (OpCodes.Conv_Ovf_I1);
1064 ig.Emit (OpCodes.Conv_I1);
1065 } else if (t == TypeManager.byte_type){
1067 ig.Emit (OpCodes.Conv_Ovf_U1);
1069 ig.Emit (OpCodes.Conv_U1);
1070 } else if (t == TypeManager.short_type){
1072 ig.Emit (OpCodes.Conv_Ovf_I2);
1074 ig.Emit (OpCodes.Conv_I2);
1075 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1077 ig.Emit (OpCodes.Conv_Ovf_U2);
1079 ig.Emit (OpCodes.Conv_U2);
1084 void EmitCode (EmitContext ec, bool is_expr)
1087 this.is_expr = is_expr;
1088 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1091 public override void Emit (EmitContext ec)
1094 // We use recurse to allow ourselfs to be the source
1095 // of an assignment. This little hack prevents us from
1096 // having to allocate another expression
1099 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1101 LoadOneAndEmitOp (ec, expr.Type);
1103 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1108 EmitCode (ec, true);
1111 public override void EmitStatement (EmitContext ec)
1113 EmitCode (ec, false);
1116 protected override void CloneTo (CloneContext clonectx, Expression t)
1118 UnaryMutator target = (UnaryMutator) t;
1120 target.expr = expr.Clone (clonectx);
1125 /// Base class for the `Is' and `As' classes.
1129 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1132 public abstract class Probe : Expression {
1133 public Expression ProbeType;
1134 protected Expression expr;
1135 protected TypeExpr probe_type_expr;
1137 public Probe (Expression expr, Expression probe_type, Location l)
1139 ProbeType = probe_type;
1144 public Expression Expr {
1150 public override Expression DoResolve (EmitContext ec)
1152 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1153 if (probe_type_expr == null)
1156 expr = expr.Resolve (ec);
1160 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1161 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1166 if (expr.Type == TypeManager.anonymous_method_type) {
1167 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1175 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1177 expr.MutateHoistedGenericType (storey);
1178 probe_type_expr.MutateHoistedGenericType (storey);
1181 protected abstract string OperatorName { get; }
1183 protected override void CloneTo (CloneContext clonectx, Expression t)
1185 Probe target = (Probe) t;
1187 target.expr = expr.Clone (clonectx);
1188 target.ProbeType = ProbeType.Clone (clonectx);
1194 /// Implementation of the `is' operator.
1196 public class Is : Probe {
1197 Nullable.Unwrap expr_unwrap;
1199 public Is (Expression expr, Expression probe_type, Location l)
1200 : base (expr, probe_type, l)
1204 public override Expression CreateExpressionTree (EmitContext ec)
1206 ArrayList args = new ArrayList (2);
1207 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1208 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1209 return CreateExpressionFactoryCall ("TypeIs", args);
1212 public override void Emit (EmitContext ec)
1214 ILGenerator ig = ec.ig;
1215 if (expr_unwrap != null) {
1216 expr_unwrap.EmitCheck (ec);
1221 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1222 ig.Emit (OpCodes.Ldnull);
1223 ig.Emit (OpCodes.Cgt_Un);
1226 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1228 ILGenerator ig = ec.ig;
1229 if (expr_unwrap != null) {
1230 expr_unwrap.EmitCheck (ec);
1233 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1235 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1238 Expression CreateConstantResult (bool result)
1241 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1242 TypeManager.CSharpName (probe_type_expr.Type));
1244 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1245 TypeManager.CSharpName (probe_type_expr.Type));
1247 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1250 public override Expression DoResolve (EmitContext ec)
1252 if (base.DoResolve (ec) == null)
1256 bool d_is_nullable = false;
1258 if (expr is Constant) {
1260 // If E is a method group or the null literal, of if the type of E is a reference
1261 // type or a nullable type and the value of E is null, the result is false
1264 return CreateConstantResult (false);
1265 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1266 d = TypeManager.GetTypeArguments (d) [0];
1267 d_is_nullable = true;
1270 type = TypeManager.bool_type;
1271 eclass = ExprClass.Value;
1272 Type t = probe_type_expr.Type;
1273 bool t_is_nullable = false;
1274 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1275 t = TypeManager.GetTypeArguments (t) [0];
1276 t_is_nullable = true;
1279 if (t.IsValueType) {
1282 // D and T are the same value types but D can be null
1284 if (d_is_nullable && !t_is_nullable) {
1285 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1290 // The result is true if D and T are the same value types
1292 return CreateConstantResult (true);
1295 if (TypeManager.IsGenericParameter (d))
1296 return ResolveGenericParameter (t, d);
1299 // An unboxing conversion exists
1301 if (Convert.ExplicitReferenceConversionExists (d, t))
1304 if (TypeManager.IsGenericParameter (t))
1305 return ResolveGenericParameter (d, t);
1307 if (d.IsValueType) {
1309 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1310 return CreateConstantResult (true);
1312 if (TypeManager.IsGenericParameter (d))
1313 return ResolveGenericParameter (t, d);
1315 if (TypeManager.ContainsGenericParameters (d))
1318 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1319 Convert.ExplicitReferenceConversionExists (d, t)) {
1325 return CreateConstantResult (false);
1328 Expression ResolveGenericParameter (Type d, Type t)
1331 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1332 if (constraints != null) {
1333 if (constraints.IsReferenceType && d.IsValueType)
1334 return CreateConstantResult (false);
1336 if (constraints.IsValueType && !d.IsValueType)
1337 return CreateConstantResult (TypeManager.IsEqual (d, t));
1340 if (!TypeManager.IsReferenceType (expr.Type))
1341 expr = new BoxedCast (expr, d);
1349 protected override string OperatorName {
1350 get { return "is"; }
1355 /// Implementation of the `as' operator.
1357 public class As : Probe {
1359 Expression resolved_type;
1361 public As (Expression expr, Expression probe_type, Location l)
1362 : base (expr, probe_type, l)
1366 public override Expression CreateExpressionTree (EmitContext ec)
1368 ArrayList args = new ArrayList (2);
1369 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1370 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1371 return CreateExpressionFactoryCall ("TypeAs", args);
1374 public override void Emit (EmitContext ec)
1376 ILGenerator ig = ec.ig;
1381 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1384 if (TypeManager.IsNullableType (type))
1385 ig.Emit (OpCodes.Unbox_Any, type);
1389 public override Expression DoResolve (EmitContext ec)
1391 if (resolved_type == null) {
1392 resolved_type = base.DoResolve (ec);
1394 if (resolved_type == null)
1398 type = probe_type_expr.Type;
1399 eclass = ExprClass.Value;
1400 Type etype = expr.Type;
1402 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1403 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1404 TypeManager.CSharpName (type));
1411 // If the type is a type parameter, ensure
1412 // that it is constrained by a class
1414 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1416 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1419 if (constraints == null)
1422 if (!constraints.HasClassConstraint)
1423 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1427 Report.Error (413, loc,
1428 "The as operator requires that the `{0}' type parameter be constrained by a class",
1429 probe_type_expr.GetSignatureForError ());
1434 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1435 return Nullable.LiftedNull.CreateFromExpression (this);
1438 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1445 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1446 if (TypeManager.IsGenericParameter (etype))
1447 expr = new BoxedCast (expr, etype);
1453 if (TypeManager.ContainsGenericParameters (etype) ||
1454 TypeManager.ContainsGenericParameters (type)) {
1455 expr = new BoxedCast (expr, etype);
1460 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1461 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1466 protected override string OperatorName {
1467 get { return "as"; }
1470 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1472 return expr.GetAttributableValue (ec, value_type, out value);
1477 /// This represents a typecast in the source language.
1479 /// FIXME: Cast expressions have an unusual set of parsing
1480 /// rules, we need to figure those out.
1482 public class Cast : Expression {
1483 Expression target_type;
1486 public Cast (Expression cast_type, Expression expr)
1487 : this (cast_type, expr, cast_type.Location)
1491 public Cast (Expression cast_type, Expression expr, Location loc)
1493 this.target_type = cast_type;
1497 if (target_type == TypeManager.system_void_expr)
1498 Error_VoidInvalidInTheContext (loc);
1501 public Expression TargetType {
1502 get { return target_type; }
1505 public Expression Expr {
1506 get { return expr; }
1509 public override Expression CreateExpressionTree (EmitContext ec)
1511 throw new NotSupportedException ("ET");
1514 public override Expression DoResolve (EmitContext ec)
1516 expr = expr.Resolve (ec);
1520 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1526 if (type.IsAbstract && type.IsSealed) {
1527 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1531 eclass = ExprClass.Value;
1533 Constant c = expr as Constant;
1535 c = c.TryReduce (ec, type, loc);
1540 if (type.IsPointer && !ec.InUnsafe) {
1544 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1548 public override void Emit (EmitContext ec)
1550 throw new Exception ("Should not happen");
1553 protected override void CloneTo (CloneContext clonectx, Expression t)
1555 Cast target = (Cast) t;
1557 target.target_type = target_type.Clone (clonectx);
1558 target.expr = expr.Clone (clonectx);
1563 // C# 2.0 Default value expression
1565 public class DefaultValueExpression : Expression
1569 public DefaultValueExpression (Expression expr, Location loc)
1575 public override Expression CreateExpressionTree (EmitContext ec)
1577 ArrayList args = new ArrayList (2);
1578 args.Add (new Argument (this));
1579 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1580 return CreateExpressionFactoryCall ("Constant", args);
1583 public override Expression DoResolve (EmitContext ec)
1585 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1591 if (type == TypeManager.void_type) {
1592 Error_VoidInvalidInTheContext (loc);
1596 if (TypeManager.IsGenericParameter (type)) {
1597 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1598 if (constraints != null && constraints.IsReferenceType)
1599 return new EmptyConstantCast (new NullLiteral (Location), type);
1601 Constant c = New.Constantify (type);
1605 if (!TypeManager.IsValueType (type))
1606 return new EmptyConstantCast (new NullLiteral (Location), type);
1608 eclass = ExprClass.Variable;
1612 public override void Emit (EmitContext ec)
1614 LocalTemporary temp_storage = new LocalTemporary(type);
1616 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1617 ec.ig.Emit(OpCodes.Initobj, type);
1618 temp_storage.Emit(ec);
1621 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1623 type = storey.MutateType (type);
1626 protected override void CloneTo (CloneContext clonectx, Expression t)
1628 DefaultValueExpression target = (DefaultValueExpression) t;
1630 target.expr = expr.Clone (clonectx);
1635 /// Binary operators
1637 public class Binary : Expression {
1639 protected class PredefinedOperator {
1640 protected readonly Type left;
1641 protected readonly Type right;
1642 public readonly Operator OperatorsMask;
1643 public Type ReturnType;
1645 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1646 : this (ltype, rtype, op_mask, ltype)
1650 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1651 : this (type, type, op_mask, return_type)
1655 public PredefinedOperator (Type type, Operator op_mask)
1656 : this (type, type, op_mask, type)
1660 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1662 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1663 throw new InternalErrorException ("Only masked values can be used");
1667 this.OperatorsMask = op_mask;
1668 this.ReturnType = return_type;
1671 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1673 b.type = ReturnType;
1675 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1676 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1679 // A user operators does not support multiple user conversions, but decimal type
1680 // is considered to be predefined type therefore we apply predefined operators rules
1681 // and then look for decimal user-operator implementation
1683 if (left == TypeManager.decimal_type)
1684 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1689 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1692 // We are dealing with primitive types only
1694 return left == ltype && ltype == rtype;
1697 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1699 if (TypeManager.IsEqual (left, lexpr.Type) &&
1700 TypeManager.IsEqual (right, rexpr.Type))
1703 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1704 Convert.ImplicitConversionExists (ec, rexpr, right);
1707 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1710 if (left != null && best_operator.left != null) {
1711 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1715 // When second arguments are same as the first one, the result is same
1717 if (left != right || best_operator.left != best_operator.right) {
1718 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1721 if (result == 0 || result > 2)
1724 return result == 1 ? best_operator : this;
1728 class PredefinedStringOperator : PredefinedOperator {
1729 public PredefinedStringOperator (Type type, Operator op_mask)
1730 : base (type, op_mask, type)
1732 ReturnType = TypeManager.string_type;
1735 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1736 : base (ltype, rtype, op_mask)
1738 ReturnType = TypeManager.string_type;
1741 public override Expression ConvertResult (EmitContext ec, Binary b)
1744 // Use original expression for nullable arguments
1746 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1748 b.left = unwrap.Original;
1750 unwrap = b.right as Nullable.Unwrap;
1752 b.right = unwrap.Original;
1754 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1755 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1758 // Start a new concat expression using converted expression
1760 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1764 class PredefinedShiftOperator : PredefinedOperator {
1765 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1766 base (ltype, TypeManager.int32_type, op_mask)
1770 public override Expression ConvertResult (EmitContext ec, Binary b)
1772 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1774 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1776 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1779 // b = b.left >> b.right & (0x1f|0x3f)
1781 b.right = new Binary (Operator.BitwiseAnd,
1782 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1785 // Expression tree representation does not use & mask
1787 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1788 b.type = ReturnType;
1793 class PredefinedPointerOperator : PredefinedOperator {
1794 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1795 : base (ltype, rtype, op_mask)
1799 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1800 : base (type, op_mask, return_type)
1804 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1807 if (!lexpr.Type.IsPointer)
1810 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1814 if (right == null) {
1815 if (!rexpr.Type.IsPointer)
1818 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1825 public override Expression ConvertResult (EmitContext ec, Binary b)
1828 b.left = EmptyCast.Create (b.left, left);
1829 } else if (right != null) {
1830 b.right = EmptyCast.Create (b.right, right);
1833 Type r_type = ReturnType;
1834 if (r_type == null) {
1835 r_type = b.left.Type;
1837 r_type = b.right.Type;
1840 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1845 public enum Operator {
1846 Multiply = 0 | ArithmeticMask,
1847 Division = 1 | ArithmeticMask,
1848 Modulus = 2 | ArithmeticMask,
1849 Addition = 3 | ArithmeticMask | AdditionMask,
1850 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1852 LeftShift = 5 | ShiftMask,
1853 RightShift = 6 | ShiftMask,
1855 LessThan = 7 | ComparisonMask | RelationalMask,
1856 GreaterThan = 8 | ComparisonMask | RelationalMask,
1857 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1858 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1859 Equality = 11 | ComparisonMask | EqualityMask,
1860 Inequality = 12 | ComparisonMask | EqualityMask,
1862 BitwiseAnd = 13 | BitwiseMask,
1863 ExclusiveOr = 14 | BitwiseMask,
1864 BitwiseOr = 15 | BitwiseMask,
1866 LogicalAnd = 16 | LogicalMask,
1867 LogicalOr = 17 | LogicalMask,
1872 ValuesOnlyMask = ArithmeticMask - 1,
1873 ArithmeticMask = 1 << 5,
1875 ComparisonMask = 1 << 7,
1876 EqualityMask = 1 << 8,
1877 BitwiseMask = 1 << 9,
1878 LogicalMask = 1 << 10,
1879 AdditionMask = 1 << 11,
1880 SubtractionMask = 1 << 12,
1881 RelationalMask = 1 << 13
1884 readonly Operator oper;
1885 protected Expression left, right;
1886 readonly bool is_compound;
1887 Expression enum_conversion;
1889 static PredefinedOperator [] standard_operators;
1890 static PredefinedOperator [] pointer_operators;
1892 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1893 : this (oper, left, right)
1895 this.is_compound = isCompound;
1898 public Binary (Operator oper, Expression left, Expression right)
1903 this.loc = left.Location;
1906 public Operator Oper {
1913 /// Returns a stringified representation of the Operator
1915 string OperName (Operator oper)
1919 case Operator.Multiply:
1922 case Operator.Division:
1925 case Operator.Modulus:
1928 case Operator.Addition:
1931 case Operator.Subtraction:
1934 case Operator.LeftShift:
1937 case Operator.RightShift:
1940 case Operator.LessThan:
1943 case Operator.GreaterThan:
1946 case Operator.LessThanOrEqual:
1949 case Operator.GreaterThanOrEqual:
1952 case Operator.Equality:
1955 case Operator.Inequality:
1958 case Operator.BitwiseAnd:
1961 case Operator.BitwiseOr:
1964 case Operator.ExclusiveOr:
1967 case Operator.LogicalOr:
1970 case Operator.LogicalAnd:
1974 s = oper.ToString ();
1984 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1986 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1989 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1992 // TODO: This should be handled as Type of method group in CSharpName
1993 if (left.eclass == ExprClass.MethodGroup)
1994 l = left.ExprClassName;
1996 l = TypeManager.CSharpName (left.Type);
1998 if (right.eclass == ExprClass.MethodGroup)
1999 r = right.ExprClassName;
2001 r = TypeManager.CSharpName (right.Type);
2003 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2007 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2009 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2012 static string GetOperatorMetadataName (Operator op)
2014 CSharp.Operator.OpType op_type;
2016 case Operator.Addition:
2017 op_type = CSharp.Operator.OpType.Addition; break;
2018 case Operator.BitwiseAnd:
2019 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2020 case Operator.BitwiseOr:
2021 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2022 case Operator.Division:
2023 op_type = CSharp.Operator.OpType.Division; break;
2024 case Operator.Equality:
2025 op_type = CSharp.Operator.OpType.Equality; break;
2026 case Operator.ExclusiveOr:
2027 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2028 case Operator.GreaterThan:
2029 op_type = CSharp.Operator.OpType.GreaterThan; break;
2030 case Operator.GreaterThanOrEqual:
2031 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2032 case Operator.Inequality:
2033 op_type = CSharp.Operator.OpType.Inequality; break;
2034 case Operator.LeftShift:
2035 op_type = CSharp.Operator.OpType.LeftShift; break;
2036 case Operator.LessThan:
2037 op_type = CSharp.Operator.OpType.LessThan; break;
2038 case Operator.LessThanOrEqual:
2039 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2040 case Operator.Modulus:
2041 op_type = CSharp.Operator.OpType.Modulus; break;
2042 case Operator.Multiply:
2043 op_type = CSharp.Operator.OpType.Multiply; break;
2044 case Operator.RightShift:
2045 op_type = CSharp.Operator.OpType.RightShift; break;
2046 case Operator.Subtraction:
2047 op_type = CSharp.Operator.OpType.Subtraction; break;
2049 throw new InternalErrorException (op.ToString ());
2052 return CSharp.Operator.GetMetadataName (op_type);
2055 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2058 ILGenerator ig = ec.ig;
2061 case Operator.Multiply:
2063 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2064 opcode = OpCodes.Mul_Ovf;
2065 else if (!IsFloat (l))
2066 opcode = OpCodes.Mul_Ovf_Un;
2068 opcode = OpCodes.Mul;
2070 opcode = OpCodes.Mul;
2074 case Operator.Division:
2076 opcode = OpCodes.Div_Un;
2078 opcode = OpCodes.Div;
2081 case Operator.Modulus:
2083 opcode = OpCodes.Rem_Un;
2085 opcode = OpCodes.Rem;
2088 case Operator.Addition:
2090 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2091 opcode = OpCodes.Add_Ovf;
2092 else if (!IsFloat (l))
2093 opcode = OpCodes.Add_Ovf_Un;
2095 opcode = OpCodes.Add;
2097 opcode = OpCodes.Add;
2100 case Operator.Subtraction:
2102 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2103 opcode = OpCodes.Sub_Ovf;
2104 else if (!IsFloat (l))
2105 opcode = OpCodes.Sub_Ovf_Un;
2107 opcode = OpCodes.Sub;
2109 opcode = OpCodes.Sub;
2112 case Operator.RightShift:
2114 opcode = OpCodes.Shr_Un;
2116 opcode = OpCodes.Shr;
2119 case Operator.LeftShift:
2120 opcode = OpCodes.Shl;
2123 case Operator.Equality:
2124 opcode = OpCodes.Ceq;
2127 case Operator.Inequality:
2128 ig.Emit (OpCodes.Ceq);
2129 ig.Emit (OpCodes.Ldc_I4_0);
2131 opcode = OpCodes.Ceq;
2134 case Operator.LessThan:
2136 opcode = OpCodes.Clt_Un;
2138 opcode = OpCodes.Clt;
2141 case Operator.GreaterThan:
2143 opcode = OpCodes.Cgt_Un;
2145 opcode = OpCodes.Cgt;
2148 case Operator.LessThanOrEqual:
2149 if (IsUnsigned (l) || IsFloat (l))
2150 ig.Emit (OpCodes.Cgt_Un);
2152 ig.Emit (OpCodes.Cgt);
2153 ig.Emit (OpCodes.Ldc_I4_0);
2155 opcode = OpCodes.Ceq;
2158 case Operator.GreaterThanOrEqual:
2159 if (IsUnsigned (l) || IsFloat (l))
2160 ig.Emit (OpCodes.Clt_Un);
2162 ig.Emit (OpCodes.Clt);
2164 ig.Emit (OpCodes.Ldc_I4_0);
2166 opcode = OpCodes.Ceq;
2169 case Operator.BitwiseOr:
2170 opcode = OpCodes.Or;
2173 case Operator.BitwiseAnd:
2174 opcode = OpCodes.And;
2177 case Operator.ExclusiveOr:
2178 opcode = OpCodes.Xor;
2182 throw new InternalErrorException (oper.ToString ());
2188 static bool IsUnsigned (Type t)
2193 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2194 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2197 static bool IsFloat (Type t)
2199 return t == TypeManager.float_type || t == TypeManager.double_type;
2202 Expression ResolveOperator (EmitContext ec)
2205 Type r = right.Type;
2207 bool primitives_only = false;
2209 if (standard_operators == null)
2210 CreateStandardOperatorsTable ();
2213 // Handles predefined primitive types
2215 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2216 if ((oper & Operator.ShiftMask) == 0) {
2217 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2220 primitives_only = true;
2224 if (l.IsPointer || r.IsPointer)
2225 return ResolveOperatorPointer (ec, l, r);
2228 bool lenum = TypeManager.IsEnumType (l);
2229 bool renum = TypeManager.IsEnumType (r);
2230 if (lenum || renum) {
2231 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2233 // TODO: Can this be ambiguous
2239 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2240 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2242 expr = ResolveOperatorDelegate (ec, l, r);
2244 // TODO: Can this be ambiguous
2250 expr = ResolveUserOperator (ec, l, r);
2254 // Predefined reference types equality
2255 if ((oper & Operator.EqualityMask) != 0) {
2256 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2262 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2265 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2266 // if 'left' is not an enumeration constant, create one from the type of 'right'
2267 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2270 case Operator.BitwiseOr:
2271 case Operator.BitwiseAnd:
2272 case Operator.ExclusiveOr:
2273 case Operator.Equality:
2274 case Operator.Inequality:
2275 case Operator.LessThan:
2276 case Operator.LessThanOrEqual:
2277 case Operator.GreaterThan:
2278 case Operator.GreaterThanOrEqual:
2279 if (TypeManager.IsEnumType (left.Type))
2282 if (left.IsZeroInteger)
2283 return left.TryReduce (ec, right.Type, loc);
2287 case Operator.Addition:
2288 case Operator.Subtraction:
2291 case Operator.Multiply:
2292 case Operator.Division:
2293 case Operator.Modulus:
2294 case Operator.LeftShift:
2295 case Operator.RightShift:
2296 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2300 Error_OperatorCannotBeApplied (this.left, this.right);
2305 // The `|' operator used on types which were extended is dangerous
2307 void CheckBitwiseOrOnSignExtended ()
2309 OpcodeCast lcast = left as OpcodeCast;
2310 if (lcast != null) {
2311 if (IsUnsigned (lcast.UnderlyingType))
2315 OpcodeCast rcast = right as OpcodeCast;
2316 if (rcast != null) {
2317 if (IsUnsigned (rcast.UnderlyingType))
2321 if (lcast == null && rcast == null)
2324 // FIXME: consider constants
2326 Report.Warning (675, 3, loc,
2327 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2328 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2331 static void CreatePointerOperatorsTable ()
2333 ArrayList temp = new ArrayList ();
2336 // Pointer arithmetic:
2338 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2339 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2340 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2341 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2343 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2344 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2345 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2346 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2349 // T* operator + (int y, T* x);
2350 // T* operator + (uint y, T *x);
2351 // T* operator + (long y, T *x);
2352 // T* operator + (ulong y, T *x);
2354 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
2355 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
2356 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
2357 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
2360 // long operator - (T* x, T *y)
2362 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2364 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2367 static void CreateStandardOperatorsTable ()
2369 ArrayList temp = new ArrayList ();
2370 Type bool_type = TypeManager.bool_type;
2372 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2373 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2374 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2375 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2376 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2377 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2378 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2380 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2381 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2382 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2383 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2384 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2385 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2386 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2388 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2390 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2391 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2392 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2394 temp.Add (new PredefinedOperator (bool_type,
2395 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2397 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2398 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2399 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2400 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2402 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2406 // Rules used during binary numeric promotion
2408 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2413 Constant c = prim_expr as Constant;
2415 temp = c.ConvertImplicitly (type);
2422 if (type == TypeManager.uint32_type) {
2423 etype = prim_expr.Type;
2424 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2425 type = TypeManager.int64_type;
2427 if (type != second_expr.Type) {
2428 c = second_expr as Constant;
2430 temp = c.ConvertImplicitly (type);
2432 temp = Convert.ImplicitNumericConversion (second_expr, type);
2438 } else if (type == TypeManager.uint64_type) {
2440 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2442 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2443 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2447 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2456 // 7.2.6.2 Binary numeric promotions
2458 public bool DoBinaryOperatorPromotion (EmitContext ec)
2460 Type ltype = left.Type;
2461 Type rtype = right.Type;
2464 foreach (Type t in ConstantFold.binary_promotions) {
2466 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2469 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2472 Type int32 = TypeManager.int32_type;
2473 if (ltype != int32) {
2474 Constant c = left as Constant;
2476 temp = c.ConvertImplicitly (int32);
2478 temp = Convert.ImplicitNumericConversion (left, int32);
2485 if (rtype != int32) {
2486 Constant c = right as Constant;
2488 temp = c.ConvertImplicitly (int32);
2490 temp = Convert.ImplicitNumericConversion (right, int32);
2500 public override Expression DoResolve (EmitContext ec)
2505 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2506 left = ((ParenthesizedExpression) left).Expr;
2507 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2511 if (left.eclass == ExprClass.Type) {
2512 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2516 left = left.Resolve (ec);
2521 Constant lc = left as Constant;
2523 if (lc != null && lc.Type == TypeManager.bool_type &&
2524 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2525 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2527 // FIXME: resolve right expression as unreachable
2528 // right.Resolve (ec);
2530 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2534 right = right.Resolve (ec);
2538 eclass = ExprClass.Value;
2539 Constant rc = right as Constant;
2541 // The conversion rules are ignored in enum context but why
2542 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2543 left = lc = EnumLiftUp (ec, lc, rc, loc);
2547 right = rc = EnumLiftUp (ec, rc, lc, loc);
2552 if (rc != null && lc != null) {
2553 int prev_e = Report.Errors;
2554 Expression e = ConstantFold.BinaryFold (
2555 ec, oper, lc, rc, loc);
2556 if (e != null || Report.Errors != prev_e)
2559 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2560 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2562 if ((ResolveOperator (ec)) == null) {
2563 Error_OperatorCannotBeApplied (left, right);
2572 // The result is a constant with side-effect
2573 return new SideEffectConstant (lc, right, loc);
2577 // Comparison warnings
2578 if ((oper & Operator.ComparisonMask) != 0) {
2579 if (left.Equals (right)) {
2580 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2582 CheckUselessComparison (lc, right.Type);
2583 CheckUselessComparison (rc, left.Type);
2586 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2587 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2588 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2589 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2591 return DoResolveCore (ec, left, right);
2594 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2596 Expression expr = ResolveOperator (ec);
2598 Error_OperatorCannotBeApplied (left_orig, right_orig);
2600 if (left == null || right == null)
2601 throw new InternalErrorException ("Invalid conversion");
2603 if (oper == Operator.BitwiseOr)
2604 CheckBitwiseOrOnSignExtended ();
2609 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2611 left.MutateHoistedGenericType (storey);
2612 right.MutateHoistedGenericType (storey);
2616 // D operator + (D x, D y)
2617 // D operator - (D x, D y)
2618 // bool operator == (D x, D y)
2619 // bool operator != (D x, D y)
2621 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2623 bool is_equality = (oper & Operator.EqualityMask) != 0;
2624 if (!TypeManager.IsEqual (l, r)) {
2626 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2627 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2632 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2633 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2644 // Resolve delegate equality as a user operator
2647 return ResolveUserOperator (ec, l, r);
2650 ArrayList args = new ArrayList (2);
2651 args.Add (new Argument (left, Argument.AType.Expression));
2652 args.Add (new Argument (right, Argument.AType.Expression));
2654 if (oper == Operator.Addition) {
2655 if (TypeManager.delegate_combine_delegate_delegate == null) {
2656 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2657 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2660 method = TypeManager.delegate_combine_delegate_delegate;
2662 if (TypeManager.delegate_remove_delegate_delegate == null) {
2663 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2664 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2667 method = TypeManager.delegate_remove_delegate_delegate;
2670 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2671 mg = mg.OverloadResolve (ec, ref args, false, loc);
2673 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2677 // Enumeration operators
2679 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
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);
2686 // bool operator <= (E x, E y);
2687 // bool operator >= (E x, E y);
2689 // E operator & (E x, E y);
2690 // E operator | (E x, E y);
2691 // E operator ^ (E x, E y);
2693 // U operator - (E e, E f)
2694 // E operator - (E e, U x)
2696 // E operator + (U x, E e)
2697 // E operator + (E e, U x)
2699 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2700 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2703 Expression ltemp = left;
2704 Expression rtemp = right;
2705 Type underlying_type;
2708 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2710 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2716 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2724 if (TypeManager.IsEqual (ltype, rtype)) {
2725 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2727 if (left is Constant)
2728 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2730 left = EmptyCast.Create (left, underlying_type);
2732 if (right is Constant)
2733 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2735 right = EmptyCast.Create (right, underlying_type);
2737 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2739 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2740 Constant c = right as Constant;
2741 if (c == null || !c.IsDefaultValue)
2744 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2747 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2750 if (left is Constant)
2751 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2753 left = EmptyCast.Create (left, underlying_type);
2756 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2758 if (oper != Operator.Addition) {
2759 Constant c = left as Constant;
2760 if (c == null || !c.IsDefaultValue)
2763 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2766 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2769 if (right is Constant)
2770 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2772 right = EmptyCast.Create (right, underlying_type);
2779 // C# specification uses explicit cast syntax which means binary promotion
2780 // should happen, however it seems that csc does not do that
2782 if (!DoBinaryOperatorPromotion (ec)) {
2788 Type res_type = null;
2789 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2790 Type promoted_type = lenum ? left.Type : right.Type;
2791 enum_conversion = Convert.ExplicitNumericConversion (
2792 new EmptyExpression (promoted_type), underlying_type);
2794 if (oper == Operator.Subtraction && renum && lenum)
2795 res_type = underlying_type;
2796 else if (oper == Operator.Addition && renum)
2802 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2803 if (!is_compound || expr == null)
2807 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2810 if (Convert.ImplicitConversionExists (ec, left, rtype))
2813 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2816 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2821 // 7.9.6 Reference type equality operators
2823 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2826 // operator != (object a, object b)
2827 // operator == (object a, object b)
2830 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2832 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2835 type = TypeManager.bool_type;
2836 GenericConstraints constraints;
2838 bool lgen = TypeManager.IsGenericParameter (l);
2840 if (TypeManager.IsEqual (l, r)) {
2843 // Only allow to compare same reference type parameter
2845 constraints = TypeManager.GetTypeParameterConstraints (l);
2846 if (constraints != null && constraints.IsReferenceType)
2852 if (l == TypeManager.anonymous_method_type)
2855 if (TypeManager.IsValueType (l))
2861 bool rgen = TypeManager.IsGenericParameter (r);
2864 // a, Both operands are reference-type values or the value null
2865 // b, One operand is a value of type T where T is a type-parameter and
2866 // the other operand is the value null. Furthermore T does not have the
2867 // value type constrain
2869 if (left is NullLiteral || right is NullLiteral) {
2871 constraints = TypeManager.GetTypeParameterConstraints (l);
2872 if (constraints != null && constraints.HasValueTypeConstraint)
2875 left = new BoxedCast (left, TypeManager.object_type);
2880 constraints = TypeManager.GetTypeParameterConstraints (r);
2881 if (constraints != null && constraints.HasValueTypeConstraint)
2884 right = new BoxedCast (right, TypeManager.object_type);
2890 // An interface is converted to the object before the
2891 // standard conversion is applied. It's not clear from the
2892 // standard but it looks like it works like that.
2895 constraints = TypeManager.GetTypeParameterConstraints (l);
2896 if (constraints == null || constraints.IsReferenceType)
2898 } else if (l.IsInterface) {
2899 l = TypeManager.object_type;
2900 } else if (l.IsValueType) {
2905 constraints = TypeManager.GetTypeParameterConstraints (r);
2906 if (constraints == null || constraints.IsReferenceType)
2908 } else if (r.IsInterface) {
2909 r = TypeManager.object_type;
2910 } else if (r.IsValueType) {
2915 const string ref_comparison = "Possible unintended reference comparison. " +
2916 "Consider casting the {0} side of the expression to `string' to compare the values";
2919 // A standard implicit conversion exists from the type of either
2920 // operand to the type of the other operand
2922 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2923 if (l == TypeManager.string_type)
2924 Report.Warning (253, 2, loc, ref_comparison, "right");
2929 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2930 if (r == TypeManager.string_type)
2931 Report.Warning (252, 2, loc, ref_comparison, "left");
2940 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
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);
2947 // bool operator <= (void* x, void* y);
2948 // bool operator >= (void* x, void* y);
2950 if ((oper & Operator.ComparisonMask) != 0) {
2953 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2960 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2966 type = TypeManager.bool_type;
2970 if (pointer_operators == null)
2971 CreatePointerOperatorsTable ();
2973 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2977 // Build-in operators method overloading
2979 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2981 PredefinedOperator best_operator = null;
2983 Type r = right.Type;
2984 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2986 foreach (PredefinedOperator po in operators) {
2987 if ((po.OperatorsMask & oper_mask) == 0)
2990 if (primitives_only) {
2991 if (!po.IsPrimitiveApplicable (l, r))
2994 if (!po.IsApplicable (ec, left, right))
2998 if (best_operator == null) {
3000 if (primitives_only)
3006 best_operator = po.ResolveBetterOperator (ec, best_operator);
3008 if (best_operator == null) {
3009 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3010 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3017 if (best_operator == null)
3020 Expression expr = best_operator.ConvertResult (ec, this);
3021 if (enum_type == null)
3025 // HACK: required by enum_conversion
3027 expr.Type = enum_type;
3028 return EmptyCast.Create (expr, enum_type);
3032 // Performs user-operator overloading
3034 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3037 if (oper == Operator.LogicalAnd)
3038 user_oper = Operator.BitwiseAnd;
3039 else if (oper == Operator.LogicalOr)
3040 user_oper = Operator.BitwiseOr;
3044 string op = GetOperatorMetadataName (user_oper);
3046 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3047 MethodGroupExpr right_operators = null;
3049 if (!TypeManager.IsEqual (r, l)) {
3050 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3051 if (right_operators == null && left_operators == null)
3053 } else if (left_operators == null) {
3057 ArrayList args = new ArrayList (2);
3058 Argument larg = new Argument (left);
3060 Argument rarg = new Argument (right);
3063 MethodGroupExpr union;
3066 // User-defined operator implementations always take precedence
3067 // over predefined operator implementations
3069 if (left_operators != null && right_operators != null) {
3070 if (IsPredefinedUserOperator (l, user_oper)) {
3071 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3073 union = left_operators;
3074 } else if (IsPredefinedUserOperator (r, user_oper)) {
3075 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3077 union = right_operators;
3079 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3081 } else if (left_operators != null) {
3082 union = left_operators;
3084 union = right_operators;
3087 union = union.OverloadResolve (ec, ref args, true, loc);
3091 Expression oper_expr;
3093 // TODO: CreateExpressionTree is allocated every time
3094 if (user_oper != oper) {
3095 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3096 oper == Operator.LogicalAnd, loc).Resolve (ec);
3098 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3101 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3102 // and not invoke user operator
3104 if ((oper & Operator.EqualityMask) != 0) {
3105 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3106 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3107 type = TypeManager.bool_type;
3108 if (left is NullLiteral || right is NullLiteral)
3109 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3110 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3112 // Two System.Delegate(s) are never equal
3124 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3129 private void CheckUselessComparison (Constant c, Type type)
3131 if (c == null || !IsTypeIntegral (type)
3132 || c is StringConstant
3133 || c is BoolConstant
3134 || c is FloatConstant
3135 || c is DoubleConstant
3136 || c is DecimalConstant
3142 if (c is ULongConstant) {
3143 ulong uvalue = ((ULongConstant) c).Value;
3144 if (uvalue > long.MaxValue) {
3145 if (type == TypeManager.byte_type ||
3146 type == TypeManager.sbyte_type ||
3147 type == TypeManager.short_type ||
3148 type == TypeManager.ushort_type ||
3149 type == TypeManager.int32_type ||
3150 type == TypeManager.uint32_type ||
3151 type == TypeManager.int64_type ||
3152 type == TypeManager.char_type)
3153 WarnUselessComparison (type);
3156 value = (long) uvalue;
3158 else if (c is ByteConstant)
3159 value = ((ByteConstant) c).Value;
3160 else if (c is SByteConstant)
3161 value = ((SByteConstant) c).Value;
3162 else if (c is ShortConstant)
3163 value = ((ShortConstant) c).Value;
3164 else if (c is UShortConstant)
3165 value = ((UShortConstant) c).Value;
3166 else if (c is IntConstant)
3167 value = ((IntConstant) c).Value;
3168 else if (c is UIntConstant)
3169 value = ((UIntConstant) c).Value;
3170 else if (c is LongConstant)
3171 value = ((LongConstant) c).Value;
3172 else if (c is CharConstant)
3173 value = ((CharConstant)c).Value;
3178 if (IsValueOutOfRange (value, type))
3179 WarnUselessComparison (type);
3182 static bool IsValueOutOfRange (long value, Type type)
3184 if (IsTypeUnsigned (type) && value < 0)
3186 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3187 type == TypeManager.byte_type && value >= 0x100 ||
3188 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3189 type == TypeManager.ushort_type && value >= 0x10000 ||
3190 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3191 type == TypeManager.uint32_type && value >= 0x100000000;
3194 static bool IsBuildInEqualityOperator (Type t)
3196 return t == TypeManager.object_type || t == TypeManager.string_type ||
3197 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3200 static bool IsPredefinedUserOperator (Type t, Operator op)
3203 // Some predefined types have user operators
3205 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3208 private static bool IsTypeIntegral (Type type)
3210 return type == TypeManager.uint64_type ||
3211 type == TypeManager.int64_type ||
3212 type == TypeManager.uint32_type ||
3213 type == TypeManager.int32_type ||
3214 type == TypeManager.ushort_type ||
3215 type == TypeManager.short_type ||
3216 type == TypeManager.sbyte_type ||
3217 type == TypeManager.byte_type ||
3218 type == TypeManager.char_type;
3221 private static bool IsTypeUnsigned (Type type)
3223 return type == TypeManager.uint64_type ||
3224 type == TypeManager.uint32_type ||
3225 type == TypeManager.ushort_type ||
3226 type == TypeManager.byte_type ||
3227 type == TypeManager.char_type;
3230 private void WarnUselessComparison (Type type)
3232 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}'",
3233 TypeManager.CSharpName (type));
3237 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3238 /// context of a conditional bool expression. This function will return
3239 /// false if it is was possible to use EmitBranchable, or true if it was.
3241 /// The expression's code is generated, and we will generate a branch to `target'
3242 /// if the resulting expression value is equal to isTrue
3244 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3246 ILGenerator ig = ec.ig;
3249 // This is more complicated than it looks, but its just to avoid
3250 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3251 // but on top of that we want for == and != to use a special path
3252 // if we are comparing against null
3254 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3255 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3258 // put the constant on the rhs, for simplicity
3260 if (left is Constant) {
3261 Expression swap = right;
3266 if (((Constant) right).IsZeroInteger) {
3267 left.EmitBranchable (ec, target, my_on_true);
3270 if (right.Type == TypeManager.bool_type) {
3271 // right is a boolean, and it's not 'false' => it is 'true'
3272 left.EmitBranchable (ec, target, !my_on_true);
3276 } else if (oper == Operator.LogicalAnd) {
3279 Label tests_end = ig.DefineLabel ();
3281 left.EmitBranchable (ec, tests_end, false);
3282 right.EmitBranchable (ec, target, true);
3283 ig.MarkLabel (tests_end);
3286 // This optimizes code like this
3287 // if (true && i > 4)
3289 if (!(left is Constant))
3290 left.EmitBranchable (ec, target, false);
3292 if (!(right is Constant))
3293 right.EmitBranchable (ec, target, false);
3298 } else if (oper == Operator.LogicalOr){
3300 left.EmitBranchable (ec, target, true);
3301 right.EmitBranchable (ec, target, true);
3304 Label tests_end = ig.DefineLabel ();
3305 left.EmitBranchable (ec, tests_end, true);
3306 right.EmitBranchable (ec, target, false);
3307 ig.MarkLabel (tests_end);
3312 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3313 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3314 oper == Operator.Equality || oper == Operator.Inequality)) {
3315 base.EmitBranchable (ec, target, on_true);
3323 bool is_unsigned = IsUnsigned (t) || IsFloat (t);
3326 case Operator.Equality:
3328 ig.Emit (OpCodes.Beq, target);
3330 ig.Emit (OpCodes.Bne_Un, target);
3333 case Operator.Inequality:
3335 ig.Emit (OpCodes.Bne_Un, target);
3337 ig.Emit (OpCodes.Beq, target);
3340 case Operator.LessThan:
3343 ig.Emit (OpCodes.Blt_Un, target);
3345 ig.Emit (OpCodes.Blt, target);
3348 ig.Emit (OpCodes.Bge_Un, target);
3350 ig.Emit (OpCodes.Bge, target);
3353 case Operator.GreaterThan:
3356 ig.Emit (OpCodes.Bgt_Un, target);
3358 ig.Emit (OpCodes.Bgt, target);
3361 ig.Emit (OpCodes.Ble_Un, target);
3363 ig.Emit (OpCodes.Ble, target);
3366 case Operator.LessThanOrEqual:
3369 ig.Emit (OpCodes.Ble_Un, target);
3371 ig.Emit (OpCodes.Ble, target);
3374 ig.Emit (OpCodes.Bgt_Un, target);
3376 ig.Emit (OpCodes.Bgt, target);
3380 case Operator.GreaterThanOrEqual:
3383 ig.Emit (OpCodes.Bge_Un, target);
3385 ig.Emit (OpCodes.Bge, target);
3388 ig.Emit (OpCodes.Blt_Un, target);
3390 ig.Emit (OpCodes.Blt, target);
3393 throw new InternalErrorException (oper.ToString ());
3397 public override void Emit (EmitContext ec)
3399 EmitOperator (ec, left.Type);
3402 protected virtual void EmitOperator (EmitContext ec, Type l)
3404 ILGenerator ig = ec.ig;
3407 // Handle short-circuit operators differently
3410 if ((oper & Operator.LogicalMask) != 0) {
3411 Label load_result = ig.DefineLabel ();
3412 Label end = ig.DefineLabel ();
3414 bool is_or = oper == Operator.LogicalOr;
3415 left.EmitBranchable (ec, load_result, is_or);
3417 ig.Emit (OpCodes.Br_S, end);
3419 ig.MarkLabel (load_result);
3420 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3428 // Optimize zero-based operations
3430 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3432 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3433 Constant rc = right as Constant;
3434 if (rc != null && rc.IsDefaultValue) {
3440 EmitOperatorOpcode (ec, oper, l);
3443 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3444 // expression because that would wrap lifted binary operation
3446 if (enum_conversion != null)
3447 enum_conversion.Emit (ec);
3450 public override void EmitSideEffect (EmitContext ec)
3452 if ((oper & Operator.LogicalMask) != 0 ||
3453 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3454 base.EmitSideEffect (ec);
3456 left.EmitSideEffect (ec);
3457 right.EmitSideEffect (ec);
3461 protected override void CloneTo (CloneContext clonectx, Expression t)
3463 Binary target = (Binary) t;
3465 target.left = left.Clone (clonectx);
3466 target.right = right.Clone (clonectx);
3469 public override Expression CreateExpressionTree (EmitContext ec)
3471 return CreateExpressionTree (ec, null);
3474 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3477 bool lift_arg = false;
3480 case Operator.Addition:
3481 if (method == null && ec.CheckState && !IsFloat (type))
3482 method_name = "AddChecked";
3484 method_name = "Add";
3486 case Operator.BitwiseAnd:
3487 method_name = "And";
3489 case Operator.BitwiseOr:
3492 case Operator.Division:
3493 method_name = "Divide";
3495 case Operator.Equality:
3496 method_name = "Equal";
3499 case Operator.ExclusiveOr:
3500 method_name = "ExclusiveOr";
3502 case Operator.GreaterThan:
3503 method_name = "GreaterThan";
3506 case Operator.GreaterThanOrEqual:
3507 method_name = "GreaterThanOrEqual";
3510 case Operator.Inequality:
3511 method_name = "NotEqual";
3514 case Operator.LeftShift:
3515 method_name = "LeftShift";
3517 case Operator.LessThan:
3518 method_name = "LessThan";
3521 case Operator.LessThanOrEqual:
3522 method_name = "LessThanOrEqual";
3525 case Operator.LogicalAnd:
3526 method_name = "AndAlso";
3528 case Operator.LogicalOr:
3529 method_name = "OrElse";
3531 case Operator.Modulus:
3532 method_name = "Modulo";
3534 case Operator.Multiply:
3535 if (method == null && ec.CheckState && !IsFloat (type))
3536 method_name = "MultiplyChecked";
3538 method_name = "Multiply";
3540 case Operator.RightShift:
3541 method_name = "RightShift";
3543 case Operator.Subtraction:
3544 if (method == null && ec.CheckState && !IsFloat (type))
3545 method_name = "SubtractChecked";
3547 method_name = "Subtract";
3551 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3554 ArrayList args = new ArrayList (2);
3555 args.Add (new Argument (left.CreateExpressionTree (ec)));
3556 args.Add (new Argument (right.CreateExpressionTree (ec)));
3557 if (method != null) {
3559 args.Add (new Argument (new BoolConstant (false, loc)));
3561 args.Add (new Argument (method.CreateExpressionTree (ec)));
3564 return CreateExpressionFactoryCall (method_name, args);
3569 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3570 // b, c, d... may be strings or objects.
3572 public class StringConcat : Expression {
3573 ArrayList arguments;
3575 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3578 type = TypeManager.string_type;
3579 eclass = ExprClass.Value;
3581 arguments = new ArrayList (2);
3586 public override Expression CreateExpressionTree (EmitContext ec)
3588 Argument arg = (Argument) arguments [0];
3589 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3593 // Creates nested calls tree from an array of arguments used for IL emit
3595 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3597 ArrayList concat_args = new ArrayList (2);
3598 ArrayList add_args = new ArrayList (3);
3600 concat_args.Add (left);
3601 add_args.Add (new Argument (left_etree));
3603 concat_args.Add (arguments [pos]);
3604 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3606 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3610 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3614 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3616 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3617 if (++pos == arguments.Count)
3620 left = new Argument (new EmptyExpression (method.Type));
3621 return CreateExpressionAddCall (ec, left, expr, pos);
3624 public override Expression DoResolve (EmitContext ec)
3629 public void Append (EmitContext ec, Expression operand)
3634 StringConstant sc = operand as StringConstant;
3636 if (arguments.Count != 0) {
3637 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3638 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3639 if (last_expr_constant != null) {
3640 last_argument.Expr = new StringConstant (
3641 last_expr_constant.Value + sc.Value, sc.Location);
3647 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3649 StringConcat concat_oper = operand as StringConcat;
3650 if (concat_oper != null) {
3651 arguments.AddRange (concat_oper.arguments);
3656 arguments.Add (new Argument (operand));
3659 Expression CreateConcatMemberExpression ()
3661 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3664 public override void Emit (EmitContext ec)
3666 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3667 concat = concat.Resolve (ec);
3674 // User-defined conditional logical operator
3676 public class ConditionalLogicalOperator : UserOperatorCall {
3677 readonly bool is_and;
3680 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3681 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3682 : base (oper_method, arguments, expr_tree, loc)
3684 this.is_and = is_and;
3687 public override Expression DoResolve (EmitContext ec)
3689 MethodInfo method = (MethodInfo)mg;
3690 type = TypeManager.TypeToCoreType (method.ReturnType);
3691 ParameterData pd = TypeManager.GetParameterData (method);
3692 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3693 Report.Error (217, loc,
3694 "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",
3695 TypeManager.CSharpSignature (method));
3699 Expression left_dup = new EmptyExpression (type);
3700 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3701 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3702 if (op_true == null || op_false == null) {
3703 Report.Error (218, loc,
3704 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3705 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3709 oper = is_and ? op_false : op_true;
3710 eclass = ExprClass.Value;
3714 public override void Emit (EmitContext ec)
3716 ILGenerator ig = ec.ig;
3717 Label end_target = ig.DefineLabel ();
3720 // Emit and duplicate left argument
3722 ((Argument)arguments [0]).Expr.Emit (ec);
3723 ig.Emit (OpCodes.Dup);
3724 arguments.RemoveAt (0);
3726 oper.EmitBranchable (ec, end_target, true);
3728 ig.MarkLabel (end_target);
3732 public class PointerArithmetic : Expression {
3733 Expression left, right;
3737 // We assume that `l' is always a pointer
3739 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3748 public override Expression CreateExpressionTree (EmitContext ec)
3750 Error_PointerInsideExpressionTree ();
3754 public override Expression DoResolve (EmitContext ec)
3756 eclass = ExprClass.Variable;
3758 if (left.Type == TypeManager.void_ptr_type) {
3759 Error (242, "The operation in question is undefined on void pointers");
3766 public override void Emit (EmitContext ec)
3768 Type op_type = left.Type;
3769 ILGenerator ig = ec.ig;
3771 // It must be either array or fixed buffer
3772 Type element = TypeManager.HasElementType (op_type) ?
3773 TypeManager.GetElementType (op_type) :
3774 AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3776 int size = GetTypeSize (element);
3777 Type rtype = right.Type;
3779 if (rtype.IsPointer){
3781 // handle (pointer - pointer)
3785 ig.Emit (OpCodes.Sub);
3789 ig.Emit (OpCodes.Sizeof, element);
3791 IntLiteral.EmitInt (ig, size);
3792 ig.Emit (OpCodes.Div);
3794 ig.Emit (OpCodes.Conv_I8);
3797 // handle + and - on (pointer op int)
3801 Constant right_const = right as Constant;
3802 if (right_const != null) {
3804 // Optimize 0-based arithmetic
3806 if (right_const.IsDefaultValue)
3810 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3814 ig.Emit (OpCodes.Sizeof, element);
3815 right = EmptyExpression.Null;
3820 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3821 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3822 ig.Emit (OpCodes.Conv_I);
3823 } else if (rtype == TypeManager.uint32_type) {
3824 ig.Emit (OpCodes.Conv_U);
3827 if (right_const == null && size != 1){
3829 ig.Emit (OpCodes.Sizeof, element);
3831 IntLiteral.EmitInt (ig, size);
3832 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3833 ig.Emit (OpCodes.Conv_I8);
3835 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3838 if (rtype == TypeManager.int64_type)
3839 ig.Emit (OpCodes.Conv_I);
3840 else if (rtype == TypeManager.uint64_type)
3841 ig.Emit (OpCodes.Conv_U);
3843 Binary.EmitOperatorOpcode (ec, op, op_type);
3849 /// Implements the ternary conditional operator (?:)
3851 public class Conditional : Expression {
3852 Expression expr, true_expr, false_expr;
3854 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3857 this.true_expr = true_expr;
3858 this.false_expr = false_expr;
3859 this.loc = expr.Location;
3862 public Expression Expr {
3868 public Expression TrueExpr {
3874 public Expression FalseExpr {
3880 public override Expression CreateExpressionTree (EmitContext ec)
3882 ArrayList args = new ArrayList (3);
3883 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3884 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3885 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3886 return CreateExpressionFactoryCall ("Condition", args);
3889 public override Expression DoResolve (EmitContext ec)
3891 expr = expr.Resolve (ec);
3896 if (expr.Type != TypeManager.bool_type){
3897 expr = Expression.ResolveBoolean (
3904 Assign ass = expr as Assign;
3905 if (ass != null && ass.Source is Constant) {
3906 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3909 true_expr = true_expr.Resolve (ec);
3910 false_expr = false_expr.Resolve (ec);
3912 if (true_expr == null || false_expr == null)
3915 eclass = ExprClass.Value;
3916 Type true_type = true_expr.Type;
3917 Type false_type = false_expr.Type;
3921 // First, if an implicit conversion exists from true_expr
3922 // to false_expr, then the result type is of type false_expr.Type
3924 if (!TypeManager.IsEqual (true_type, false_type)) {
3925 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3928 // Check if both can convert implicitl to each other's type
3930 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3932 "Can not compute type of conditional expression " +
3933 "as `" + TypeManager.CSharpName (true_expr.Type) +
3934 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3935 "' convert implicitly to each other");
3940 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3943 Report.Error (173, loc,
3944 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3945 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3950 // Dead code optimalization
3951 Constant c = expr as Constant;
3953 bool value = (bool) c.GetValue ();
3954 Report.Warning (429, 4, value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3955 return value ? true_expr : false_expr;
3961 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3963 expr.MutateHoistedGenericType (storey);
3964 true_expr.MutateHoistedGenericType (storey);
3965 false_expr.MutateHoistedGenericType (storey);
3966 type = storey.MutateType (type);
3969 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3974 public override void Emit (EmitContext ec)
3976 ILGenerator ig = ec.ig;
3977 Label false_target = ig.DefineLabel ();
3978 Label end_target = ig.DefineLabel ();
3980 expr.EmitBranchable (ec, false_target, false);
3981 true_expr.Emit (ec);
3983 if (type.IsInterface) {
3984 LocalBuilder temp = ec.GetTemporaryLocal (type);
3985 ig.Emit (OpCodes.Stloc, temp);
3986 ig.Emit (OpCodes.Ldloc, temp);
3987 ec.FreeTemporaryLocal (temp, type);
3990 ig.Emit (OpCodes.Br, end_target);
3991 ig.MarkLabel (false_target);
3992 false_expr.Emit (ec);
3993 ig.MarkLabel (end_target);
3996 protected override void CloneTo (CloneContext clonectx, Expression t)
3998 Conditional target = (Conditional) t;
4000 target.expr = expr.Clone (clonectx);
4001 target.true_expr = true_expr.Clone (clonectx);
4002 target.false_expr = false_expr.Clone (clonectx);
4006 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
4007 LocalTemporary temp;
4010 public abstract HoistedVariable HoistedVariable { get; }
4011 public abstract bool IsFixed { get; }
4012 public abstract bool IsRef { get; }
4015 // Variable IL data, it has to be protected to encapsulate hoisted variables
4017 protected abstract ILocalVariable Variable { get; }
4020 // Variable flow-analysis data
4022 public abstract VariableInfo VariableInfo { get; }
4025 public void AddressOf (EmitContext ec, AddressOp mode)
4027 if (IsHoistedEmitRequired (ec)) {
4028 HoistedVariable.AddressOf (ec, mode);
4032 Variable.EmitAddressOf (ec);
4035 public override void Emit (EmitContext ec)
4040 public override void EmitSideEffect (EmitContext ec)
4046 // This method is used by parameters that are references, that are
4047 // being passed as references: we only want to pass the pointer (that
4048 // is already stored in the parameter, not the address of the pointer,
4049 // and not the value of the variable).
4051 public void EmitLoad (EmitContext ec)
4056 public void Emit (EmitContext ec, bool leave_copy)
4058 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4060 if (IsHoistedEmitRequired (ec)) {
4061 HoistedVariable.Emit (ec, leave_copy);
4069 // If we are a reference, we loaded on the stack a pointer
4070 // Now lets load the real value
4072 LoadFromPtr (ec.ig, type);
4076 ec.ig.Emit (OpCodes.Dup);
4079 temp = new LocalTemporary (Type);
4085 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4086 bool prepare_for_load)
4088 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4091 if (IsHoistedEmitRequired (ec)) {
4092 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4101 // HACK: variable is already emitted when source is an initializer
4102 if (source is NewInitialize) {
4110 ec.ig.Emit (OpCodes.Dup);
4112 temp = new LocalTemporary (Type);
4118 StoreFromPtr (ec.ig, type);
4120 Variable.EmitAssign (ec);
4128 public bool IsHoisted {
4129 get { return HoistedVariable != null; }
4132 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4135 // Default implementation return true when there is a hosted variable
4137 return HoistedVariable != null;
4140 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4142 type = storey.MutateType (type);
4149 public class LocalVariableReference : VariableReference {
4150 public readonly string Name;
4152 public LocalInfo local_info;
4155 public LocalVariableReference (Block block, string name, Location l)
4160 eclass = ExprClass.Variable;
4164 // Setting `is_readonly' to false will allow you to create a writable
4165 // reference to a read-only variable. This is used by foreach and using.
4167 public LocalVariableReference (Block block, string name, Location l,
4168 LocalInfo local_info, bool is_readonly)
4169 : this (block, name, l)
4171 this.local_info = local_info;
4172 this.is_readonly = is_readonly;
4175 public override VariableInfo VariableInfo {
4176 get { return local_info.VariableInfo; }
4179 public override HoistedVariable HoistedVariable {
4180 get { return local_info.HoistedVariableReference; }
4184 // A local Variable is always fixed.
4186 public override bool IsFixed {
4187 get { return true; }
4190 public override bool IsRef {
4191 get { return false; }
4194 public bool IsReadOnly {
4195 get { return is_readonly; }
4198 public bool VerifyAssigned (EmitContext ec)
4200 VariableInfo variable_info = local_info.VariableInfo;
4201 return variable_info == null || variable_info.IsAssigned (ec, loc);
4204 void ResolveLocalInfo ()
4206 if (local_info == null) {
4207 local_info = Block.GetLocalInfo (Name);
4208 type = local_info.VariableType;
4209 is_readonly = local_info.ReadOnly;
4213 public override Expression CreateExpressionTree (EmitContext ec)
4215 ArrayList arg = new ArrayList (1);
4216 arg.Add (new Argument (this));
4217 return CreateExpressionFactoryCall ("Constant", arg);
4220 Expression DoResolveBase (EmitContext ec)
4222 type = local_info.VariableType;
4224 Expression e = Block.GetConstantExpression (Name);
4226 return e.Resolve (ec);
4228 VerifyAssigned (ec);
4231 // If we are referencing a variable from the external block
4232 // flag it for capturing
4234 if (ec.MustCaptureVariable (local_info)) {
4235 if (local_info.AddressTaken){
4236 AnonymousMethodBody.Error_AddressOfCapturedVar (local_info.Name, loc);
4240 if (ec.IsVariableCapturingRequired) {
4241 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4242 storey.CaptureLocalVariable (ec, local_info);
4249 public override Expression DoResolve (EmitContext ec)
4251 ResolveLocalInfo ();
4252 local_info.Used = true;
4254 if (type == null && local_info.Type is VarExpr) {
4255 local_info.VariableType = TypeManager.object_type;
4256 Error_VariableIsUsedBeforeItIsDeclared (Name);
4260 return DoResolveBase (ec);
4263 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4265 ResolveLocalInfo ();
4268 if (right_side == EmptyExpression.OutAccess)
4269 local_info.Used = true;
4271 // Infer implicitly typed local variable
4273 VarExpr ve = local_info.Type as VarExpr;
4275 if (!ve.InferType (ec, right_side))
4277 type = local_info.VariableType = ve.Type;
4284 if (right_side == EmptyExpression.OutAccess) {
4285 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4286 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4287 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4288 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4289 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4290 } else if (right_side == EmptyExpression.UnaryAddress) {
4291 code = 459; msg = "Cannot take the address of {1} `{0}'";
4293 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4295 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4296 } else if (VariableInfo != null) {
4297 VariableInfo.SetAssigned (ec);
4300 return DoResolveBase (ec);
4303 public override int GetHashCode ()
4305 return Name.GetHashCode ();
4308 public override bool Equals (object obj)
4310 LocalVariableReference lvr = obj as LocalVariableReference;
4314 return Name == lvr.Name && Block == lvr.Block;
4317 protected override ILocalVariable Variable {
4318 get { return local_info; }
4321 public override string ToString ()
4323 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4326 protected override void CloneTo (CloneContext clonectx, Expression t)
4328 LocalVariableReference target = (LocalVariableReference) t;
4330 target.Block = clonectx.LookupBlock (Block);
4331 if (local_info != null)
4332 target.local_info = clonectx.LookupVariable (local_info);
4337 /// This represents a reference to a parameter in the intermediate
4340 public class ParameterReference : VariableReference {
4341 readonly ToplevelParameterInfo pi;
4342 readonly ToplevelBlock referenced;
4344 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4347 this.referenced = referenced;
4351 public override bool IsRef {
4352 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4355 bool HasOutModifier {
4356 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4359 public override HoistedVariable HoistedVariable {
4360 get { return pi.Parameter.HoistedVariableReference; }
4364 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4366 public override bool IsFixed {
4367 get { return pi.Parameter.ModFlags == Parameter.Modifier.NONE; }
4370 public string Name {
4371 get { return Parameter.Name; }
4374 public Parameter Parameter {
4375 get { return pi.Parameter; }
4378 public override VariableInfo VariableInfo {
4379 get { return pi.VariableInfo; }
4382 protected override ILocalVariable Variable {
4383 get { return Parameter; }
4386 public bool IsAssigned (EmitContext ec, Location loc)
4388 // HACK: Variables are not captured in probing mode
4389 if (ec.IsInProbingMode)
4392 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4395 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4399 void SetAssigned (EmitContext ec)
4401 if (HasOutModifier && ec.DoFlowAnalysis)
4402 ec.CurrentBranching.SetAssigned (VariableInfo);
4405 bool DoResolveBase (EmitContext ec)
4407 Parameter par = Parameter;
4408 type = par.ParameterType;
4409 eclass = ExprClass.Variable;
4411 AnonymousExpression am = ec.CurrentAnonymousMethod;
4415 ToplevelBlock declared = pi.Block;
4416 if (declared != referenced) {
4418 Report.Error (1628, loc,
4419 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4420 par.Name, am.ContainerType);
4428 if (ec.IsVariableCapturingRequired) {
4429 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4430 storey.CaptureParameter (ec, this);
4436 public override int GetHashCode ()
4438 return Name.GetHashCode ();
4441 public override bool Equals (object obj)
4443 ParameterReference pr = obj as ParameterReference;
4447 return Name == pr.Name && referenced == pr.referenced;
4450 protected override void CloneTo (CloneContext clonectx, Expression target)
4455 public override Expression CreateExpressionTree (EmitContext ec)
4457 if (IsHoistedEmitRequired (ec))
4458 return HoistedVariable.CreateExpressionTree (ec);
4460 return Parameter.ExpressionTreeVariableReference ();
4464 // Notice that for ref/out parameters, the type exposed is not the
4465 // same type exposed externally.
4468 // externally we expose "int&"
4469 // here we expose "int".
4471 // We record this in "is_ref". This means that the type system can treat
4472 // the type as it is expected, but when we generate the code, we generate
4473 // the alternate kind of code.
4475 public override Expression DoResolve (EmitContext ec)
4477 if (!DoResolveBase (ec))
4480 if (HasOutModifier && ec.DoFlowAnalysis &&
4481 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4487 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4489 if (!DoResolveBase (ec))
4492 // HACK: parameters are not captured when probing is on
4493 if (!ec.IsInProbingMode)
4499 static public void EmitLdArg (ILGenerator ig, int x)
4503 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4504 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4505 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4506 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4507 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4510 ig.Emit (OpCodes.Ldarg, x);
4513 public override string ToString ()
4515 return "ParameterReference[" + Name + "]";
4520 /// Used for arguments to New(), Invocation()
4522 public class Argument {
4523 public enum AType : byte {
4530 public static readonly Argument[] Empty = new Argument [0];
4532 public readonly AType ArgType;
4533 public Expression Expr;
4535 public Argument (Expression expr, AType type)
4538 this.ArgType = type;
4541 public Argument (Expression expr)
4544 this.ArgType = AType.Expression;
4549 if (ArgType == AType.Ref || ArgType == AType.Out)
4550 return TypeManager.GetReferenceType (Expr.Type);
4556 public Parameter.Modifier Modifier
4561 return Parameter.Modifier.OUT;
4564 return Parameter.Modifier.REF;
4567 return Parameter.Modifier.NONE;
4572 public string GetSignatureForError ()
4574 if (Expr.eclass == ExprClass.MethodGroup)
4575 return Expr.ExprClassName;
4577 return TypeManager.CSharpName (Expr.Type);
4580 public bool ResolveMethodGroup (EmitContext ec)
4582 SimpleName sn = Expr as SimpleName;
4584 Expr = sn.GetMethodGroup ();
4586 // FIXME: csc doesn't report any error if you try to use `ref' or
4587 // `out' in a delegate creation expression.
4588 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4595 public bool Resolve (EmitContext ec, Location loc)
4600 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4601 // Verify that the argument is readable
4602 if (ArgType != AType.Out)
4603 Expr = Expr.Resolve (ec);
4605 // Verify that the argument is writeable
4606 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4607 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4609 return Expr != null;
4613 public void Emit (EmitContext ec)
4615 if (ArgType != AType.Ref && ArgType != AType.Out) {
4620 AddressOp mode = AddressOp.Store;
4621 if (ArgType == AType.Ref)
4622 mode |= AddressOp.Load;
4624 IMemoryLocation ml = (IMemoryLocation) Expr;
4625 ParameterReference pr = ml as ParameterReference;
4628 // ParameterReferences might already be references, so we want
4629 // to pass just the value
4631 if (pr != null && pr.IsRef)
4634 ml.AddressOf (ec, mode);
4637 public Argument Clone (CloneContext clonectx)
4639 return new Argument (Expr.Clone (clonectx), ArgType);
4644 /// Invocation of methods or delegates.
4646 public class Invocation : ExpressionStatement {
4647 protected ArrayList Arguments;
4648 protected Expression expr;
4649 protected MethodGroupExpr mg;
4650 bool arguments_resolved;
4653 // arguments is an ArrayList, but we do not want to typecast,
4654 // as it might be null.
4656 public Invocation (Expression expr, ArrayList arguments)
4658 SimpleName sn = expr as SimpleName;
4660 this.expr = sn.GetMethodGroup ();
4664 Arguments = arguments;
4666 loc = expr.Location;
4669 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4670 : this (expr, arguments)
4672 this.arguments_resolved = arguments_resolved;
4675 public override Expression CreateExpressionTree (EmitContext ec)
4680 // Special conversion for nested expression trees
4682 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4683 args = new ArrayList (1);
4684 args.Add (new Argument (this));
4685 return CreateExpressionFactoryCall ("Quote", args);
4688 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4690 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4693 args = new ArrayList (arg_count);
4696 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4698 args.Add (new Argument (new NullLiteral (loc)));
4700 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4703 // Use extension argument when exists
4706 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4708 args.Add (new Argument (e));
4711 if (Arguments != null) {
4712 foreach (Argument a in Arguments) {
4713 Expression e = a.Expr.CreateExpressionTree (ec);
4715 args.Add (new Argument (e));
4720 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4722 return CreateExpressionFactoryCall ("Call", args);
4725 public override Expression DoResolve (EmitContext ec)
4727 // Don't resolve already resolved expression
4728 if (eclass != ExprClass.Invalid)
4731 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4732 if (expr_resolved == null)
4735 mg = expr_resolved as MethodGroupExpr;
4737 Type expr_type = expr_resolved.Type;
4739 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4740 return (new DelegateInvocation (
4741 expr_resolved, Arguments, loc)).Resolve (ec);
4744 MemberExpr me = expr_resolved as MemberExpr;
4746 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4750 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4752 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4753 expr_resolved.GetSignatureForError ());
4757 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4761 // Next, evaluate all the expressions in the argument list
4763 if (Arguments != null && !arguments_resolved) {
4764 for (int i = 0; i < Arguments.Count; ++i)
4766 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4771 mg = DoResolveOverload (ec);
4775 MethodInfo method = (MethodInfo)mg;
4776 if (method != null) {
4777 type = TypeManager.TypeToCoreType (method.ReturnType);
4779 // TODO: this is a copy of mg.ResolveMemberAccess method
4780 Expression iexpr = mg.InstanceExpression;
4781 if (method.IsStatic) {
4782 if (iexpr == null ||
4783 iexpr is This || iexpr is EmptyExpression ||
4784 mg.IdenticalTypeName) {
4785 mg.InstanceExpression = null;
4787 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4793 if (type.IsPointer){
4801 // Only base will allow this invocation to happen.
4803 if (mg.IsBase && method.IsAbstract){
4804 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4808 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4810 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4812 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4816 IsSpecialMethodInvocation (method, loc);
4818 if (mg.InstanceExpression != null)
4819 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4821 eclass = ExprClass.Value;
4825 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4827 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4830 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4832 if (!TypeManager.IsSpecialMethod (method))
4835 Report.SymbolRelatedToPreviousError (method);
4836 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4837 TypeManager.CSharpSignature (method, true));
4843 /// Emits a list of resolved Arguments that are in the arguments
4846 /// The MethodBase argument might be null if the
4847 /// emission of the arguments is known not to contain
4848 /// a `params' field (for example in constructors or other routines
4849 /// that keep their arguments in this structure)
4851 /// if `dup_args' is true, a copy of the arguments will be left
4852 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4853 /// which will be duplicated before any other args. Only EmitCall
4854 /// should be using this interface.
4856 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4858 if (arguments == null)
4861 int top = arguments.Count;
4862 LocalTemporary [] temps = null;
4864 if (dup_args && top != 0)
4865 temps = new LocalTemporary [top];
4867 int argument_index = 0;
4869 for (int i = 0; i < top; i++) {
4870 a = (Argument) arguments [argument_index++];
4873 ec.ig.Emit (OpCodes.Dup);
4874 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4879 if (this_arg != null)
4882 for (int i = 0; i < top; i ++) {
4883 temps [i].Emit (ec);
4884 temps [i].Release (ec);
4889 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4891 ParameterData pd = TypeManager.GetParameterData (mb);
4893 if (arguments == null)
4894 return Type.EmptyTypes;
4896 Argument a = (Argument) arguments [pd.Count - 1];
4897 Arglist list = (Arglist) a.Expr;
4899 return list.ArgumentTypes;
4903 /// This checks the ConditionalAttribute on the method
4905 public static bool IsMethodExcluded (MethodBase method, Location loc)
4907 if (method.IsConstructor)
4910 method = TypeManager.DropGenericMethodArguments (method);
4911 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4912 IMethodData md = TypeManager.GetMethod (method);
4914 return md.IsExcluded ();
4916 // For some methods (generated by delegate class) GetMethod returns null
4917 // because they are not included in builder_to_method table
4921 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4925 /// is_base tells whether we want to force the use of the `call'
4926 /// opcode instead of using callvirt. Call is required to call
4927 /// a specific method, while callvirt will always use the most
4928 /// recent method in the vtable.
4930 /// is_static tells whether this is an invocation on a static method
4932 /// instance_expr is an expression that represents the instance
4933 /// it must be non-null if is_static is false.
4935 /// method is the method to invoke.
4937 /// Arguments is the list of arguments to pass to the method or constructor.
4939 public static void EmitCall (EmitContext ec, bool is_base,
4940 Expression instance_expr,
4941 MethodBase method, ArrayList Arguments, Location loc)
4943 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4946 // `dup_args' leaves an extra copy of the arguments on the stack
4947 // `omit_args' does not leave any arguments at all.
4948 // So, basically, you could make one call with `dup_args' set to true,
4949 // and then another with `omit_args' set to true, and the two calls
4950 // would have the same set of arguments. However, each argument would
4951 // only have been evaluated once.
4952 public static void EmitCall (EmitContext ec, bool is_base,
4953 Expression instance_expr,
4954 MethodBase method, ArrayList Arguments, Location loc,
4955 bool dup_args, bool omit_args)
4957 ILGenerator ig = ec.ig;
4958 bool struct_call = false;
4959 bool this_call = false;
4960 LocalTemporary this_arg = null;
4962 Type decl_type = method.DeclaringType;
4964 if (!ec.IsInObsoleteScope) {
4966 // This checks ObsoleteAttribute on the method and on the declaring type
4968 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4970 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4972 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4974 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4978 if (IsMethodExcluded (method, loc))
4981 bool is_static = method.IsStatic;
4983 if (instance_expr == EmptyExpression.Null) {
4984 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4988 this_call = instance_expr is This;
4989 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4993 // If this is ourselves, push "this"
4997 Type iexpr_type = instance_expr.Type;
5000 // Push the instance expression
5002 if (TypeManager.IsValueType (iexpr_type)) {
5004 // Special case: calls to a function declared in a
5005 // reference-type with a value-type argument need
5006 // to have their value boxed.
5007 if (decl_type.IsValueType ||
5008 TypeManager.IsGenericParameter (iexpr_type)) {
5010 // If the expression implements IMemoryLocation, then
5011 // we can optimize and use AddressOf on the
5014 // If not we have to use some temporary storage for
5016 if (instance_expr is IMemoryLocation) {
5017 ((IMemoryLocation)instance_expr).
5018 AddressOf (ec, AddressOp.LoadStore);
5020 LocalTemporary temp = new LocalTemporary (iexpr_type);
5021 instance_expr.Emit (ec);
5023 temp.AddressOf (ec, AddressOp.Load);
5026 // avoid the overhead of doing this all the time.
5028 t = TypeManager.GetReferenceType (iexpr_type);
5030 instance_expr.Emit (ec);
5031 ig.Emit (OpCodes.Box, instance_expr.Type);
5032 t = TypeManager.object_type;
5035 instance_expr.Emit (ec);
5036 t = instance_expr.Type;
5040 ig.Emit (OpCodes.Dup);
5041 if (Arguments != null && Arguments.Count != 0) {
5042 this_arg = new LocalTemporary (t);
5043 this_arg.Store (ec);
5050 EmitArguments (ec, Arguments, dup_args, this_arg);
5053 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5054 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5058 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5059 call_op = OpCodes.Call;
5061 call_op = OpCodes.Callvirt;
5063 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5064 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5065 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5072 // and DoFoo is not virtual, you can omit the callvirt,
5073 // because you don't need the null checking behavior.
5075 if (method is MethodInfo)
5076 ig.Emit (call_op, (MethodInfo) method);
5078 ig.Emit (call_op, (ConstructorInfo) method);
5081 public override void Emit (EmitContext ec)
5083 mg.EmitCall (ec, Arguments);
5086 public override void EmitStatement (EmitContext ec)
5091 // Pop the return value if there is one
5093 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5094 ec.ig.Emit (OpCodes.Pop);
5097 protected override void CloneTo (CloneContext clonectx, Expression t)
5099 Invocation target = (Invocation) t;
5101 if (Arguments != null) {
5102 target.Arguments = new ArrayList (Arguments.Count);
5103 foreach (Argument a in Arguments)
5104 target.Arguments.Add (a.Clone (clonectx));
5107 target.expr = expr.Clone (clonectx);
5110 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5112 mg.MutateHoistedGenericType (storey);
5113 if (Arguments != null) {
5114 foreach (Argument a in Arguments)
5115 a.Expr.MutateHoistedGenericType (storey);
5120 public class InvocationOrCast : ExpressionStatement
5123 Expression argument;
5125 public InvocationOrCast (Expression expr, Expression argument)
5128 this.argument = argument;
5129 this.loc = expr.Location;
5132 public override Expression CreateExpressionTree (EmitContext ec)
5134 throw new NotSupportedException ("ET");
5137 public override Expression DoResolve (EmitContext ec)
5140 // First try to resolve it as a cast.
5142 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5143 if ((te != null) && (te.eclass == ExprClass.Type)) {
5144 Cast cast = new Cast (te, argument, loc);
5145 return cast.Resolve (ec);
5149 // This can either be a type or a delegate invocation.
5150 // Let's just resolve it and see what we'll get.
5152 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5157 // Ok, so it's a Cast.
5159 if (expr.eclass == ExprClass.Type) {
5160 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5161 return cast.Resolve (ec);
5165 // It's a delegate invocation.
5167 if (!TypeManager.IsDelegateType (expr.Type)) {
5168 Error (149, "Method name expected");
5172 ArrayList args = new ArrayList ();
5173 args.Add (new Argument (argument, Argument.AType.Expression));
5174 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5175 return invocation.Resolve (ec);
5178 public override ExpressionStatement ResolveStatement (EmitContext ec)
5181 // First try to resolve it as a cast.
5183 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5184 if ((te != null) && (te.eclass == ExprClass.Type)) {
5185 Error_InvalidExpressionStatement ();
5190 // This can either be a type or a delegate invocation.
5191 // Let's just resolve it and see what we'll get.
5193 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5194 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5195 Error_InvalidExpressionStatement ();
5200 // It's a delegate invocation.
5202 if (!TypeManager.IsDelegateType (expr.Type)) {
5203 Error (149, "Method name expected");
5207 ArrayList args = new ArrayList ();
5208 args.Add (new Argument (argument, Argument.AType.Expression));
5209 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5210 return invocation.ResolveStatement (ec);
5213 public override void Emit (EmitContext ec)
5215 throw new Exception ("Cannot happen");
5218 public override void EmitStatement (EmitContext ec)
5220 throw new Exception ("Cannot happen");
5223 protected override void CloneTo (CloneContext clonectx, Expression t)
5225 InvocationOrCast target = (InvocationOrCast) t;
5227 target.expr = expr.Clone (clonectx);
5228 target.argument = argument.Clone (clonectx);
5233 // This class is used to "disable" the code generation for the
5234 // temporary variable when initializing value types.
5236 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5237 public void AddressOf (EmitContext ec, AddressOp Mode)
5244 /// Implements the new expression
5246 public class New : ExpressionStatement, IMemoryLocation {
5247 ArrayList Arguments;
5250 // During bootstrap, it contains the RequestedType,
5251 // but if `type' is not null, it *might* contain a NewDelegate
5252 // (because of field multi-initialization)
5254 public Expression RequestedType;
5256 MethodGroupExpr method;
5259 // If set, the new expression is for a value_target, and
5260 // we will not leave anything on the stack.
5262 protected Expression value_target;
5263 protected bool value_target_set;
5264 bool is_type_parameter = false;
5266 public New (Expression requested_type, ArrayList arguments, Location l)
5268 RequestedType = requested_type;
5269 Arguments = arguments;
5273 public bool SetTargetVariable (Expression value)
5275 value_target = value;
5276 value_target_set = true;
5277 if (!(value_target is IMemoryLocation)){
5278 Error_UnexpectedKind (null, "variable", loc);
5285 // This function is used to disable the following code sequence for
5286 // value type initialization:
5288 // AddressOf (temporary)
5292 // Instead the provide will have provided us with the address on the
5293 // stack to store the results.
5295 static Expression MyEmptyExpression;
5297 public void DisableTemporaryValueType ()
5299 if (MyEmptyExpression == null)
5300 MyEmptyExpression = new EmptyAddressOf ();
5303 // To enable this, look into:
5304 // test-34 and test-89 and self bootstrapping.
5306 // For instance, we can avoid a copy by using `newobj'
5307 // instead of Call + Push-temp on value types.
5308 // value_target = MyEmptyExpression;
5313 /// Converts complex core type syntax like 'new int ()' to simple constant
5315 public static Constant Constantify (Type t)
5317 if (t == TypeManager.int32_type)
5318 return new IntConstant (0, Location.Null);
5319 if (t == TypeManager.uint32_type)
5320 return new UIntConstant (0, Location.Null);
5321 if (t == TypeManager.int64_type)
5322 return new LongConstant (0, Location.Null);
5323 if (t == TypeManager.uint64_type)
5324 return new ULongConstant (0, Location.Null);
5325 if (t == TypeManager.float_type)
5326 return new FloatConstant (0, Location.Null);
5327 if (t == TypeManager.double_type)
5328 return new DoubleConstant (0, Location.Null);
5329 if (t == TypeManager.short_type)
5330 return new ShortConstant (0, Location.Null);
5331 if (t == TypeManager.ushort_type)
5332 return new UShortConstant (0, Location.Null);
5333 if (t == TypeManager.sbyte_type)
5334 return new SByteConstant (0, Location.Null);
5335 if (t == TypeManager.byte_type)
5336 return new ByteConstant (0, Location.Null);
5337 if (t == TypeManager.char_type)
5338 return new CharConstant ('\0', Location.Null);
5339 if (t == TypeManager.bool_type)
5340 return new BoolConstant (false, Location.Null);
5341 if (t == TypeManager.decimal_type)
5342 return new DecimalConstant (0, Location.Null);
5343 if (TypeManager.IsEnumType (t))
5344 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5350 // Checks whether the type is an interface that has the
5351 // [ComImport, CoClass] attributes and must be treated
5354 public Expression CheckComImport (EmitContext ec)
5356 if (!type.IsInterface)
5360 // Turn the call into:
5361 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5363 Type real_class = AttributeTester.GetCoClassAttribute (type);
5364 if (real_class == null)
5367 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5368 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5369 return cast.Resolve (ec);
5372 public override Expression CreateExpressionTree (EmitContext ec)
5374 ArrayList args = Arguments == null ?
5375 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5377 if (method == null) {
5378 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5380 args.Add (new Argument (method.CreateExpressionTree (ec)));
5381 if (Arguments != null) {
5383 foreach (Argument a in Arguments) {
5384 expr = a.Expr.CreateExpressionTree (ec);
5386 args.Add (new Argument (expr));
5391 return CreateExpressionFactoryCall ("New", args);
5394 public override Expression DoResolve (EmitContext ec)
5397 // The New DoResolve might be called twice when initializing field
5398 // expressions (see EmitFieldInitializers, the call to
5399 // GetInitializerExpression will perform a resolve on the expression,
5400 // and later the assign will trigger another resolution
5402 // This leads to bugs (#37014)
5405 if (RequestedType is NewDelegate)
5406 return RequestedType;
5410 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5416 if (type == TypeManager.void_type) {
5417 Error_VoidInvalidInTheContext (loc);
5421 if (type.IsPointer) {
5422 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5423 TypeManager.CSharpName (type));
5427 if (Arguments == null) {
5428 Expression c = Constantify (type);
5433 if (TypeManager.IsDelegateType (type)) {
5434 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5438 if (type.IsGenericParameter) {
5439 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5441 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5442 Error (304, String.Format (
5443 "Cannot create an instance of the " +
5444 "variable type '{0}' because it " +
5445 "doesn't have the new() constraint",
5450 if ((Arguments != null) && (Arguments.Count != 0)) {
5451 Error (417, String.Format (
5452 "`{0}': cannot provide arguments " +
5453 "when creating an instance of a " +
5454 "variable type.", type));
5458 if (TypeManager.activator_create_instance == null) {
5459 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5460 if (activator_type != null) {
5461 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5462 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5466 is_type_parameter = true;
5467 eclass = ExprClass.Value;
5472 if (type.IsAbstract && type.IsSealed) {
5473 Report.SymbolRelatedToPreviousError (type);
5474 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5478 if (type.IsInterface || type.IsAbstract){
5479 if (!TypeManager.IsGenericType (type)) {
5480 RequestedType = CheckComImport (ec);
5481 if (RequestedType != null)
5482 return RequestedType;
5485 Report.SymbolRelatedToPreviousError (type);
5486 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5490 bool is_struct = type.IsValueType;
5491 eclass = ExprClass.Value;
5494 // SRE returns a match for .ctor () on structs (the object constructor),
5495 // so we have to manually ignore it.
5497 if (is_struct && Arguments == null)
5500 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5501 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5502 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5504 if (Arguments != null){
5505 foreach (Argument a in Arguments){
5506 if (!a.Resolve (ec, loc))
5514 method = ml as MethodGroupExpr;
5515 if (method == null) {
5516 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5520 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5527 bool DoEmitTypeParameter (EmitContext ec)
5530 ILGenerator ig = ec.ig;
5531 // IMemoryLocation ml;
5533 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5534 new Type [] { type });
5536 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5537 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5538 ig.Emit (OpCodes.Call, ci);
5542 // Allow DoEmit() to be called multiple times.
5543 // We need to create a new LocalTemporary each time since
5544 // you can't share LocalBuilders among ILGeneators.
5545 LocalTemporary temp = new LocalTemporary (type);
5547 Label label_activator = ig.DefineLabel ();
5548 Label label_end = ig.DefineLabel ();
5550 temp.AddressOf (ec, AddressOp.Store);
5551 ig.Emit (OpCodes.Initobj, type);
5554 ig.Emit (OpCodes.Box, type);
5555 ig.Emit (OpCodes.Brfalse, label_activator);
5557 temp.AddressOf (ec, AddressOp.Store);
5558 ig.Emit (OpCodes.Initobj, type);
5560 ig.Emit (OpCodes.Br, label_end);
5562 ig.MarkLabel (label_activator);
5564 ig.Emit (OpCodes.Call, ci);
5565 ig.MarkLabel (label_end);
5568 throw new InternalErrorException ();
5573 // This DoEmit can be invoked in two contexts:
5574 // * As a mechanism that will leave a value on the stack (new object)
5575 // * As one that wont (init struct)
5577 // You can control whether a value is required on the stack by passing
5578 // need_value_on_stack. The code *might* leave a value on the stack
5579 // so it must be popped manually
5581 // If we are dealing with a ValueType, we have a few
5582 // situations to deal with:
5584 // * The target is a ValueType, and we have been provided
5585 // the instance (this is easy, we are being assigned).
5587 // * The target of New is being passed as an argument,
5588 // to a boxing operation or a function that takes a
5591 // In this case, we need to create a temporary variable
5592 // that is the argument of New.
5594 // Returns whether a value is left on the stack
5596 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5598 bool is_value_type = TypeManager.IsValueType (type);
5599 ILGenerator ig = ec.ig;
5604 // Allow DoEmit() to be called multiple times.
5605 // We need to create a new LocalTemporary each time since
5606 // you can't share LocalBuilders among ILGeneators.
5607 if (!value_target_set)
5608 value_target = new LocalTemporary (type);
5610 ml = (IMemoryLocation) value_target;
5611 ml.AddressOf (ec, AddressOp.Store);
5615 method.EmitArguments (ec, Arguments);
5619 ig.Emit (OpCodes.Initobj, type);
5621 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5622 if (need_value_on_stack){
5623 value_target.Emit (ec);
5628 ConstructorInfo ci = (ConstructorInfo) method;
5630 if (TypeManager.IsGenericType (type))
5631 ci = TypeBuilder.GetConstructor (type, ci);
5633 ig.Emit (OpCodes.Newobj, ci);
5638 public override void Emit (EmitContext ec)
5640 if (is_type_parameter)
5641 DoEmitTypeParameter (ec);
5646 public override void EmitStatement (EmitContext ec)
5648 bool value_on_stack;
5650 if (is_type_parameter)
5651 value_on_stack = DoEmitTypeParameter (ec);
5653 value_on_stack = DoEmit (ec, false);
5656 ec.ig.Emit (OpCodes.Pop);
5660 public virtual bool HasInitializer {
5666 public void AddressOf (EmitContext ec, AddressOp Mode)
5668 if (is_type_parameter) {
5669 LocalTemporary temp = new LocalTemporary (type);
5670 DoEmitTypeParameter (ec);
5672 temp.AddressOf (ec, Mode);
5676 if (!type.IsValueType){
5678 // We throw an exception. So far, I believe we only need to support
5680 // foreach (int j in new StructType ())
5683 throw new Exception ("AddressOf should not be used for classes");
5686 if (!value_target_set)
5687 value_target = new LocalTemporary (type);
5688 IMemoryLocation ml = (IMemoryLocation) value_target;
5690 ml.AddressOf (ec, AddressOp.Store);
5691 if (method == null) {
5692 ec.ig.Emit (OpCodes.Initobj, type);
5694 method.EmitArguments (ec, Arguments);
5695 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5698 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5701 protected override void CloneTo (CloneContext clonectx, Expression t)
5703 New target = (New) t;
5705 target.RequestedType = RequestedType.Clone (clonectx);
5706 if (Arguments != null){
5707 target.Arguments = new ArrayList ();
5708 foreach (Argument a in Arguments){
5709 target.Arguments.Add (a.Clone (clonectx));
5714 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5716 if (method != null) {
5717 method.MutateHoistedGenericType (storey);
5718 if (Arguments != null) {
5719 foreach (Argument a in Arguments)
5720 a.Expr.MutateHoistedGenericType (storey);
5724 type = storey.MutateType (type);
5729 /// 14.5.10.2: Represents an array creation expression.
5733 /// There are two possible scenarios here: one is an array creation
5734 /// expression that specifies the dimensions and optionally the
5735 /// initialization data and the other which does not need dimensions
5736 /// specified but where initialization data is mandatory.
5738 public class ArrayCreation : Expression {
5739 FullNamedExpression requested_base_type;
5740 ArrayList initializers;
5743 // The list of Argument types.
5744 // This is used to construct the `newarray' or constructor signature
5746 protected ArrayList arguments;
5748 protected Type array_element_type;
5749 bool expect_initializers = false;
5750 int num_arguments = 0;
5751 protected int dimensions;
5752 protected readonly string rank;
5754 protected ArrayList array_data;
5758 // The number of constants in array initializers
5759 int const_initializers_count;
5760 bool only_constant_initializers;
5762 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5764 this.requested_base_type = requested_base_type;
5765 this.initializers = initializers;
5769 arguments = new ArrayList ();
5771 foreach (Expression e in exprs) {
5772 arguments.Add (new Argument (e, Argument.AType.Expression));
5777 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5779 this.requested_base_type = requested_base_type;
5780 this.initializers = initializers;
5784 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5786 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5788 //dimensions = tmp.Length - 1;
5789 expect_initializers = true;
5792 void Error_IncorrectArrayInitializer ()
5794 Error (178, "Invalid rank specifier: expected `,' or `]'");
5797 protected override void Error_NegativeArrayIndex (Location loc)
5799 Report.Error (248, loc, "Cannot create an array with a negative size");
5802 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5804 if (specified_dims) {
5805 Argument a = (Argument) arguments [idx];
5807 if (!a.Resolve (ec, loc))
5810 Constant c = a.Expr as Constant;
5812 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
5816 Report.Error (150, a.Expr.Location, "A constant value is expected");
5820 int value = (int) c.GetValue ();
5822 if (value != probe.Count) {
5823 Error_IncorrectArrayInitializer ();
5827 bounds [idx] = value;
5830 int child_bounds = -1;
5831 only_constant_initializers = true;
5832 for (int i = 0; i < probe.Count; ++i) {
5833 object o = probe [i];
5834 if (o is ArrayList) {
5835 ArrayList sub_probe = o as ArrayList;
5836 int current_bounds = sub_probe.Count;
5838 if (child_bounds == -1)
5839 child_bounds = current_bounds;
5841 else if (child_bounds != current_bounds){
5842 Error_IncorrectArrayInitializer ();
5845 if (idx + 1 >= dimensions){
5846 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5850 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5854 if (child_bounds != -1){
5855 Error_IncorrectArrayInitializer ();
5859 Expression element = ResolveArrayElement (ec, (Expression) o);
5860 if (element == null)
5863 // Initializers with the default values can be ignored
5864 Constant c = element as Constant;
5866 if (c.IsDefaultInitializer (array_element_type)) {
5870 ++const_initializers_count;
5873 only_constant_initializers = false;
5876 array_data.Add (element);
5883 public override Expression CreateExpressionTree (EmitContext ec)
5887 if (array_data == null) {
5888 args = new ArrayList (arguments.Count + 1);
5889 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5890 foreach (Argument a in arguments) {
5891 if (arguments.Count == 1) {
5892 Constant c = a.Expr as Constant;
5893 if (c.IsDefaultValue)
5894 return CreateExpressionFactoryCall ("NewArrayInit", args);
5896 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5899 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5902 if (dimensions > 1) {
5903 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5907 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5908 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5909 if (array_data != null) {
5910 for (int i = 0; i < array_data.Count; ++i) {
5911 Expression e = (Expression) array_data [i];
5913 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5915 args.Add (new Argument (e.CreateExpressionTree (ec)));
5919 return CreateExpressionFactoryCall ("NewArrayInit", args);
5922 public void UpdateIndices ()
5925 for (ArrayList probe = initializers; probe != null;) {
5926 if (probe.Count > 0 && probe [0] is ArrayList) {
5927 Expression e = new IntConstant (probe.Count, Location.Null);
5928 arguments.Add (new Argument (e, Argument.AType.Expression));
5930 bounds [i++] = probe.Count;
5932 probe = (ArrayList) probe [0];
5935 Expression e = new IntConstant (probe.Count, Location.Null);
5936 arguments.Add (new Argument (e, Argument.AType.Expression));
5938 bounds [i++] = probe.Count;
5945 Expression first_emit;
5946 LocalTemporary first_emit_temp;
5948 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5950 element = element.Resolve (ec);
5951 if (element == null)
5954 if (element is CompoundAssign.Helper) {
5955 if (first_emit != null)
5956 throw new InternalErrorException ("Can only handle one mutator at a time");
5957 first_emit = element;
5958 element = first_emit_temp = new LocalTemporary (element.Type);
5961 return Convert.ImplicitConversionRequired (
5962 ec, element, array_element_type, loc);
5965 protected bool ResolveInitializers (EmitContext ec)
5967 if (initializers == null) {
5968 return !expect_initializers;
5972 // We use this to store all the date values in the order in which we
5973 // will need to store them in the byte blob later
5975 array_data = new ArrayList ();
5976 bounds = new System.Collections.Specialized.HybridDictionary ();
5978 if (arguments != null)
5979 return CheckIndices (ec, initializers, 0, true);
5981 arguments = new ArrayList ();
5983 if (!CheckIndices (ec, initializers, 0, false))
5992 // Resolved the type of the array
5994 bool ResolveArrayType (EmitContext ec)
5996 if (requested_base_type == null) {
5997 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6001 StringBuilder array_qualifier = new StringBuilder (rank);
6004 // `In the first form allocates an array instace of the type that results
6005 // from deleting each of the individual expression from the expression list'
6007 if (num_arguments > 0) {
6008 array_qualifier.Append ("[");
6009 for (int i = num_arguments-1; i > 0; i--)
6010 array_qualifier.Append (",");
6011 array_qualifier.Append ("]");
6017 TypeExpr array_type_expr;
6018 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6019 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6020 if (array_type_expr == null)
6023 type = array_type_expr.Type;
6024 array_element_type = TypeManager.GetElementType (type);
6025 dimensions = type.GetArrayRank ();
6030 public override Expression DoResolve (EmitContext ec)
6035 if (!ResolveArrayType (ec))
6038 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
6039 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
6040 TypeManager.CSharpName (array_element_type));
6044 // First step is to validate the initializers and fill
6045 // in any missing bits
6047 if (!ResolveInitializers (ec))
6050 if (arguments.Count != dimensions) {
6051 Error_IncorrectArrayInitializer ();
6054 foreach (Argument a in arguments){
6055 if (!a.Resolve (ec, loc))
6058 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6061 eclass = ExprClass.Value;
6065 MethodInfo GetArrayMethod (int arguments)
6067 ModuleBuilder mb = CodeGen.Module.Builder;
6069 Type[] arg_types = new Type[arguments];
6070 for (int i = 0; i < arguments; i++)
6071 arg_types[i] = TypeManager.int32_type;
6073 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6077 Report.Error (-6, "New invocation: Can not find a constructor for " +
6078 "this argument list");
6085 byte [] MakeByteBlob ()
6090 int count = array_data.Count;
6092 if (TypeManager.IsEnumType (array_element_type))
6093 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6095 factor = GetTypeSize (array_element_type);
6097 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6099 data = new byte [(count * factor + 3) & ~3];
6102 for (int i = 0; i < count; ++i) {
6103 object v = array_data [i];
6105 if (v is EnumConstant)
6106 v = ((EnumConstant) v).Child;
6108 if (v is Constant && !(v is StringConstant))
6109 v = ((Constant) v).GetValue ();
6115 if (array_element_type == TypeManager.int64_type){
6116 if (!(v is Expression)){
6117 long val = (long) v;
6119 for (int j = 0; j < factor; ++j) {
6120 data [idx + j] = (byte) (val & 0xFF);
6124 } else if (array_element_type == TypeManager.uint64_type){
6125 if (!(v is Expression)){
6126 ulong val = (ulong) v;
6128 for (int j = 0; j < factor; ++j) {
6129 data [idx + j] = (byte) (val & 0xFF);
6133 } else if (array_element_type == TypeManager.float_type) {
6134 if (!(v is Expression)){
6135 element = BitConverter.GetBytes ((float) v);
6137 for (int j = 0; j < factor; ++j)
6138 data [idx + j] = element [j];
6139 if (!BitConverter.IsLittleEndian)
6140 System.Array.Reverse (data, idx, 4);
6142 } else if (array_element_type == TypeManager.double_type) {
6143 if (!(v is Expression)){
6144 element = BitConverter.GetBytes ((double) v);
6146 for (int j = 0; j < factor; ++j)
6147 data [idx + j] = element [j];
6149 // FIXME: Handle the ARM float format.
6150 if (!BitConverter.IsLittleEndian)
6151 System.Array.Reverse (data, idx, 8);
6153 } else if (array_element_type == TypeManager.char_type){
6154 if (!(v is Expression)){
6155 int val = (int) ((char) v);
6157 data [idx] = (byte) (val & 0xff);
6158 data [idx+1] = (byte) (val >> 8);
6160 } else if (array_element_type == TypeManager.short_type){
6161 if (!(v is Expression)){
6162 int val = (int) ((short) v);
6164 data [idx] = (byte) (val & 0xff);
6165 data [idx+1] = (byte) (val >> 8);
6167 } else if (array_element_type == TypeManager.ushort_type){
6168 if (!(v is Expression)){
6169 int val = (int) ((ushort) v);
6171 data [idx] = (byte) (val & 0xff);
6172 data [idx+1] = (byte) (val >> 8);
6174 } else if (array_element_type == TypeManager.int32_type) {
6175 if (!(v is Expression)){
6178 data [idx] = (byte) (val & 0xff);
6179 data [idx+1] = (byte) ((val >> 8) & 0xff);
6180 data [idx+2] = (byte) ((val >> 16) & 0xff);
6181 data [idx+3] = (byte) (val >> 24);
6183 } else if (array_element_type == TypeManager.uint32_type) {
6184 if (!(v is Expression)){
6185 uint val = (uint) v;
6187 data [idx] = (byte) (val & 0xff);
6188 data [idx+1] = (byte) ((val >> 8) & 0xff);
6189 data [idx+2] = (byte) ((val >> 16) & 0xff);
6190 data [idx+3] = (byte) (val >> 24);
6192 } else if (array_element_type == TypeManager.sbyte_type) {
6193 if (!(v is Expression)){
6194 sbyte val = (sbyte) v;
6195 data [idx] = (byte) val;
6197 } else if (array_element_type == TypeManager.byte_type) {
6198 if (!(v is Expression)){
6199 byte val = (byte) v;
6200 data [idx] = (byte) val;
6202 } else if (array_element_type == TypeManager.bool_type) {
6203 if (!(v is Expression)){
6204 bool val = (bool) v;
6205 data [idx] = (byte) (val ? 1 : 0);
6207 } else if (array_element_type == TypeManager.decimal_type){
6208 if (!(v is Expression)){
6209 int [] bits = Decimal.GetBits ((decimal) v);
6212 // FIXME: For some reason, this doesn't work on the MS runtime.
6213 int [] nbits = new int [4];
6214 nbits [0] = bits [3];
6215 nbits [1] = bits [2];
6216 nbits [2] = bits [0];
6217 nbits [3] = bits [1];
6219 for (int j = 0; j < 4; j++){
6220 data [p++] = (byte) (nbits [j] & 0xff);
6221 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6222 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6223 data [p++] = (byte) (nbits [j] >> 24);
6227 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6235 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6237 array_element_type = storey.MutateType (array_element_type);
6238 type = storey.MutateType (type);
6239 if (arguments != null) {
6240 foreach (Argument a in arguments)
6241 a.Expr.MutateHoistedGenericType (storey);
6244 if (array_data != null) {
6245 foreach (Expression e in array_data)
6246 e.MutateHoistedGenericType (storey);
6251 // Emits the initializers for the array
6253 void EmitStaticInitializers (EmitContext ec)
6255 // FIXME: This should go to Resolve !
6256 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6257 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6258 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6259 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6260 if (TypeManager.void_initializearray_array_fieldhandle == null)
6265 // First, the static data
6268 ILGenerator ig = ec.ig;
6270 byte [] data = MakeByteBlob ();
6272 fb = RootContext.MakeStaticData (data);
6274 ig.Emit (OpCodes.Dup);
6275 ig.Emit (OpCodes.Ldtoken, fb);
6276 ig.Emit (OpCodes.Call,
6277 TypeManager.void_initializearray_array_fieldhandle);
6281 // Emits pieces of the array that can not be computed at compile
6282 // time (variables and string locations).
6284 // This always expect the top value on the stack to be the array
6286 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6288 ILGenerator ig = ec.ig;
6289 int dims = bounds.Count;
6290 int [] current_pos = new int [dims];
6292 MethodInfo set = null;
6295 Type [] args = new Type [dims + 1];
6297 for (int j = 0; j < dims; j++)
6298 args [j] = TypeManager.int32_type;
6299 args [dims] = array_element_type;
6301 set = CodeGen.Module.Builder.GetArrayMethod (
6303 CallingConventions.HasThis | CallingConventions.Standard,
6304 TypeManager.void_type, args);
6307 for (int i = 0; i < array_data.Count; i++){
6309 Expression e = (Expression)array_data [i];
6311 // Constant can be initialized via StaticInitializer
6312 if (e != null && !(!emitConstants && e is Constant)) {
6313 Type etype = e.Type;
6315 ig.Emit (OpCodes.Dup);
6317 for (int idx = 0; idx < dims; idx++)
6318 IntConstant.EmitInt (ig, current_pos [idx]);
6321 // If we are dealing with a struct, get the
6322 // address of it, so we can store it.
6324 if ((dims == 1) && etype.IsValueType &&
6325 (!TypeManager.IsBuiltinOrEnum (etype) ||
6326 etype == TypeManager.decimal_type)) {
6331 // Let new know that we are providing
6332 // the address where to store the results
6334 n.DisableTemporaryValueType ();
6337 ig.Emit (OpCodes.Ldelema, etype);
6343 bool is_stobj, has_type_arg;
6344 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6346 ig.Emit (OpCodes.Stobj, etype);
6347 else if (has_type_arg)
6348 ig.Emit (op, etype);
6352 ig.Emit (OpCodes.Call, set);
6359 for (int j = dims - 1; j >= 0; j--){
6361 if (current_pos [j] < (int) bounds [j])
6363 current_pos [j] = 0;
6368 public override void Emit (EmitContext ec)
6370 ILGenerator ig = ec.ig;
6372 if (first_emit != null) {
6373 first_emit.Emit (ec);
6374 first_emit_temp.Store (ec);
6377 foreach (Argument a in arguments)
6380 if (arguments.Count == 1)
6381 ig.Emit (OpCodes.Newarr, array_element_type);
6383 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6386 if (initializers == null)
6389 // Emit static initializer for arrays which have contain more than 4 items and
6390 // the static initializer will initialize at least 25% of array values.
6391 // NOTE: const_initializers_count does not contain default constant values.
6392 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6393 TypeManager.IsPrimitiveType (array_element_type)) {
6394 EmitStaticInitializers (ec);
6396 if (!only_constant_initializers)
6397 EmitDynamicInitializers (ec, false);
6399 EmitDynamicInitializers (ec, true);
6402 if (first_emit_temp != null)
6403 first_emit_temp.Release (ec);
6406 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6408 if (arguments.Count != 1) {
6409 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6410 return base.GetAttributableValue (ec, null, out value);
6413 if (array_data == null) {
6414 Constant c = (Constant)((Argument)arguments [0]).Expr;
6415 if (c.IsDefaultValue) {
6416 value = Array.CreateInstance (array_element_type, 0);
6419 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6420 return base.GetAttributableValue (ec, null, out value);
6423 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6424 object element_value;
6425 for (int i = 0; i < ret.Length; ++i)
6427 Expression e = (Expression)array_data [i];
6429 // Is null when an initializer is optimized (value == predefined value)
6433 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6437 ret.SetValue (element_value, i);
6443 protected override void CloneTo (CloneContext clonectx, Expression t)
6445 ArrayCreation target = (ArrayCreation) t;
6447 if (requested_base_type != null)
6448 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6450 if (arguments != null){
6451 target.arguments = new ArrayList (arguments.Count);
6452 foreach (Argument a in arguments)
6453 target.arguments.Add (a.Clone (clonectx));
6456 if (initializers != null){
6457 target.initializers = new ArrayList (initializers.Count);
6458 foreach (object initializer in initializers)
6459 if (initializer is ArrayList) {
6460 ArrayList this_al = (ArrayList)initializer;
6461 ArrayList al = new ArrayList (this_al.Count);
6462 target.initializers.Add (al);
6463 foreach (Expression e in this_al)
6464 al.Add (e.Clone (clonectx));
6466 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6473 // Represents an implicitly typed array epxression
6475 public class ImplicitlyTypedArrayCreation : ArrayCreation
6477 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6478 : base (null, rank, initializers, loc)
6480 if (RootContext.Version <= LanguageVersion.ISO_2)
6481 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6483 if (rank.Length > 2) {
6484 while (rank [++dimensions] == ',');
6490 public override Expression DoResolve (EmitContext ec)
6495 if (!ResolveInitializers (ec))
6498 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6499 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6500 arguments.Count != dimensions) {
6501 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6506 // At this point we found common base type for all initializer elements
6507 // but we have to be sure that all static initializer elements are of
6510 UnifyInitializerElement (ec);
6512 type = TypeManager.GetConstructedType (array_element_type, rank);
6513 eclass = ExprClass.Value;
6518 // Converts static initializer only
6520 void UnifyInitializerElement (EmitContext ec)
6522 for (int i = 0; i < array_data.Count; ++i) {
6523 Expression e = (Expression)array_data[i];
6525 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6529 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6531 element = element.Resolve (ec);
6532 if (element == null)
6535 if (array_element_type == null) {
6536 array_element_type = element.Type;
6540 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6544 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6545 array_element_type = element.Type;
6549 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6554 public sealed class CompilerGeneratedThis : This
6556 public static This Instance = new CompilerGeneratedThis ();
6558 private CompilerGeneratedThis ()
6559 : base (Location.Null)
6563 public CompilerGeneratedThis (Type type, Location loc)
6569 public override Expression DoResolve (EmitContext ec)
6571 eclass = ExprClass.Variable;
6573 type = ec.ContainerType;
6577 public override HoistedVariable HoistedVariable {
6578 get { return null; }
6583 /// Represents the `this' construct
6586 public class This : VariableReference
6588 class ThisVariable : ILocalVariable
6590 public static readonly ILocalVariable Instance = new ThisVariable ();
6592 public void Emit (EmitContext ec)
6594 ec.ig.Emit (OpCodes.Ldarg_0);
6597 public void EmitAssign (EmitContext ec)
6599 throw new InvalidOperationException ();
6602 public void EmitAddressOf (EmitContext ec)
6604 ec.ig.Emit (OpCodes.Ldarg_0);
6609 VariableInfo variable_info;
6612 public This (Block block, Location loc)
6618 public This (Location loc)
6623 public override VariableInfo VariableInfo {
6624 get { return variable_info; }
6627 public override bool IsFixed {
6628 get { return !TypeManager.IsValueType (type); }
6631 protected override bool IsHoistedEmitRequired (EmitContext ec)
6634 // Handle 'this' differently, it cannot be assigned hence
6635 // when we are not inside anonymous method we can emit direct access
6637 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6640 public override HoistedVariable HoistedVariable {
6641 get { return TopToplevelBlock.HoistedThisVariable; }
6644 public override bool IsRef {
6645 get { return is_struct; }
6648 protected override ILocalVariable Variable {
6649 get { return ThisVariable.Instance; }
6652 // TODO: Move to ToplevelBlock
6653 ToplevelBlock TopToplevelBlock {
6655 ToplevelBlock tl = block.Toplevel;
6656 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6661 public bool ResolveBase (EmitContext ec)
6663 eclass = ExprClass.Variable;
6665 if (ec.TypeContainer.CurrentType != null)
6666 type = ec.TypeContainer.CurrentType;
6668 type = ec.ContainerType;
6670 is_struct = ec.TypeContainer is Struct;
6673 Error (26, "Keyword `this' is not valid in a static property, " +
6674 "static method, or static field initializer");
6678 if (block != null) {
6679 if (block.Toplevel.ThisVariable != null)
6680 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6682 AnonymousExpression am = ec.CurrentAnonymousMethod;
6684 if (is_struct && !am.IsIterator) {
6685 Report.Error (1673, loc, "Anonymous methods inside structs " +
6686 "cannot access instance members of `this'. " +
6687 "Consider copying `this' to a local variable " +
6688 "outside the anonymous method and using the " +
6693 // this is hoisted to very top level block
6695 if (ec.IsVariableCapturingRequired) {
6696 // TODO: it could be optimized
6697 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6698 if (HoistedVariable == null) {
6699 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6709 // Called from Invocation to check if the invocation is correct
6711 public override void CheckMarshalByRefAccess (EmitContext ec)
6713 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6714 !variable_info.IsAssigned (ec)) {
6715 Error (188, "The `this' object cannot be used before all of its " +
6716 "fields are assigned to");
6717 variable_info.SetAssigned (ec);
6721 public override Expression CreateExpressionTree (EmitContext ec)
6723 ArrayList args = new ArrayList (2);
6724 args.Add (new Argument (this));
6725 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6726 return CreateExpressionFactoryCall ("Constant", args);
6729 public override Expression DoResolve (EmitContext ec)
6731 if (!ResolveBase (ec))
6735 if (ec.IsInFieldInitializer) {
6736 Error (27, "Keyword `this' is not available in the current context");
6743 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6745 if (!ResolveBase (ec))
6748 if (variable_info != null)
6749 variable_info.SetAssigned (ec);
6751 if (ec.TypeContainer is Class){
6752 Error (1604, "Cannot assign to 'this' because it is read-only");
6759 public override int GetHashCode()
6761 return block.GetHashCode ();
6764 public override bool Equals (object obj)
6766 This t = obj as This;
6770 return block == t.block;
6773 protected override void CloneTo (CloneContext clonectx, Expression t)
6775 This target = (This) t;
6777 target.block = clonectx.LookupBlock (block);
6780 public void RemoveHoisting ()
6782 TopToplevelBlock.HoistedThisVariable = null;
6787 /// Represents the `__arglist' construct
6789 public class ArglistAccess : Expression
6791 public ArglistAccess (Location loc)
6796 public override Expression CreateExpressionTree (EmitContext ec)
6798 throw new NotSupportedException ("ET");
6801 public override Expression DoResolve (EmitContext ec)
6803 eclass = ExprClass.Variable;
6804 type = TypeManager.runtime_argument_handle_type;
6806 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6808 Error (190, "The __arglist construct is valid only within " +
6809 "a variable argument method");
6816 public override void Emit (EmitContext ec)
6818 ec.ig.Emit (OpCodes.Arglist);
6821 protected override void CloneTo (CloneContext clonectx, Expression target)
6828 /// Represents the `__arglist (....)' construct
6830 public class Arglist : Expression
6832 Argument[] Arguments;
6834 public Arglist (Location loc)
6835 : this (Argument.Empty, loc)
6839 public Arglist (Argument[] args, Location l)
6845 public Type[] ArgumentTypes {
6847 Type[] retval = new Type [Arguments.Length];
6848 for (int i = 0; i < Arguments.Length; i++)
6849 retval [i] = Arguments [i].Type;
6854 public override Expression CreateExpressionTree (EmitContext ec)
6856 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6860 public override Expression DoResolve (EmitContext ec)
6862 eclass = ExprClass.Variable;
6863 type = TypeManager.runtime_argument_handle_type;
6865 foreach (Argument arg in Arguments) {
6866 if (!arg.Resolve (ec, loc))
6873 public override void Emit (EmitContext ec)
6875 foreach (Argument arg in Arguments)
6879 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6881 foreach (Argument arg in Arguments)
6882 arg.Expr.MutateHoistedGenericType (storey);
6885 protected override void CloneTo (CloneContext clonectx, Expression t)
6887 Arglist target = (Arglist) t;
6889 target.Arguments = new Argument [Arguments.Length];
6890 for (int i = 0; i < Arguments.Length; i++)
6891 target.Arguments [i] = Arguments [i].Clone (clonectx);
6896 /// Implements the typeof operator
6898 public class TypeOf : Expression {
6899 Expression QueriedType;
6900 protected Type typearg;
6902 public TypeOf (Expression queried_type, Location l)
6904 QueriedType = queried_type;
6908 public override Expression CreateExpressionTree (EmitContext ec)
6910 ArrayList args = new ArrayList (2);
6911 args.Add (new Argument (this));
6912 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6913 return CreateExpressionFactoryCall ("Constant", args);
6916 public override Expression DoResolve (EmitContext ec)
6918 if (eclass != ExprClass.Invalid)
6921 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6925 typearg = texpr.Type;
6927 if (typearg == TypeManager.void_type) {
6928 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6932 if (typearg.IsPointer && !ec.InUnsafe){
6937 type = TypeManager.type_type;
6939 return DoResolveBase ();
6942 protected Expression DoResolveBase ()
6944 if (TypeManager.system_type_get_type_from_handle == null) {
6945 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6946 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6949 // Even though what is returned is a type object, it's treated as a value by the compiler.
6950 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6951 eclass = ExprClass.Value;
6955 public override void Emit (EmitContext ec)
6957 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6958 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6961 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6963 if (TypeManager.ContainsGenericParameters (typearg) &&
6964 !TypeManager.IsGenericTypeDefinition (typearg)) {
6965 Report.SymbolRelatedToPreviousError (typearg);
6966 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6967 TypeManager.CSharpName (typearg));
6972 if (value_type == TypeManager.object_type) {
6973 value = (object)typearg;
6980 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6982 typearg = storey.MutateType (typearg);
6985 public Type TypeArgument {
6991 protected override void CloneTo (CloneContext clonectx, Expression t)
6993 TypeOf target = (TypeOf) t;
6994 if (QueriedType != null)
6995 target.QueriedType = QueriedType.Clone (clonectx);
7000 /// Implements the `typeof (void)' operator
7002 public class TypeOfVoid : TypeOf {
7003 public TypeOfVoid (Location l) : base (null, l)
7008 public override Expression DoResolve (EmitContext ec)
7010 type = TypeManager.type_type;
7011 typearg = TypeManager.void_type;
7013 return DoResolveBase ();
7017 class TypeOfMethodInfo : TypeOfMethod
7019 public TypeOfMethodInfo (MethodBase method, Location loc)
7020 : base (method, loc)
7024 public override Expression DoResolve (EmitContext ec)
7026 type = typeof (MethodInfo);
7027 return base.DoResolve (ec);
7030 public override void Emit (EmitContext ec)
7032 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7034 ec.ig.Emit (OpCodes.Castclass, type);
7038 class TypeOfConstructorInfo : TypeOfMethod
7040 public TypeOfConstructorInfo (MethodBase method, Location loc)
7041 : base (method, loc)
7045 public override Expression DoResolve (EmitContext ec)
7047 type = typeof (ConstructorInfo);
7048 return base.DoResolve (ec);
7051 public override void Emit (EmitContext ec)
7053 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7055 ec.ig.Emit (OpCodes.Castclass, type);
7059 abstract class TypeOfMethod : Expression
7061 protected readonly MethodBase method;
7063 protected TypeOfMethod (MethodBase method, Location loc)
7065 this.method = method;
7069 public override Expression CreateExpressionTree (EmitContext ec)
7071 ArrayList args = new ArrayList (2);
7072 args.Add (new Argument (this));
7073 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7074 return CreateExpressionFactoryCall ("Constant", args);
7077 public override Expression DoResolve (EmitContext ec)
7079 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7080 MethodInfo mi = is_generic ?
7081 TypeManager.methodbase_get_type_from_handle_generic :
7082 TypeManager.methodbase_get_type_from_handle;
7085 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7086 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7088 if (t == null || handle_type == null)
7091 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7093 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7094 new Type[] { handle_type } );
7097 TypeManager.methodbase_get_type_from_handle_generic = mi;
7099 TypeManager.methodbase_get_type_from_handle = mi;
7102 eclass = ExprClass.Value;
7106 public override void Emit (EmitContext ec)
7108 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7111 mi = TypeManager.methodbase_get_type_from_handle_generic;
7112 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7114 mi = TypeManager.methodbase_get_type_from_handle;
7117 ec.ig.Emit (OpCodes.Call, mi);
7121 internal class TypeOfField : Expression
7123 readonly FieldInfo field;
7125 public TypeOfField (FieldInfo field, Location loc)
7131 public override Expression CreateExpressionTree (EmitContext ec)
7133 throw new NotSupportedException ("ET");
7136 public override Expression DoResolve (EmitContext ec)
7138 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7139 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7140 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7142 if (t != null && handle_type != null)
7143 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7144 "GetFieldFromHandle", loc, handle_type);
7147 type = typeof (FieldInfo);
7148 eclass = ExprClass.Value;
7152 public override void Emit (EmitContext ec)
7154 ec.ig.Emit (OpCodes.Ldtoken, field);
7155 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7160 /// Implements the sizeof expression
7162 public class SizeOf : Expression {
7163 readonly Expression QueriedType;
7166 public SizeOf (Expression queried_type, Location l)
7168 this.QueriedType = queried_type;
7172 public override Expression CreateExpressionTree (EmitContext ec)
7174 Error_PointerInsideExpressionTree ();
7178 public override Expression DoResolve (EmitContext ec)
7180 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7184 type_queried = texpr.Type;
7185 if (TypeManager.IsEnumType (type_queried))
7186 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7188 if (type_queried == TypeManager.void_type) {
7189 Expression.Error_VoidInvalidInTheContext (loc);
7193 int size_of = GetTypeSize (type_queried);
7195 return new IntConstant (size_of, loc);
7198 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7203 Report.Error (233, loc,
7204 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7205 TypeManager.CSharpName (type_queried));
7208 type = TypeManager.int32_type;
7209 eclass = ExprClass.Value;
7213 public override void Emit (EmitContext ec)
7215 int size = GetTypeSize (type_queried);
7218 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7220 IntConstant.EmitInt (ec.ig, size);
7223 protected override void CloneTo (CloneContext clonectx, Expression t)
7229 /// Implements the qualified-alias-member (::) expression.
7231 public class QualifiedAliasMember : MemberAccess
7233 readonly string alias;
7234 public static readonly string GlobalAlias = "global";
7236 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7237 : base (null, identifier, targs, l)
7242 public QualifiedAliasMember (string alias, string identifier, Location l)
7243 : base (null, identifier, l)
7248 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7250 if (alias == GlobalAlias) {
7251 expr = RootNamespace.Global;
7252 return base.ResolveAsTypeStep (ec, silent);
7255 int errors = Report.Errors;
7256 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7258 if (errors == Report.Errors)
7259 Report.Error (432, loc, "Alias `{0}' not found", alias);
7263 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7267 if (expr.eclass == ExprClass.Type) {
7269 Report.Error (431, loc,
7270 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7278 public override Expression DoResolve (EmitContext ec)
7280 return ResolveAsTypeStep (ec, false);
7283 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7285 Report.Error (687, loc,
7286 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7287 GetSignatureForError ());
7290 public override string GetSignatureForError ()
7293 if (targs != null) {
7294 name = TypeManager.RemoveGenericArity (Name) + "<" +
7295 targs.GetSignatureForError () + ">";
7298 return alias + "::" + name;
7301 protected override void CloneTo (CloneContext clonectx, Expression t)
7308 /// Implements the member access expression
7310 public class MemberAccess : ATypeNameExpression {
7311 protected Expression expr;
7313 public MemberAccess (Expression expr, string id)
7314 : base (id, expr.Location)
7319 public MemberAccess (Expression expr, string identifier, Location loc)
7320 : base (identifier, loc)
7325 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7326 : base (identifier, args, loc)
7331 // TODO: this method has very poor performace for Enum fields and
7332 // probably for other constants as well
7333 Expression DoResolve (EmitContext ec, Expression right_side)
7336 throw new Exception ();
7339 // Resolve the expression with flow analysis turned off, we'll do the definite
7340 // assignment checks later. This is because we don't know yet what the expression
7341 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7342 // definite assignment check on the actual field and not on the whole struct.
7345 SimpleName original = expr as SimpleName;
7346 Expression expr_resolved = expr.Resolve (ec,
7347 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7348 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7350 if (expr_resolved == null)
7353 string LookupIdentifier = MemberName.MakeName (Name, targs);
7355 if (expr_resolved is Namespace) {
7356 Namespace ns = (Namespace) expr_resolved;
7357 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7359 if ((retval != null) && (targs != null))
7360 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7364 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7368 Type expr_type = expr_resolved.Type;
7369 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7370 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7371 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7375 Constant c = expr_resolved as Constant;
7376 if (c != null && c.GetValue () == null) {
7377 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7378 "System.NullReferenceException");
7381 if (targs != null) {
7382 if (!targs.Resolve (ec))
7386 Expression member_lookup;
7387 member_lookup = MemberLookup (
7388 ec.ContainerType, expr_type, expr_type, Name, loc);
7390 if ((member_lookup == null) && (targs != null)) {
7391 member_lookup = MemberLookup (
7392 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7395 if (member_lookup == null) {
7396 ExprClass expr_eclass = expr_resolved.eclass;
7399 // Extension methods are not allowed on all expression types
7401 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7402 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7403 expr_eclass == ExprClass.EventAccess) {
7404 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7405 if (ex_method_lookup != null) {
7406 ex_method_lookup.ExtensionExpression = expr_resolved;
7408 if (targs != null) {
7409 ex_method_lookup.SetTypeArguments (targs);
7412 return ex_method_lookup.DoResolve (ec);
7416 expr = expr_resolved;
7417 Error_MemberLookupFailed (
7418 ec.ContainerType, expr_type, expr_type, Name, null,
7419 AllMemberTypes, AllBindingFlags);
7423 TypeExpr texpr = member_lookup as TypeExpr;
7424 if (texpr != null) {
7425 if (!(expr_resolved is TypeExpr) &&
7426 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7427 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7428 Name, member_lookup.GetSignatureForError ());
7432 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7433 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7434 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7439 ConstructedType ct = expr_resolved as ConstructedType;
7442 // When looking up a nested type in a generic instance
7443 // via reflection, we always get a generic type definition
7444 // and not a generic instance - so we have to do this here.
7446 // See gtest-172-lib.cs and gtest-172.cs for an example.
7448 ct = new ConstructedType (
7449 member_lookup.Type, ct.TypeArguments, loc);
7451 return ct.ResolveAsTypeStep (ec, false);
7454 return member_lookup;
7457 MemberExpr me = (MemberExpr) member_lookup;
7458 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7462 if (targs != null) {
7463 me.SetTypeArguments (targs);
7466 if (original != null && !TypeManager.IsValueType (expr_type)) {
7467 if (me.IsInstance) {
7468 LocalVariableReference var = expr_resolved as LocalVariableReference;
7469 if (var != null && !var.VerifyAssigned (ec))
7474 // The following DoResolve/DoResolveLValue will do the definite assignment
7477 if (right_side != null)
7478 return me.DoResolveLValue (ec, right_side);
7480 return me.DoResolve (ec);
7483 public override Expression DoResolve (EmitContext ec)
7485 return DoResolve (ec, null);
7488 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7490 return DoResolve (ec, right_side);
7493 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7495 return ResolveNamespaceOrType (ec, silent);
7498 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7500 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7502 if (new_expr == null)
7505 string LookupIdentifier = MemberName.MakeName (Name, targs);
7507 if (new_expr is Namespace) {
7508 Namespace ns = (Namespace) new_expr;
7509 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7511 if ((retval != null) && (targs != null))
7512 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7514 if (!silent && retval == null)
7515 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7519 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7520 if (tnew_expr == null)
7523 Type expr_type = tnew_expr.Type;
7525 if (expr_type.IsPointer){
7526 Error (23, "The `.' operator can not be applied to pointer operands (" +
7527 TypeManager.CSharpName (expr_type) + ")");
7531 Expression member_lookup = MemberLookup (
7532 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7533 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7534 if (member_lookup == null) {
7538 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7542 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7547 TypeArguments the_args = targs;
7548 Type declaring_type = texpr.Type.DeclaringType;
7549 if (TypeManager.HasGenericArguments (declaring_type)) {
7550 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7551 expr_type = expr_type.BaseType;
7554 TypeArguments new_args = new TypeArguments (loc);
7555 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7556 new_args.Add (new TypeExpression (decl, loc));
7559 new_args.Add (targs);
7561 the_args = new_args;
7564 if (the_args != null) {
7565 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7566 return ctype.ResolveAsTypeStep (rc, false);
7573 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7575 Expression member_lookup = MemberLookup (
7576 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7577 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7579 if (member_lookup != null) {
7580 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7581 if (expr_type == null)
7584 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7588 member_lookup = MemberLookup (
7589 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7590 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7592 if (member_lookup == null) {
7593 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7594 Name, expr_type.GetSignatureForError ());
7596 // TODO: Report.SymbolRelatedToPreviousError
7597 member_lookup.Error_UnexpectedKind (null, "type", loc);
7601 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7603 if (RootContext.Version > LanguageVersion.ISO_2 &&
7604 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7605 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7606 "extension method `{1}' of type `{0}' could be found " +
7607 "(are you missing a using directive or an assembly reference?)",
7608 TypeManager.CSharpName (type), name);
7612 base.Error_TypeDoesNotContainDefinition (type, name);
7615 public override string GetSignatureForError ()
7617 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7620 protected override void CloneTo (CloneContext clonectx, Expression t)
7622 MemberAccess target = (MemberAccess) t;
7624 target.expr = expr.Clone (clonectx);
7629 /// Implements checked expressions
7631 public class CheckedExpr : Expression {
7633 public Expression Expr;
7635 public CheckedExpr (Expression e, Location l)
7641 public override Expression CreateExpressionTree (EmitContext ec)
7643 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7644 return Expr.CreateExpressionTree (ec);
7647 public override Expression DoResolve (EmitContext ec)
7649 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7650 Expr = Expr.Resolve (ec);
7655 if (Expr is Constant || Expr is MethodGroupExpr)
7658 eclass = Expr.eclass;
7663 public override void Emit (EmitContext ec)
7665 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7669 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7671 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7672 Expr.EmitBranchable (ec, target, on_true);
7675 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7677 Expr.MutateHoistedGenericType (storey);
7680 protected override void CloneTo (CloneContext clonectx, Expression t)
7682 CheckedExpr target = (CheckedExpr) t;
7684 target.Expr = Expr.Clone (clonectx);
7689 /// Implements the unchecked expression
7691 public class UnCheckedExpr : Expression {
7693 public Expression Expr;
7695 public UnCheckedExpr (Expression e, Location l)
7701 public override Expression CreateExpressionTree (EmitContext ec)
7703 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7704 return Expr.CreateExpressionTree (ec);
7707 public override Expression DoResolve (EmitContext ec)
7709 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7710 Expr = Expr.Resolve (ec);
7715 if (Expr is Constant || Expr is MethodGroupExpr)
7718 eclass = Expr.eclass;
7723 public override void Emit (EmitContext ec)
7725 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7729 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7731 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7732 Expr.EmitBranchable (ec, target, on_true);
7735 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7737 Expr.MutateHoistedGenericType (storey);
7740 protected override void CloneTo (CloneContext clonectx, Expression t)
7742 UnCheckedExpr target = (UnCheckedExpr) t;
7744 target.Expr = Expr.Clone (clonectx);
7749 /// An Element Access expression.
7751 /// During semantic analysis these are transformed into
7752 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7754 public class ElementAccess : Expression {
7755 public ArrayList Arguments;
7756 public Expression Expr;
7758 public ElementAccess (Expression e, ArrayList e_list)
7766 Arguments = new ArrayList (e_list.Count);
7767 foreach (Expression tmp in e_list)
7768 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7771 bool CommonResolve (EmitContext ec)
7773 Expr = Expr.Resolve (ec);
7775 if (Arguments == null)
7778 foreach (Argument a in Arguments){
7779 if (!a.Resolve (ec, loc))
7783 return Expr != null;
7786 public override Expression CreateExpressionTree (EmitContext ec)
7788 ArrayList args = new ArrayList (Arguments.Count + 1);
7789 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7790 foreach (Argument a in Arguments)
7791 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7793 return CreateExpressionFactoryCall ("ArrayIndex", args);
7796 Expression MakePointerAccess (EmitContext ec, Type t)
7798 if (t == TypeManager.void_ptr_type){
7799 Error (242, "The array index operation is not valid on void pointers");
7802 if (Arguments.Count != 1){
7803 Error (196, "A pointer must be indexed by only one value");
7807 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7810 return new Indirection (p, loc).Resolve (ec);
7813 public override Expression DoResolve (EmitContext ec)
7815 if (!CommonResolve (ec))
7819 // We perform some simple tests, and then to "split" the emit and store
7820 // code we create an instance of a different class, and return that.
7822 // I am experimenting with this pattern.
7826 if (t == TypeManager.array_type){
7827 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7832 return (new ArrayAccess (this, loc)).Resolve (ec);
7834 return MakePointerAccess (ec, t);
7836 FieldExpr fe = Expr as FieldExpr;
7838 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7840 return MakePointerAccess (ec, ff.ElementType);
7843 return (new IndexerAccess (this, loc)).Resolve (ec);
7846 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7848 if (!CommonResolve (ec))
7853 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7856 return MakePointerAccess (ec, type);
7858 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7859 Error_CannotModifyIntermediateExpressionValue (ec);
7861 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7864 public override void Emit (EmitContext ec)
7866 throw new Exception ("Should never be reached");
7869 public override string GetSignatureForError ()
7871 return Expr.GetSignatureForError ();
7874 protected override void CloneTo (CloneContext clonectx, Expression t)
7876 ElementAccess target = (ElementAccess) t;
7878 target.Expr = Expr.Clone (clonectx);
7879 target.Arguments = new ArrayList (Arguments.Count);
7880 foreach (Argument a in Arguments)
7881 target.Arguments.Add (a.Clone (clonectx));
7886 /// Implements array access
7888 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7890 // Points to our "data" repository
7894 LocalTemporary temp;
7898 public ArrayAccess (ElementAccess ea_data, Location l)
7904 public override Expression CreateExpressionTree (EmitContext ec)
7906 return ea.CreateExpressionTree (ec);
7909 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7911 return DoResolve (ec);
7914 public override Expression DoResolve (EmitContext ec)
7917 ExprClass eclass = ea.Expr.eclass;
7919 // As long as the type is valid
7920 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7921 eclass == ExprClass.Value)) {
7922 ea.Expr.Error_UnexpectedKind ("variable or value");
7927 if (eclass != ExprClass.Invalid)
7930 Type t = ea.Expr.Type;
7931 int rank = ea.Arguments.Count;
7932 if (t.GetArrayRank () != rank) {
7933 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7934 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7938 type = TypeManager.GetElementType (t);
7939 if (type.IsPointer && !ec.InUnsafe) {
7940 UnsafeError (ea.Location);
7944 foreach (Argument a in ea.Arguments) {
7945 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7948 eclass = ExprClass.Variable;
7954 /// Emits the right opcode to load an object of Type `t'
7955 /// from an array of T
7957 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7960 MethodInfo get = FetchGetMethod ();
7961 ig.Emit (OpCodes.Call, get);
7965 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7966 ig.Emit (OpCodes.Ldelem_U1);
7967 else if (type == TypeManager.sbyte_type)
7968 ig.Emit (OpCodes.Ldelem_I1);
7969 else if (type == TypeManager.short_type)
7970 ig.Emit (OpCodes.Ldelem_I2);
7971 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7972 ig.Emit (OpCodes.Ldelem_U2);
7973 else if (type == TypeManager.int32_type)
7974 ig.Emit (OpCodes.Ldelem_I4);
7975 else if (type == TypeManager.uint32_type)
7976 ig.Emit (OpCodes.Ldelem_U4);
7977 else if (type == TypeManager.uint64_type)
7978 ig.Emit (OpCodes.Ldelem_I8);
7979 else if (type == TypeManager.int64_type)
7980 ig.Emit (OpCodes.Ldelem_I8);
7981 else if (type == TypeManager.float_type)
7982 ig.Emit (OpCodes.Ldelem_R4);
7983 else if (type == TypeManager.double_type)
7984 ig.Emit (OpCodes.Ldelem_R8);
7985 else if (type == TypeManager.intptr_type)
7986 ig.Emit (OpCodes.Ldelem_I);
7987 else if (TypeManager.IsEnumType (type)){
7988 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7989 } else if (type.IsValueType){
7990 ig.Emit (OpCodes.Ldelema, type);
7991 ig.Emit (OpCodes.Ldobj, type);
7993 } else if (type.IsGenericParameter) {
7994 ig.Emit (OpCodes.Ldelem, type);
7996 } else if (type.IsPointer)
7997 ig.Emit (OpCodes.Ldelem_I);
7999 ig.Emit (OpCodes.Ldelem_Ref);
8002 protected override void Error_NegativeArrayIndex (Location loc)
8004 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8008 /// Returns the right opcode to store an object of Type `t'
8009 /// from an array of T.
8011 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8013 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8014 has_type_arg = false; is_stobj = false;
8015 t = TypeManager.TypeToCoreType (t);
8016 if (TypeManager.IsEnumType (t))
8017 t = TypeManager.GetEnumUnderlyingType (t);
8018 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8019 t == TypeManager.bool_type)
8020 return OpCodes.Stelem_I1;
8021 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8022 t == TypeManager.char_type)
8023 return OpCodes.Stelem_I2;
8024 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8025 return OpCodes.Stelem_I4;
8026 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8027 return OpCodes.Stelem_I8;
8028 else if (t == TypeManager.float_type)
8029 return OpCodes.Stelem_R4;
8030 else if (t == TypeManager.double_type)
8031 return OpCodes.Stelem_R8;
8032 else if (t == TypeManager.intptr_type) {
8033 has_type_arg = true;
8035 return OpCodes.Stobj;
8036 } else if (t.IsValueType) {
8037 has_type_arg = true;
8039 return OpCodes.Stobj;
8041 } else if (t.IsGenericParameter) {
8042 has_type_arg = true;
8043 return OpCodes.Stelem;
8046 } else if (t.IsPointer)
8047 return OpCodes.Stelem_I;
8049 return OpCodes.Stelem_Ref;
8052 MethodInfo FetchGetMethod ()
8054 ModuleBuilder mb = CodeGen.Module.Builder;
8055 int arg_count = ea.Arguments.Count;
8056 Type [] args = new Type [arg_count];
8059 for (int i = 0; i < arg_count; i++){
8060 //args [i++] = a.Type;
8061 args [i] = TypeManager.int32_type;
8064 get = mb.GetArrayMethod (
8065 ea.Expr.Type, "Get",
8066 CallingConventions.HasThis |
8067 CallingConventions.Standard,
8073 MethodInfo FetchAddressMethod ()
8075 ModuleBuilder mb = CodeGen.Module.Builder;
8076 int arg_count = ea.Arguments.Count;
8077 Type [] args = new Type [arg_count];
8081 ret_type = TypeManager.GetReferenceType (type);
8083 for (int i = 0; i < arg_count; i++){
8084 //args [i++] = a.Type;
8085 args [i] = TypeManager.int32_type;
8088 address = mb.GetArrayMethod (
8089 ea.Expr.Type, "Address",
8090 CallingConventions.HasThis |
8091 CallingConventions.Standard,
8098 // Load the array arguments into the stack.
8100 void LoadArrayAndArguments (EmitContext ec)
8104 for (int i = 0; i < ea.Arguments.Count; ++i) {
8105 ((Argument)ea.Arguments [i]).Emit (ec);
8109 public void Emit (EmitContext ec, bool leave_copy)
8111 int rank = ea.Expr.Type.GetArrayRank ();
8112 ILGenerator ig = ec.ig;
8115 LoadFromPtr (ig, this.type);
8117 LoadArrayAndArguments (ec);
8118 EmitLoadOpcode (ig, type, rank);
8122 ig.Emit (OpCodes.Dup);
8123 temp = new LocalTemporary (this.type);
8128 public override void Emit (EmitContext ec)
8133 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8135 int rank = ea.Expr.Type.GetArrayRank ();
8136 ILGenerator ig = ec.ig;
8137 Type t = source.Type;
8138 prepared = prepare_for_load;
8141 AddressOf (ec, AddressOp.LoadStore);
8142 ec.ig.Emit (OpCodes.Dup);
8144 LoadArrayAndArguments (ec);
8148 bool is_stobj, has_type_arg;
8149 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8153 // The stobj opcode used by value types will need
8154 // an address on the stack, not really an array/array
8158 ig.Emit (OpCodes.Ldelema, t);
8163 ec.ig.Emit (OpCodes.Dup);
8164 temp = new LocalTemporary (this.type);
8169 StoreFromPtr (ig, t);
8171 ig.Emit (OpCodes.Stobj, t);
8172 else if (has_type_arg)
8179 ec.ig.Emit (OpCodes.Dup);
8180 temp = new LocalTemporary (this.type);
8185 StoreFromPtr (ig, t);
8187 int arg_count = ea.Arguments.Count;
8188 Type [] args = new Type [arg_count + 1];
8189 for (int i = 0; i < arg_count; i++) {
8190 //args [i++] = a.Type;
8191 args [i] = TypeManager.int32_type;
8193 args [arg_count] = type;
8195 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8196 ea.Expr.Type, "Set",
8197 CallingConventions.HasThis |
8198 CallingConventions.Standard,
8199 TypeManager.void_type, args);
8201 ig.Emit (OpCodes.Call, set);
8211 public void AddressOf (EmitContext ec, AddressOp mode)
8213 int rank = ea.Expr.Type.GetArrayRank ();
8214 ILGenerator ig = ec.ig;
8216 LoadArrayAndArguments (ec);
8219 ig.Emit (OpCodes.Ldelema, type);
8221 MethodInfo address = FetchAddressMethod ();
8222 ig.Emit (OpCodes.Call, address);
8226 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8228 type = storey.MutateType (type);
8233 /// Expressions that represent an indexer call.
8235 public class IndexerAccess : Expression, IAssignMethod
8237 class IndexerMethodGroupExpr : MethodGroupExpr
8239 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8242 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8245 public override string Name {
8251 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
8254 // Here is the trick, decrease number of arguments by 1 when only
8255 // available property method is setter. This makes overload resolution
8256 // work correctly for indexers.
8259 if (method.Name [0] == 'g')
8260 return parameters.Count;
8262 return parameters.Count - 1;
8268 // Contains either property getter or setter
8269 public ArrayList Methods;
8270 public ArrayList Properties;
8276 void Append (Type caller_type, MemberInfo [] mi)
8281 foreach (PropertyInfo property in mi) {
8282 MethodInfo accessor = property.GetGetMethod (true);
8283 if (accessor == null)
8284 accessor = property.GetSetMethod (true);
8286 if (Methods == null) {
8287 Methods = new ArrayList ();
8288 Properties = new ArrayList ();
8291 Methods.Add (accessor);
8292 Properties.Add (property);
8296 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8298 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8300 return TypeManager.MemberLookup (
8301 caller_type, caller_type, lookup_type, MemberTypes.Property,
8302 BindingFlags.Public | BindingFlags.Instance |
8303 BindingFlags.DeclaredOnly, p_name, null);
8306 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8308 Indexers ix = new Indexers ();
8311 if (lookup_type.IsGenericParameter) {
8312 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8316 if (gc.HasClassConstraint)
8317 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8319 Type[] ifaces = gc.InterfaceConstraints;
8320 foreach (Type itype in ifaces)
8321 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8327 Type copy = lookup_type;
8328 while (copy != TypeManager.object_type && copy != null){
8329 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8330 copy = copy.BaseType;
8333 if (lookup_type.IsInterface) {
8334 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8335 if (ifaces != null) {
8336 foreach (Type itype in ifaces)
8337 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8352 // Points to our "data" repository
8354 MethodInfo get, set;
8355 bool is_base_indexer;
8357 LocalTemporary temp;
8358 LocalTemporary prepared_value;
8359 Expression set_expr;
8361 protected Type indexer_type;
8362 protected Type current_type;
8363 protected Expression instance_expr;
8364 protected ArrayList arguments;
8366 public IndexerAccess (ElementAccess ea, Location loc)
8367 : this (ea.Expr, false, loc)
8369 this.arguments = ea.Arguments;
8372 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8375 this.instance_expr = instance_expr;
8376 this.is_base_indexer = is_base_indexer;
8377 this.eclass = ExprClass.Value;
8381 static string GetAccessorName (AccessorType at)
8383 if (at == AccessorType.Set)
8386 if (at == AccessorType.Get)
8389 throw new NotImplementedException (at.ToString ());
8392 public override Expression CreateExpressionTree (EmitContext ec)
8394 ArrayList args = new ArrayList (arguments.Count + 2);
8395 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8396 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8397 foreach (Argument a in arguments)
8398 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8400 return CreateExpressionFactoryCall ("Call", args);
8403 protected virtual bool CommonResolve (EmitContext ec)
8405 indexer_type = instance_expr.Type;
8406 current_type = ec.ContainerType;
8411 public override Expression DoResolve (EmitContext ec)
8413 return ResolveAccessor (ec, AccessorType.Get);
8416 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8418 if (right_side == EmptyExpression.OutAccess) {
8419 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8420 GetSignatureForError ());
8424 // if the indexer returns a value type, and we try to set a field in it
8425 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8426 Error_CannotModifyIntermediateExpressionValue (ec);
8429 Expression e = ResolveAccessor (ec, AccessorType.Set);
8433 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8437 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8439 if (!CommonResolve (ec))
8442 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8443 if (ilist.Methods == null) {
8444 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8445 TypeManager.CSharpName (indexer_type));
8449 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8450 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8454 MethodInfo mi = (MethodInfo) mg;
8455 PropertyInfo pi = null;
8456 for (int i = 0; i < ilist.Methods.Count; ++i) {
8457 if (ilist.Methods [i] == mi) {
8458 pi = (PropertyInfo) ilist.Properties [i];
8463 type = TypeManager.TypeToCoreType (pi.PropertyType);
8464 if (type.IsPointer && !ec.InUnsafe)
8467 MethodInfo accessor;
8468 if (accessorType == AccessorType.Get) {
8469 accessor = get = pi.GetGetMethod (true);
8471 accessor = set = pi.GetSetMethod (true);
8472 if (accessor == null && pi.GetGetMethod (true) != null) {
8473 Report.SymbolRelatedToPreviousError (pi);
8474 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8475 TypeManager.GetFullNameSignature (pi));
8480 if (accessor == null) {
8481 Report.SymbolRelatedToPreviousError (pi);
8482 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8483 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8488 // Only base will allow this invocation to happen.
8490 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8491 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8494 bool must_do_cs1540_check;
8495 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8497 set = pi.GetSetMethod (true);
8499 get = pi.GetGetMethod (true);
8501 if (set != null && get != null &&
8502 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8503 Report.SymbolRelatedToPreviousError (accessor);
8504 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8505 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8507 Report.SymbolRelatedToPreviousError (pi);
8508 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8512 instance_expr.CheckMarshalByRefAccess (ec);
8513 eclass = ExprClass.IndexerAccess;
8517 public void Emit (EmitContext ec, bool leave_copy)
8520 prepared_value.Emit (ec);
8522 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8523 arguments, loc, false, false);
8527 ec.ig.Emit (OpCodes.Dup);
8528 temp = new LocalTemporary (Type);
8534 // source is ignored, because we already have a copy of it from the
8535 // LValue resolution and we have already constructed a pre-cached
8536 // version of the arguments (ea.set_arguments);
8538 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8540 prepared = prepare_for_load;
8541 Expression value = set_expr;
8544 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8545 arguments, loc, true, false);
8547 prepared_value = new LocalTemporary (type);
8548 prepared_value.Store (ec);
8550 prepared_value.Release (ec);
8553 ec.ig.Emit (OpCodes.Dup);
8554 temp = new LocalTemporary (Type);
8557 } else if (leave_copy) {
8558 temp = new LocalTemporary (Type);
8564 arguments.Add (new Argument (value, Argument.AType.Expression));
8565 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8573 public override void Emit (EmitContext ec)
8578 public override string GetSignatureForError ()
8580 return TypeManager.CSharpSignature (get != null ? get : set, false);
8583 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8586 get = storey.MutateGenericMethod (get);
8588 set = storey.MutateGenericMethod (set);
8590 instance_expr.MutateHoistedGenericType (storey);
8591 foreach (Argument a in arguments)
8592 a.Expr.MutateHoistedGenericType (storey);
8594 type = storey.MutateType (type);
8597 protected override void CloneTo (CloneContext clonectx, Expression t)
8599 IndexerAccess target = (IndexerAccess) t;
8601 if (arguments != null){
8602 target.arguments = new ArrayList ();
8603 foreach (Argument a in arguments)
8604 target.arguments.Add (a.Clone (clonectx));
8606 if (instance_expr != null)
8607 target.instance_expr = instance_expr.Clone (clonectx);
8612 /// The base operator for method names
8614 public class BaseAccess : Expression {
8615 public readonly string Identifier;
8618 public BaseAccess (string member, Location l)
8620 this.Identifier = member;
8624 public BaseAccess (string member, TypeArguments args, Location l)
8630 public override Expression CreateExpressionTree (EmitContext ec)
8632 throw new NotSupportedException ("ET");
8635 public override Expression DoResolve (EmitContext ec)
8637 Expression c = CommonResolve (ec);
8643 // MethodGroups use this opportunity to flag an error on lacking ()
8645 if (!(c is MethodGroupExpr))
8646 return c.Resolve (ec);
8650 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8652 Expression c = CommonResolve (ec);
8658 // MethodGroups use this opportunity to flag an error on lacking ()
8660 if (! (c is MethodGroupExpr))
8661 return c.DoResolveLValue (ec, right_side);
8666 Expression CommonResolve (EmitContext ec)
8668 Expression member_lookup;
8669 Type current_type = ec.ContainerType;
8670 Type base_type = current_type.BaseType;
8673 Error (1511, "Keyword `base' is not available in a static method");
8677 if (ec.IsInFieldInitializer){
8678 Error (1512, "Keyword `base' is not available in the current context");
8682 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8683 AllMemberTypes, AllBindingFlags, loc);
8684 if (member_lookup == null) {
8685 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8686 null, AllMemberTypes, AllBindingFlags);
8693 left = new TypeExpression (base_type, loc);
8695 left = ec.GetThis (loc);
8697 MemberExpr me = (MemberExpr) member_lookup;
8698 me = me.ResolveMemberAccess (ec, left, loc, null);
8705 me.SetTypeArguments (args);
8711 public override void Emit (EmitContext ec)
8713 throw new Exception ("Should never be called");
8716 protected override void CloneTo (CloneContext clonectx, Expression t)
8718 BaseAccess target = (BaseAccess) t;
8721 target.args = args.Clone ();
8726 /// The base indexer operator
8728 public class BaseIndexerAccess : IndexerAccess {
8729 public BaseIndexerAccess (ArrayList args, Location loc)
8730 : base (null, true, loc)
8732 arguments = new ArrayList ();
8733 foreach (Expression tmp in args)
8734 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8737 protected override bool CommonResolve (EmitContext ec)
8739 instance_expr = ec.GetThis (loc);
8741 current_type = ec.ContainerType.BaseType;
8742 indexer_type = current_type;
8744 foreach (Argument a in arguments){
8745 if (!a.Resolve (ec, loc))
8752 public override Expression CreateExpressionTree (EmitContext ec)
8754 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8755 return base.CreateExpressionTree (ec);
8760 /// This class exists solely to pass the Type around and to be a dummy
8761 /// that can be passed to the conversion functions (this is used by
8762 /// foreach implementation to typecast the object return value from
8763 /// get_Current into the proper type. All code has been generated and
8764 /// we only care about the side effect conversions to be performed
8766 /// This is also now used as a placeholder where a no-action expression
8767 /// is needed (the `New' class).
8769 public class EmptyExpression : Expression {
8770 public static readonly EmptyExpression Null = new EmptyExpression ();
8772 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8773 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8774 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8775 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8777 static EmptyExpression temp = new EmptyExpression ();
8778 public static EmptyExpression Grab ()
8780 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8785 public static void Release (EmptyExpression e)
8790 // TODO: should be protected
8791 public EmptyExpression ()
8793 type = TypeManager.object_type;
8794 eclass = ExprClass.Value;
8795 loc = Location.Null;
8798 public EmptyExpression (Type t)
8801 eclass = ExprClass.Value;
8802 loc = Location.Null;
8805 public override Expression CreateExpressionTree (EmitContext ec)
8807 throw new NotSupportedException ("ET");
8810 public override Expression DoResolve (EmitContext ec)
8815 public override void Emit (EmitContext ec)
8817 // nothing, as we only exist to not do anything.
8820 public override void EmitSideEffect (EmitContext ec)
8825 // This is just because we might want to reuse this bad boy
8826 // instead of creating gazillions of EmptyExpressions.
8827 // (CanImplicitConversion uses it)
8829 public void SetType (Type t)
8836 // Empty statement expression
8838 public sealed class EmptyExpressionStatement : ExpressionStatement
8840 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8842 private EmptyExpressionStatement ()
8844 type = TypeManager.object_type;
8845 eclass = ExprClass.Value;
8846 loc = Location.Null;
8849 public override Expression CreateExpressionTree (EmitContext ec)
8854 public override void EmitStatement (EmitContext ec)
8859 public override Expression DoResolve (EmitContext ec)
8864 public override void Emit (EmitContext ec)
8870 public class UserCast : Expression {
8874 public UserCast (MethodInfo method, Expression source, Location l)
8876 this.method = method;
8877 this.source = source;
8878 type = TypeManager.TypeToCoreType (method.ReturnType);
8879 eclass = ExprClass.Value;
8883 public Expression Source {
8889 public override Expression CreateExpressionTree (EmitContext ec)
8891 ArrayList args = new ArrayList (3);
8892 args.Add (new Argument (source.CreateExpressionTree (ec)));
8893 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8894 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8895 return CreateExpressionFactoryCall ("Convert", args);
8898 public override Expression DoResolve (EmitContext ec)
8901 // We are born fully resolved
8906 public override void Emit (EmitContext ec)
8909 ec.ig.Emit (OpCodes.Call, method);
8912 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8914 source.MutateHoistedGenericType (storey);
8915 method = storey.MutateGenericMethod (method);
8920 // This class is used to "construct" the type during a typecast
8921 // operation. Since the Type.GetType class in .NET can parse
8922 // the type specification, we just use this to construct the type
8923 // one bit at a time.
8925 public class ComposedCast : TypeExpr {
8926 FullNamedExpression left;
8929 public ComposedCast (FullNamedExpression left, string dim)
8930 : this (left, dim, left.Location)
8934 public ComposedCast (FullNamedExpression left, string dim, Location l)
8941 public Expression RemoveNullable ()
8943 if (dim.EndsWith ("?")) {
8944 dim = dim.Substring (0, dim.Length - 1);
8945 if (dim.Length == 0)
8952 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8954 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8958 Type ltype = lexpr.Type;
8959 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8960 Error_VoidInvalidInTheContext (loc);
8965 if ((dim.Length > 0) && (dim [0] == '?')) {
8966 TypeExpr nullable = new Nullable.NullableType (left, loc);
8968 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8969 return nullable.ResolveAsTypeTerminal (ec, false);
8973 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8976 if (dim != "" && dim [0] == '[' &&
8977 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8978 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8983 type = TypeManager.GetConstructedType (ltype, dim);
8988 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8990 if (type.IsPointer && !ec.IsInUnsafeScope){
8995 eclass = ExprClass.Type;
8999 public override string GetSignatureForError ()
9001 return left.GetSignatureForError () + dim;
9004 protected override void CloneTo (CloneContext clonectx, Expression t)
9006 ComposedCast target = (ComposedCast) t;
9008 target.left = (FullNamedExpression)left.Clone (clonectx);
9012 public class FixedBufferPtr : Expression {
9015 public FixedBufferPtr (Expression array, Type array_type, Location l)
9020 type = TypeManager.GetPointerType (array_type);
9021 eclass = ExprClass.Value;
9024 public override Expression CreateExpressionTree (EmitContext ec)
9026 Error_PointerInsideExpressionTree ();
9030 public override void Emit(EmitContext ec)
9035 public override Expression DoResolve (EmitContext ec)
9038 // We are born fully resolved
9046 // This class is used to represent the address of an array, used
9047 // only by the Fixed statement, this generates "&a [0]" construct
9048 // for fixed (char *pa = a)
9050 public class ArrayPtr : FixedBufferPtr {
9053 public ArrayPtr (Expression array, Type array_type, Location l):
9054 base (array, array_type, l)
9056 this.array_type = array_type;
9059 public override void Emit (EmitContext ec)
9063 ILGenerator ig = ec.ig;
9064 IntLiteral.EmitInt (ig, 0);
9065 ig.Emit (OpCodes.Ldelema, array_type);
9070 // Encapsulates a conversion rules required for array indexes
9072 public class ArrayIndexCast : TypeCast
9074 public ArrayIndexCast (Expression expr)
9075 : base (expr, expr.Type)
9079 public override Expression CreateExpressionTree (EmitContext ec)
9081 ArrayList args = new ArrayList (2);
9082 args.Add (new Argument (child.CreateExpressionTree (ec)));
9083 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9084 return CreateExpressionFactoryCall ("ConvertChecked", args);
9087 public override void Emit (EmitContext ec)
9091 if (type == TypeManager.int32_type)
9094 if (type == TypeManager.uint32_type)
9095 ec.ig.Emit (OpCodes.Conv_U);
9096 else if (type == TypeManager.int64_type)
9097 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9098 else if (type == TypeManager.uint64_type)
9099 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9101 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9106 // Implements the `stackalloc' keyword
9108 public class StackAlloc : Expression {
9113 public StackAlloc (Expression type, Expression count, Location l)
9120 public override Expression CreateExpressionTree (EmitContext ec)
9122 throw new NotSupportedException ("ET");
9125 public override Expression DoResolve (EmitContext ec)
9127 count = count.Resolve (ec);
9131 if (count.Type != TypeManager.uint32_type){
9132 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9137 Constant c = count as Constant;
9138 if (c != null && c.IsNegative) {
9139 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9143 if (ec.InCatch || ec.InFinally) {
9144 Error (255, "Cannot use stackalloc in finally or catch");
9148 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9154 if (!TypeManager.VerifyUnManaged (otype, loc))
9157 type = TypeManager.GetPointerType (otype);
9158 eclass = ExprClass.Value;
9163 public override void Emit (EmitContext ec)
9165 int size = GetTypeSize (otype);
9166 ILGenerator ig = ec.ig;
9171 ig.Emit (OpCodes.Sizeof, otype);
9173 IntConstant.EmitInt (ig, size);
9175 ig.Emit (OpCodes.Mul_Ovf_Un);
9176 ig.Emit (OpCodes.Localloc);
9179 protected override void CloneTo (CloneContext clonectx, Expression t)
9181 StackAlloc target = (StackAlloc) t;
9182 target.count = count.Clone (clonectx);
9183 target.t = t.Clone (clonectx);
9188 // An object initializer expression
9190 public class ElementInitializer : Assign
9192 public readonly string Name;
9194 public ElementInitializer (string name, Expression initializer, Location loc)
9195 : base (null, initializer, loc)
9200 protected override void CloneTo (CloneContext clonectx, Expression t)
9202 ElementInitializer target = (ElementInitializer) t;
9203 target.source = source.Clone (clonectx);
9206 public override Expression CreateExpressionTree (EmitContext ec)
9208 ArrayList args = new ArrayList (2);
9209 FieldExpr fe = target as FieldExpr;
9211 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9213 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9215 args.Add (new Argument (source.CreateExpressionTree (ec)));
9216 return CreateExpressionFactoryCall (
9217 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9221 public override Expression DoResolve (EmitContext ec)
9224 return EmptyExpressionStatement.Instance;
9226 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9227 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9233 me.InstanceExpression = ec.CurrentInitializerVariable;
9235 if (source is CollectionOrObjectInitializers) {
9236 Expression previous = ec.CurrentInitializerVariable;
9237 ec.CurrentInitializerVariable = target;
9238 source = source.Resolve (ec);
9239 ec.CurrentInitializerVariable = previous;
9243 eclass = source.eclass;
9248 Expression expr = base.DoResolve (ec);
9253 // Ignore field initializers with default value
9255 Constant c = source as Constant;
9256 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9257 return EmptyExpressionStatement.Instance;
9262 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9264 MemberInfo member = members [0];
9265 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9266 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9267 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9269 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9270 TypeManager.GetFullNameSignature (member));
9275 public override void EmitStatement (EmitContext ec)
9277 if (source is CollectionOrObjectInitializers)
9280 base.EmitStatement (ec);
9285 // A collection initializer expression
9287 public class CollectionElementInitializer : Invocation
9289 public class ElementInitializerArgument : Argument
9291 public ElementInitializerArgument (Expression e)
9297 public CollectionElementInitializer (Expression argument)
9298 : base (null, new ArrayList (1), true)
9300 Arguments.Add (argument);
9301 this.loc = argument.Location;
9304 public CollectionElementInitializer (ArrayList arguments, Location loc)
9305 : base (null, arguments, true)
9310 public override Expression CreateExpressionTree (EmitContext ec)
9312 ArrayList args = new ArrayList (2);
9313 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9315 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9316 foreach (Argument a in Arguments)
9317 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9319 args.Add (new Argument (new ArrayCreation (
9320 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9321 return CreateExpressionFactoryCall ("ElementInit", args);
9324 protected override void CloneTo (CloneContext clonectx, Expression t)
9326 CollectionElementInitializer target = (CollectionElementInitializer) t;
9328 target.Arguments = new ArrayList (Arguments.Count);
9329 foreach (Expression e in Arguments)
9330 target.Arguments.Add (e.Clone (clonectx));
9333 public override Expression DoResolve (EmitContext ec)
9335 if (eclass != ExprClass.Invalid)
9338 // TODO: We could call a constructor which takes element count argument,
9339 // for known types like List<T>, Dictionary<T, U>
9341 for (int i = 0; i < Arguments.Count; ++i) {
9342 Expression expr = Arguments [i] as Expression;
9346 expr = expr.Resolve (ec);
9350 Arguments [i] = new ElementInitializerArgument (expr);
9353 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9355 return base.DoResolve (ec);
9360 // A block of object or collection initializers
9362 public class CollectionOrObjectInitializers : ExpressionStatement
9364 ArrayList initializers;
9366 public static readonly CollectionOrObjectInitializers Empty =
9367 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9369 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9371 this.initializers = initializers;
9375 public bool IsEmpty {
9377 return initializers.Count == 0;
9381 public bool IsCollectionInitializer {
9383 return type == typeof (CollectionOrObjectInitializers);
9387 protected override void CloneTo (CloneContext clonectx, Expression target)
9389 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9391 t.initializers = new ArrayList (initializers.Count);
9392 foreach (Expression e in initializers)
9393 t.initializers.Add (e.Clone (clonectx));
9396 public override Expression CreateExpressionTree (EmitContext ec)
9398 ArrayList expr_initializers = new ArrayList (initializers.Count);
9399 foreach (Expression e in initializers) {
9400 Expression expr = e.CreateExpressionTree (ec);
9402 expr_initializers.Add (expr);
9405 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9408 public override Expression DoResolve (EmitContext ec)
9410 if (eclass != ExprClass.Invalid)
9413 bool is_elements_initialization = false;
9414 ArrayList element_names = null;
9415 for (int i = 0; i < initializers.Count; ++i) {
9416 Expression initializer = (Expression) initializers [i];
9417 ElementInitializer element_initializer = initializer as ElementInitializer;
9420 if (element_initializer != null) {
9421 is_elements_initialization = true;
9422 element_names = new ArrayList (initializers.Count);
9423 element_names.Add (element_initializer.Name);
9425 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9426 TypeManager.ienumerable_type)) {
9427 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9428 "object initializer because type `{1}' does not implement `{2}' interface",
9429 ec.CurrentInitializerVariable.GetSignatureForError (),
9430 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9431 TypeManager.CSharpName (TypeManager.ienumerable_type));
9436 if (is_elements_initialization == (element_initializer == null)) {
9437 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9438 is_elements_initialization ? "object initializer" : "collection initializer");
9442 if (is_elements_initialization) {
9443 if (element_names.Contains (element_initializer.Name)) {
9444 Report.Error (1912, element_initializer.Location,
9445 "An object initializer includes more than one member `{0}' initialization",
9446 element_initializer.Name);
9448 element_names.Add (element_initializer.Name);
9453 Expression e = initializer.Resolve (ec);
9454 if (e == EmptyExpressionStatement.Instance)
9455 initializers.RemoveAt (i--);
9457 initializers [i] = e;
9460 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9461 eclass = ExprClass.Variable;
9465 public override void Emit (EmitContext ec)
9470 public override void EmitStatement (EmitContext ec)
9472 foreach (ExpressionStatement e in initializers)
9473 e.EmitStatement (ec);
9476 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9478 foreach (Expression e in initializers)
9479 e.MutateHoistedGenericType (storey);
9484 // New expression with element/object initializers
9486 public class NewInitialize : New
9489 // This class serves as a proxy for variable initializer target instances.
9490 // A real variable is assigned later when we resolve left side of an
9493 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9495 NewInitialize new_instance;
9497 public InitializerTargetExpression (NewInitialize newInstance)
9499 this.type = newInstance.type;
9500 this.loc = newInstance.loc;
9501 this.eclass = newInstance.eclass;
9502 this.new_instance = newInstance;
9505 public override Expression CreateExpressionTree (EmitContext ec)
9507 // Should not be reached
9508 throw new NotSupportedException ("ET");
9511 public override Expression DoResolve (EmitContext ec)
9516 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9521 public override void Emit (EmitContext ec)
9523 new_instance.value_target.Emit (ec);
9526 #region IMemoryLocation Members
9528 public void AddressOf (EmitContext ec, AddressOp mode)
9530 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9536 CollectionOrObjectInitializers initializers;
9538 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9539 : base (requested_type, arguments, l)
9541 this.initializers = initializers;
9544 protected override void CloneTo (CloneContext clonectx, Expression t)
9546 base.CloneTo (clonectx, t);
9548 NewInitialize target = (NewInitialize) t;
9549 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9552 public override Expression CreateExpressionTree (EmitContext ec)
9554 ArrayList args = new ArrayList (2);
9555 args.Add (new Argument (base.CreateExpressionTree (ec)));
9556 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9558 return CreateExpressionFactoryCall (
9559 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9563 public override Expression DoResolve (EmitContext ec)
9565 if (eclass != ExprClass.Invalid)
9568 Expression e = base.DoResolve (ec);
9572 // Empty initializer can be optimized to simple new
9573 if (initializers.IsEmpty)
9576 Expression previous = ec.CurrentInitializerVariable;
9577 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9578 initializers.Resolve (ec);
9579 ec.CurrentInitializerVariable = previous;
9583 public override void Emit (EmitContext ec)
9588 // If target is non-hoisted variable, let's use it
9590 VariableReference variable = value_target as VariableReference;
9591 if (variable != null && variable.HoistedVariable == null) {
9593 StoreFromPtr (ec.ig, type);
9595 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9598 if (value_target == null || value_target_set)
9599 value_target = new LocalTemporary (type);
9601 ((LocalTemporary) value_target).Store (ec);
9604 initializers.Emit (ec);
9606 if (variable == null) {
9607 value_target.Emit (ec);
9608 value_target = null;
9612 public override void EmitStatement (EmitContext ec)
9614 if (initializers.IsEmpty) {
9615 base.EmitStatement (ec);
9621 if (value_target == null) {
9622 LocalTemporary variable = new LocalTemporary (type);
9623 variable.Store (ec);
9624 value_target = variable;
9627 initializers.EmitStatement (ec);
9630 public override bool HasInitializer {
9632 return !initializers.IsEmpty;
9636 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9638 base.MutateHoistedGenericType (storey);
9639 initializers.MutateHoistedGenericType (storey);
9643 public class AnonymousTypeDeclaration : Expression
9645 ArrayList parameters;
9646 readonly TypeContainer parent;
9647 static readonly ArrayList EmptyParameters = new ArrayList (0);
9649 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9651 this.parameters = parameters;
9652 this.parent = parent;
9656 protected override void CloneTo (CloneContext clonectx, Expression target)
9658 if (parameters == null)
9661 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9662 t.parameters = new ArrayList (parameters.Count);
9663 foreach (AnonymousTypeParameter atp in parameters)
9664 t.parameters.Add (atp.Clone (clonectx));
9667 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9669 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9673 type = AnonymousTypeClass.Create (parent, parameters, loc);
9678 type.DefineMembers ();
9683 RootContext.ToplevelTypes.AddAnonymousType (type);
9687 public override Expression CreateExpressionTree (EmitContext ec)
9689 throw new NotSupportedException ("ET");
9692 public override Expression DoResolve (EmitContext ec)
9694 AnonymousTypeClass anonymous_type;
9696 if (parameters == null) {
9697 anonymous_type = CreateAnonymousType (EmptyParameters);
9698 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9699 null, loc).Resolve (ec);
9703 ArrayList arguments = new ArrayList (parameters.Count);
9704 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9705 for (int i = 0; i < parameters.Count; ++i) {
9706 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9712 arguments.Add (new Argument (e));
9713 t_args [i] = new TypeExpression (e.Type, e.Location);
9719 anonymous_type = CreateAnonymousType (parameters);
9720 if (anonymous_type == null)
9723 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9724 new TypeArguments (loc, t_args), loc);
9726 return new New (te, arguments, loc).Resolve (ec);
9729 public override void Emit (EmitContext ec)
9731 throw new InternalErrorException ("Should not be reached");
9735 public class AnonymousTypeParameter : Expression
9737 public readonly string Name;
9738 Expression initializer;
9740 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9744 this.initializer = initializer;
9747 public AnonymousTypeParameter (Parameter parameter)
9749 this.Name = parameter.Name;
9750 this.loc = parameter.Location;
9751 this.initializer = new SimpleName (Name, loc);
9754 protected override void CloneTo (CloneContext clonectx, Expression target)
9756 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9757 t.initializer = initializer.Clone (clonectx);
9760 public override Expression CreateExpressionTree (EmitContext ec)
9762 throw new NotSupportedException ("ET");
9765 public override bool Equals (object o)
9767 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9768 return other != null && Name == other.Name;
9771 public override int GetHashCode ()
9773 return Name.GetHashCode ();
9776 public override Expression DoResolve (EmitContext ec)
9778 Expression e = initializer.Resolve (ec);
9783 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9784 type == TypeManager.anonymous_method_type || type.IsPointer) {
9785 Error_InvalidInitializer (e);
9792 protected virtual void Error_InvalidInitializer (Expression initializer)
9794 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9795 Name, initializer.GetSignatureForError ());
9798 public override void Emit (EmitContext ec)
9800 throw new InternalErrorException ("Should not be reached");