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 [Obsolete ("It may not be compatible with expression trees")]
76 static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
77 Expression e, Location loc)
81 args = new ArrayList (1);
82 Argument a = new Argument (e, Argument.AType.Expression);
84 // We need to resolve the arguments before sending them in !
85 if (!a.Resolve (ec, loc))
89 mg = mg.OverloadResolve (ec, ref args, false, loc);
94 return new UserOperatorCall (mg, args, null, loc);
97 public MethodGroupExpr Method {
101 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
103 foreach (Argument a in arguments)
104 a.Expr.MutateHoistedGenericType (storey);
106 mg.MutateHoistedGenericType (storey);
110 public class ParenthesizedExpression : Expression
112 public Expression Expr;
114 public ParenthesizedExpression (Expression expr)
117 this.loc = expr.Location;
120 public override Expression CreateExpressionTree (EmitContext ec)
122 throw new NotSupportedException ("ET");
125 public override Expression DoResolve (EmitContext ec)
127 Expr = Expr.Resolve (ec);
131 public override void Emit (EmitContext ec)
133 throw new Exception ("Should not happen");
136 protected override void CloneTo (CloneContext clonectx, Expression t)
138 ParenthesizedExpression target = (ParenthesizedExpression) t;
140 target.Expr = Expr.Clone (clonectx);
145 // Unary implements unary expressions.
147 public class Unary : Expression {
148 public enum Operator : byte {
149 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
153 static Type [] [] predefined_operators;
155 public readonly Operator Oper;
156 public Expression Expr;
157 Expression enum_conversion;
159 public Unary (Operator op, Expression expr, Location loc)
167 // This routine will attempt to simplify the unary expression when the
168 // argument is a constant.
170 Constant TryReduceConstant (EmitContext ec, Constant e)
172 if (e is SideEffectConstant) {
173 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
174 return r == null ? null : new SideEffectConstant (r, e, r.Location);
177 Type expr_type = e.Type;
180 case Operator.UnaryPlus:
181 // Unary numeric promotions
182 if (expr_type == TypeManager.byte_type)
183 return new IntConstant (((ByteConstant)e).Value, e.Location);
184 if (expr_type == TypeManager.sbyte_type)
185 return new IntConstant (((SByteConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.short_type)
187 return new IntConstant (((ShortConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.ushort_type)
189 return new IntConstant (((UShortConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.char_type)
191 return new IntConstant (((CharConstant)e).Value, e.Location);
193 // Predefined operators
194 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
195 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
196 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
197 expr_type == TypeManager.decimal_type)
204 case Operator.UnaryNegation:
205 // Unary numeric promotions
206 if (expr_type == TypeManager.byte_type)
207 return new IntConstant (-((ByteConstant)e).Value, e.Location);
208 if (expr_type == TypeManager.sbyte_type)
209 return new IntConstant (-((SByteConstant)e).Value, e.Location);
210 if (expr_type == TypeManager.short_type)
211 return new IntConstant (-((ShortConstant)e).Value, e.Location);
212 if (expr_type == TypeManager.ushort_type)
213 return new IntConstant (-((UShortConstant)e).Value, e.Location);
214 if (expr_type == TypeManager.char_type)
215 return new IntConstant (-((CharConstant)e).Value, e.Location);
217 // Predefined operators
218 if (expr_type == TypeManager.int32_type) {
219 int value = ((IntConstant)e).Value;
220 if (value == int.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (loc);
227 return new IntConstant (-value, e.Location);
229 if (expr_type == TypeManager.int64_type) {
230 long value = ((LongConstant)e).Value;
231 if (value == long.MinValue) {
232 if (ec.ConstantCheckState) {
233 ConstantFold.Error_CompileTimeOverflow (loc);
238 return new LongConstant (-value, e.Location);
241 if (expr_type == TypeManager.uint32_type) {
242 UIntLiteral uil = e as UIntLiteral;
244 if (uil.Value == 2147483648)
245 return new IntLiteral (int.MinValue, e.Location);
246 return new LongLiteral (-uil.Value, e.Location);
248 return new LongConstant (-((UIntConstant)e).Value, e.Location);
251 if (expr_type == TypeManager.uint64_type) {
252 ULongLiteral ull = e as ULongLiteral;
253 if (ull != null && ull.Value == 9223372036854775808)
254 return new LongLiteral (long.MinValue, e.Location);
258 if (expr_type == TypeManager.float_type) {
259 FloatLiteral fl = e as FloatLiteral;
260 // For better error reporting
262 fl.Value = -fl.Value;
265 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
267 if (expr_type == TypeManager.double_type) {
268 DoubleLiteral dl = e as DoubleLiteral;
269 // For better error reporting
271 dl.Value = -dl.Value;
275 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.decimal_type)
278 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
282 case Operator.LogicalNot:
283 if (expr_type != TypeManager.bool_type)
286 bool b = (bool)e.GetValue ();
287 return new BoolConstant (!b, e.Location);
289 case Operator.OnesComplement:
290 // Unary numeric promotions
291 if (expr_type == TypeManager.byte_type)
292 return new IntConstant (~((ByteConstant)e).Value, e.Location);
293 if (expr_type == TypeManager.sbyte_type)
294 return new IntConstant (~((SByteConstant)e).Value, e.Location);
295 if (expr_type == TypeManager.short_type)
296 return new IntConstant (~((ShortConstant)e).Value, e.Location);
297 if (expr_type == TypeManager.ushort_type)
298 return new IntConstant (~((UShortConstant)e).Value, e.Location);
299 if (expr_type == TypeManager.char_type)
300 return new IntConstant (~((CharConstant)e).Value, e.Location);
302 // Predefined operators
303 if (expr_type == TypeManager.int32_type)
304 return new IntConstant (~((IntConstant)e).Value, e.Location);
305 if (expr_type == TypeManager.uint32_type)
306 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
307 if (expr_type == TypeManager.int64_type)
308 return new LongConstant (~((LongConstant)e).Value, e.Location);
309 if (expr_type == TypeManager.uint64_type){
310 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
312 if (e is EnumConstant) {
313 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
315 e = new EnumConstant (e, expr_type);
320 throw new Exception ("Can not constant fold: " + Oper.ToString());
323 protected Expression ResolveOperator (EmitContext ec, Expression expr)
325 eclass = ExprClass.Value;
327 if (predefined_operators == null)
328 CreatePredefinedOperatorsTable ();
330 Type expr_type = expr.Type;
331 Expression best_expr;
334 // Primitive types first
336 if (TypeManager.IsPrimitiveType (expr_type)) {
337 best_expr = ResolvePrimitivePredefinedType (expr);
338 if (best_expr == null)
341 type = best_expr.Type;
347 // E operator ~(E x);
349 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
350 return ResolveEnumOperator (ec, expr);
352 return ResolveUserType (ec, expr);
355 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
357 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
358 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
359 if (best_expr == null)
363 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
365 return EmptyCast.Create (this, type);
368 public override Expression CreateExpressionTree (EmitContext ec)
370 return CreateExpressionTree (ec, null);
373 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
377 case Operator.AddressOf:
378 Error_PointerInsideExpressionTree ();
380 case Operator.UnaryNegation:
381 if (ec.CheckState && user_op == null && !IsFloat (type))
382 method_name = "NegateChecked";
384 method_name = "Negate";
386 case Operator.OnesComplement:
387 case Operator.LogicalNot:
390 case Operator.UnaryPlus:
391 method_name = "UnaryPlus";
394 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
397 ArrayList args = new ArrayList (2);
398 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
400 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
401 return CreateExpressionFactoryCall (method_name, args);
404 static void CreatePredefinedOperatorsTable ()
406 predefined_operators = new Type [(int) Operator.TOP] [];
409 // 7.6.1 Unary plus operator
411 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
412 TypeManager.int32_type, TypeManager.uint32_type,
413 TypeManager.int64_type, TypeManager.uint64_type,
414 TypeManager.float_type, TypeManager.double_type,
415 TypeManager.decimal_type
419 // 7.6.2 Unary minus operator
421 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
422 TypeManager.int32_type,
423 TypeManager.int64_type,
424 TypeManager.float_type, TypeManager.double_type,
425 TypeManager.decimal_type
429 // 7.6.3 Logical negation operator
431 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
432 TypeManager.bool_type
436 // 7.6.4 Bitwise complement operator
438 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
439 TypeManager.int32_type, TypeManager.uint32_type,
440 TypeManager.int64_type, TypeManager.uint64_type
445 // Unary numeric promotions
447 static Expression DoNumericPromotion (Operator op, Expression expr)
449 Type expr_type = expr.Type;
450 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
451 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
452 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
453 expr_type == TypeManager.char_type)
454 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
456 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
457 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
462 public override Expression DoResolve (EmitContext ec)
464 if (Oper == Operator.AddressOf) {
465 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
467 if (Expr == null || Expr.eclass != ExprClass.Variable){
468 Error (211, "Cannot take the address of the given expression");
472 return ResolveAddressOf (ec);
475 Expr = Expr.Resolve (ec);
479 if (TypeManager.IsNullableValueType (Expr.Type))
480 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
483 // Attempt to use a constant folding operation.
485 Constant cexpr = Expr as Constant;
487 cexpr = TryReduceConstant (ec, cexpr);
492 Expression expr = ResolveOperator (ec, Expr);
494 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
497 // Reduce unary operator on predefined types
499 if (expr == this && Oper == Operator.UnaryPlus)
505 public override Expression DoResolveLValue (EmitContext ec, Expression right)
510 public override void Emit (EmitContext ec)
512 EmitOperator (ec, type);
515 protected void EmitOperator (EmitContext ec, Type type)
517 ILGenerator ig = ec.ig;
520 case Operator.UnaryPlus:
524 case Operator.UnaryNegation:
525 if (ec.CheckState && !IsFloat (type)) {
526 ig.Emit (OpCodes.Ldc_I4_0);
527 if (type == TypeManager.int64_type)
528 ig.Emit (OpCodes.Conv_U8);
530 ig.Emit (OpCodes.Sub_Ovf);
533 ig.Emit (OpCodes.Neg);
538 case Operator.LogicalNot:
540 ig.Emit (OpCodes.Ldc_I4_0);
541 ig.Emit (OpCodes.Ceq);
544 case Operator.OnesComplement:
546 ig.Emit (OpCodes.Not);
549 case Operator.AddressOf:
550 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
554 throw new Exception ("This should not happen: Operator = "
559 // Same trick as in Binary expression
561 if (enum_conversion != null)
562 enum_conversion.Emit (ec);
565 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
567 if (Oper == Operator.LogicalNot)
568 Expr.EmitBranchable (ec, target, !on_true);
570 base.EmitBranchable (ec, target, on_true);
573 public override void EmitSideEffect (EmitContext ec)
575 Expr.EmitSideEffect (ec);
578 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
580 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
581 oper, TypeManager.CSharpName (t));
584 static bool IsFloat (Type t)
586 return t == TypeManager.float_type || t == TypeManager.double_type;
590 // Returns a stringified representation of the Operator
592 public static string OperName (Operator oper)
595 case Operator.UnaryPlus:
597 case Operator.UnaryNegation:
599 case Operator.LogicalNot:
601 case Operator.OnesComplement:
603 case Operator.AddressOf:
607 throw new NotImplementedException (oper.ToString ());
610 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
612 type = storey.MutateType (type);
613 Expr.MutateHoistedGenericType (storey);
616 Expression ResolveAddressOf (EmitContext ec)
623 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
627 IVariable variable = Expr as IVariable;
628 if (variable != null && variable.IsFixed) {
629 if (ec.InFixedInitializer) {
630 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
634 if (!ec.InFixedInitializer) {
635 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
640 LocalVariableReference lr = Expr as LocalVariableReference;
643 AnonymousMethodBody.Error_AddressOfCapturedVar (lr.Name, loc);
646 lr.local_info.AddressTaken = true;
647 lr.local_info.Used = true;
650 ParameterReference pr = Expr as ParameterReference;
651 if ((pr != null) && pr.IsHoisted) {
652 AnonymousMethodBody.Error_AddressOfCapturedVar (pr.Name, loc);
656 // According to the specs, a variable is considered definitely assigned if you take
658 if ((variable != null) && (variable.VariableInfo != null)) {
659 variable.VariableInfo.SetAssigned (ec);
662 type = TypeManager.GetPointerType (Expr.Type);
663 eclass = ExprClass.Value;
667 Expression ResolvePrimitivePredefinedType (Expression expr)
669 expr = DoNumericPromotion (Oper, expr);
670 Type expr_type = expr.Type;
671 Type[] predefined = predefined_operators [(int) Oper];
672 foreach (Type t in predefined) {
680 // Perform user-operator overload resolution
682 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
684 CSharp.Operator.OpType op_type;
686 case Operator.LogicalNot:
687 op_type = CSharp.Operator.OpType.LogicalNot; break;
688 case Operator.OnesComplement:
689 op_type = CSharp.Operator.OpType.OnesComplement; break;
690 case Operator.UnaryNegation:
691 op_type = CSharp.Operator.OpType.UnaryNegation; break;
692 case Operator.UnaryPlus:
693 op_type = CSharp.Operator.OpType.UnaryPlus; break;
695 throw new InternalErrorException (Oper.ToString ());
698 string op_name = CSharp.Operator.GetMetadataName (op_type);
699 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
703 ArrayList args = new ArrayList (1);
704 args.Add (new Argument (expr));
705 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
710 Expr = ((Argument) args [0]).Expr;
711 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
715 // Unary user type overload resolution
717 Expression ResolveUserType (EmitContext ec, Expression expr)
719 Expression best_expr = ResolveUserOperator (ec, expr);
720 if (best_expr != null)
723 Type[] predefined = predefined_operators [(int) Oper];
724 foreach (Type t in predefined) {
725 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
726 if (oper_expr == null)
730 // decimal type is predefined but has user-operators
732 if (oper_expr.Type == TypeManager.decimal_type)
733 oper_expr = ResolveUserType (ec, oper_expr);
735 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
737 if (oper_expr == null)
740 if (best_expr == null) {
741 best_expr = oper_expr;
745 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
747 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
748 OperName (Oper), TypeManager.CSharpName (expr.Type));
753 best_expr = oper_expr;
756 if (best_expr == null)
760 // HACK: Decimal user-operator is included in standard operators
762 if (best_expr.Type == TypeManager.decimal_type)
766 type = best_expr.Type;
770 protected override void CloneTo (CloneContext clonectx, Expression t)
772 Unary target = (Unary) t;
774 target.Expr = Expr.Clone (clonectx);
779 // Unary operators are turned into Indirection expressions
780 // after semantic analysis (this is so we can take the address
781 // of an indirection).
783 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
785 LocalTemporary temporary;
788 public Indirection (Expression expr, Location l)
794 public override Expression CreateExpressionTree (EmitContext ec)
796 Error_PointerInsideExpressionTree ();
800 protected override void CloneTo (CloneContext clonectx, Expression t)
802 Indirection target = (Indirection) t;
803 target.expr = expr.Clone (clonectx);
806 public override void Emit (EmitContext ec)
811 LoadFromPtr (ec.ig, Type);
814 public void Emit (EmitContext ec, bool leave_copy)
818 ec.ig.Emit (OpCodes.Dup);
819 temporary = new LocalTemporary (expr.Type);
820 temporary.Store (ec);
824 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
826 prepared = prepare_for_load;
830 if (prepare_for_load)
831 ec.ig.Emit (OpCodes.Dup);
835 ec.ig.Emit (OpCodes.Dup);
836 temporary = new LocalTemporary (expr.Type);
837 temporary.Store (ec);
840 StoreFromPtr (ec.ig, type);
842 if (temporary != null) {
844 temporary.Release (ec);
848 public void AddressOf (EmitContext ec, AddressOp Mode)
853 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
855 return DoResolve (ec);
858 public override Expression DoResolve (EmitContext ec)
860 expr = expr.Resolve (ec);
867 if (!expr.Type.IsPointer) {
868 Error (193, "The * or -> operator must be applied to a pointer");
872 type = TypeManager.GetElementType (expr.Type);
873 eclass = ExprClass.Variable;
877 public override string ToString ()
879 return "*(" + expr + ")";
882 #region IVariable Members
884 public VariableInfo VariableInfo {
889 // A pointer-indirection is always fixed.
891 public bool IsFixed {
899 /// Unary Mutator expressions (pre and post ++ and --)
903 /// UnaryMutator implements ++ and -- expressions. It derives from
904 /// ExpressionStatement becuase the pre/post increment/decrement
905 /// operators can be used in a statement context.
907 /// FIXME: Idea, we could split this up in two classes, one simpler
908 /// for the common case, and one with the extra fields for more complex
909 /// classes (indexers require temporary access; overloaded require method)
912 public class UnaryMutator : ExpressionStatement {
914 public enum Mode : byte {
921 PreDecrement = IsDecrement,
922 PostIncrement = IsPost,
923 PostDecrement = IsPost | IsDecrement
927 bool is_expr = false;
928 bool recurse = false;
933 // This is expensive for the simplest case.
935 UserOperatorCall method;
937 public UnaryMutator (Mode m, Expression e, Location l)
944 static string OperName (Mode mode)
946 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
951 /// Returns whether an object of type `t' can be incremented
952 /// or decremented with add/sub (ie, basically whether we can
953 /// use pre-post incr-decr operations on it, but it is not a
954 /// System.Decimal, which we require operator overloading to catch)
956 static bool IsIncrementableNumber (Type t)
958 return (t == TypeManager.sbyte_type) ||
959 (t == TypeManager.byte_type) ||
960 (t == TypeManager.short_type) ||
961 (t == TypeManager.ushort_type) ||
962 (t == TypeManager.int32_type) ||
963 (t == TypeManager.uint32_type) ||
964 (t == TypeManager.int64_type) ||
965 (t == TypeManager.uint64_type) ||
966 (t == TypeManager.char_type) ||
967 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
968 (t == TypeManager.float_type) ||
969 (t == TypeManager.double_type) ||
970 (t.IsPointer && t != TypeManager.void_ptr_type);
973 Expression ResolveOperator (EmitContext ec)
975 Type expr_type = expr.Type;
978 // Step 1: Perform Operator Overload location
983 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
984 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
986 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
988 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
991 method = UserOperatorCall.MakeSimpleCall (
992 ec, (MethodGroupExpr) mg, expr, loc);
995 } else if (!IsIncrementableNumber (expr_type)) {
996 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
997 TypeManager.CSharpName (expr_type) + "'");
1002 // The operand of the prefix/postfix increment decrement operators
1003 // should be an expression that is classified as a variable,
1004 // a property access or an indexer access
1007 if (expr.eclass == ExprClass.Variable){
1008 LocalVariableReference var = expr as LocalVariableReference;
1009 if ((var != null) && var.IsReadOnly) {
1010 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
1013 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
1014 expr = expr.ResolveLValue (ec, this, Location);
1018 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1025 public override Expression CreateExpressionTree (EmitContext ec)
1027 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1030 public override Expression DoResolve (EmitContext ec)
1032 expr = expr.Resolve (ec);
1037 eclass = ExprClass.Value;
1040 if (TypeManager.IsNullableValueType (expr.Type))
1041 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1044 return ResolveOperator (ec);
1048 // Loads the proper "1" into the stack based on the type, then it emits the
1049 // opcode for the operation requested
1051 void LoadOneAndEmitOp (EmitContext ec, Type t)
1054 // Measure if getting the typecode and using that is more/less efficient
1055 // that comparing types. t.GetTypeCode() is an internal call.
1057 ILGenerator ig = ec.ig;
1059 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1060 LongConstant.EmitLong (ig, 1);
1061 else if (t == TypeManager.double_type)
1062 ig.Emit (OpCodes.Ldc_R8, 1.0);
1063 else if (t == TypeManager.float_type)
1064 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1065 else if (t.IsPointer){
1066 Type et = TypeManager.GetElementType (t);
1067 int n = GetTypeSize (et);
1070 ig.Emit (OpCodes.Sizeof, et);
1072 IntConstant.EmitInt (ig, n);
1073 ig.Emit (OpCodes.Conv_I);
1076 ig.Emit (OpCodes.Ldc_I4_1);
1079 // Now emit the operation
1082 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1083 Binary.EmitOperatorOpcode (ec, op, t);
1085 if (t == TypeManager.sbyte_type){
1087 ig.Emit (OpCodes.Conv_Ovf_I1);
1089 ig.Emit (OpCodes.Conv_I1);
1090 } else if (t == TypeManager.byte_type){
1092 ig.Emit (OpCodes.Conv_Ovf_U1);
1094 ig.Emit (OpCodes.Conv_U1);
1095 } else if (t == TypeManager.short_type){
1097 ig.Emit (OpCodes.Conv_Ovf_I2);
1099 ig.Emit (OpCodes.Conv_I2);
1100 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1102 ig.Emit (OpCodes.Conv_Ovf_U2);
1104 ig.Emit (OpCodes.Conv_U2);
1109 void EmitCode (EmitContext ec, bool is_expr)
1112 this.is_expr = is_expr;
1113 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1116 public override void Emit (EmitContext ec)
1119 // We use recurse to allow ourselfs to be the source
1120 // of an assignment. This little hack prevents us from
1121 // having to allocate another expression
1124 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1126 LoadOneAndEmitOp (ec, expr.Type);
1128 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1133 EmitCode (ec, true);
1136 public override void EmitStatement (EmitContext ec)
1138 EmitCode (ec, false);
1141 protected override void CloneTo (CloneContext clonectx, Expression t)
1143 UnaryMutator target = (UnaryMutator) t;
1145 target.expr = expr.Clone (clonectx);
1150 /// Base class for the `Is' and `As' classes.
1154 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1157 public abstract class Probe : Expression {
1158 public Expression ProbeType;
1159 protected Expression expr;
1160 protected TypeExpr probe_type_expr;
1162 public Probe (Expression expr, Expression probe_type, Location l)
1164 ProbeType = probe_type;
1169 public Expression Expr {
1175 public override Expression DoResolve (EmitContext ec)
1177 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1178 if (probe_type_expr == null)
1181 expr = expr.Resolve (ec);
1185 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1186 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1191 if (expr.Type == TypeManager.anonymous_method_type) {
1192 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1200 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1202 expr.MutateHoistedGenericType (storey);
1203 probe_type_expr.MutateHoistedGenericType (storey);
1206 protected abstract string OperatorName { get; }
1208 protected override void CloneTo (CloneContext clonectx, Expression t)
1210 Probe target = (Probe) t;
1212 target.expr = expr.Clone (clonectx);
1213 target.ProbeType = ProbeType.Clone (clonectx);
1219 /// Implementation of the `is' operator.
1221 public class Is : Probe {
1222 Nullable.Unwrap expr_unwrap;
1224 public Is (Expression expr, Expression probe_type, Location l)
1225 : base (expr, probe_type, l)
1229 public override Expression CreateExpressionTree (EmitContext ec)
1231 ArrayList args = new ArrayList (2);
1232 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1233 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1234 return CreateExpressionFactoryCall ("TypeIs", args);
1237 public override void Emit (EmitContext ec)
1239 ILGenerator ig = ec.ig;
1240 if (expr_unwrap != null) {
1241 expr_unwrap.EmitCheck (ec);
1246 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1247 ig.Emit (OpCodes.Ldnull);
1248 ig.Emit (OpCodes.Cgt_Un);
1251 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1253 ILGenerator ig = ec.ig;
1254 if (expr_unwrap != null) {
1255 expr_unwrap.EmitCheck (ec);
1258 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1260 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1263 Expression CreateConstantResult (bool result)
1266 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1267 TypeManager.CSharpName (probe_type_expr.Type));
1269 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1270 TypeManager.CSharpName (probe_type_expr.Type));
1272 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1275 public override Expression DoResolve (EmitContext ec)
1277 if (base.DoResolve (ec) == null)
1281 bool d_is_nullable = false;
1283 if (expr is Constant) {
1285 // If E is a method group or the null literal, of if the type of E is a reference
1286 // type or a nullable type and the value of E is null, the result is false
1289 return CreateConstantResult (false);
1290 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1291 d = TypeManager.GetTypeArguments (d) [0];
1292 d_is_nullable = true;
1295 type = TypeManager.bool_type;
1296 eclass = ExprClass.Value;
1297 Type t = probe_type_expr.Type;
1298 bool t_is_nullable = false;
1299 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1300 t = TypeManager.GetTypeArguments (t) [0];
1301 t_is_nullable = true;
1304 if (t.IsValueType) {
1307 // D and T are the same value types but D can be null
1309 if (d_is_nullable && !t_is_nullable) {
1310 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1315 // The result is true if D and T are the same value types
1317 return CreateConstantResult (true);
1320 if (TypeManager.IsGenericParameter (d))
1321 return ResolveGenericParameter (t, d);
1324 // An unboxing conversion exists
1326 if (Convert.ExplicitReferenceConversionExists (d, t))
1329 if (TypeManager.IsGenericParameter (t))
1330 return ResolveGenericParameter (d, t);
1332 if (d.IsValueType) {
1334 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1335 return CreateConstantResult (true);
1337 if (TypeManager.IsGenericParameter (d))
1338 return ResolveGenericParameter (t, d);
1340 if (TypeManager.ContainsGenericParameters (d))
1343 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1344 Convert.ExplicitReferenceConversionExists (d, t)) {
1350 return CreateConstantResult (false);
1353 Expression ResolveGenericParameter (Type d, Type t)
1356 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1357 if (constraints != null) {
1358 if (constraints.IsReferenceType && d.IsValueType)
1359 return CreateConstantResult (false);
1361 if (constraints.IsValueType && !d.IsValueType)
1362 return CreateConstantResult (TypeManager.IsEqual (d, t));
1365 if (!TypeManager.IsReferenceType (expr.Type))
1366 expr = new BoxedCast (expr, d);
1374 protected override string OperatorName {
1375 get { return "is"; }
1380 /// Implementation of the `as' operator.
1382 public class As : Probe {
1384 Expression resolved_type;
1386 public As (Expression expr, Expression probe_type, Location l)
1387 : base (expr, probe_type, l)
1391 public override Expression CreateExpressionTree (EmitContext ec)
1393 ArrayList args = new ArrayList (2);
1394 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1395 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1396 return CreateExpressionFactoryCall ("TypeAs", args);
1399 public override void Emit (EmitContext ec)
1401 ILGenerator ig = ec.ig;
1406 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1409 if (TypeManager.IsNullableType (type))
1410 ig.Emit (OpCodes.Unbox_Any, type);
1414 static void Error_CannotConvertType (Type source, Type target, Location loc)
1416 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1417 TypeManager.CSharpName (source),
1418 TypeManager.CSharpName (target));
1421 public override Expression DoResolve (EmitContext ec)
1423 if (resolved_type == null) {
1424 resolved_type = base.DoResolve (ec);
1426 if (resolved_type == null)
1430 type = probe_type_expr.Type;
1431 eclass = ExprClass.Value;
1432 Type etype = expr.Type;
1434 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1435 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1436 TypeManager.CSharpName (type));
1443 // If the type is a type parameter, ensure
1444 // that it is constrained by a class
1446 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1448 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1451 if (constraints == null)
1454 if (!constraints.HasClassConstraint)
1455 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1459 Report.Error (413, loc,
1460 "The as operator requires that the `{0}' type parameter be constrained by a class",
1461 probe_type_expr.GetSignatureForError ());
1466 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1467 return Nullable.LiftedNull.CreateFromExpression (this);
1470 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1477 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1478 if (TypeManager.IsGenericParameter (etype))
1479 expr = new BoxedCast (expr, etype);
1485 if (TypeManager.ContainsGenericParameters (etype) ||
1486 TypeManager.ContainsGenericParameters (type)) {
1487 expr = new BoxedCast (expr, etype);
1492 Error_CannotConvertType (etype, type, loc);
1496 protected override string OperatorName {
1497 get { return "as"; }
1500 public override bool GetAttributableValue (Type value_type, out object value)
1502 return expr.GetAttributableValue (value_type, out value);
1507 /// This represents a typecast in the source language.
1509 /// FIXME: Cast expressions have an unusual set of parsing
1510 /// rules, we need to figure those out.
1512 public class Cast : Expression {
1513 Expression target_type;
1516 public Cast (Expression cast_type, Expression expr)
1517 : this (cast_type, expr, cast_type.Location)
1521 public Cast (Expression cast_type, Expression expr, Location loc)
1523 this.target_type = cast_type;
1527 if (target_type == TypeManager.system_void_expr)
1528 Error_VoidInvalidInTheContext (loc);
1531 public Expression TargetType {
1532 get { return target_type; }
1535 public Expression Expr {
1536 get { return expr; }
1539 public override Expression CreateExpressionTree (EmitContext ec)
1541 throw new NotSupportedException ("ET");
1544 public override Expression DoResolve (EmitContext ec)
1546 expr = expr.Resolve (ec);
1550 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1556 if (type.IsAbstract && type.IsSealed) {
1557 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1561 eclass = ExprClass.Value;
1563 Constant c = expr as Constant;
1565 c = c.TryReduce (ec, type, loc);
1570 if (type.IsPointer && !ec.InUnsafe) {
1574 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1578 public override void Emit (EmitContext ec)
1580 throw new Exception ("Should not happen");
1583 protected override void CloneTo (CloneContext clonectx, Expression t)
1585 Cast target = (Cast) t;
1587 target.target_type = target_type.Clone (clonectx);
1588 target.expr = expr.Clone (clonectx);
1593 // C# 2.0 Default value expression
1595 public class DefaultValueExpression : Expression
1599 public DefaultValueExpression (Expression expr, Location loc)
1605 public override Expression CreateExpressionTree (EmitContext ec)
1607 ArrayList args = new ArrayList (2);
1608 args.Add (new Argument (this));
1609 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1610 return CreateExpressionFactoryCall ("Constant", args);
1613 public override Expression DoResolve (EmitContext ec)
1615 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1621 if (type == TypeManager.void_type) {
1622 Error_VoidInvalidInTheContext (loc);
1626 if (TypeManager.IsGenericParameter (type)) {
1627 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1628 if (constraints != null && constraints.IsReferenceType)
1629 return new EmptyConstantCast (new NullLiteral (Location), type);
1631 Constant c = New.Constantify (type);
1635 if (!TypeManager.IsValueType (type))
1636 return new EmptyConstantCast (new NullLiteral (Location), type);
1638 eclass = ExprClass.Variable;
1642 public override void Emit (EmitContext ec)
1644 LocalTemporary temp_storage = new LocalTemporary(type);
1646 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1647 ec.ig.Emit(OpCodes.Initobj, type);
1648 temp_storage.Emit(ec);
1651 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1653 type = storey.MutateType (type);
1656 protected override void CloneTo (CloneContext clonectx, Expression t)
1658 DefaultValueExpression target = (DefaultValueExpression) t;
1660 target.expr = expr.Clone (clonectx);
1665 /// Binary operators
1667 public class Binary : Expression {
1669 protected class PredefinedOperator {
1670 protected readonly Type left;
1671 protected readonly Type right;
1672 public readonly Operator OperatorsMask;
1673 public Type ReturnType;
1675 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1676 : this (ltype, rtype, op_mask, ltype)
1680 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1681 : this (type, type, op_mask, return_type)
1685 public PredefinedOperator (Type type, Operator op_mask)
1686 : this (type, type, op_mask, type)
1690 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1692 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1693 throw new InternalErrorException ("Only masked values can be used");
1697 this.OperatorsMask = op_mask;
1698 this.ReturnType = return_type;
1701 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1703 b.type = ReturnType;
1705 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1706 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1709 // A user operators does not support multiple user conversions, but decimal type
1710 // is considered to be predefined type therefore we apply predefined operators rules
1711 // and then look for decimal user-operator implementation
1713 if (left == TypeManager.decimal_type)
1714 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1719 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1722 // We are dealing with primitive types only
1724 return left == ltype && ltype == rtype;
1727 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1729 if (TypeManager.IsEqual (left, lexpr.Type) &&
1730 TypeManager.IsEqual (right, rexpr.Type))
1733 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1734 Convert.ImplicitConversionExists (ec, rexpr, right);
1737 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1740 if (left != null && best_operator.left != null) {
1741 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1745 // When second arguments are same as the first one, the result is same
1747 if (left != right || best_operator.left != best_operator.right) {
1748 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1751 if (result == 0 || result > 2)
1754 return result == 1 ? best_operator : this;
1758 class PredefinedStringOperator : PredefinedOperator {
1759 public PredefinedStringOperator (Type type, Operator op_mask)
1760 : base (type, op_mask, type)
1762 ReturnType = TypeManager.string_type;
1765 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1766 : base (ltype, rtype, op_mask)
1768 ReturnType = TypeManager.string_type;
1771 public override Expression ConvertResult (EmitContext ec, Binary b)
1774 // Use original expression for nullable arguments
1776 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1778 b.left = unwrap.Original;
1780 unwrap = b.right as Nullable.Unwrap;
1782 b.right = unwrap.Original;
1784 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1785 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1788 // Start a new concat expression using converted expression
1790 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1794 class PredefinedShiftOperator : PredefinedOperator {
1795 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1796 base (ltype, TypeManager.int32_type, op_mask)
1800 public override Expression ConvertResult (EmitContext ec, Binary b)
1802 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1804 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1806 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1809 // b = b.left >> b.right & (0x1f|0x3f)
1811 b.right = new Binary (Operator.BitwiseAnd,
1812 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1815 // Expression tree representation does not use & mask
1817 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1818 b.type = ReturnType;
1823 class PredefinedPointerOperator : PredefinedOperator {
1824 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1825 : base (ltype, rtype, op_mask)
1829 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1830 : base (type, op_mask, return_type)
1834 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1837 if (!lexpr.Type.IsPointer)
1840 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1844 if (right == null) {
1845 if (!rexpr.Type.IsPointer)
1848 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1855 public override Expression ConvertResult (EmitContext ec, Binary b)
1858 b.left = EmptyCast.Create (b.left, left);
1859 } else if (right != null) {
1860 b.right = EmptyCast.Create (b.right, right);
1863 Type r_type = ReturnType;
1864 if (r_type == null) {
1865 r_type = b.left.Type;
1867 r_type = b.right.Type;
1870 return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
1875 public enum Operator {
1876 Multiply = 0 | ArithmeticMask,
1877 Division = 1 | ArithmeticMask,
1878 Modulus = 2 | ArithmeticMask,
1879 Addition = 3 | ArithmeticMask | AdditionMask,
1880 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1882 LeftShift = 5 | ShiftMask,
1883 RightShift = 6 | ShiftMask,
1885 LessThan = 7 | ComparisonMask | RelationalMask,
1886 GreaterThan = 8 | ComparisonMask | RelationalMask,
1887 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1888 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1889 Equality = 11 | ComparisonMask | EqualityMask,
1890 Inequality = 12 | ComparisonMask | EqualityMask,
1892 BitwiseAnd = 13 | BitwiseMask,
1893 ExclusiveOr = 14 | BitwiseMask,
1894 BitwiseOr = 15 | BitwiseMask,
1896 LogicalAnd = 16 | LogicalMask,
1897 LogicalOr = 17 | LogicalMask,
1902 ValuesOnlyMask = ArithmeticMask - 1,
1903 ArithmeticMask = 1 << 5,
1905 ComparisonMask = 1 << 7,
1906 EqualityMask = 1 << 8,
1907 BitwiseMask = 1 << 9,
1908 LogicalMask = 1 << 10,
1909 AdditionMask = 1 << 11,
1910 SubtractionMask = 1 << 12,
1911 RelationalMask = 1 << 13
1914 readonly Operator oper;
1915 protected Expression left, right;
1916 readonly bool is_compound;
1917 Expression enum_conversion;
1919 static PredefinedOperator [] standard_operators;
1920 static PredefinedOperator [] pointer_operators;
1922 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1923 : this (oper, left, right)
1925 this.is_compound = isCompound;
1928 public Binary (Operator oper, Expression left, Expression right)
1933 this.loc = left.Location;
1936 public Operator Oper {
1943 /// Returns a stringified representation of the Operator
1945 string OperName (Operator oper)
1949 case Operator.Multiply:
1952 case Operator.Division:
1955 case Operator.Modulus:
1958 case Operator.Addition:
1961 case Operator.Subtraction:
1964 case Operator.LeftShift:
1967 case Operator.RightShift:
1970 case Operator.LessThan:
1973 case Operator.GreaterThan:
1976 case Operator.LessThanOrEqual:
1979 case Operator.GreaterThanOrEqual:
1982 case Operator.Equality:
1985 case Operator.Inequality:
1988 case Operator.BitwiseAnd:
1991 case Operator.BitwiseOr:
1994 case Operator.ExclusiveOr:
1997 case Operator.LogicalOr:
2000 case Operator.LogicalAnd:
2004 s = oper.ToString ();
2014 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
2016 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
2019 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
2022 // TODO: This should be handled as Type of method group in CSharpName
2023 if (left.eclass == ExprClass.MethodGroup)
2024 l = left.ExprClassName;
2026 l = TypeManager.CSharpName (left.Type);
2028 if (right.eclass == ExprClass.MethodGroup)
2029 r = right.ExprClassName;
2031 r = TypeManager.CSharpName (right.Type);
2033 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2037 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2039 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2042 static string GetOperatorMetadataName (Operator op)
2044 CSharp.Operator.OpType op_type;
2046 case Operator.Addition:
2047 op_type = CSharp.Operator.OpType.Addition; break;
2048 case Operator.BitwiseAnd:
2049 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2050 case Operator.BitwiseOr:
2051 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2052 case Operator.Division:
2053 op_type = CSharp.Operator.OpType.Division; break;
2054 case Operator.Equality:
2055 op_type = CSharp.Operator.OpType.Equality; break;
2056 case Operator.ExclusiveOr:
2057 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2058 case Operator.GreaterThan:
2059 op_type = CSharp.Operator.OpType.GreaterThan; break;
2060 case Operator.GreaterThanOrEqual:
2061 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2062 case Operator.Inequality:
2063 op_type = CSharp.Operator.OpType.Inequality; break;
2064 case Operator.LeftShift:
2065 op_type = CSharp.Operator.OpType.LeftShift; break;
2066 case Operator.LessThan:
2067 op_type = CSharp.Operator.OpType.LessThan; break;
2068 case Operator.LessThanOrEqual:
2069 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2070 case Operator.Modulus:
2071 op_type = CSharp.Operator.OpType.Modulus; break;
2072 case Operator.Multiply:
2073 op_type = CSharp.Operator.OpType.Multiply; break;
2074 case Operator.RightShift:
2075 op_type = CSharp.Operator.OpType.RightShift; break;
2076 case Operator.Subtraction:
2077 op_type = CSharp.Operator.OpType.Subtraction; break;
2079 throw new InternalErrorException (op.ToString ());
2082 return CSharp.Operator.GetMetadataName (op_type);
2085 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2088 ILGenerator ig = ec.ig;
2091 case Operator.Multiply:
2093 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2094 opcode = OpCodes.Mul_Ovf;
2095 else if (!IsFloat (l))
2096 opcode = OpCodes.Mul_Ovf_Un;
2098 opcode = OpCodes.Mul;
2100 opcode = OpCodes.Mul;
2104 case Operator.Division:
2106 opcode = OpCodes.Div_Un;
2108 opcode = OpCodes.Div;
2111 case Operator.Modulus:
2113 opcode = OpCodes.Rem_Un;
2115 opcode = OpCodes.Rem;
2118 case Operator.Addition:
2120 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2121 opcode = OpCodes.Add_Ovf;
2122 else if (!IsFloat (l))
2123 opcode = OpCodes.Add_Ovf_Un;
2125 opcode = OpCodes.Add;
2127 opcode = OpCodes.Add;
2130 case Operator.Subtraction:
2132 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2133 opcode = OpCodes.Sub_Ovf;
2134 else if (!IsFloat (l))
2135 opcode = OpCodes.Sub_Ovf_Un;
2137 opcode = OpCodes.Sub;
2139 opcode = OpCodes.Sub;
2142 case Operator.RightShift:
2144 opcode = OpCodes.Shr_Un;
2146 opcode = OpCodes.Shr;
2149 case Operator.LeftShift:
2150 opcode = OpCodes.Shl;
2153 case Operator.Equality:
2154 opcode = OpCodes.Ceq;
2157 case Operator.Inequality:
2158 ig.Emit (OpCodes.Ceq);
2159 ig.Emit (OpCodes.Ldc_I4_0);
2161 opcode = OpCodes.Ceq;
2164 case Operator.LessThan:
2166 opcode = OpCodes.Clt_Un;
2168 opcode = OpCodes.Clt;
2171 case Operator.GreaterThan:
2173 opcode = OpCodes.Cgt_Un;
2175 opcode = OpCodes.Cgt;
2178 case Operator.LessThanOrEqual:
2179 if (IsUnsigned (l) || IsFloat (l))
2180 ig.Emit (OpCodes.Cgt_Un);
2182 ig.Emit (OpCodes.Cgt);
2183 ig.Emit (OpCodes.Ldc_I4_0);
2185 opcode = OpCodes.Ceq;
2188 case Operator.GreaterThanOrEqual:
2189 if (IsUnsigned (l) || IsFloat (l))
2190 ig.Emit (OpCodes.Clt_Un);
2192 ig.Emit (OpCodes.Clt);
2194 ig.Emit (OpCodes.Ldc_I4_0);
2196 opcode = OpCodes.Ceq;
2199 case Operator.BitwiseOr:
2200 opcode = OpCodes.Or;
2203 case Operator.BitwiseAnd:
2204 opcode = OpCodes.And;
2207 case Operator.ExclusiveOr:
2208 opcode = OpCodes.Xor;
2212 throw new InternalErrorException (oper.ToString ());
2218 static bool IsUnsigned (Type t)
2223 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2224 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2227 static bool IsFloat (Type t)
2229 return t == TypeManager.float_type || t == TypeManager.double_type;
2232 Expression ResolveOperator (EmitContext ec)
2235 Type r = right.Type;
2237 bool primitives_only = false;
2239 if (standard_operators == null)
2240 CreateStandardOperatorsTable ();
2243 // Handles predefined primitive types
2245 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2246 if ((oper & Operator.ShiftMask) == 0) {
2247 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2250 primitives_only = true;
2254 if (l.IsPointer || r.IsPointer)
2255 return ResolveOperatorPointer (ec, l, r);
2258 bool lenum = TypeManager.IsEnumType (l);
2259 bool renum = TypeManager.IsEnumType (r);
2260 if (lenum || renum) {
2261 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2263 // TODO: Can this be ambiguous
2269 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2270 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2272 expr = ResolveOperatorDelegate (ec, l, r);
2274 // TODO: Can this be ambiguous
2280 expr = ResolveUserOperator (ec, l, r);
2284 // Predefined reference types equality
2285 if ((oper & Operator.EqualityMask) != 0) {
2286 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2292 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2295 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2296 // if 'left' is not an enumeration constant, create one from the type of 'right'
2297 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2300 case Operator.BitwiseOr:
2301 case Operator.BitwiseAnd:
2302 case Operator.ExclusiveOr:
2303 case Operator.Equality:
2304 case Operator.Inequality:
2305 case Operator.LessThan:
2306 case Operator.LessThanOrEqual:
2307 case Operator.GreaterThan:
2308 case Operator.GreaterThanOrEqual:
2309 if (TypeManager.IsEnumType (left.Type))
2312 if (left.IsZeroInteger)
2313 return left.TryReduce (ec, right.Type, loc);
2317 case Operator.Addition:
2318 case Operator.Subtraction:
2321 case Operator.Multiply:
2322 case Operator.Division:
2323 case Operator.Modulus:
2324 case Operator.LeftShift:
2325 case Operator.RightShift:
2326 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2330 Error_OperatorCannotBeApplied (this.left, this.right);
2335 // The `|' operator used on types which were extended is dangerous
2337 void CheckBitwiseOrOnSignExtended ()
2339 OpcodeCast lcast = left as OpcodeCast;
2340 if (lcast != null) {
2341 if (IsUnsigned (lcast.UnderlyingType))
2345 OpcodeCast rcast = right as OpcodeCast;
2346 if (rcast != null) {
2347 if (IsUnsigned (rcast.UnderlyingType))
2351 if (lcast == null && rcast == null)
2354 // FIXME: consider constants
2356 Report.Warning (675, 3, loc,
2357 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2358 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2361 static void CreatePointerOperatorsTable ()
2363 ArrayList temp = new ArrayList ();
2366 // Pointer arithmetic:
2368 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2369 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2370 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2371 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2373 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2374 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2375 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2376 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2379 // T* operator + (int y, T* x);
2380 // T* operator + (uint y, T *x);
2381 // T* operator + (long y, T *x);
2382 // T* operator + (ulong y, T *x);
2384 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
2385 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
2386 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
2387 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
2390 // long operator - (T* x, T *y)
2392 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2394 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2397 static void CreateStandardOperatorsTable ()
2399 ArrayList temp = new ArrayList ();
2400 Type bool_type = TypeManager.bool_type;
2402 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2403 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2404 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2405 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2406 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2407 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2408 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2410 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2411 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2412 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2413 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2414 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2415 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2416 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2418 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2420 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2421 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2422 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2424 temp.Add (new PredefinedOperator (bool_type,
2425 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2427 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2428 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2429 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2430 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2432 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2436 // Rules used during binary numeric promotion
2438 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2443 Constant c = prim_expr as Constant;
2445 temp = c.ConvertImplicitly (type);
2452 if (type == TypeManager.uint32_type) {
2453 etype = prim_expr.Type;
2454 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2455 type = TypeManager.int64_type;
2457 if (type != second_expr.Type) {
2458 c = second_expr as Constant;
2460 temp = c.ConvertImplicitly (type);
2462 temp = Convert.ImplicitNumericConversion (second_expr, type);
2468 } else if (type == TypeManager.uint64_type) {
2470 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2472 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2473 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2477 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2486 // 7.2.6.2 Binary numeric promotions
2488 public bool DoBinaryOperatorPromotion (EmitContext ec)
2490 Type ltype = left.Type;
2491 Type rtype = right.Type;
2494 foreach (Type t in ConstantFold.binary_promotions) {
2496 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2499 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2502 Type int32 = TypeManager.int32_type;
2503 if (ltype != int32) {
2504 Constant c = left as Constant;
2506 temp = c.ConvertImplicitly (int32);
2508 temp = Convert.ImplicitNumericConversion (left, int32);
2515 if (rtype != int32) {
2516 Constant c = right as Constant;
2518 temp = c.ConvertImplicitly (int32);
2520 temp = Convert.ImplicitNumericConversion (right, int32);
2530 public override Expression DoResolve (EmitContext ec)
2535 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2536 left = ((ParenthesizedExpression) left).Expr;
2537 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2541 if (left.eclass == ExprClass.Type) {
2542 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2546 left = left.Resolve (ec);
2551 Constant lc = left as Constant;
2553 if (lc != null && lc.Type == TypeManager.bool_type &&
2554 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2555 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2557 // FIXME: resolve right expression as unreachable
2558 // right.Resolve (ec);
2560 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2564 right = right.Resolve (ec);
2568 eclass = ExprClass.Value;
2569 Constant rc = right as Constant;
2571 // The conversion rules are ignored in enum context but why
2572 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2573 left = lc = EnumLiftUp (ec, lc, rc, loc);
2577 right = rc = EnumLiftUp (ec, rc, lc, loc);
2582 if (rc != null && lc != null) {
2583 int prev_e = Report.Errors;
2584 Expression e = ConstantFold.BinaryFold (
2585 ec, oper, lc, rc, loc);
2586 if (e != null || Report.Errors != prev_e)
2589 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2590 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2592 if ((ResolveOperator (ec)) == null) {
2593 Error_OperatorCannotBeApplied (left, right);
2602 // The result is a constant with side-effect
2603 return new SideEffectConstant (lc, right, loc);
2607 // Comparison warnings
2608 if ((oper & Operator.ComparisonMask) != 0) {
2609 if (left.Equals (right)) {
2610 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2612 CheckUselessComparison (lc, right.Type);
2613 CheckUselessComparison (rc, left.Type);
2616 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2617 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2618 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2619 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2621 return DoResolveCore (ec, left, right);
2624 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2626 Expression expr = ResolveOperator (ec);
2628 Error_OperatorCannotBeApplied (left_orig, right_orig);
2630 if (left == null || right == null)
2631 throw new InternalErrorException ("Invalid conversion");
2633 if (oper == Operator.BitwiseOr)
2634 CheckBitwiseOrOnSignExtended ();
2639 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2641 left.MutateHoistedGenericType (storey);
2642 right.MutateHoistedGenericType (storey);
2646 // D operator + (D x, D y)
2647 // D operator - (D x, D y)
2648 // bool operator == (D x, D y)
2649 // bool operator != (D x, D y)
2651 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2653 bool is_equality = (oper & Operator.EqualityMask) != 0;
2654 if (!TypeManager.IsEqual (l, r)) {
2656 if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
2657 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2662 } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
2663 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2674 // Resolve delegate equality as a user operator
2677 return ResolveUserOperator (ec, l, r);
2680 ArrayList args = new ArrayList (2);
2681 args.Add (new Argument (left, Argument.AType.Expression));
2682 args.Add (new Argument (right, Argument.AType.Expression));
2684 if (oper == Operator.Addition) {
2685 if (TypeManager.delegate_combine_delegate_delegate == null) {
2686 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2687 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2690 method = TypeManager.delegate_combine_delegate_delegate;
2692 if (TypeManager.delegate_remove_delegate_delegate == null) {
2693 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2694 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2697 method = TypeManager.delegate_remove_delegate_delegate;
2700 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2701 mg = mg.OverloadResolve (ec, ref args, false, loc);
2703 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2707 // Enumeration operators
2709 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2712 // bool operator == (E x, E y);
2713 // bool operator != (E x, E y);
2714 // bool operator < (E x, E y);
2715 // bool operator > (E x, E y);
2716 // bool operator <= (E x, E y);
2717 // bool operator >= (E x, E y);
2719 // E operator & (E x, E y);
2720 // E operator | (E x, E y);
2721 // E operator ^ (E x, E y);
2723 // U operator - (E e, E f)
2724 // E operator - (E e, U x)
2726 // E operator + (U x, E e)
2727 // E operator + (E e, U x)
2729 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2730 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2733 Expression ltemp = left;
2734 Expression rtemp = right;
2735 Type underlying_type;
2737 if (TypeManager.IsEqual (ltype, rtype)) {
2738 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2740 if (left is Constant)
2741 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2743 left = EmptyCast.Create (left, underlying_type);
2745 if (right is Constant)
2746 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2748 right = EmptyCast.Create (right, underlying_type);
2750 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2752 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2753 Constant c = right as Constant;
2754 if (c == null || !c.IsDefaultValue)
2757 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2760 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2763 if (left is Constant)
2764 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2766 left = EmptyCast.Create (left, underlying_type);
2769 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2771 if (oper != Operator.Addition) {
2772 Constant c = left as Constant;
2773 if (c == null || !c.IsDefaultValue)
2776 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2779 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2782 if (right is Constant)
2783 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2785 right = EmptyCast.Create (right, underlying_type);
2792 // C# specification uses explicit cast syntax which means binary promotion
2793 // should happen, however it seems that csc does not do that
2795 if (!DoBinaryOperatorPromotion (ec)) {
2801 Type res_type = null;
2802 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2803 Type promoted_type = lenum ? left.Type : right.Type;
2804 enum_conversion = Convert.ExplicitNumericConversion (
2805 new EmptyExpression (promoted_type), underlying_type);
2807 if (oper == Operator.Subtraction && renum && lenum)
2808 res_type = underlying_type;
2809 else if (oper == Operator.Addition && renum)
2815 Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2816 if (!is_compound || expr == null)
2820 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2823 if (Convert.ImplicitConversionExists (ec, left, rtype))
2826 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2829 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2834 // 7.9.6 Reference type equality operators
2836 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2839 // operator != (object a, object b)
2840 // operator == (object a, object b)
2843 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2845 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2848 type = TypeManager.bool_type;
2849 GenericConstraints constraints;
2851 bool lgen = TypeManager.IsGenericParameter (l);
2853 if (TypeManager.IsEqual (l, r)) {
2856 // Only allow to compare same reference type parameter
2858 constraints = TypeManager.GetTypeParameterConstraints (l);
2859 if (constraints != null && constraints.IsReferenceType)
2865 if (l == TypeManager.anonymous_method_type)
2868 if (TypeManager.IsValueType (l))
2874 bool rgen = TypeManager.IsGenericParameter (r);
2877 // a, Both operands are reference-type values or the value null
2878 // b, One operand is a value of type T where T is a type-parameter and
2879 // the other operand is the value null. Furthermore T does not have the
2880 // value type constrain
2882 if (left is NullLiteral || right is NullLiteral) {
2884 constraints = TypeManager.GetTypeParameterConstraints (l);
2885 if (constraints != null && constraints.HasValueTypeConstraint)
2888 left = new BoxedCast (left, TypeManager.object_type);
2893 constraints = TypeManager.GetTypeParameterConstraints (r);
2894 if (constraints != null && constraints.HasValueTypeConstraint)
2897 right = new BoxedCast (right, TypeManager.object_type);
2903 // An interface is converted to the object before the
2904 // standard conversion is applied. It's not clear from the
2905 // standard but it looks like it works like that.
2908 constraints = TypeManager.GetTypeParameterConstraints (l);
2909 if (constraints == null || constraints.IsReferenceType)
2911 } else if (l.IsInterface) {
2912 l = TypeManager.object_type;
2913 } else if (l.IsValueType) {
2918 constraints = TypeManager.GetTypeParameterConstraints (r);
2919 if (constraints == null || constraints.IsReferenceType)
2921 } else if (r.IsInterface) {
2922 r = TypeManager.object_type;
2923 } else if (r.IsValueType) {
2928 const string ref_comparison = "Possible unintended reference comparison. " +
2929 "Consider casting the {0} side of the expression to `string' to compare the values";
2932 // A standard implicit conversion exists from the type of either
2933 // operand to the type of the other operand
2935 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2936 if (l == TypeManager.string_type)
2937 Report.Warning (253, 2, loc, ref_comparison, "right");
2942 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2943 if (r == TypeManager.string_type)
2944 Report.Warning (252, 2, loc, ref_comparison, "left");
2953 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2956 // bool operator == (void* x, void* y);
2957 // bool operator != (void* x, void* y);
2958 // bool operator < (void* x, void* y);
2959 // bool operator > (void* x, void* y);
2960 // bool operator <= (void* x, void* y);
2961 // bool operator >= (void* x, void* y);
2963 if ((oper & Operator.ComparisonMask) != 0) {
2966 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2973 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2979 type = TypeManager.bool_type;
2983 if (pointer_operators == null)
2984 CreatePointerOperatorsTable ();
2986 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2990 // Build-in operators method overloading
2992 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2994 PredefinedOperator best_operator = null;
2996 Type r = right.Type;
2997 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2999 foreach (PredefinedOperator po in operators) {
3000 if ((po.OperatorsMask & oper_mask) == 0)
3003 if (primitives_only) {
3004 if (!po.IsPrimitiveApplicable (l, r))
3007 if (!po.IsApplicable (ec, left, right))
3011 if (best_operator == null) {
3013 if (primitives_only)
3019 best_operator = po.ResolveBetterOperator (ec, best_operator);
3021 if (best_operator == null) {
3022 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3023 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3030 if (best_operator == null)
3033 Expression expr = best_operator.ConvertResult (ec, this);
3034 if (enum_type == null)
3038 // HACK: required by enum_conversion
3040 expr.Type = enum_type;
3041 return EmptyCast.Create (expr, enum_type);
3045 // Performs user-operator overloading
3047 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3050 if (oper == Operator.LogicalAnd)
3051 user_oper = Operator.BitwiseAnd;
3052 else if (oper == Operator.LogicalOr)
3053 user_oper = Operator.BitwiseOr;
3057 string op = GetOperatorMetadataName (user_oper);
3059 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3060 MethodGroupExpr right_operators = null;
3062 if (!TypeManager.IsEqual (r, l)) {
3063 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3064 if (right_operators == null && left_operators == null)
3066 } else if (left_operators == null) {
3070 ArrayList args = new ArrayList (2);
3071 Argument larg = new Argument (left);
3073 Argument rarg = new Argument (right);
3076 MethodGroupExpr union;
3079 // User-defined operator implementations always take precedence
3080 // over predefined operator implementations
3082 if (left_operators != null && right_operators != null) {
3083 if (IsPredefinedUserOperator (l, user_oper)) {
3084 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3086 union = left_operators;
3087 } else if (IsPredefinedUserOperator (r, user_oper)) {
3088 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3090 union = right_operators;
3092 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3094 } else if (left_operators != null) {
3095 union = left_operators;
3097 union = right_operators;
3100 union = union.OverloadResolve (ec, ref args, true, loc);
3104 Expression oper_expr;
3106 // TODO: CreateExpressionTree is allocated every time
3107 if (user_oper != oper) {
3108 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3109 oper == Operator.LogicalAnd, loc).Resolve (ec);
3111 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3114 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3115 // and not invoke user operator
3117 if ((oper & Operator.EqualityMask) != 0) {
3118 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3119 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3120 type = TypeManager.bool_type;
3121 if (left is NullLiteral || right is NullLiteral)
3122 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3123 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
3125 // Two System.Delegate(s) are never equal
3137 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3142 private void CheckUselessComparison (Constant c, Type type)
3144 if (c == null || !IsTypeIntegral (type)
3145 || c is StringConstant
3146 || c is BoolConstant
3147 || c is FloatConstant
3148 || c is DoubleConstant
3149 || c is DecimalConstant
3155 if (c is ULongConstant) {
3156 ulong uvalue = ((ULongConstant) c).Value;
3157 if (uvalue > long.MaxValue) {
3158 if (type == TypeManager.byte_type ||
3159 type == TypeManager.sbyte_type ||
3160 type == TypeManager.short_type ||
3161 type == TypeManager.ushort_type ||
3162 type == TypeManager.int32_type ||
3163 type == TypeManager.uint32_type ||
3164 type == TypeManager.int64_type ||
3165 type == TypeManager.char_type)
3166 WarnUselessComparison (type);
3169 value = (long) uvalue;
3171 else if (c is ByteConstant)
3172 value = ((ByteConstant) c).Value;
3173 else if (c is SByteConstant)
3174 value = ((SByteConstant) c).Value;
3175 else if (c is ShortConstant)
3176 value = ((ShortConstant) c).Value;
3177 else if (c is UShortConstant)
3178 value = ((UShortConstant) c).Value;
3179 else if (c is IntConstant)
3180 value = ((IntConstant) c).Value;
3181 else if (c is UIntConstant)
3182 value = ((UIntConstant) c).Value;
3183 else if (c is LongConstant)
3184 value = ((LongConstant) c).Value;
3185 else if (c is CharConstant)
3186 value = ((CharConstant)c).Value;
3191 if (IsValueOutOfRange (value, type))
3192 WarnUselessComparison (type);
3195 static bool IsValueOutOfRange (long value, Type type)
3197 if (IsTypeUnsigned (type) && value < 0)
3199 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3200 type == TypeManager.byte_type && value >= 0x100 ||
3201 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3202 type == TypeManager.ushort_type && value >= 0x10000 ||
3203 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3204 type == TypeManager.uint32_type && value >= 0x100000000;
3207 static bool IsBuildInEqualityOperator (Type t)
3209 return t == TypeManager.object_type || t == TypeManager.string_type ||
3210 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3213 static bool IsPredefinedUserOperator (Type t, Operator op)
3216 // Some predefined types have user operators
3218 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3221 private static bool IsTypeIntegral (Type type)
3223 return type == TypeManager.uint64_type ||
3224 type == TypeManager.int64_type ||
3225 type == TypeManager.uint32_type ||
3226 type == TypeManager.int32_type ||
3227 type == TypeManager.ushort_type ||
3228 type == TypeManager.short_type ||
3229 type == TypeManager.sbyte_type ||
3230 type == TypeManager.byte_type ||
3231 type == TypeManager.char_type;
3234 private static bool IsTypeUnsigned (Type type)
3236 return type == TypeManager.uint64_type ||
3237 type == TypeManager.uint32_type ||
3238 type == TypeManager.ushort_type ||
3239 type == TypeManager.byte_type ||
3240 type == TypeManager.char_type;
3243 private void WarnUselessComparison (Type type)
3245 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}'",
3246 TypeManager.CSharpName (type));
3250 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3251 /// context of a conditional bool expression. This function will return
3252 /// false if it is was possible to use EmitBranchable, or true if it was.
3254 /// The expression's code is generated, and we will generate a branch to `target'
3255 /// if the resulting expression value is equal to isTrue
3257 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3259 ILGenerator ig = ec.ig;
3262 // This is more complicated than it looks, but its just to avoid
3263 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3264 // but on top of that we want for == and != to use a special path
3265 // if we are comparing against null
3267 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3268 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3271 // put the constant on the rhs, for simplicity
3273 if (left is Constant) {
3274 Expression swap = right;
3279 if (((Constant) right).IsZeroInteger) {
3280 left.EmitBranchable (ec, target, my_on_true);
3283 if (right.Type == TypeManager.bool_type) {
3284 // right is a boolean, and it's not 'false' => it is 'true'
3285 left.EmitBranchable (ec, target, !my_on_true);
3289 } else if (oper == Operator.LogicalAnd) {
3292 Label tests_end = ig.DefineLabel ();
3294 left.EmitBranchable (ec, tests_end, false);
3295 right.EmitBranchable (ec, target, true);
3296 ig.MarkLabel (tests_end);
3299 // This optimizes code like this
3300 // if (true && i > 4)
3302 if (!(left is Constant))
3303 left.EmitBranchable (ec, target, false);
3305 if (!(right is Constant))
3306 right.EmitBranchable (ec, target, false);
3311 } else if (oper == Operator.LogicalOr){
3313 left.EmitBranchable (ec, target, true);
3314 right.EmitBranchable (ec, target, true);
3317 Label tests_end = ig.DefineLabel ();
3318 left.EmitBranchable (ec, tests_end, true);
3319 right.EmitBranchable (ec, target, false);
3320 ig.MarkLabel (tests_end);
3325 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3326 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3327 oper == Operator.Equality || oper == Operator.Inequality)) {
3328 base.EmitBranchable (ec, target, on_true);
3336 bool is_unsigned = IsUnsigned (t) || IsFloat (t);
3339 case Operator.Equality:
3341 ig.Emit (OpCodes.Beq, target);
3343 ig.Emit (OpCodes.Bne_Un, target);
3346 case Operator.Inequality:
3348 ig.Emit (OpCodes.Bne_Un, target);
3350 ig.Emit (OpCodes.Beq, target);
3353 case Operator.LessThan:
3356 ig.Emit (OpCodes.Blt_Un, target);
3358 ig.Emit (OpCodes.Blt, target);
3361 ig.Emit (OpCodes.Bge_Un, target);
3363 ig.Emit (OpCodes.Bge, target);
3366 case Operator.GreaterThan:
3369 ig.Emit (OpCodes.Bgt_Un, target);
3371 ig.Emit (OpCodes.Bgt, target);
3374 ig.Emit (OpCodes.Ble_Un, target);
3376 ig.Emit (OpCodes.Ble, target);
3379 case Operator.LessThanOrEqual:
3382 ig.Emit (OpCodes.Ble_Un, target);
3384 ig.Emit (OpCodes.Ble, target);
3387 ig.Emit (OpCodes.Bgt_Un, target);
3389 ig.Emit (OpCodes.Bgt, target);
3393 case Operator.GreaterThanOrEqual:
3396 ig.Emit (OpCodes.Bge_Un, target);
3398 ig.Emit (OpCodes.Bge, target);
3401 ig.Emit (OpCodes.Blt_Un, target);
3403 ig.Emit (OpCodes.Blt, target);
3406 throw new InternalErrorException (oper.ToString ());
3410 public override void Emit (EmitContext ec)
3412 EmitOperator (ec, left.Type);
3415 protected virtual void EmitOperator (EmitContext ec, Type l)
3417 ILGenerator ig = ec.ig;
3420 // Handle short-circuit operators differently
3423 if ((oper & Operator.LogicalMask) != 0) {
3424 Label load_result = ig.DefineLabel ();
3425 Label end = ig.DefineLabel ();
3427 bool is_or = oper == Operator.LogicalOr;
3428 left.EmitBranchable (ec, load_result, is_or);
3430 ig.Emit (OpCodes.Br_S, end);
3432 ig.MarkLabel (load_result);
3433 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3441 // Optimize zero-based operations
3443 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3445 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3446 Constant rc = right as Constant;
3447 if (rc != null && rc.IsDefaultValue) {
3453 EmitOperatorOpcode (ec, oper, l);
3456 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3457 // expression because that would wrap lifted binary operation
3459 if (enum_conversion != null)
3460 enum_conversion.Emit (ec);
3463 public override void EmitSideEffect (EmitContext ec)
3465 if ((oper & Operator.LogicalMask) != 0 ||
3466 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3467 base.EmitSideEffect (ec);
3469 left.EmitSideEffect (ec);
3470 right.EmitSideEffect (ec);
3474 protected override void CloneTo (CloneContext clonectx, Expression t)
3476 Binary target = (Binary) t;
3478 target.left = left.Clone (clonectx);
3479 target.right = right.Clone (clonectx);
3482 public override Expression CreateExpressionTree (EmitContext ec)
3484 return CreateExpressionTree (ec, null);
3487 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3490 bool lift_arg = false;
3493 case Operator.Addition:
3494 if (method == null && ec.CheckState && !IsFloat (type))
3495 method_name = "AddChecked";
3497 method_name = "Add";
3499 case Operator.BitwiseAnd:
3500 method_name = "And";
3502 case Operator.BitwiseOr:
3505 case Operator.Division:
3506 method_name = "Divide";
3508 case Operator.Equality:
3509 method_name = "Equal";
3512 case Operator.ExclusiveOr:
3513 method_name = "ExclusiveOr";
3515 case Operator.GreaterThan:
3516 method_name = "GreaterThan";
3519 case Operator.GreaterThanOrEqual:
3520 method_name = "GreaterThanOrEqual";
3523 case Operator.Inequality:
3524 method_name = "NotEqual";
3527 case Operator.LeftShift:
3528 method_name = "LeftShift";
3530 case Operator.LessThan:
3531 method_name = "LessThan";
3534 case Operator.LessThanOrEqual:
3535 method_name = "LessThanOrEqual";
3538 case Operator.LogicalAnd:
3539 method_name = "AndAlso";
3541 case Operator.LogicalOr:
3542 method_name = "OrElse";
3544 case Operator.Modulus:
3545 method_name = "Modulo";
3547 case Operator.Multiply:
3548 if (method == null && ec.CheckState && !IsFloat (type))
3549 method_name = "MultiplyChecked";
3551 method_name = "Multiply";
3553 case Operator.RightShift:
3554 method_name = "RightShift";
3556 case Operator.Subtraction:
3557 if (method == null && ec.CheckState && !IsFloat (type))
3558 method_name = "SubtractChecked";
3560 method_name = "Subtract";
3564 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3567 ArrayList args = new ArrayList (2);
3568 args.Add (new Argument (left.CreateExpressionTree (ec)));
3569 args.Add (new Argument (right.CreateExpressionTree (ec)));
3570 if (method != null) {
3572 args.Add (new Argument (new BoolConstant (false, loc)));
3574 args.Add (new Argument (method.CreateExpressionTree (ec)));
3577 return CreateExpressionFactoryCall (method_name, args);
3582 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3583 // b, c, d... may be strings or objects.
3585 public class StringConcat : Expression {
3586 ArrayList arguments;
3588 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3591 type = TypeManager.string_type;
3592 eclass = ExprClass.Value;
3594 arguments = new ArrayList (2);
3599 public override Expression CreateExpressionTree (EmitContext ec)
3601 Argument arg = (Argument) arguments [0];
3602 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3606 // Creates nested calls tree from an array of arguments used for IL emit
3608 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3610 ArrayList concat_args = new ArrayList (2);
3611 ArrayList add_args = new ArrayList (3);
3613 concat_args.Add (left);
3614 add_args.Add (new Argument (left_etree));
3616 concat_args.Add (arguments [pos]);
3617 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3619 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3623 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3627 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3629 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3630 if (++pos == arguments.Count)
3633 left = new Argument (new EmptyExpression (method.Type));
3634 return CreateExpressionAddCall (ec, left, expr, pos);
3637 public override Expression DoResolve (EmitContext ec)
3642 public void Append (EmitContext ec, Expression operand)
3647 StringConstant sc = operand as StringConstant;
3649 if (arguments.Count != 0) {
3650 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3651 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3652 if (last_expr_constant != null) {
3653 last_argument.Expr = new StringConstant (
3654 last_expr_constant.Value + sc.Value, sc.Location);
3660 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3662 StringConcat concat_oper = operand as StringConcat;
3663 if (concat_oper != null) {
3664 arguments.AddRange (concat_oper.arguments);
3669 arguments.Add (new Argument (operand));
3672 Expression CreateConcatMemberExpression ()
3674 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3677 public override void Emit (EmitContext ec)
3679 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3680 concat = concat.Resolve (ec);
3687 // User-defined conditional logical operator
3689 public class ConditionalLogicalOperator : UserOperatorCall {
3690 readonly bool is_and;
3693 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3694 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3695 : base (oper_method, arguments, expr_tree, loc)
3697 this.is_and = is_and;
3700 public override Expression DoResolve (EmitContext ec)
3702 MethodInfo method = (MethodInfo)mg;
3703 type = TypeManager.TypeToCoreType (method.ReturnType);
3704 ParameterData pd = TypeManager.GetParameterData (method);
3705 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3706 Report.Error (217, loc,
3707 "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",
3708 TypeManager.CSharpSignature (method));
3712 Expression left_dup = new EmptyExpression (type);
3713 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3714 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3715 if (op_true == null || op_false == null) {
3716 Report.Error (218, loc,
3717 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3718 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3722 oper = is_and ? op_false : op_true;
3723 eclass = ExprClass.Value;
3727 public override void Emit (EmitContext ec)
3729 ILGenerator ig = ec.ig;
3730 Label end_target = ig.DefineLabel ();
3733 // Emit and duplicate left argument
3735 ((Argument)arguments [0]).Expr.Emit (ec);
3736 ig.Emit (OpCodes.Dup);
3737 arguments.RemoveAt (0);
3739 oper.EmitBranchable (ec, end_target, true);
3741 ig.MarkLabel (end_target);
3745 public class PointerArithmetic : Expression {
3746 Expression left, right;
3750 // We assume that `l' is always a pointer
3752 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3761 public override Expression CreateExpressionTree (EmitContext ec)
3763 Error_PointerInsideExpressionTree ();
3767 public override Expression DoResolve (EmitContext ec)
3769 eclass = ExprClass.Variable;
3771 if (left.Type == TypeManager.void_ptr_type) {
3772 Error (242, "The operation in question is undefined on void pointers");
3779 public override void Emit (EmitContext ec)
3781 Type op_type = left.Type;
3782 ILGenerator ig = ec.ig;
3784 // It must be either array or fixed buffer
3785 Type element = TypeManager.HasElementType (op_type) ?
3786 TypeManager.GetElementType (op_type) :
3787 AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3789 int size = GetTypeSize (element);
3790 Type rtype = right.Type;
3792 if (rtype.IsPointer){
3794 // handle (pointer - pointer)
3798 ig.Emit (OpCodes.Sub);
3802 ig.Emit (OpCodes.Sizeof, element);
3804 IntLiteral.EmitInt (ig, size);
3805 ig.Emit (OpCodes.Div);
3807 ig.Emit (OpCodes.Conv_I8);
3810 // handle + and - on (pointer op int)
3814 Constant right_const = right as Constant;
3815 if (right_const != null) {
3817 // Optimize 0-based arithmetic
3819 if (right_const.IsDefaultValue)
3823 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3827 ig.Emit (OpCodes.Sizeof, element);
3828 right = EmptyExpression.Null;
3833 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3834 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3835 ig.Emit (OpCodes.Conv_I);
3836 } else if (rtype == TypeManager.uint32_type) {
3837 ig.Emit (OpCodes.Conv_U);
3840 if (right_const == null && size != 1){
3842 ig.Emit (OpCodes.Sizeof, element);
3844 IntLiteral.EmitInt (ig, size);
3845 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3846 ig.Emit (OpCodes.Conv_I8);
3848 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3851 if (rtype == TypeManager.int64_type)
3852 ig.Emit (OpCodes.Conv_I);
3853 else if (rtype == TypeManager.uint64_type)
3854 ig.Emit (OpCodes.Conv_U);
3856 Binary.EmitOperatorOpcode (ec, op, op_type);
3862 /// Implements the ternary conditional operator (?:)
3864 public class Conditional : Expression {
3865 Expression expr, true_expr, false_expr;
3867 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3870 this.true_expr = true_expr;
3871 this.false_expr = false_expr;
3872 this.loc = expr.Location;
3875 public Expression Expr {
3881 public Expression TrueExpr {
3887 public Expression FalseExpr {
3893 public override Expression CreateExpressionTree (EmitContext ec)
3895 ArrayList args = new ArrayList (3);
3896 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3897 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3898 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3899 return CreateExpressionFactoryCall ("Condition", args);
3902 public override Expression DoResolve (EmitContext ec)
3904 expr = expr.Resolve (ec);
3909 if (expr.Type != TypeManager.bool_type){
3910 expr = Expression.ResolveBoolean (
3917 Assign ass = expr as Assign;
3918 if (ass != null && ass.Source is Constant) {
3919 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3922 true_expr = true_expr.Resolve (ec);
3923 false_expr = false_expr.Resolve (ec);
3925 if (true_expr == null || false_expr == null)
3928 eclass = ExprClass.Value;
3929 if (true_expr.Type == false_expr.Type) {
3930 type = true_expr.Type;
3931 if (type == TypeManager.null_type) {
3932 // TODO: probably will have to implement ConditionalConstant
3933 // to call method without return constant as well
3934 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3939 Type true_type = true_expr.Type;
3940 Type false_type = false_expr.Type;
3943 // First, if an implicit conversion exists from true_expr
3944 // to false_expr, then the result type is of type false_expr.Type
3946 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3949 // Check if both can convert implicitl to each other's type
3951 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3953 "Can not compute type of conditional expression " +
3954 "as `" + TypeManager.CSharpName (true_expr.Type) +
3955 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3956 "' convert implicitly to each other");
3961 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3965 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3966 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3971 // Dead code optimalization
3972 if (expr is BoolConstant){
3973 BoolConstant bc = (BoolConstant) expr;
3975 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3976 return bc.Value ? true_expr : false_expr;
3982 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3984 expr.MutateHoistedGenericType (storey);
3985 true_expr.MutateHoistedGenericType (storey);
3986 false_expr.MutateHoistedGenericType (storey);
3987 type = storey.MutateType (type);
3990 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3995 public override void Emit (EmitContext ec)
3997 ILGenerator ig = ec.ig;
3998 Label false_target = ig.DefineLabel ();
3999 Label end_target = ig.DefineLabel ();
4001 expr.EmitBranchable (ec, false_target, false);
4002 true_expr.Emit (ec);
4004 if (type.IsInterface) {
4005 LocalBuilder temp = ec.GetTemporaryLocal (type);
4006 ig.Emit (OpCodes.Stloc, temp);
4007 ig.Emit (OpCodes.Ldloc, temp);
4008 ec.FreeTemporaryLocal (temp, type);
4011 ig.Emit (OpCodes.Br, end_target);
4012 ig.MarkLabel (false_target);
4013 false_expr.Emit (ec);
4014 ig.MarkLabel (end_target);
4017 protected override void CloneTo (CloneContext clonectx, Expression t)
4019 Conditional target = (Conditional) t;
4021 target.expr = expr.Clone (clonectx);
4022 target.true_expr = true_expr.Clone (clonectx);
4023 target.false_expr = false_expr.Clone (clonectx);
4027 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
4028 LocalTemporary temp;
4031 public abstract HoistedVariable HoistedVariable { get; }
4032 public abstract bool IsFixed { get; }
4033 public abstract bool IsRef { get; }
4036 // Variable IL data, it has to be protected to encapsulate hoisted variables
4038 protected abstract ILocalVariable Variable { get; }
4041 // Variable flow-analysis data
4043 public abstract VariableInfo VariableInfo { get; }
4046 public void AddressOf (EmitContext ec, AddressOp mode)
4048 if (IsHoistedEmitRequired (ec)) {
4049 HoistedVariable.AddressOf (ec, mode);
4053 Variable.EmitAddressOf (ec);
4056 public override void Emit (EmitContext ec)
4061 public override void EmitSideEffect (EmitContext ec)
4067 // This method is used by parameters that are references, that are
4068 // being passed as references: we only want to pass the pointer (that
4069 // is already stored in the parameter, not the address of the pointer,
4070 // and not the value of the variable).
4072 public void EmitLoad (EmitContext ec)
4077 public void Emit (EmitContext ec, bool leave_copy)
4079 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4081 if (IsHoistedEmitRequired (ec)) {
4082 HoistedVariable.Emit (ec, leave_copy);
4090 // If we are a reference, we loaded on the stack a pointer
4091 // Now lets load the real value
4093 LoadFromPtr (ec.ig, type);
4097 ec.ig.Emit (OpCodes.Dup);
4100 temp = new LocalTemporary (Type);
4106 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4107 bool prepare_for_load)
4109 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4112 if (IsHoistedEmitRequired (ec)) {
4113 HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
4117 ILGenerator ig = ec.ig;
4124 // HACK: variable is already emitted when source is an initializer
4125 if (source is NewInitialize) {
4133 ig.Emit (OpCodes.Dup);
4135 temp = new LocalTemporary (Type);
4141 StoreFromPtr (ig, type);
4143 Variable.EmitAssign (ec);
4151 public bool IsHoisted {
4152 get { return HoistedVariable != null; }
4155 protected virtual bool IsHoistedEmitRequired (EmitContext ec)
4158 // Default implementation return true when there is a hosted variable
4160 return HoistedVariable != null;
4163 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4165 type = storey.MutateType (type);
4172 public class LocalVariableReference : VariableReference {
4173 public readonly string Name;
4175 public LocalInfo local_info;
4178 public LocalVariableReference (Block block, string name, Location l)
4183 eclass = ExprClass.Variable;
4187 // Setting `is_readonly' to false will allow you to create a writable
4188 // reference to a read-only variable. This is used by foreach and using.
4190 public LocalVariableReference (Block block, string name, Location l,
4191 LocalInfo local_info, bool is_readonly)
4192 : this (block, name, l)
4194 this.local_info = local_info;
4195 this.is_readonly = is_readonly;
4198 public override VariableInfo VariableInfo {
4199 get { return local_info.VariableInfo; }
4202 public override HoistedVariable HoistedVariable {
4203 get { return local_info.HoistedVariableReference; }
4207 // A local Variable is always fixed.
4209 public override bool IsFixed {
4210 get { return true; }
4213 public override bool IsRef {
4214 get { return false; }
4217 public bool IsReadOnly {
4218 get { return is_readonly; }
4221 public bool VerifyAssigned (EmitContext ec)
4223 VariableInfo variable_info = local_info.VariableInfo;
4224 return variable_info == null || variable_info.IsAssigned (ec, loc);
4227 void ResolveLocalInfo ()
4229 if (local_info == null) {
4230 local_info = Block.GetLocalInfo (Name);
4231 type = local_info.VariableType;
4232 is_readonly = local_info.ReadOnly;
4236 public override Expression CreateExpressionTree (EmitContext ec)
4238 ArrayList arg = new ArrayList (1);
4239 arg.Add (new Argument (this));
4240 return CreateExpressionFactoryCall ("Constant", arg);
4243 Expression DoResolveBase (EmitContext ec)
4245 type = local_info.VariableType;
4247 Expression e = Block.GetConstantExpression (Name);
4249 return e.Resolve (ec);
4251 VerifyAssigned (ec);
4254 // If we are referencing a variable from the external block
4255 // flag it for capturing
4257 if (ec.MustCaptureVariable (local_info)) {
4258 if (local_info.AddressTaken){
4259 AnonymousMethodBody.Error_AddressOfCapturedVar (local_info.Name, loc);
4263 if (!ec.IsInProbingMode) {
4264 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4265 storey.CaptureLocalVariable (ec, local_info);
4272 public override Expression DoResolve (EmitContext ec)
4274 ResolveLocalInfo ();
4275 local_info.Used = true;
4277 if (type == null && local_info.Type is VarExpr) {
4278 local_info.VariableType = TypeManager.object_type;
4279 Error_VariableIsUsedBeforeItIsDeclared (Name);
4283 return DoResolveBase (ec);
4286 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4288 ResolveLocalInfo ();
4291 if (right_side == EmptyExpression.OutAccess)
4292 local_info.Used = true;
4294 // Infer implicitly typed local variable
4296 VarExpr ve = local_info.Type as VarExpr;
4298 if (!ve.InferType (ec, right_side))
4300 type = local_info.VariableType = ve.Type;
4307 if (right_side == EmptyExpression.OutAccess) {
4308 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4309 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4310 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4311 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4312 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4314 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4316 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4320 if (VariableInfo != null)
4321 VariableInfo.SetAssigned (ec);
4323 return DoResolveBase (ec);
4326 public override int GetHashCode ()
4328 return Name.GetHashCode ();
4331 public override bool Equals (object obj)
4333 LocalVariableReference lvr = obj as LocalVariableReference;
4337 return Name == lvr.Name && Block == lvr.Block;
4340 protected override ILocalVariable Variable {
4341 get { return local_info; }
4344 public override string ToString ()
4346 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4349 protected override void CloneTo (CloneContext clonectx, Expression t)
4351 LocalVariableReference target = (LocalVariableReference) t;
4353 target.Block = clonectx.LookupBlock (Block);
4354 if (local_info != null)
4355 target.local_info = clonectx.LookupVariable (local_info);
4360 /// This represents a reference to a parameter in the intermediate
4363 public class ParameterReference : VariableReference {
4364 readonly ToplevelParameterInfo pi;
4365 readonly ToplevelBlock referenced;
4367 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4370 this.referenced = referenced;
4374 public override bool IsRef {
4375 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4378 bool HasOutModifier {
4379 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4382 public override HoistedVariable HoistedVariable {
4383 get { return pi.Parameter.HoistedVariableReference; }
4387 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4389 public override bool IsFixed {
4390 get { return pi.Parameter.ModFlags == Parameter.Modifier.NONE; }
4393 public string Name {
4394 get { return Parameter.Name; }
4397 public Parameter Parameter {
4398 get { return pi.Parameter; }
4401 public override VariableInfo VariableInfo {
4402 get { return pi.VariableInfo; }
4405 protected override ILocalVariable Variable {
4406 get { return Parameter; }
4409 public bool IsAssigned (EmitContext ec, Location loc)
4411 // HACK: Variables are not captured in probing mode
4412 if (ec.IsInProbingMode)
4415 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4418 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4422 void SetAssigned (EmitContext ec)
4424 if (HasOutModifier && ec.DoFlowAnalysis)
4425 ec.CurrentBranching.SetAssigned (VariableInfo);
4428 bool DoResolveBase (EmitContext ec)
4430 Parameter par = Parameter;
4431 type = par.ParameterType;
4432 eclass = ExprClass.Variable;
4434 AnonymousExpression am = ec.CurrentAnonymousMethod;
4438 ToplevelBlock declared = pi.Block;
4439 if (declared != referenced) {
4441 Report.Error (1628, loc,
4442 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4443 par.Name, am.ContainerType);
4451 // Don't capture parameters when the probing is on
4452 if (!ec.IsInProbingMode) {
4453 AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
4454 storey.CaptureParameter (ec, this);
4460 public override int GetHashCode ()
4462 return Name.GetHashCode ();
4465 public override bool Equals (object obj)
4467 ParameterReference pr = obj as ParameterReference;
4471 return Name == pr.Name && referenced == pr.referenced;
4474 protected override void CloneTo (CloneContext clonectx, Expression target)
4479 public override Expression CreateExpressionTree (EmitContext ec)
4481 if (IsHoistedEmitRequired (ec))
4482 return HoistedVariable.CreateExpressionTree (ec);
4484 return Parameter.ExpressionTreeVariableReference ();
4488 // Notice that for ref/out parameters, the type exposed is not the
4489 // same type exposed externally.
4492 // externally we expose "int&"
4493 // here we expose "int".
4495 // We record this in "is_ref". This means that the type system can treat
4496 // the type as it is expected, but when we generate the code, we generate
4497 // the alternate kind of code.
4499 public override Expression DoResolve (EmitContext ec)
4501 if (!DoResolveBase (ec))
4504 if (HasOutModifier && ec.DoFlowAnalysis &&
4505 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4511 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4513 if (!DoResolveBase (ec))
4516 // HACK: parameters are not captured when probing is on
4517 if (!ec.IsInProbingMode)
4523 static public void EmitLdArg (ILGenerator ig, int x)
4527 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4528 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4529 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4530 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4531 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4534 ig.Emit (OpCodes.Ldarg, x);
4537 public override string ToString ()
4539 return "ParameterReference[" + Name + "]";
4544 /// Used for arguments to New(), Invocation()
4546 public class Argument {
4547 public enum AType : byte {
4554 public static readonly Argument[] Empty = new Argument [0];
4556 public readonly AType ArgType;
4557 public Expression Expr;
4559 public Argument (Expression expr, AType type)
4562 this.ArgType = type;
4565 public Argument (Expression expr)
4568 this.ArgType = AType.Expression;
4573 if (ArgType == AType.Ref || ArgType == AType.Out)
4574 return TypeManager.GetReferenceType (Expr.Type);
4580 public Parameter.Modifier Modifier
4585 return Parameter.Modifier.OUT;
4588 return Parameter.Modifier.REF;
4591 return Parameter.Modifier.NONE;
4596 public string GetSignatureForError ()
4598 if (Expr.eclass == ExprClass.MethodGroup)
4599 return Expr.ExprClassName;
4601 return Expr.GetSignatureForError ();
4604 public bool ResolveMethodGroup (EmitContext ec)
4606 SimpleName sn = Expr as SimpleName;
4608 Expr = sn.GetMethodGroup ();
4610 // FIXME: csc doesn't report any error if you try to use `ref' or
4611 // `out' in a delegate creation expression.
4612 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4619 public bool Resolve (EmitContext ec, Location loc)
4624 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4625 // Verify that the argument is readable
4626 if (ArgType != AType.Out)
4627 Expr = Expr.Resolve (ec);
4629 // Verify that the argument is writeable
4630 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4631 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4633 return Expr != null;
4637 public void Emit (EmitContext ec)
4639 if (ArgType != AType.Ref && ArgType != AType.Out) {
4644 AddressOp mode = AddressOp.Store;
4645 if (ArgType == AType.Ref)
4646 mode |= AddressOp.Load;
4648 IMemoryLocation ml = (IMemoryLocation) Expr;
4649 ParameterReference pr = ml as ParameterReference;
4652 // ParameterReferences might already be references, so we want
4653 // to pass just the value
4655 if (pr != null && pr.IsRef)
4658 ml.AddressOf (ec, mode);
4661 public Argument Clone (CloneContext clonectx)
4663 return new Argument (Expr.Clone (clonectx), ArgType);
4668 /// Invocation of methods or delegates.
4670 public class Invocation : ExpressionStatement {
4671 protected ArrayList Arguments;
4672 protected Expression expr;
4673 protected MethodGroupExpr mg;
4674 bool arguments_resolved;
4677 // arguments is an ArrayList, but we do not want to typecast,
4678 // as it might be null.
4680 public Invocation (Expression expr, ArrayList arguments)
4682 SimpleName sn = expr as SimpleName;
4684 this.expr = sn.GetMethodGroup ();
4688 Arguments = arguments;
4690 loc = expr.Location;
4693 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4694 : this (expr, arguments)
4696 this.arguments_resolved = arguments_resolved;
4699 public override Expression CreateExpressionTree (EmitContext ec)
4704 // Special conversion for nested expression trees
4706 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4707 args = new ArrayList (1);
4708 args.Add (new Argument (this));
4709 return CreateExpressionFactoryCall ("Quote", args);
4712 ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
4714 int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
4717 args = new ArrayList (arg_count);
4720 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4722 args.Add (new Argument (new NullLiteral (loc)));
4724 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4727 // Use extension argument when exists
4730 Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
4732 args.Add (new Argument (e));
4735 if (Arguments != null) {
4736 foreach (Argument a in Arguments) {
4737 Expression e = a.Expr.CreateExpressionTree (ec);
4739 args.Add (new Argument (e));
4744 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4746 return CreateExpressionFactoryCall ("Call", args);
4749 public override Expression DoResolve (EmitContext ec)
4751 // Don't resolve already resolved expression
4752 if (eclass != ExprClass.Invalid)
4755 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4756 if (expr_resolved == null)
4759 mg = expr_resolved as MethodGroupExpr;
4761 Type expr_type = expr_resolved.Type;
4763 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4764 return (new DelegateInvocation (
4765 expr_resolved, Arguments, loc)).Resolve (ec);
4768 MemberExpr me = expr_resolved as MemberExpr;
4770 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4774 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4776 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4777 expr_resolved.GetSignatureForError ());
4781 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4785 // Next, evaluate all the expressions in the argument list
4787 if (Arguments != null && !arguments_resolved) {
4788 for (int i = 0; i < Arguments.Count; ++i)
4790 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4795 mg = DoResolveOverload (ec);
4799 MethodInfo method = (MethodInfo)mg;
4800 if (method != null) {
4801 type = TypeManager.TypeToCoreType (method.ReturnType);
4803 // TODO: this is a copy of mg.ResolveMemberAccess method
4804 Expression iexpr = mg.InstanceExpression;
4805 if (method.IsStatic) {
4806 if (iexpr == null ||
4807 iexpr is This || iexpr is EmptyExpression ||
4808 mg.IdenticalTypeName) {
4809 mg.InstanceExpression = null;
4811 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4817 if (type.IsPointer){
4825 // Only base will allow this invocation to happen.
4827 if (mg.IsBase && method.IsAbstract){
4828 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4832 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4834 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4836 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4840 if (IsSpecialMethodInvocation (method)) {
4844 if (mg.InstanceExpression != null)
4845 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4847 eclass = ExprClass.Value;
4851 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4853 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4856 bool IsSpecialMethodInvocation (MethodBase method)
4858 if (!TypeManager.IsSpecialMethod (method))
4861 Report.SymbolRelatedToPreviousError (method);
4862 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4863 TypeManager.CSharpSignature (method, true));
4869 /// Emits a list of resolved Arguments that are in the arguments
4872 /// The MethodBase argument might be null if the
4873 /// emission of the arguments is known not to contain
4874 /// a `params' field (for example in constructors or other routines
4875 /// that keep their arguments in this structure)
4877 /// if `dup_args' is true, a copy of the arguments will be left
4878 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4879 /// which will be duplicated before any other args. Only EmitCall
4880 /// should be using this interface.
4882 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4884 if (arguments == null)
4887 int top = arguments.Count;
4888 LocalTemporary [] temps = null;
4890 if (dup_args && top != 0)
4891 temps = new LocalTemporary [top];
4893 int argument_index = 0;
4895 for (int i = 0; i < top; i++) {
4896 a = (Argument) arguments [argument_index++];
4899 ec.ig.Emit (OpCodes.Dup);
4900 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4905 if (this_arg != null)
4908 for (int i = 0; i < top; i ++) {
4909 temps [i].Emit (ec);
4910 temps [i].Release (ec);
4915 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4917 ParameterData pd = TypeManager.GetParameterData (mb);
4919 if (arguments == null)
4920 return Type.EmptyTypes;
4922 Argument a = (Argument) arguments [pd.Count - 1];
4923 Arglist list = (Arglist) a.Expr;
4925 return list.ArgumentTypes;
4929 /// This checks the ConditionalAttribute on the method
4931 public static bool IsMethodExcluded (MethodBase method)
4933 if (method.IsConstructor)
4936 method = TypeManager.DropGenericMethodArguments (method);
4937 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4938 IMethodData md = TypeManager.GetMethod (method);
4940 return md.IsExcluded ();
4942 // For some methods (generated by delegate class) GetMethod returns null
4943 // because they are not included in builder_to_method table
4947 return AttributeTester.IsConditionalMethodExcluded (method);
4951 /// is_base tells whether we want to force the use of the `call'
4952 /// opcode instead of using callvirt. Call is required to call
4953 /// a specific method, while callvirt will always use the most
4954 /// recent method in the vtable.
4956 /// is_static tells whether this is an invocation on a static method
4958 /// instance_expr is an expression that represents the instance
4959 /// it must be non-null if is_static is false.
4961 /// method is the method to invoke.
4963 /// Arguments is the list of arguments to pass to the method or constructor.
4965 public static void EmitCall (EmitContext ec, bool is_base,
4966 Expression instance_expr,
4967 MethodBase method, ArrayList Arguments, Location loc)
4969 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4972 // `dup_args' leaves an extra copy of the arguments on the stack
4973 // `omit_args' does not leave any arguments at all.
4974 // So, basically, you could make one call with `dup_args' set to true,
4975 // and then another with `omit_args' set to true, and the two calls
4976 // would have the same set of arguments. However, each argument would
4977 // only have been evaluated once.
4978 public static void EmitCall (EmitContext ec, bool is_base,
4979 Expression instance_expr,
4980 MethodBase method, ArrayList Arguments, Location loc,
4981 bool dup_args, bool omit_args)
4983 ILGenerator ig = ec.ig;
4984 bool struct_call = false;
4985 bool this_call = false;
4986 LocalTemporary this_arg = null;
4988 Type decl_type = method.DeclaringType;
4990 if (!ec.IsInObsoleteScope) {
4992 // This checks ObsoleteAttribute on the method and on the declaring type
4994 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4996 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4998 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5000 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5004 if (IsMethodExcluded (method))
5007 bool is_static = method.IsStatic;
5009 if (instance_expr == EmptyExpression.Null) {
5010 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5014 this_call = instance_expr is This;
5015 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5019 // If this is ourselves, push "this"
5023 Type iexpr_type = instance_expr.Type;
5026 // Push the instance expression
5028 if (TypeManager.IsValueType (iexpr_type)) {
5030 // Special case: calls to a function declared in a
5031 // reference-type with a value-type argument need
5032 // to have their value boxed.
5033 if (decl_type.IsValueType ||
5034 TypeManager.IsGenericParameter (iexpr_type)) {
5036 // If the expression implements IMemoryLocation, then
5037 // we can optimize and use AddressOf on the
5040 // If not we have to use some temporary storage for
5042 if (instance_expr is IMemoryLocation) {
5043 ((IMemoryLocation)instance_expr).
5044 AddressOf (ec, AddressOp.LoadStore);
5046 LocalTemporary temp = new LocalTemporary (iexpr_type);
5047 instance_expr.Emit (ec);
5049 temp.AddressOf (ec, AddressOp.Load);
5052 // avoid the overhead of doing this all the time.
5054 t = TypeManager.GetReferenceType (iexpr_type);
5056 instance_expr.Emit (ec);
5057 ig.Emit (OpCodes.Box, instance_expr.Type);
5058 t = TypeManager.object_type;
5061 instance_expr.Emit (ec);
5062 t = instance_expr.Type;
5066 ig.Emit (OpCodes.Dup);
5067 if (Arguments != null && Arguments.Count != 0) {
5068 this_arg = new LocalTemporary (t);
5069 this_arg.Store (ec);
5076 EmitArguments (ec, Arguments, dup_args, this_arg);
5079 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5080 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5084 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5085 call_op = OpCodes.Call;
5087 call_op = OpCodes.Callvirt;
5089 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5090 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5091 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5098 // and DoFoo is not virtual, you can omit the callvirt,
5099 // because you don't need the null checking behavior.
5101 if (method is MethodInfo)
5102 ig.Emit (call_op, (MethodInfo) method);
5104 ig.Emit (call_op, (ConstructorInfo) method);
5107 public override void Emit (EmitContext ec)
5109 mg.EmitCall (ec, Arguments);
5112 public override void EmitStatement (EmitContext ec)
5117 // Pop the return value if there is one
5119 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5120 ec.ig.Emit (OpCodes.Pop);
5123 protected override void CloneTo (CloneContext clonectx, Expression t)
5125 Invocation target = (Invocation) t;
5127 if (Arguments != null) {
5128 target.Arguments = new ArrayList (Arguments.Count);
5129 foreach (Argument a in Arguments)
5130 target.Arguments.Add (a.Clone (clonectx));
5133 target.expr = expr.Clone (clonectx);
5136 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5138 mg.MutateHoistedGenericType (storey);
5139 if (Arguments != null) {
5140 foreach (Argument a in Arguments)
5141 a.Expr.MutateHoistedGenericType (storey);
5146 public class InvocationOrCast : ExpressionStatement
5149 Expression argument;
5151 public InvocationOrCast (Expression expr, Expression argument)
5154 this.argument = argument;
5155 this.loc = expr.Location;
5158 public override Expression CreateExpressionTree (EmitContext ec)
5160 throw new NotSupportedException ("ET");
5163 public override Expression DoResolve (EmitContext ec)
5166 // First try to resolve it as a cast.
5168 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5169 if ((te != null) && (te.eclass == ExprClass.Type)) {
5170 Cast cast = new Cast (te, argument, loc);
5171 return cast.Resolve (ec);
5175 // This can either be a type or a delegate invocation.
5176 // Let's just resolve it and see what we'll get.
5178 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5183 // Ok, so it's a Cast.
5185 if (expr.eclass == ExprClass.Type) {
5186 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5187 return cast.Resolve (ec);
5191 // It's a delegate invocation.
5193 if (!TypeManager.IsDelegateType (expr.Type)) {
5194 Error (149, "Method name expected");
5198 ArrayList args = new ArrayList ();
5199 args.Add (new Argument (argument, Argument.AType.Expression));
5200 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5201 return invocation.Resolve (ec);
5204 public override ExpressionStatement ResolveStatement (EmitContext ec)
5207 // First try to resolve it as a cast.
5209 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5210 if ((te != null) && (te.eclass == ExprClass.Type)) {
5211 Error_InvalidExpressionStatement ();
5216 // This can either be a type or a delegate invocation.
5217 // Let's just resolve it and see what we'll get.
5219 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5220 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5221 Error_InvalidExpressionStatement ();
5226 // It's a delegate invocation.
5228 if (!TypeManager.IsDelegateType (expr.Type)) {
5229 Error (149, "Method name expected");
5233 ArrayList args = new ArrayList ();
5234 args.Add (new Argument (argument, Argument.AType.Expression));
5235 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5236 return invocation.ResolveStatement (ec);
5239 public override void Emit (EmitContext ec)
5241 throw new Exception ("Cannot happen");
5244 public override void EmitStatement (EmitContext ec)
5246 throw new Exception ("Cannot happen");
5249 protected override void CloneTo (CloneContext clonectx, Expression t)
5251 InvocationOrCast target = (InvocationOrCast) t;
5253 target.expr = expr.Clone (clonectx);
5254 target.argument = argument.Clone (clonectx);
5259 // This class is used to "disable" the code generation for the
5260 // temporary variable when initializing value types.
5262 sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5263 public void AddressOf (EmitContext ec, AddressOp Mode)
5270 /// Implements the new expression
5272 public class New : ExpressionStatement, IMemoryLocation {
5273 ArrayList Arguments;
5276 // During bootstrap, it contains the RequestedType,
5277 // but if `type' is not null, it *might* contain a NewDelegate
5278 // (because of field multi-initialization)
5280 public Expression RequestedType;
5282 MethodGroupExpr method;
5285 // If set, the new expression is for a value_target, and
5286 // we will not leave anything on the stack.
5288 protected Expression value_target;
5289 protected bool value_target_set;
5290 bool is_type_parameter = false;
5292 public New (Expression requested_type, ArrayList arguments, Location l)
5294 RequestedType = requested_type;
5295 Arguments = arguments;
5299 public bool SetTargetVariable (Expression value)
5301 value_target = value;
5302 value_target_set = true;
5303 if (!(value_target is IMemoryLocation)){
5304 Error_UnexpectedKind (null, "variable", loc);
5311 // This function is used to disable the following code sequence for
5312 // value type initialization:
5314 // AddressOf (temporary)
5318 // Instead the provide will have provided us with the address on the
5319 // stack to store the results.
5321 static Expression MyEmptyExpression;
5323 public void DisableTemporaryValueType ()
5325 if (MyEmptyExpression == null)
5326 MyEmptyExpression = new EmptyAddressOf ();
5329 // To enable this, look into:
5330 // test-34 and test-89 and self bootstrapping.
5332 // For instance, we can avoid a copy by using `newobj'
5333 // instead of Call + Push-temp on value types.
5334 // value_target = MyEmptyExpression;
5339 /// Converts complex core type syntax like 'new int ()' to simple constant
5341 public static Constant Constantify (Type t)
5343 if (t == TypeManager.int32_type)
5344 return new IntConstant (0, Location.Null);
5345 if (t == TypeManager.uint32_type)
5346 return new UIntConstant (0, Location.Null);
5347 if (t == TypeManager.int64_type)
5348 return new LongConstant (0, Location.Null);
5349 if (t == TypeManager.uint64_type)
5350 return new ULongConstant (0, Location.Null);
5351 if (t == TypeManager.float_type)
5352 return new FloatConstant (0, Location.Null);
5353 if (t == TypeManager.double_type)
5354 return new DoubleConstant (0, Location.Null);
5355 if (t == TypeManager.short_type)
5356 return new ShortConstant (0, Location.Null);
5357 if (t == TypeManager.ushort_type)
5358 return new UShortConstant (0, Location.Null);
5359 if (t == TypeManager.sbyte_type)
5360 return new SByteConstant (0, Location.Null);
5361 if (t == TypeManager.byte_type)
5362 return new ByteConstant (0, Location.Null);
5363 if (t == TypeManager.char_type)
5364 return new CharConstant ('\0', Location.Null);
5365 if (t == TypeManager.bool_type)
5366 return new BoolConstant (false, Location.Null);
5367 if (t == TypeManager.decimal_type)
5368 return new DecimalConstant (0, Location.Null);
5369 if (TypeManager.IsEnumType (t))
5370 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5376 // Checks whether the type is an interface that has the
5377 // [ComImport, CoClass] attributes and must be treated
5380 public Expression CheckComImport (EmitContext ec)
5382 if (!type.IsInterface)
5386 // Turn the call into:
5387 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5389 Type real_class = AttributeTester.GetCoClassAttribute (type);
5390 if (real_class == null)
5393 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5394 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5395 return cast.Resolve (ec);
5398 public override Expression CreateExpressionTree (EmitContext ec)
5400 ArrayList args = Arguments == null ?
5401 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5403 if (method == null) {
5404 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5406 args.Add (new Argument (method.CreateExpressionTree (ec)));
5407 if (Arguments != null) {
5409 foreach (Argument a in Arguments) {
5410 expr = a.Expr.CreateExpressionTree (ec);
5412 args.Add (new Argument (expr));
5417 return CreateExpressionFactoryCall ("New", args);
5420 public override Expression DoResolve (EmitContext ec)
5423 // The New DoResolve might be called twice when initializing field
5424 // expressions (see EmitFieldInitializers, the call to
5425 // GetInitializerExpression will perform a resolve on the expression,
5426 // and later the assign will trigger another resolution
5428 // This leads to bugs (#37014)
5431 if (RequestedType is NewDelegate)
5432 return RequestedType;
5436 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5442 if (type == TypeManager.void_type) {
5443 Error_VoidInvalidInTheContext (loc);
5447 if (type.IsPointer) {
5448 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5449 TypeManager.CSharpName (type));
5453 if (Arguments == null) {
5454 Expression c = Constantify (type);
5459 if (TypeManager.IsDelegateType (type)) {
5460 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5464 if (type.IsGenericParameter) {
5465 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5467 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5468 Error (304, String.Format (
5469 "Cannot create an instance of the " +
5470 "variable type '{0}' because it " +
5471 "doesn't have the new() constraint",
5476 if ((Arguments != null) && (Arguments.Count != 0)) {
5477 Error (417, String.Format (
5478 "`{0}': cannot provide arguments " +
5479 "when creating an instance of a " +
5480 "variable type.", type));
5484 if (TypeManager.activator_create_instance == null) {
5485 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5486 if (activator_type != null) {
5487 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5488 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5492 is_type_parameter = true;
5493 eclass = ExprClass.Value;
5498 if (type.IsAbstract && type.IsSealed) {
5499 Report.SymbolRelatedToPreviousError (type);
5500 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5504 if (type.IsInterface || type.IsAbstract){
5505 if (!TypeManager.IsGenericType (type)) {
5506 RequestedType = CheckComImport (ec);
5507 if (RequestedType != null)
5508 return RequestedType;
5511 Report.SymbolRelatedToPreviousError (type);
5512 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5516 bool is_struct = type.IsValueType;
5517 eclass = ExprClass.Value;
5520 // SRE returns a match for .ctor () on structs (the object constructor),
5521 // so we have to manually ignore it.
5523 if (is_struct && Arguments == null)
5526 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5527 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5528 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5530 if (Arguments != null){
5531 foreach (Argument a in Arguments){
5532 if (!a.Resolve (ec, loc))
5540 method = ml as MethodGroupExpr;
5541 if (method == null) {
5542 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5546 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5553 bool DoEmitTypeParameter (EmitContext ec)
5556 ILGenerator ig = ec.ig;
5557 // IMemoryLocation ml;
5559 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5560 new Type [] { type });
5562 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5563 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5564 ig.Emit (OpCodes.Call, ci);
5568 // Allow DoEmit() to be called multiple times.
5569 // We need to create a new LocalTemporary each time since
5570 // you can't share LocalBuilders among ILGeneators.
5571 LocalTemporary temp = new LocalTemporary (type);
5573 Label label_activator = ig.DefineLabel ();
5574 Label label_end = ig.DefineLabel ();
5576 temp.AddressOf (ec, AddressOp.Store);
5577 ig.Emit (OpCodes.Initobj, type);
5580 ig.Emit (OpCodes.Box, type);
5581 ig.Emit (OpCodes.Brfalse, label_activator);
5583 temp.AddressOf (ec, AddressOp.Store);
5584 ig.Emit (OpCodes.Initobj, type);
5586 ig.Emit (OpCodes.Br, label_end);
5588 ig.MarkLabel (label_activator);
5590 ig.Emit (OpCodes.Call, ci);
5591 ig.MarkLabel (label_end);
5594 throw new InternalErrorException ();
5599 // This DoEmit can be invoked in two contexts:
5600 // * As a mechanism that will leave a value on the stack (new object)
5601 // * As one that wont (init struct)
5603 // You can control whether a value is required on the stack by passing
5604 // need_value_on_stack. The code *might* leave a value on the stack
5605 // so it must be popped manually
5607 // If we are dealing with a ValueType, we have a few
5608 // situations to deal with:
5610 // * The target is a ValueType, and we have been provided
5611 // the instance (this is easy, we are being assigned).
5613 // * The target of New is being passed as an argument,
5614 // to a boxing operation or a function that takes a
5617 // In this case, we need to create a temporary variable
5618 // that is the argument of New.
5620 // Returns whether a value is left on the stack
5622 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5624 bool is_value_type = TypeManager.IsValueType (type);
5625 ILGenerator ig = ec.ig;
5630 // Allow DoEmit() to be called multiple times.
5631 // We need to create a new LocalTemporary each time since
5632 // you can't share LocalBuilders among ILGeneators.
5633 if (!value_target_set)
5634 value_target = new LocalTemporary (type);
5636 ml = (IMemoryLocation) value_target;
5637 ml.AddressOf (ec, AddressOp.Store);
5641 method.EmitArguments (ec, Arguments);
5645 ig.Emit (OpCodes.Initobj, type);
5647 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5648 if (need_value_on_stack){
5649 value_target.Emit (ec);
5654 ConstructorInfo ci = (ConstructorInfo) method;
5656 if (TypeManager.IsGenericType (type))
5657 ci = TypeBuilder.GetConstructor (type, ci);
5659 ig.Emit (OpCodes.Newobj, ci);
5664 public override void Emit (EmitContext ec)
5666 if (is_type_parameter)
5667 DoEmitTypeParameter (ec);
5672 public override void EmitStatement (EmitContext ec)
5674 bool value_on_stack;
5676 if (is_type_parameter)
5677 value_on_stack = DoEmitTypeParameter (ec);
5679 value_on_stack = DoEmit (ec, false);
5682 ec.ig.Emit (OpCodes.Pop);
5686 public virtual bool HasInitializer {
5692 public void AddressOf (EmitContext ec, AddressOp Mode)
5694 if (is_type_parameter) {
5695 LocalTemporary temp = new LocalTemporary (type);
5696 DoEmitTypeParameter (ec);
5698 temp.AddressOf (ec, Mode);
5702 if (!type.IsValueType){
5704 // We throw an exception. So far, I believe we only need to support
5706 // foreach (int j in new StructType ())
5709 throw new Exception ("AddressOf should not be used for classes");
5712 if (!value_target_set)
5713 value_target = new LocalTemporary (type);
5714 IMemoryLocation ml = (IMemoryLocation) value_target;
5716 ml.AddressOf (ec, AddressOp.Store);
5717 if (method == null) {
5718 ec.ig.Emit (OpCodes.Initobj, type);
5720 method.EmitArguments (ec, Arguments);
5721 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5724 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5727 protected override void CloneTo (CloneContext clonectx, Expression t)
5729 New target = (New) t;
5731 target.RequestedType = RequestedType.Clone (clonectx);
5732 if (Arguments != null){
5733 target.Arguments = new ArrayList ();
5734 foreach (Argument a in Arguments){
5735 target.Arguments.Add (a.Clone (clonectx));
5740 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5742 if (method != null) {
5743 method.MutateHoistedGenericType (storey);
5744 if (Arguments != null) {
5745 foreach (Argument a in Arguments)
5746 a.Expr.MutateHoistedGenericType (storey);
5750 type = storey.MutateType (type);
5755 /// 14.5.10.2: Represents an array creation expression.
5759 /// There are two possible scenarios here: one is an array creation
5760 /// expression that specifies the dimensions and optionally the
5761 /// initialization data and the other which does not need dimensions
5762 /// specified but where initialization data is mandatory.
5764 public class ArrayCreation : Expression {
5765 FullNamedExpression requested_base_type;
5766 ArrayList initializers;
5769 // The list of Argument types.
5770 // This is used to construct the `newarray' or constructor signature
5772 protected ArrayList arguments;
5774 protected Type array_element_type;
5775 bool expect_initializers = false;
5776 int num_arguments = 0;
5777 protected int dimensions;
5778 protected readonly string rank;
5780 protected ArrayList array_data;
5784 // The number of constants in array initializers
5785 int const_initializers_count;
5786 bool only_constant_initializers;
5788 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5790 this.requested_base_type = requested_base_type;
5791 this.initializers = initializers;
5795 arguments = new ArrayList ();
5797 foreach (Expression e in exprs) {
5798 arguments.Add (new Argument (e, Argument.AType.Expression));
5803 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5805 this.requested_base_type = requested_base_type;
5806 this.initializers = initializers;
5810 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5812 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5814 //dimensions = tmp.Length - 1;
5815 expect_initializers = true;
5818 void Error_IncorrectArrayInitializer ()
5820 Error (178, "Invalid rank specifier: expected `,' or `]'");
5823 protected override void Error_NegativeArrayIndex (Location loc)
5825 Report.Error (248, loc, "Cannot create an array with a negative size");
5828 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5830 if (specified_dims) {
5831 Argument a = (Argument) arguments [idx];
5833 if (!a.Resolve (ec, loc))
5836 Constant c = a.Expr as Constant;
5838 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5842 Report.Error (150, a.Expr.Location, "A constant value is expected");
5846 int value = (int) c.GetValue ();
5848 if (value != probe.Count) {
5849 Error_IncorrectArrayInitializer ();
5853 bounds [idx] = value;
5856 int child_bounds = -1;
5857 only_constant_initializers = true;
5858 for (int i = 0; i < probe.Count; ++i) {
5859 object o = probe [i];
5860 if (o is ArrayList) {
5861 ArrayList sub_probe = o as ArrayList;
5862 int current_bounds = sub_probe.Count;
5864 if (child_bounds == -1)
5865 child_bounds = current_bounds;
5867 else if (child_bounds != current_bounds){
5868 Error_IncorrectArrayInitializer ();
5871 if (idx + 1 >= dimensions){
5872 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5876 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5880 if (child_bounds != -1){
5881 Error_IncorrectArrayInitializer ();
5885 Expression element = ResolveArrayElement (ec, (Expression) o);
5886 if (element == null)
5889 // Initializers with the default values can be ignored
5890 Constant c = element as Constant;
5892 if (c.IsDefaultInitializer (array_element_type)) {
5896 ++const_initializers_count;
5899 only_constant_initializers = false;
5902 array_data.Add (element);
5909 public override Expression CreateExpressionTree (EmitContext ec)
5913 if (array_data == null) {
5914 args = new ArrayList (arguments.Count + 1);
5915 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5916 foreach (Argument a in arguments) {
5917 if (arguments.Count == 1) {
5918 Constant c = a.Expr as Constant;
5919 if (c.IsDefaultValue)
5920 return CreateExpressionFactoryCall ("NewArrayInit", args);
5922 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5925 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5928 if (dimensions > 1) {
5929 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5933 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5934 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5935 if (array_data != null) {
5936 foreach (Expression e in array_data)
5937 args.Add (new Argument (e.CreateExpressionTree (ec)));
5940 return CreateExpressionFactoryCall ("NewArrayInit", args);
5943 public void UpdateIndices ()
5946 for (ArrayList probe = initializers; probe != null;) {
5947 if (probe.Count > 0 && probe [0] is ArrayList) {
5948 Expression e = new IntConstant (probe.Count, Location.Null);
5949 arguments.Add (new Argument (e, Argument.AType.Expression));
5951 bounds [i++] = probe.Count;
5953 probe = (ArrayList) probe [0];
5956 Expression e = new IntConstant (probe.Count, Location.Null);
5957 arguments.Add (new Argument (e, Argument.AType.Expression));
5959 bounds [i++] = probe.Count;
5966 Expression first_emit;
5967 LocalTemporary first_emit_temp;
5969 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5971 element = element.Resolve (ec);
5972 if (element == null)
5975 if (element is CompoundAssign.Helper) {
5976 if (first_emit != null)
5977 throw new InternalErrorException ("Can only handle one mutator at a time");
5978 first_emit = element;
5979 element = first_emit_temp = new LocalTemporary (element.Type);
5982 return Convert.ImplicitConversionRequired (
5983 ec, element, array_element_type, loc);
5986 protected bool ResolveInitializers (EmitContext ec)
5988 if (initializers == null) {
5989 return !expect_initializers;
5993 // We use this to store all the date values in the order in which we
5994 // will need to store them in the byte blob later
5996 array_data = new ArrayList ();
5997 bounds = new System.Collections.Specialized.HybridDictionary ();
5999 if (arguments != null)
6000 return CheckIndices (ec, initializers, 0, true);
6002 arguments = new ArrayList ();
6004 if (!CheckIndices (ec, initializers, 0, false))
6013 // Resolved the type of the array
6015 bool ResolveArrayType (EmitContext ec)
6017 if (requested_base_type == null) {
6018 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
6022 StringBuilder array_qualifier = new StringBuilder (rank);
6025 // `In the first form allocates an array instace of the type that results
6026 // from deleting each of the individual expression from the expression list'
6028 if (num_arguments > 0) {
6029 array_qualifier.Append ("[");
6030 for (int i = num_arguments-1; i > 0; i--)
6031 array_qualifier.Append (",");
6032 array_qualifier.Append ("]");
6038 TypeExpr array_type_expr;
6039 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6040 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6041 if (array_type_expr == null)
6044 type = array_type_expr.Type;
6045 array_element_type = TypeManager.GetElementType (type);
6046 dimensions = type.GetArrayRank ();
6051 public override Expression DoResolve (EmitContext ec)
6056 if (!ResolveArrayType (ec))
6059 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
6060 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
6061 TypeManager.CSharpName (array_element_type));
6065 // First step is to validate the initializers and fill
6066 // in any missing bits
6068 if (!ResolveInitializers (ec))
6071 if (arguments.Count != dimensions) {
6072 Error_IncorrectArrayInitializer ();
6075 foreach (Argument a in arguments){
6076 if (!a.Resolve (ec, loc))
6079 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
6082 eclass = ExprClass.Value;
6086 MethodInfo GetArrayMethod (int arguments)
6088 ModuleBuilder mb = CodeGen.Module.Builder;
6090 Type[] arg_types = new Type[arguments];
6091 for (int i = 0; i < arguments; i++)
6092 arg_types[i] = TypeManager.int32_type;
6094 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6098 Report.Error (-6, "New invocation: Can not find a constructor for " +
6099 "this argument list");
6106 byte [] MakeByteBlob ()
6111 int count = array_data.Count;
6113 if (TypeManager.IsEnumType (array_element_type))
6114 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
6116 factor = GetTypeSize (array_element_type);
6118 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
6120 data = new byte [(count * factor + 3) & ~3];
6123 for (int i = 0; i < count; ++i) {
6124 object v = array_data [i];
6126 if (v is EnumConstant)
6127 v = ((EnumConstant) v).Child;
6129 if (v is Constant && !(v is StringConstant))
6130 v = ((Constant) v).GetValue ();
6136 if (array_element_type == TypeManager.int64_type){
6137 if (!(v is Expression)){
6138 long val = (long) v;
6140 for (int j = 0; j < factor; ++j) {
6141 data [idx + j] = (byte) (val & 0xFF);
6145 } else if (array_element_type == TypeManager.uint64_type){
6146 if (!(v is Expression)){
6147 ulong val = (ulong) v;
6149 for (int j = 0; j < factor; ++j) {
6150 data [idx + j] = (byte) (val & 0xFF);
6154 } else if (array_element_type == TypeManager.float_type) {
6155 if (!(v is Expression)){
6156 element = BitConverter.GetBytes ((float) v);
6158 for (int j = 0; j < factor; ++j)
6159 data [idx + j] = element [j];
6160 if (!BitConverter.IsLittleEndian)
6161 System.Array.Reverse (data, idx, 4);
6163 } else if (array_element_type == TypeManager.double_type) {
6164 if (!(v is Expression)){
6165 element = BitConverter.GetBytes ((double) v);
6167 for (int j = 0; j < factor; ++j)
6168 data [idx + j] = element [j];
6170 // FIXME: Handle the ARM float format.
6171 if (!BitConverter.IsLittleEndian)
6172 System.Array.Reverse (data, idx, 8);
6174 } else if (array_element_type == TypeManager.char_type){
6175 if (!(v is Expression)){
6176 int val = (int) ((char) v);
6178 data [idx] = (byte) (val & 0xff);
6179 data [idx+1] = (byte) (val >> 8);
6181 } else if (array_element_type == TypeManager.short_type){
6182 if (!(v is Expression)){
6183 int val = (int) ((short) v);
6185 data [idx] = (byte) (val & 0xff);
6186 data [idx+1] = (byte) (val >> 8);
6188 } else if (array_element_type == TypeManager.ushort_type){
6189 if (!(v is Expression)){
6190 int val = (int) ((ushort) v);
6192 data [idx] = (byte) (val & 0xff);
6193 data [idx+1] = (byte) (val >> 8);
6195 } else if (array_element_type == TypeManager.int32_type) {
6196 if (!(v is Expression)){
6199 data [idx] = (byte) (val & 0xff);
6200 data [idx+1] = (byte) ((val >> 8) & 0xff);
6201 data [idx+2] = (byte) ((val >> 16) & 0xff);
6202 data [idx+3] = (byte) (val >> 24);
6204 } else if (array_element_type == TypeManager.uint32_type) {
6205 if (!(v is Expression)){
6206 uint val = (uint) v;
6208 data [idx] = (byte) (val & 0xff);
6209 data [idx+1] = (byte) ((val >> 8) & 0xff);
6210 data [idx+2] = (byte) ((val >> 16) & 0xff);
6211 data [idx+3] = (byte) (val >> 24);
6213 } else if (array_element_type == TypeManager.sbyte_type) {
6214 if (!(v is Expression)){
6215 sbyte val = (sbyte) v;
6216 data [idx] = (byte) val;
6218 } else if (array_element_type == TypeManager.byte_type) {
6219 if (!(v is Expression)){
6220 byte val = (byte) v;
6221 data [idx] = (byte) val;
6223 } else if (array_element_type == TypeManager.bool_type) {
6224 if (!(v is Expression)){
6225 bool val = (bool) v;
6226 data [idx] = (byte) (val ? 1 : 0);
6228 } else if (array_element_type == TypeManager.decimal_type){
6229 if (!(v is Expression)){
6230 int [] bits = Decimal.GetBits ((decimal) v);
6233 // FIXME: For some reason, this doesn't work on the MS runtime.
6234 int [] nbits = new int [4];
6235 nbits [0] = bits [3];
6236 nbits [1] = bits [2];
6237 nbits [2] = bits [0];
6238 nbits [3] = bits [1];
6240 for (int j = 0; j < 4; j++){
6241 data [p++] = (byte) (nbits [j] & 0xff);
6242 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6243 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6244 data [p++] = (byte) (nbits [j] >> 24);
6248 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6256 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6258 array_element_type = storey.MutateType (array_element_type);
6259 type = storey.MutateType (type);
6260 if (arguments != null) {
6261 foreach (Argument a in arguments)
6262 a.Expr.MutateHoistedGenericType (storey);
6269 // Emits the initializers for the array
6271 void EmitStaticInitializers (EmitContext ec)
6273 // FIXME: This should go to Resolve !
6274 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6275 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6276 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6277 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6278 if (TypeManager.void_initializearray_array_fieldhandle == null)
6283 // First, the static data
6286 ILGenerator ig = ec.ig;
6288 byte [] data = MakeByteBlob ();
6290 fb = RootContext.MakeStaticData (data);
6292 ig.Emit (OpCodes.Dup);
6293 ig.Emit (OpCodes.Ldtoken, fb);
6294 ig.Emit (OpCodes.Call,
6295 TypeManager.void_initializearray_array_fieldhandle);
6299 // Emits pieces of the array that can not be computed at compile
6300 // time (variables and string locations).
6302 // This always expect the top value on the stack to be the array
6304 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6306 ILGenerator ig = ec.ig;
6307 int dims = bounds.Count;
6308 int [] current_pos = new int [dims];
6310 MethodInfo set = null;
6313 Type [] args = new Type [dims + 1];
6315 for (int j = 0; j < dims; j++)
6316 args [j] = TypeManager.int32_type;
6317 args [dims] = array_element_type;
6319 set = CodeGen.Module.Builder.GetArrayMethod (
6321 CallingConventions.HasThis | CallingConventions.Standard,
6322 TypeManager.void_type, args);
6325 for (int i = 0; i < array_data.Count; i++){
6327 Expression e = (Expression)array_data [i];
6329 // Constant can be initialized via StaticInitializer
6330 if (e != null && !(!emitConstants && e is Constant)) {
6331 Type etype = e.Type;
6333 ig.Emit (OpCodes.Dup);
6335 for (int idx = 0; idx < dims; idx++)
6336 IntConstant.EmitInt (ig, current_pos [idx]);
6339 // If we are dealing with a struct, get the
6340 // address of it, so we can store it.
6342 if ((dims == 1) && etype.IsValueType &&
6343 (!TypeManager.IsBuiltinOrEnum (etype) ||
6344 etype == TypeManager.decimal_type)) {
6349 // Let new know that we are providing
6350 // the address where to store the results
6352 n.DisableTemporaryValueType ();
6355 ig.Emit (OpCodes.Ldelema, etype);
6361 bool is_stobj, has_type_arg;
6362 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6364 ig.Emit (OpCodes.Stobj, etype);
6365 else if (has_type_arg)
6366 ig.Emit (op, etype);
6370 ig.Emit (OpCodes.Call, set);
6377 for (int j = dims - 1; j >= 0; j--){
6379 if (current_pos [j] < (int) bounds [j])
6381 current_pos [j] = 0;
6386 public override void Emit (EmitContext ec)
6388 ILGenerator ig = ec.ig;
6390 if (first_emit != null) {
6391 first_emit.Emit (ec);
6392 first_emit_temp.Store (ec);
6395 foreach (Argument a in arguments)
6398 if (arguments.Count == 1)
6399 ig.Emit (OpCodes.Newarr, array_element_type);
6401 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6404 if (initializers == null)
6407 // Emit static initializer for arrays which have contain more than 4 items and
6408 // the static initializer will initialize at least 25% of array values.
6409 // NOTE: const_initializers_count does not contain default constant values.
6410 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6411 TypeManager.IsPrimitiveType (array_element_type)) {
6412 EmitStaticInitializers (ec);
6414 if (!only_constant_initializers)
6415 EmitDynamicInitializers (ec, false);
6417 EmitDynamicInitializers (ec, true);
6420 if (first_emit_temp != null)
6421 first_emit_temp.Release (ec);
6424 public override bool GetAttributableValue (Type value_type, out object value)
6426 if (arguments.Count != 1) {
6427 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6428 return base.GetAttributableValue (null, out value);
6431 if (array_data == null) {
6432 Constant c = (Constant)((Argument)arguments [0]).Expr;
6433 if (c.IsDefaultValue) {
6434 value = Array.CreateInstance (array_element_type, 0);
6437 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6438 return base.GetAttributableValue (null, out value);
6441 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6442 object element_value;
6443 for (int i = 0; i < ret.Length; ++i)
6445 Expression e = (Expression)array_data [i];
6447 // Is null when an initializer is optimized (value == predefined value)
6451 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6455 ret.SetValue (element_value, i);
6461 protected override void CloneTo (CloneContext clonectx, Expression t)
6463 ArrayCreation target = (ArrayCreation) t;
6465 if (requested_base_type != null)
6466 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6468 if (arguments != null){
6469 target.arguments = new ArrayList (arguments.Count);
6470 foreach (Argument a in arguments)
6471 target.arguments.Add (a.Clone (clonectx));
6474 if (initializers != null){
6475 target.initializers = new ArrayList (initializers.Count);
6476 foreach (object initializer in initializers)
6477 if (initializer is ArrayList) {
6478 ArrayList this_al = (ArrayList)initializer;
6479 ArrayList al = new ArrayList (this_al.Count);
6480 target.initializers.Add (al);
6481 foreach (Expression e in this_al)
6482 al.Add (e.Clone (clonectx));
6484 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6491 // Represents an implicitly typed array epxression
6493 public class ImplicitlyTypedArrayCreation : ArrayCreation
6495 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6496 : base (null, rank, initializers, loc)
6498 if (RootContext.Version <= LanguageVersion.ISO_2)
6499 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6501 if (rank.Length > 2) {
6502 while (rank [++dimensions] == ',');
6508 public override Expression DoResolve (EmitContext ec)
6513 if (!ResolveInitializers (ec))
6516 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6517 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6518 arguments.Count != dimensions) {
6519 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6524 // At this point we found common base type for all initializer elements
6525 // but we have to be sure that all static initializer elements are of
6528 UnifyInitializerElement (ec);
6530 type = TypeManager.GetConstructedType (array_element_type, rank);
6531 eclass = ExprClass.Value;
6536 // Converts static initializer only
6538 void UnifyInitializerElement (EmitContext ec)
6540 for (int i = 0; i < array_data.Count; ++i) {
6541 Expression e = (Expression)array_data[i];
6543 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6547 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6549 element = element.Resolve (ec);
6550 if (element == null)
6553 if (array_element_type == null) {
6554 array_element_type = element.Type;
6558 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6562 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6563 array_element_type = element.Type;
6567 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6572 public sealed class CompilerGeneratedThis : This
6574 public static This Instance = new CompilerGeneratedThis ();
6576 private CompilerGeneratedThis ()
6577 : base (Location.Null)
6581 public CompilerGeneratedThis (Type type, Location loc)
6587 public override Expression DoResolve (EmitContext ec)
6589 eclass = ExprClass.Variable;
6591 type = ec.ContainerType;
6595 public override HoistedVariable HoistedVariable {
6596 get { return null; }
6601 /// Represents the `this' construct
6604 public class This : VariableReference
6606 class ThisVariable : ILocalVariable
6608 public static readonly ILocalVariable Instance = new ThisVariable ();
6610 public void Emit (EmitContext ec)
6612 ec.ig.Emit (OpCodes.Ldarg_0);
6615 public void EmitAssign (EmitContext ec)
6617 throw new InvalidOperationException ();
6620 public void EmitAddressOf (EmitContext ec)
6622 ec.ig.Emit (OpCodes.Ldarg_0);
6627 VariableInfo variable_info;
6630 public This (Block block, Location loc)
6636 public This (Location loc)
6641 public override VariableInfo VariableInfo {
6642 get { return variable_info; }
6645 public override bool IsFixed {
6646 get { return !TypeManager.IsValueType (type); }
6649 protected override bool IsHoistedEmitRequired (EmitContext ec)
6652 // Handle 'this' differently, it cannot be assigned hence
6653 // when we are not inside anonymous method we can emit direct access
6655 return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
6658 public override HoistedVariable HoistedVariable {
6659 get { return TopToplevelBlock.HoistedThisVariable; }
6662 public override bool IsRef {
6663 get { return is_struct; }
6666 protected override ILocalVariable Variable {
6667 get { return ThisVariable.Instance; }
6670 // TODO: Move to ToplevelBlock
6671 ToplevelBlock TopToplevelBlock {
6673 ToplevelBlock tl = block.Toplevel;
6674 while (tl.Parent != null) tl = tl.Parent.Toplevel;
6679 public bool ResolveBase (EmitContext ec)
6681 eclass = ExprClass.Variable;
6683 if (ec.TypeContainer.CurrentType != null)
6684 type = ec.TypeContainer.CurrentType;
6686 type = ec.ContainerType;
6688 is_struct = ec.TypeContainer is Struct;
6691 Error (26, "Keyword `this' is not valid in a static property, " +
6692 "static method, or static field initializer");
6696 if (block != null) {
6697 if (block.Toplevel.ThisVariable != null)
6698 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6700 AnonymousExpression am = ec.CurrentAnonymousMethod;
6702 if (is_struct && !am.IsIterator) {
6703 Report.Error (1673, loc, "Anonymous methods inside structs " +
6704 "cannot access instance members of `this'. " +
6705 "Consider copying `this' to a local variable " +
6706 "outside the anonymous method and using the " +
6711 // this is hoisted to very top level block
6713 if (!ec.IsInProbingMode) {
6714 // TODO: it could be optimized
6715 AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
6716 if (HoistedVariable == null) {
6717 TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
6727 // Called from Invocation to check if the invocation is correct
6729 public override void CheckMarshalByRefAccess (EmitContext ec)
6731 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6732 !variable_info.IsAssigned (ec)) {
6733 Error (188, "The `this' object cannot be used before all of its " +
6734 "fields are assigned to");
6735 variable_info.SetAssigned (ec);
6739 public override Expression CreateExpressionTree (EmitContext ec)
6741 ArrayList args = new ArrayList (2);
6742 args.Add (new Argument (this));
6743 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6744 return CreateExpressionFactoryCall ("Constant", args);
6747 public override Expression DoResolve (EmitContext ec)
6749 if (!ResolveBase (ec))
6753 if (ec.IsInFieldInitializer) {
6754 Error (27, "Keyword `this' is not available in the current context");
6761 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6763 if (!ResolveBase (ec))
6766 if (variable_info != null)
6767 variable_info.SetAssigned (ec);
6769 if (ec.TypeContainer is Class){
6770 Error (1604, "Cannot assign to 'this' because it is read-only");
6777 public override int GetHashCode()
6779 return block.GetHashCode ();
6782 public override bool Equals (object obj)
6784 This t = obj as This;
6788 return block == t.block;
6791 protected override void CloneTo (CloneContext clonectx, Expression t)
6793 This target = (This) t;
6795 target.block = clonectx.LookupBlock (block);
6798 public void RemoveHoisting ()
6800 TopToplevelBlock.HoistedThisVariable = null;
6805 /// Represents the `__arglist' construct
6807 public class ArglistAccess : Expression
6809 public ArglistAccess (Location loc)
6814 public override Expression CreateExpressionTree (EmitContext ec)
6816 throw new NotSupportedException ("ET");
6819 public override Expression DoResolve (EmitContext ec)
6821 eclass = ExprClass.Variable;
6822 type = TypeManager.runtime_argument_handle_type;
6824 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6826 Error (190, "The __arglist construct is valid only within " +
6827 "a variable argument method");
6834 public override void Emit (EmitContext ec)
6836 ec.ig.Emit (OpCodes.Arglist);
6839 protected override void CloneTo (CloneContext clonectx, Expression target)
6846 /// Represents the `__arglist (....)' construct
6848 public class Arglist : Expression
6850 Argument[] Arguments;
6852 public Arglist (Location loc)
6853 : this (Argument.Empty, loc)
6857 public Arglist (Argument[] args, Location l)
6863 public Type[] ArgumentTypes {
6865 Type[] retval = new Type [Arguments.Length];
6866 for (int i = 0; i < Arguments.Length; i++)
6867 retval [i] = Arguments [i].Type;
6872 public override Expression CreateExpressionTree (EmitContext ec)
6874 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6878 public override Expression DoResolve (EmitContext ec)
6880 eclass = ExprClass.Variable;
6881 type = TypeManager.runtime_argument_handle_type;
6883 foreach (Argument arg in Arguments) {
6884 if (!arg.Resolve (ec, loc))
6891 public override void Emit (EmitContext ec)
6893 foreach (Argument arg in Arguments)
6897 protected override void CloneTo (CloneContext clonectx, Expression t)
6899 Arglist target = (Arglist) t;
6901 target.Arguments = new Argument [Arguments.Length];
6902 for (int i = 0; i < Arguments.Length; i++)
6903 target.Arguments [i] = Arguments [i].Clone (clonectx);
6908 /// Implements the typeof operator
6910 public class TypeOf : Expression {
6911 Expression QueriedType;
6912 protected Type typearg;
6914 public TypeOf (Expression queried_type, Location l)
6916 QueriedType = queried_type;
6920 public override Expression CreateExpressionTree (EmitContext ec)
6922 ArrayList args = new ArrayList (2);
6923 args.Add (new Argument (this));
6924 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6925 return CreateExpressionFactoryCall ("Constant", args);
6928 public override Expression DoResolve (EmitContext ec)
6930 if (eclass != ExprClass.Invalid)
6933 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6937 typearg = texpr.Type;
6939 if (typearg == TypeManager.void_type) {
6940 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6944 if (typearg.IsPointer && !ec.InUnsafe){
6949 type = TypeManager.type_type;
6951 return DoResolveBase ();
6954 protected Expression DoResolveBase ()
6956 if (TypeManager.system_type_get_type_from_handle == null) {
6957 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6958 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6961 // Even though what is returned is a type object, it's treated as a value by the compiler.
6962 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6963 eclass = ExprClass.Value;
6967 public override void Emit (EmitContext ec)
6969 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6970 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6973 public override bool GetAttributableValue (Type value_type, out object value)
6975 if (TypeManager.ContainsGenericParameters (typearg) &&
6976 !TypeManager.IsGenericTypeDefinition (typearg)) {
6977 Report.SymbolRelatedToPreviousError (typearg);
6978 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6979 TypeManager.CSharpName (typearg));
6984 if (value_type == TypeManager.object_type) {
6985 value = (object)typearg;
6992 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6994 typearg = storey.MutateType (typearg);
6997 public Type TypeArgument {
7003 protected override void CloneTo (CloneContext clonectx, Expression t)
7005 TypeOf target = (TypeOf) t;
7006 if (QueriedType != null)
7007 target.QueriedType = QueriedType.Clone (clonectx);
7012 /// Implements the `typeof (void)' operator
7014 public class TypeOfVoid : TypeOf {
7015 public TypeOfVoid (Location l) : base (null, l)
7020 public override Expression DoResolve (EmitContext ec)
7022 type = TypeManager.type_type;
7023 typearg = TypeManager.void_type;
7025 return DoResolveBase ();
7029 class TypeOfMethodInfo : TypeOfMethod
7031 public TypeOfMethodInfo (MethodBase method, Location loc)
7032 : base (method, loc)
7036 public override Expression DoResolve (EmitContext ec)
7038 type = typeof (MethodInfo);
7039 return base.DoResolve (ec);
7042 public override void Emit (EmitContext ec)
7044 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
7046 ec.ig.Emit (OpCodes.Castclass, type);
7050 class TypeOfConstructorInfo : TypeOfMethod
7052 public TypeOfConstructorInfo (MethodBase method, Location loc)
7053 : base (method, loc)
7057 public override Expression DoResolve (EmitContext ec)
7059 type = typeof (ConstructorInfo);
7060 return base.DoResolve (ec);
7063 public override void Emit (EmitContext ec)
7065 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
7067 ec.ig.Emit (OpCodes.Castclass, type);
7071 abstract class TypeOfMethod : Expression
7073 protected readonly MethodBase method;
7075 protected TypeOfMethod (MethodBase method, Location loc)
7077 this.method = method;
7081 public override Expression CreateExpressionTree (EmitContext ec)
7083 ArrayList args = new ArrayList (2);
7084 args.Add (new Argument (this));
7085 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7086 return CreateExpressionFactoryCall ("Constant", args);
7089 public override Expression DoResolve (EmitContext ec)
7091 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7092 MethodInfo mi = is_generic ?
7093 TypeManager.methodbase_get_type_from_handle_generic :
7094 TypeManager.methodbase_get_type_from_handle;
7097 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
7098 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
7100 if (t == null || handle_type == null)
7103 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
7105 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7106 new Type[] { handle_type } );
7109 TypeManager.methodbase_get_type_from_handle_generic = mi;
7111 TypeManager.methodbase_get_type_from_handle = mi;
7114 eclass = ExprClass.Value;
7118 public override void Emit (EmitContext ec)
7120 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
7123 mi = TypeManager.methodbase_get_type_from_handle_generic;
7124 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
7126 mi = TypeManager.methodbase_get_type_from_handle;
7129 ec.ig.Emit (OpCodes.Call, mi);
7133 internal class TypeOfField : Expression
7135 readonly FieldInfo field;
7137 public TypeOfField (FieldInfo field, Location loc)
7143 public override Expression CreateExpressionTree (EmitContext ec)
7145 throw new NotSupportedException ("ET");
7148 public override Expression DoResolve (EmitContext ec)
7150 if (TypeManager.fieldinfo_get_field_from_handle == null) {
7151 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
7152 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
7154 if (t != null && handle_type != null)
7155 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
7156 "GetFieldFromHandle", loc, handle_type);
7159 type = typeof (FieldInfo);
7160 eclass = ExprClass.Value;
7164 public override void Emit (EmitContext ec)
7166 ec.ig.Emit (OpCodes.Ldtoken, field);
7167 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
7172 /// Implements the sizeof expression
7174 public class SizeOf : Expression {
7175 readonly Expression QueriedType;
7178 public SizeOf (Expression queried_type, Location l)
7180 this.QueriedType = queried_type;
7184 public override Expression CreateExpressionTree (EmitContext ec)
7186 Error_PointerInsideExpressionTree ();
7190 public override Expression DoResolve (EmitContext ec)
7192 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7196 type_queried = texpr.Type;
7197 if (TypeManager.IsEnumType (type_queried))
7198 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7200 if (type_queried == TypeManager.void_type) {
7201 Expression.Error_VoidInvalidInTheContext (loc);
7205 int size_of = GetTypeSize (type_queried);
7207 return new IntConstant (size_of, loc);
7210 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7215 Report.Error (233, loc,
7216 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7217 TypeManager.CSharpName (type_queried));
7220 type = TypeManager.int32_type;
7221 eclass = ExprClass.Value;
7225 public override void Emit (EmitContext ec)
7227 int size = GetTypeSize (type_queried);
7230 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7232 IntConstant.EmitInt (ec.ig, size);
7235 protected override void CloneTo (CloneContext clonectx, Expression t)
7241 /// Implements the qualified-alias-member (::) expression.
7243 public class QualifiedAliasMember : MemberAccess
7245 readonly string alias;
7247 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7248 : base (null, identifier, targs, l)
7253 public QualifiedAliasMember (string alias, string identifier, Location l)
7254 : base (null, identifier, l)
7259 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7261 if (alias == "global") {
7262 expr = RootNamespace.Global;
7263 return base.ResolveAsTypeStep (ec, silent);
7266 int errors = Report.Errors;
7267 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7269 if (errors == Report.Errors)
7270 Report.Error (432, loc, "Alias `{0}' not found", alias);
7274 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7278 if (expr.eclass == ExprClass.Type) {
7280 Report.Error (431, loc,
7281 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7289 public override Expression DoResolve (EmitContext ec)
7291 return ResolveAsTypeStep (ec, false);
7294 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7296 Report.Error (687, loc,
7297 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7298 GetSignatureForError ());
7301 public override string GetSignatureForError ()
7304 if (targs != null) {
7305 name = TypeManager.RemoveGenericArity (Name) + "<" +
7306 targs.GetSignatureForError () + ">";
7309 return alias + "::" + name;
7312 protected override void CloneTo (CloneContext clonectx, Expression t)
7319 /// Implements the member access expression
7321 public class MemberAccess : ATypeNameExpression {
7322 protected Expression expr;
7324 public MemberAccess (Expression expr, string id)
7325 : base (id, expr.Location)
7330 public MemberAccess (Expression expr, string identifier, Location loc)
7331 : base (identifier, loc)
7336 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7337 : base (identifier, args, loc)
7342 // TODO: this method has very poor performace for Enum fields and
7343 // probably for other constants as well
7344 Expression DoResolve (EmitContext ec, Expression right_side)
7347 throw new Exception ();
7350 // Resolve the expression with flow analysis turned off, we'll do the definite
7351 // assignment checks later. This is because we don't know yet what the expression
7352 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7353 // definite assignment check on the actual field and not on the whole struct.
7356 SimpleName original = expr as SimpleName;
7357 Expression expr_resolved = expr.Resolve (ec,
7358 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7359 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7361 if (expr_resolved == null)
7364 string LookupIdentifier = MemberName.MakeName (Name, targs);
7366 if (expr_resolved is Namespace) {
7367 Namespace ns = (Namespace) expr_resolved;
7368 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7370 if ((retval != null) && (targs != null))
7371 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7375 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7379 Type expr_type = expr_resolved.Type;
7380 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7381 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7382 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7386 Constant c = expr_resolved as Constant;
7387 if (c != null && c.GetValue () == null) {
7388 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7389 "System.NullReferenceException");
7392 if (targs != null) {
7393 if (!targs.Resolve (ec))
7397 Expression member_lookup;
7398 member_lookup = MemberLookup (
7399 ec.ContainerType, expr_type, expr_type, Name, loc);
7401 if ((member_lookup == null) && (targs != null)) {
7402 member_lookup = MemberLookup (
7403 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7406 if (member_lookup == null) {
7407 ExprClass expr_eclass = expr_resolved.eclass;
7410 // Extension methods are not allowed on all expression types
7412 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7413 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7414 expr_eclass == ExprClass.EventAccess) {
7415 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7416 if (ex_method_lookup != null) {
7417 ex_method_lookup.ExtensionExpression = expr_resolved;
7419 if (targs != null) {
7420 ex_method_lookup.SetTypeArguments (targs);
7423 return ex_method_lookup.DoResolve (ec);
7427 expr = expr_resolved;
7428 Error_MemberLookupFailed (
7429 ec.ContainerType, expr_type, expr_type, Name, null,
7430 AllMemberTypes, AllBindingFlags);
7434 TypeExpr texpr = member_lookup as TypeExpr;
7435 if (texpr != null) {
7436 if (!(expr_resolved is TypeExpr) &&
7437 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7438 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7439 Name, member_lookup.GetSignatureForError ());
7443 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7444 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7445 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7450 ConstructedType ct = expr_resolved as ConstructedType;
7453 // When looking up a nested type in a generic instance
7454 // via reflection, we always get a generic type definition
7455 // and not a generic instance - so we have to do this here.
7457 // See gtest-172-lib.cs and gtest-172.cs for an example.
7459 ct = new ConstructedType (
7460 member_lookup.Type, ct.TypeArguments, loc);
7462 return ct.ResolveAsTypeStep (ec, false);
7465 return member_lookup;
7468 MemberExpr me = (MemberExpr) member_lookup;
7469 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7473 if (targs != null) {
7474 me.SetTypeArguments (targs);
7477 if (original != null && !TypeManager.IsValueType (expr_type)) {
7478 if (me.IsInstance) {
7479 LocalVariableReference var = expr_resolved as LocalVariableReference;
7480 if (var != null && !var.VerifyAssigned (ec))
7485 // The following DoResolve/DoResolveLValue will do the definite assignment
7488 if (right_side != null)
7489 return me.DoResolveLValue (ec, right_side);
7491 return me.DoResolve (ec);
7494 public override Expression DoResolve (EmitContext ec)
7496 return DoResolve (ec, null);
7499 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7501 return DoResolve (ec, right_side);
7504 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7506 return ResolveNamespaceOrType (ec, silent);
7509 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7511 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7513 if (new_expr == null)
7516 string LookupIdentifier = MemberName.MakeName (Name, targs);
7518 if (new_expr is Namespace) {
7519 Namespace ns = (Namespace) new_expr;
7520 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7522 if ((retval != null) && (targs != null))
7523 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7525 if (!silent && retval == null)
7526 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7530 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7531 if (tnew_expr == null)
7534 Type expr_type = tnew_expr.Type;
7536 if (expr_type.IsPointer){
7537 Error (23, "The `.' operator can not be applied to pointer operands (" +
7538 TypeManager.CSharpName (expr_type) + ")");
7542 Expression member_lookup = MemberLookup (
7543 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7544 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7545 if (member_lookup == null) {
7549 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7553 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7558 TypeArguments the_args = targs;
7559 Type declaring_type = texpr.Type.DeclaringType;
7560 if (TypeManager.HasGenericArguments (declaring_type)) {
7561 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7562 expr_type = expr_type.BaseType;
7565 TypeArguments new_args = new TypeArguments (loc);
7566 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7567 new_args.Add (new TypeExpression (decl, loc));
7570 new_args.Add (targs);
7572 the_args = new_args;
7575 if (the_args != null) {
7576 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7577 return ctype.ResolveAsTypeStep (rc, false);
7584 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7586 Expression member_lookup = MemberLookup (
7587 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7588 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7590 if (member_lookup != null) {
7591 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7592 if (expr_type == null)
7595 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7599 member_lookup = MemberLookup (
7600 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7601 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7603 if (member_lookup == null) {
7604 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7605 Name, expr_type.GetSignatureForError ());
7607 // TODO: Report.SymbolRelatedToPreviousError
7608 member_lookup.Error_UnexpectedKind (null, "type", loc);
7612 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7614 if (RootContext.Version > LanguageVersion.ISO_2 &&
7615 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7616 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7617 "extension method `{1}' of type `{0}' could be found " +
7618 "(are you missing a using directive or an assembly reference?)",
7619 TypeManager.CSharpName (type), name);
7623 base.Error_TypeDoesNotContainDefinition (type, name);
7626 public override string GetSignatureForError ()
7628 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7631 protected override void CloneTo (CloneContext clonectx, Expression t)
7633 MemberAccess target = (MemberAccess) t;
7635 target.expr = expr.Clone (clonectx);
7640 /// Implements checked expressions
7642 public class CheckedExpr : Expression {
7644 public Expression Expr;
7646 public CheckedExpr (Expression e, Location l)
7652 public override Expression CreateExpressionTree (EmitContext ec)
7654 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7655 return Expr.CreateExpressionTree (ec);
7658 public override Expression DoResolve (EmitContext ec)
7660 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7661 Expr = Expr.Resolve (ec);
7666 if (Expr is Constant)
7669 eclass = Expr.eclass;
7674 public override void Emit (EmitContext ec)
7676 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7680 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7682 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7683 Expr.EmitBranchable (ec, target, on_true);
7686 protected override void CloneTo (CloneContext clonectx, Expression t)
7688 CheckedExpr target = (CheckedExpr) t;
7690 target.Expr = Expr.Clone (clonectx);
7695 /// Implements the unchecked expression
7697 public class UnCheckedExpr : Expression {
7699 public Expression Expr;
7701 public UnCheckedExpr (Expression e, Location l)
7707 public override Expression CreateExpressionTree (EmitContext ec)
7709 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7710 return Expr.CreateExpressionTree (ec);
7713 public override Expression DoResolve (EmitContext ec)
7715 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7716 Expr = Expr.Resolve (ec);
7721 if (Expr is Constant)
7724 eclass = Expr.eclass;
7729 public override void Emit (EmitContext ec)
7731 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7735 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7737 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7738 Expr.EmitBranchable (ec, target, on_true);
7741 protected override void CloneTo (CloneContext clonectx, Expression t)
7743 UnCheckedExpr target = (UnCheckedExpr) t;
7745 target.Expr = Expr.Clone (clonectx);
7750 /// An Element Access expression.
7752 /// During semantic analysis these are transformed into
7753 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7755 public class ElementAccess : Expression {
7756 public ArrayList Arguments;
7757 public Expression Expr;
7759 public ElementAccess (Expression e, ArrayList e_list)
7768 Arguments = new ArrayList ();
7769 foreach (Expression tmp in e_list)
7770 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7774 bool CommonResolve (EmitContext ec)
7776 Expr = Expr.Resolve (ec);
7778 if (Arguments == null)
7781 foreach (Argument a in Arguments){
7782 if (!a.Resolve (ec, loc))
7786 return Expr != null;
7789 public override Expression CreateExpressionTree (EmitContext ec)
7791 ArrayList args = new ArrayList (Arguments.Count + 1);
7792 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7793 foreach (Argument a in Arguments)
7794 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7796 return CreateExpressionFactoryCall ("ArrayIndex", args);
7799 Expression MakePointerAccess (EmitContext ec, Type t)
7801 if (t == TypeManager.void_ptr_type){
7802 Error (242, "The array index operation is not valid on void pointers");
7805 if (Arguments.Count != 1){
7806 Error (196, "A pointer must be indexed by only one value");
7810 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
7813 return new Indirection (p, loc).Resolve (ec);
7816 public override Expression DoResolve (EmitContext ec)
7818 if (!CommonResolve (ec))
7822 // We perform some simple tests, and then to "split" the emit and store
7823 // code we create an instance of a different class, and return that.
7825 // I am experimenting with this pattern.
7829 if (t == TypeManager.array_type){
7830 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7835 return (new ArrayAccess (this, loc)).Resolve (ec);
7837 return MakePointerAccess (ec, t);
7839 FieldExpr fe = Expr as FieldExpr;
7841 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7843 return MakePointerAccess (ec, ff.ElementType);
7846 return (new IndexerAccess (this, loc)).Resolve (ec);
7849 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7851 if (!CommonResolve (ec))
7856 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7859 return MakePointerAccess (ec, type);
7861 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7862 Error_CannotModifyIntermediateExpressionValue (ec);
7864 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7867 public override void Emit (EmitContext ec)
7869 throw new Exception ("Should never be reached");
7872 public override string GetSignatureForError ()
7874 return Expr.GetSignatureForError ();
7877 protected override void CloneTo (CloneContext clonectx, Expression t)
7879 ElementAccess target = (ElementAccess) t;
7881 target.Expr = Expr.Clone (clonectx);
7882 target.Arguments = new ArrayList (Arguments.Count);
7883 foreach (Argument a in Arguments)
7884 target.Arguments.Add (a.Clone (clonectx));
7889 /// Implements array access
7891 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7893 // Points to our "data" repository
7897 LocalTemporary temp;
7901 public ArrayAccess (ElementAccess ea_data, Location l)
7907 public override Expression CreateExpressionTree (EmitContext ec)
7909 return ea.CreateExpressionTree (ec);
7912 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7914 return DoResolve (ec);
7917 public override Expression DoResolve (EmitContext ec)
7920 ExprClass eclass = ea.Expr.eclass;
7922 // As long as the type is valid
7923 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7924 eclass == ExprClass.Value)) {
7925 ea.Expr.Error_UnexpectedKind ("variable or value");
7930 if (eclass != ExprClass.Invalid)
7933 Type t = ea.Expr.Type;
7934 int rank = ea.Arguments.Count;
7935 if (t.GetArrayRank () != rank) {
7936 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7937 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7941 type = TypeManager.GetElementType (t);
7942 if (type.IsPointer && !ec.InUnsafe) {
7943 UnsafeError (ea.Location);
7947 foreach (Argument a in ea.Arguments) {
7948 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7951 eclass = ExprClass.Variable;
7957 /// Emits the right opcode to load an object of Type `t'
7958 /// from an array of T
7960 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7963 MethodInfo get = FetchGetMethod ();
7964 ig.Emit (OpCodes.Call, get);
7968 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7969 ig.Emit (OpCodes.Ldelem_U1);
7970 else if (type == TypeManager.sbyte_type)
7971 ig.Emit (OpCodes.Ldelem_I1);
7972 else if (type == TypeManager.short_type)
7973 ig.Emit (OpCodes.Ldelem_I2);
7974 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7975 ig.Emit (OpCodes.Ldelem_U2);
7976 else if (type == TypeManager.int32_type)
7977 ig.Emit (OpCodes.Ldelem_I4);
7978 else if (type == TypeManager.uint32_type)
7979 ig.Emit (OpCodes.Ldelem_U4);
7980 else if (type == TypeManager.uint64_type)
7981 ig.Emit (OpCodes.Ldelem_I8);
7982 else if (type == TypeManager.int64_type)
7983 ig.Emit (OpCodes.Ldelem_I8);
7984 else if (type == TypeManager.float_type)
7985 ig.Emit (OpCodes.Ldelem_R4);
7986 else if (type == TypeManager.double_type)
7987 ig.Emit (OpCodes.Ldelem_R8);
7988 else if (type == TypeManager.intptr_type)
7989 ig.Emit (OpCodes.Ldelem_I);
7990 else if (TypeManager.IsEnumType (type)){
7991 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7992 } else if (type.IsValueType){
7993 ig.Emit (OpCodes.Ldelema, type);
7994 ig.Emit (OpCodes.Ldobj, type);
7996 } else if (type.IsGenericParameter) {
7997 ig.Emit (OpCodes.Ldelem, type);
7999 } else if (type.IsPointer)
8000 ig.Emit (OpCodes.Ldelem_I);
8002 ig.Emit (OpCodes.Ldelem_Ref);
8005 protected override void Error_NegativeArrayIndex (Location loc)
8007 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8011 /// Returns the right opcode to store an object of Type `t'
8012 /// from an array of T.
8014 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8016 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8017 has_type_arg = false; is_stobj = false;
8018 t = TypeManager.TypeToCoreType (t);
8019 if (TypeManager.IsEnumType (t))
8020 t = TypeManager.GetEnumUnderlyingType (t);
8021 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8022 t == TypeManager.bool_type)
8023 return OpCodes.Stelem_I1;
8024 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8025 t == TypeManager.char_type)
8026 return OpCodes.Stelem_I2;
8027 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8028 return OpCodes.Stelem_I4;
8029 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8030 return OpCodes.Stelem_I8;
8031 else if (t == TypeManager.float_type)
8032 return OpCodes.Stelem_R4;
8033 else if (t == TypeManager.double_type)
8034 return OpCodes.Stelem_R8;
8035 else if (t == TypeManager.intptr_type) {
8036 has_type_arg = true;
8038 return OpCodes.Stobj;
8039 } else if (t.IsValueType) {
8040 has_type_arg = true;
8042 return OpCodes.Stobj;
8044 } else if (t.IsGenericParameter) {
8045 has_type_arg = true;
8046 return OpCodes.Stelem;
8049 } else if (t.IsPointer)
8050 return OpCodes.Stelem_I;
8052 return OpCodes.Stelem_Ref;
8055 MethodInfo FetchGetMethod ()
8057 ModuleBuilder mb = CodeGen.Module.Builder;
8058 int arg_count = ea.Arguments.Count;
8059 Type [] args = new Type [arg_count];
8062 for (int i = 0; i < arg_count; i++){
8063 //args [i++] = a.Type;
8064 args [i] = TypeManager.int32_type;
8067 get = mb.GetArrayMethod (
8068 ea.Expr.Type, "Get",
8069 CallingConventions.HasThis |
8070 CallingConventions.Standard,
8076 MethodInfo FetchAddressMethod ()
8078 ModuleBuilder mb = CodeGen.Module.Builder;
8079 int arg_count = ea.Arguments.Count;
8080 Type [] args = new Type [arg_count];
8084 ret_type = TypeManager.GetReferenceType (type);
8086 for (int i = 0; i < arg_count; i++){
8087 //args [i++] = a.Type;
8088 args [i] = TypeManager.int32_type;
8091 address = mb.GetArrayMethod (
8092 ea.Expr.Type, "Address",
8093 CallingConventions.HasThis |
8094 CallingConventions.Standard,
8101 // Load the array arguments into the stack.
8103 void LoadArrayAndArguments (EmitContext ec)
8107 for (int i = 0; i < ea.Arguments.Count; ++i) {
8108 ((Argument)ea.Arguments [i]).Emit (ec);
8112 public void Emit (EmitContext ec, bool leave_copy)
8114 int rank = ea.Expr.Type.GetArrayRank ();
8115 ILGenerator ig = ec.ig;
8118 LoadFromPtr (ig, this.type);
8120 LoadArrayAndArguments (ec);
8121 EmitLoadOpcode (ig, type, rank);
8125 ig.Emit (OpCodes.Dup);
8126 temp = new LocalTemporary (this.type);
8131 public override void Emit (EmitContext ec)
8136 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8138 int rank = ea.Expr.Type.GetArrayRank ();
8139 ILGenerator ig = ec.ig;
8140 Type t = source.Type;
8141 prepared = prepare_for_load;
8144 AddressOf (ec, AddressOp.LoadStore);
8145 ec.ig.Emit (OpCodes.Dup);
8147 LoadArrayAndArguments (ec);
8151 bool is_stobj, has_type_arg;
8152 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8156 // The stobj opcode used by value types will need
8157 // an address on the stack, not really an array/array
8161 ig.Emit (OpCodes.Ldelema, t);
8166 ec.ig.Emit (OpCodes.Dup);
8167 temp = new LocalTemporary (this.type);
8172 StoreFromPtr (ig, t);
8174 ig.Emit (OpCodes.Stobj, t);
8175 else if (has_type_arg)
8182 ec.ig.Emit (OpCodes.Dup);
8183 temp = new LocalTemporary (this.type);
8188 StoreFromPtr (ig, t);
8190 int arg_count = ea.Arguments.Count;
8191 Type [] args = new Type [arg_count + 1];
8192 for (int i = 0; i < arg_count; i++) {
8193 //args [i++] = a.Type;
8194 args [i] = TypeManager.int32_type;
8196 args [arg_count] = type;
8198 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8199 ea.Expr.Type, "Set",
8200 CallingConventions.HasThis |
8201 CallingConventions.Standard,
8202 TypeManager.void_type, args);
8204 ig.Emit (OpCodes.Call, set);
8214 public void AddressOf (EmitContext ec, AddressOp mode)
8216 int rank = ea.Expr.Type.GetArrayRank ();
8217 ILGenerator ig = ec.ig;
8219 LoadArrayAndArguments (ec);
8222 ig.Emit (OpCodes.Ldelema, type);
8224 MethodInfo address = FetchAddressMethod ();
8225 ig.Emit (OpCodes.Call, address);
8229 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8231 type = storey.MutateType (type);
8236 /// Expressions that represent an indexer call.
8238 public class IndexerAccess : Expression, IAssignMethod
8240 class IndexerMethodGroupExpr : MethodGroupExpr
8242 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8245 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8248 public override string Name {
8254 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
8257 // Here is the trick, decrease number of arguments by 1 when only
8258 // available property method is setter. This makes overload resolution
8259 // work correctly for indexers.
8262 if (method.Name [0] == 'g')
8263 return parameters.Count;
8265 return parameters.Count - 1;
8271 // Contains either property getter or setter
8272 public ArrayList Methods;
8273 public ArrayList Properties;
8279 void Append (Type caller_type, MemberInfo [] mi)
8284 foreach (PropertyInfo property in mi) {
8285 MethodInfo accessor = property.GetGetMethod (true);
8286 if (accessor == null)
8287 accessor = property.GetSetMethod (true);
8289 if (Methods == null) {
8290 Methods = new ArrayList ();
8291 Properties = new ArrayList ();
8294 Methods.Add (accessor);
8295 Properties.Add (property);
8299 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8301 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8303 return TypeManager.MemberLookup (
8304 caller_type, caller_type, lookup_type, MemberTypes.Property,
8305 BindingFlags.Public | BindingFlags.Instance |
8306 BindingFlags.DeclaredOnly, p_name, null);
8309 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8311 Indexers ix = new Indexers ();
8314 if (lookup_type.IsGenericParameter) {
8315 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8319 if (gc.HasClassConstraint)
8320 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8322 Type[] ifaces = gc.InterfaceConstraints;
8323 foreach (Type itype in ifaces)
8324 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8330 Type copy = lookup_type;
8331 while (copy != TypeManager.object_type && copy != null){
8332 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8333 copy = copy.BaseType;
8336 if (lookup_type.IsInterface) {
8337 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8338 if (ifaces != null) {
8339 foreach (Type itype in ifaces)
8340 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8355 // Points to our "data" repository
8357 MethodInfo get, set;
8358 bool is_base_indexer;
8360 LocalTemporary temp;
8361 LocalTemporary prepared_value;
8362 Expression set_expr;
8364 protected Type indexer_type;
8365 protected Type current_type;
8366 protected Expression instance_expr;
8367 protected ArrayList arguments;
8369 public IndexerAccess (ElementAccess ea, Location loc)
8370 : this (ea.Expr, false, loc)
8372 this.arguments = ea.Arguments;
8375 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8378 this.instance_expr = instance_expr;
8379 this.is_base_indexer = is_base_indexer;
8380 this.eclass = ExprClass.Value;
8384 static string GetAccessorName (AccessorType at)
8386 if (at == AccessorType.Set)
8389 if (at == AccessorType.Get)
8392 throw new NotImplementedException (at.ToString ());
8395 public override Expression CreateExpressionTree (EmitContext ec)
8397 ArrayList args = new ArrayList (arguments.Count + 2);
8398 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8399 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8400 foreach (Argument a in arguments)
8401 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8403 return CreateExpressionFactoryCall ("Call", args);
8406 protected virtual bool CommonResolve (EmitContext ec)
8408 indexer_type = instance_expr.Type;
8409 current_type = ec.ContainerType;
8414 public override Expression DoResolve (EmitContext ec)
8416 return ResolveAccessor (ec, AccessorType.Get);
8419 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8421 if (right_side == EmptyExpression.OutAccess) {
8422 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8423 GetSignatureForError ());
8427 // if the indexer returns a value type, and we try to set a field in it
8428 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8429 Error_CannotModifyIntermediateExpressionValue (ec);
8432 Expression e = ResolveAccessor (ec, AccessorType.Set);
8436 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8440 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8442 if (!CommonResolve (ec))
8445 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8446 if (ilist.Methods == null) {
8447 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8448 TypeManager.CSharpName (indexer_type));
8452 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8453 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8457 MethodInfo mi = (MethodInfo) mg;
8458 PropertyInfo pi = null;
8459 for (int i = 0; i < ilist.Methods.Count; ++i) {
8460 if (ilist.Methods [i] == mi) {
8461 pi = (PropertyInfo) ilist.Properties [i];
8466 type = TypeManager.TypeToCoreType (pi.PropertyType);
8467 if (type.IsPointer && !ec.InUnsafe)
8470 MethodInfo accessor;
8471 if (accessorType == AccessorType.Get) {
8472 accessor = get = pi.GetGetMethod (true);
8474 accessor = set = pi.GetSetMethod (true);
8475 if (accessor == null && pi.GetGetMethod (true) != null) {
8476 Report.SymbolRelatedToPreviousError (pi);
8477 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8478 TypeManager.GetFullNameSignature (pi));
8483 if (accessor == null) {
8484 Report.SymbolRelatedToPreviousError (pi);
8485 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8486 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8491 // Only base will allow this invocation to happen.
8493 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8494 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8497 bool must_do_cs1540_check;
8498 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8500 set = pi.GetSetMethod (true);
8502 get = pi.GetGetMethod (true);
8504 if (set != null && get != null &&
8505 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8506 Report.SymbolRelatedToPreviousError (accessor);
8507 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8508 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8510 Report.SymbolRelatedToPreviousError (pi);
8511 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8515 instance_expr.CheckMarshalByRefAccess (ec);
8516 eclass = ExprClass.IndexerAccess;
8520 public void Emit (EmitContext ec, bool leave_copy)
8523 prepared_value.Emit (ec);
8525 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8526 arguments, loc, false, false);
8530 ec.ig.Emit (OpCodes.Dup);
8531 temp = new LocalTemporary (Type);
8537 // source is ignored, because we already have a copy of it from the
8538 // LValue resolution and we have already constructed a pre-cached
8539 // version of the arguments (ea.set_arguments);
8541 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8543 prepared = prepare_for_load;
8544 Expression value = set_expr;
8547 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8548 arguments, loc, true, false);
8550 prepared_value = new LocalTemporary (type);
8551 prepared_value.Store (ec);
8553 prepared_value.Release (ec);
8556 ec.ig.Emit (OpCodes.Dup);
8557 temp = new LocalTemporary (Type);
8560 } else if (leave_copy) {
8561 temp = new LocalTemporary (Type);
8567 arguments.Add (new Argument (value, Argument.AType.Expression));
8568 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8576 public override void Emit (EmitContext ec)
8581 public override string GetSignatureForError ()
8583 return TypeManager.CSharpSignature (get != null ? get : set, false);
8586 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8589 get = storey.MutateGenericMethod (get);
8591 set = storey.MutateGenericMethod (set);
8593 instance_expr.MutateHoistedGenericType (storey);
8594 foreach (Argument a in arguments)
8595 a.Expr.MutateHoistedGenericType (storey);
8597 type = storey.MutateType (type);
8600 protected override void CloneTo (CloneContext clonectx, Expression t)
8602 IndexerAccess target = (IndexerAccess) t;
8604 if (arguments != null){
8605 target.arguments = new ArrayList ();
8606 foreach (Argument a in arguments)
8607 target.arguments.Add (a.Clone (clonectx));
8609 if (instance_expr != null)
8610 target.instance_expr = instance_expr.Clone (clonectx);
8615 /// The base operator for method names
8617 public class BaseAccess : Expression {
8618 public readonly string Identifier;
8621 public BaseAccess (string member, Location l)
8623 this.Identifier = member;
8627 public BaseAccess (string member, TypeArguments args, Location l)
8633 public override Expression CreateExpressionTree (EmitContext ec)
8635 throw new NotSupportedException ("ET");
8638 public override Expression DoResolve (EmitContext ec)
8640 Expression c = CommonResolve (ec);
8646 // MethodGroups use this opportunity to flag an error on lacking ()
8648 if (!(c is MethodGroupExpr))
8649 return c.Resolve (ec);
8653 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8655 Expression c = CommonResolve (ec);
8661 // MethodGroups use this opportunity to flag an error on lacking ()
8663 if (! (c is MethodGroupExpr))
8664 return c.DoResolveLValue (ec, right_side);
8669 Expression CommonResolve (EmitContext ec)
8671 Expression member_lookup;
8672 Type current_type = ec.ContainerType;
8673 Type base_type = current_type.BaseType;
8676 Error (1511, "Keyword `base' is not available in a static method");
8680 if (ec.IsInFieldInitializer){
8681 Error (1512, "Keyword `base' is not available in the current context");
8685 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8686 AllMemberTypes, AllBindingFlags, loc);
8687 if (member_lookup == null) {
8688 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8689 null, AllMemberTypes, AllBindingFlags);
8696 left = new TypeExpression (base_type, loc);
8698 left = ec.GetThis (loc);
8700 MemberExpr me = (MemberExpr) member_lookup;
8701 me = me.ResolveMemberAccess (ec, left, loc, null);
8708 me.SetTypeArguments (args);
8714 public override void Emit (EmitContext ec)
8716 throw new Exception ("Should never be called");
8719 protected override void CloneTo (CloneContext clonectx, Expression t)
8721 BaseAccess target = (BaseAccess) t;
8724 target.args = args.Clone ();
8729 /// The base indexer operator
8731 public class BaseIndexerAccess : IndexerAccess {
8732 public BaseIndexerAccess (ArrayList args, Location loc)
8733 : base (null, true, loc)
8735 arguments = new ArrayList ();
8736 foreach (Expression tmp in args)
8737 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8740 protected override bool CommonResolve (EmitContext ec)
8742 instance_expr = ec.GetThis (loc);
8744 current_type = ec.ContainerType.BaseType;
8745 indexer_type = current_type;
8747 foreach (Argument a in arguments){
8748 if (!a.Resolve (ec, loc))
8755 public override Expression CreateExpressionTree (EmitContext ec)
8757 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8758 return base.CreateExpressionTree (ec);
8763 /// This class exists solely to pass the Type around and to be a dummy
8764 /// that can be passed to the conversion functions (this is used by
8765 /// foreach implementation to typecast the object return value from
8766 /// get_Current into the proper type. All code has been generated and
8767 /// we only care about the side effect conversions to be performed
8769 /// This is also now used as a placeholder where a no-action expression
8770 /// is needed (the `New' class).
8772 public class EmptyExpression : Expression {
8773 public static readonly EmptyExpression Null = new EmptyExpression ();
8775 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8776 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8777 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8779 static EmptyExpression temp = new EmptyExpression ();
8780 public static EmptyExpression Grab ()
8782 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8787 public static void Release (EmptyExpression e)
8792 // TODO: should be protected
8793 public EmptyExpression ()
8795 type = TypeManager.object_type;
8796 eclass = ExprClass.Value;
8797 loc = Location.Null;
8800 public EmptyExpression (Type t)
8803 eclass = ExprClass.Value;
8804 loc = Location.Null;
8807 public override Expression CreateExpressionTree (EmitContext ec)
8809 throw new NotSupportedException ("ET");
8812 public override Expression DoResolve (EmitContext ec)
8817 public override void Emit (EmitContext ec)
8819 // nothing, as we only exist to not do anything.
8822 public override void EmitSideEffect (EmitContext ec)
8827 // This is just because we might want to reuse this bad boy
8828 // instead of creating gazillions of EmptyExpressions.
8829 // (CanImplicitConversion uses it)
8831 public void SetType (Type t)
8838 // Empty statement expression
8840 public sealed class EmptyExpressionStatement : ExpressionStatement
8842 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8844 private EmptyExpressionStatement ()
8846 type = TypeManager.object_type;
8847 eclass = ExprClass.Value;
8848 loc = Location.Null;
8851 public override Expression CreateExpressionTree (EmitContext ec)
8856 public override void EmitStatement (EmitContext ec)
8861 public override Expression DoResolve (EmitContext ec)
8866 public override void Emit (EmitContext ec)
8872 public class UserCast : Expression {
8876 public UserCast (MethodInfo method, Expression source, Location l)
8878 this.method = method;
8879 this.source = source;
8880 type = TypeManager.TypeToCoreType (method.ReturnType);
8881 eclass = ExprClass.Value;
8885 public Expression Source {
8891 public override Expression CreateExpressionTree (EmitContext ec)
8893 ArrayList args = new ArrayList (3);
8894 args.Add (new Argument (source.CreateExpressionTree (ec)));
8895 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8896 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8897 return CreateExpressionFactoryCall ("Convert", args);
8900 public override Expression DoResolve (EmitContext ec)
8903 // We are born fully resolved
8908 public override void Emit (EmitContext ec)
8911 ec.ig.Emit (OpCodes.Call, method);
8916 // This class is used to "construct" the type during a typecast
8917 // operation. Since the Type.GetType class in .NET can parse
8918 // the type specification, we just use this to construct the type
8919 // one bit at a time.
8921 public class ComposedCast : TypeExpr {
8922 FullNamedExpression left;
8925 public ComposedCast (FullNamedExpression left, string dim)
8926 : this (left, dim, left.Location)
8930 public ComposedCast (FullNamedExpression left, string dim, Location l)
8937 public Expression RemoveNullable ()
8939 if (dim.EndsWith ("?")) {
8940 dim = dim.Substring (0, dim.Length - 1);
8941 if (dim.Length == 0)
8948 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8950 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8954 Type ltype = lexpr.Type;
8955 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8956 Error_VoidInvalidInTheContext (loc);
8961 if ((dim.Length > 0) && (dim [0] == '?')) {
8962 TypeExpr nullable = new Nullable.NullableType (left, loc);
8964 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8965 return nullable.ResolveAsTypeTerminal (ec, false);
8969 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8972 if (dim != "" && dim [0] == '[' &&
8973 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8974 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8979 type = TypeManager.GetConstructedType (ltype, dim);
8984 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8986 if (type.IsPointer && !ec.IsInUnsafeScope){
8991 eclass = ExprClass.Type;
8995 public override string GetSignatureForError ()
8997 return left.GetSignatureForError () + dim;
9000 protected override void CloneTo (CloneContext clonectx, Expression t)
9002 ComposedCast target = (ComposedCast) t;
9004 target.left = (FullNamedExpression)left.Clone (clonectx);
9008 public class FixedBufferPtr : Expression {
9011 public FixedBufferPtr (Expression array, Type array_type, Location l)
9016 type = TypeManager.GetPointerType (array_type);
9017 eclass = ExprClass.Value;
9020 public override Expression CreateExpressionTree (EmitContext ec)
9022 Error_PointerInsideExpressionTree ();
9026 public override void Emit(EmitContext ec)
9031 public override Expression DoResolve (EmitContext ec)
9034 // We are born fully resolved
9042 // This class is used to represent the address of an array, used
9043 // only by the Fixed statement, this generates "&a [0]" construct
9044 // for fixed (char *pa = a)
9046 public class ArrayPtr : FixedBufferPtr {
9049 public ArrayPtr (Expression array, Type array_type, Location l):
9050 base (array, array_type, l)
9052 this.array_type = array_type;
9055 public override void Emit (EmitContext ec)
9059 ILGenerator ig = ec.ig;
9060 IntLiteral.EmitInt (ig, 0);
9061 ig.Emit (OpCodes.Ldelema, array_type);
9066 // Encapsulates a conversion rules required for array indexes
9068 public class ArrayIndexCast : TypeCast
9070 public ArrayIndexCast (Expression expr)
9071 : base (expr, expr.Type)
9075 public override Expression CreateExpressionTree (EmitContext ec)
9077 ArrayList args = new ArrayList (2);
9078 args.Add (new Argument (child.CreateExpressionTree (ec)));
9079 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
9080 return CreateExpressionFactoryCall ("ConvertChecked", args);
9083 public override void Emit (EmitContext ec)
9087 if (type == TypeManager.int32_type)
9090 if (type == TypeManager.uint32_type)
9091 ec.ig.Emit (OpCodes.Conv_U);
9092 else if (type == TypeManager.int64_type)
9093 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9094 else if (type == TypeManager.uint64_type)
9095 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9097 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9102 // Implements the `stackalloc' keyword
9104 public class StackAlloc : Expression {
9109 public StackAlloc (Expression type, Expression count, Location l)
9116 public override Expression CreateExpressionTree (EmitContext ec)
9118 throw new NotSupportedException ("ET");
9121 public override Expression DoResolve (EmitContext ec)
9123 count = count.Resolve (ec);
9127 if (count.Type != TypeManager.uint32_type){
9128 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9133 Constant c = count as Constant;
9134 if (c != null && c.IsNegative) {
9135 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9139 if (ec.InCatch || ec.InFinally) {
9140 Error (255, "Cannot use stackalloc in finally or catch");
9144 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9150 if (!TypeManager.VerifyUnManaged (otype, loc))
9153 type = TypeManager.GetPointerType (otype);
9154 eclass = ExprClass.Value;
9159 public override void Emit (EmitContext ec)
9161 int size = GetTypeSize (otype);
9162 ILGenerator ig = ec.ig;
9167 ig.Emit (OpCodes.Sizeof, otype);
9169 IntConstant.EmitInt (ig, size);
9171 ig.Emit (OpCodes.Mul_Ovf_Un);
9172 ig.Emit (OpCodes.Localloc);
9175 protected override void CloneTo (CloneContext clonectx, Expression t)
9177 StackAlloc target = (StackAlloc) t;
9178 target.count = count.Clone (clonectx);
9179 target.t = t.Clone (clonectx);
9184 // An object initializer expression
9186 public class ElementInitializer : Assign
9188 public readonly string Name;
9190 public ElementInitializer (string name, Expression initializer, Location loc)
9191 : base (null, initializer, loc)
9196 protected override void CloneTo (CloneContext clonectx, Expression t)
9198 ElementInitializer target = (ElementInitializer) t;
9199 target.source = source.Clone (clonectx);
9202 public override Expression CreateExpressionTree (EmitContext ec)
9204 ArrayList args = new ArrayList (2);
9205 FieldExpr fe = target as FieldExpr;
9207 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9209 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9211 args.Add (new Argument (source.CreateExpressionTree (ec)));
9212 return CreateExpressionFactoryCall (
9213 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9217 public override Expression DoResolve (EmitContext ec)
9220 return EmptyExpressionStatement.Instance;
9222 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9223 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9229 me.InstanceExpression = ec.CurrentInitializerVariable;
9231 if (source is CollectionOrObjectInitializers) {
9232 Expression previous = ec.CurrentInitializerVariable;
9233 ec.CurrentInitializerVariable = target;
9234 source = source.Resolve (ec);
9235 ec.CurrentInitializerVariable = previous;
9239 eclass = source.eclass;
9244 Expression expr = base.DoResolve (ec);
9249 // Ignore field initializers with default value
9251 Constant c = source as Constant;
9252 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9253 return EmptyExpressionStatement.Instance;
9258 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9260 MemberInfo member = members [0];
9261 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9262 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9263 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9265 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9266 TypeManager.GetFullNameSignature (member));
9271 public override void EmitStatement (EmitContext ec)
9273 if (source is CollectionOrObjectInitializers)
9276 base.EmitStatement (ec);
9281 // A collection initializer expression
9283 public class CollectionElementInitializer : Invocation
9285 public class ElementInitializerArgument : Argument
9287 public ElementInitializerArgument (Expression e)
9293 public CollectionElementInitializer (Expression argument)
9294 : base (null, new ArrayList (1), true)
9296 Arguments.Add (argument);
9297 this.loc = argument.Location;
9300 public CollectionElementInitializer (ArrayList arguments, Location loc)
9301 : base (null, arguments, true)
9306 public override Expression CreateExpressionTree (EmitContext ec)
9308 ArrayList args = new ArrayList (2);
9309 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9311 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9312 foreach (Argument a in Arguments)
9313 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9315 args.Add (new Argument (new ArrayCreation (
9316 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9317 return CreateExpressionFactoryCall ("ElementInit", args);
9320 protected override void CloneTo (CloneContext clonectx, Expression t)
9322 CollectionElementInitializer target = (CollectionElementInitializer) t;
9324 target.Arguments = new ArrayList (Arguments.Count);
9325 foreach (Expression e in Arguments)
9326 target.Arguments.Add (e.Clone (clonectx));
9329 public override Expression DoResolve (EmitContext ec)
9331 if (eclass != ExprClass.Invalid)
9334 // TODO: We could call a constructor which takes element count argument,
9335 // for known types like List<T>, Dictionary<T, U>
9337 for (int i = 0; i < Arguments.Count; ++i) {
9338 Expression expr = ((Expression) Arguments [i]).Resolve (ec);
9342 Arguments [i] = new ElementInitializerArgument (expr);
9345 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9347 return base.DoResolve (ec);
9352 // A block of object or collection initializers
9354 public class CollectionOrObjectInitializers : ExpressionStatement
9356 ArrayList initializers;
9358 public static readonly CollectionOrObjectInitializers Empty =
9359 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9361 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9363 this.initializers = initializers;
9367 public bool IsEmpty {
9369 return initializers.Count == 0;
9373 public bool IsCollectionInitializer {
9375 return type == typeof (CollectionOrObjectInitializers);
9379 protected override void CloneTo (CloneContext clonectx, Expression target)
9381 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9383 t.initializers = new ArrayList (initializers.Count);
9384 foreach (Expression e in initializers)
9385 t.initializers.Add (e.Clone (clonectx));
9388 public override Expression CreateExpressionTree (EmitContext ec)
9390 ArrayList expr_initializers = new ArrayList (initializers.Count);
9391 foreach (Expression e in initializers) {
9392 Expression expr = e.CreateExpressionTree (ec);
9394 expr_initializers.Add (expr);
9397 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9400 public override Expression DoResolve (EmitContext ec)
9402 if (eclass != ExprClass.Invalid)
9405 bool is_elements_initialization = false;
9406 ArrayList element_names = null;
9407 for (int i = 0; i < initializers.Count; ++i) {
9408 Expression initializer = (Expression) initializers [i];
9409 ElementInitializer element_initializer = initializer as ElementInitializer;
9412 if (element_initializer != null) {
9413 is_elements_initialization = true;
9414 element_names = new ArrayList (initializers.Count);
9415 element_names.Add (element_initializer.Name);
9417 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9418 TypeManager.ienumerable_type)) {
9419 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9420 "object initializer because type `{1}' does not implement `{2}' interface",
9421 ec.CurrentInitializerVariable.GetSignatureForError (),
9422 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9423 TypeManager.CSharpName (TypeManager.ienumerable_type));
9428 if (is_elements_initialization == (element_initializer == null)) {
9429 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9430 is_elements_initialization ? "object initializer" : "collection initializer");
9434 if (is_elements_initialization) {
9435 if (element_names.Contains (element_initializer.Name)) {
9436 Report.Error (1912, element_initializer.Location,
9437 "An object initializer includes more than one member `{0}' initialization",
9438 element_initializer.Name);
9440 element_names.Add (element_initializer.Name);
9445 Expression e = initializer.Resolve (ec);
9446 if (e == EmptyExpressionStatement.Instance)
9447 initializers.RemoveAt (i--);
9449 initializers [i] = e;
9452 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9453 eclass = ExprClass.Variable;
9457 public override void Emit (EmitContext ec)
9462 public override void EmitStatement (EmitContext ec)
9464 foreach (ExpressionStatement e in initializers)
9465 e.EmitStatement (ec);
9468 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9470 foreach (Expression e in initializers)
9471 e.MutateHoistedGenericType (storey);
9476 // New expression with element/object initializers
9478 public class NewInitialize : New
9481 // This class serves as a proxy for variable initializer target instances.
9482 // A real variable is assigned later when we resolve left side of an
9485 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9487 NewInitialize new_instance;
9489 public InitializerTargetExpression (NewInitialize newInstance)
9491 this.type = newInstance.type;
9492 this.loc = newInstance.loc;
9493 this.eclass = newInstance.eclass;
9494 this.new_instance = newInstance;
9497 public override Expression CreateExpressionTree (EmitContext ec)
9499 // Should not be reached
9500 throw new NotSupportedException ("ET");
9503 public override Expression DoResolve (EmitContext ec)
9508 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9513 public override void Emit (EmitContext ec)
9515 new_instance.value_target.Emit (ec);
9518 #region IMemoryLocation Members
9520 public void AddressOf (EmitContext ec, AddressOp mode)
9522 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9528 CollectionOrObjectInitializers initializers;
9530 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9531 : base (requested_type, arguments, l)
9533 this.initializers = initializers;
9536 protected override void CloneTo (CloneContext clonectx, Expression t)
9538 base.CloneTo (clonectx, t);
9540 NewInitialize target = (NewInitialize) t;
9541 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9544 public override Expression CreateExpressionTree (EmitContext ec)
9546 ArrayList args = new ArrayList (2);
9547 args.Add (new Argument (base.CreateExpressionTree (ec)));
9548 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9550 return CreateExpressionFactoryCall (
9551 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9555 public override Expression DoResolve (EmitContext ec)
9557 if (eclass != ExprClass.Invalid)
9560 Expression e = base.DoResolve (ec);
9564 // Empty initializer can be optimized to simple new
9565 if (initializers.IsEmpty)
9568 Expression previous = ec.CurrentInitializerVariable;
9569 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9570 initializers.Resolve (ec);
9571 ec.CurrentInitializerVariable = previous;
9575 public override void Emit (EmitContext ec)
9580 // If target is non-hoisted variable, let's use it
9582 VariableReference variable = value_target as VariableReference;
9583 if (variable != null && variable.HoistedVariable == null) {
9585 StoreFromPtr (ec.ig, type);
9587 variable.EmitAssign (ec, EmptyExpression.Null, false, false);
9590 if (value_target == null || value_target_set)
9591 value_target = new LocalTemporary (type);
9593 ((LocalTemporary) value_target).Store (ec);
9596 initializers.Emit (ec);
9598 if (variable == null) {
9599 value_target.Emit (ec);
9600 value_target = null;
9604 public override void EmitStatement (EmitContext ec)
9606 if (initializers.IsEmpty) {
9607 base.EmitStatement (ec);
9613 if (value_target == null) {
9614 LocalTemporary variable = new LocalTemporary (type);
9615 variable.Store (ec);
9616 value_target = variable;
9619 initializers.EmitStatement (ec);
9622 public override bool HasInitializer {
9624 return !initializers.IsEmpty;
9628 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9630 base.MutateHoistedGenericType (storey);
9631 initializers.MutateHoistedGenericType (storey);
9635 public class AnonymousTypeDeclaration : Expression
9637 ArrayList parameters;
9638 readonly TypeContainer parent;
9639 static readonly ArrayList EmptyParameters = new ArrayList (0);
9641 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9643 this.parameters = parameters;
9644 this.parent = parent;
9648 protected override void CloneTo (CloneContext clonectx, Expression target)
9650 if (parameters == null)
9653 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9654 t.parameters = new ArrayList (parameters.Count);
9655 foreach (AnonymousTypeParameter atp in parameters)
9656 t.parameters.Add (atp.Clone (clonectx));
9659 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9661 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9665 type = AnonymousTypeClass.Create (parent, parameters, loc);
9670 type.DefineMembers ();
9675 RootContext.ToplevelTypes.AddAnonymousType (type);
9679 public override Expression CreateExpressionTree (EmitContext ec)
9681 throw new NotSupportedException ("ET");
9684 public override Expression DoResolve (EmitContext ec)
9686 AnonymousTypeClass anonymous_type;
9688 if (parameters == null) {
9689 anonymous_type = CreateAnonymousType (EmptyParameters);
9690 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9691 null, loc).Resolve (ec);
9695 ArrayList arguments = new ArrayList (parameters.Count);
9696 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9697 for (int i = 0; i < parameters.Count; ++i) {
9698 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9704 arguments.Add (new Argument (e));
9705 t_args [i] = new TypeExpression (e.Type, e.Location);
9711 anonymous_type = CreateAnonymousType (parameters);
9712 if (anonymous_type == null)
9715 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9716 new TypeArguments (loc, t_args), loc);
9718 return new New (te, arguments, loc).Resolve (ec);
9721 public override void Emit (EmitContext ec)
9723 throw new InternalErrorException ("Should not be reached");
9727 public class AnonymousTypeParameter : Expression
9729 public readonly string Name;
9730 Expression initializer;
9732 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9736 this.initializer = initializer;
9739 public AnonymousTypeParameter (Parameter parameter)
9741 this.Name = parameter.Name;
9742 this.loc = parameter.Location;
9743 this.initializer = new SimpleName (Name, loc);
9746 protected override void CloneTo (CloneContext clonectx, Expression target)
9748 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9749 t.initializer = initializer.Clone (clonectx);
9752 public override Expression CreateExpressionTree (EmitContext ec)
9754 throw new NotSupportedException ("ET");
9757 public override bool Equals (object o)
9759 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9760 return other != null && Name == other.Name;
9763 public override int GetHashCode ()
9765 return Name.GetHashCode ();
9768 public override Expression DoResolve (EmitContext ec)
9770 Expression e = initializer.Resolve (ec);
9775 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9776 type == TypeManager.anonymous_method_type || type.IsPointer) {
9777 Error_InvalidInitializer (e);
9784 protected virtual void Error_InvalidInitializer (Expression initializer)
9786 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9787 Name, initializer.GetSignatureForError ());
9790 public override void Emit (EmitContext ec)
9792 throw new InternalErrorException ("Should not be reached");