2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// This is just a helper class, it is generated by Unary, UnaryMutator
22 /// when an overloaded method has been found. It just emits the code for a
25 public class StaticCallExpr : ExpressionStatement {
29 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
35 eclass = ExprClass.Value;
39 public override Expression DoResolve (EmitContext ec)
42 // We are born fully resolved
47 public override void Emit (EmitContext ec)
50 Invocation.EmitArguments (ec, mi, args, false, null);
52 ec.ig.Emit (OpCodes.Call, mi);
56 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
57 Expression e, Location loc)
62 args = new ArrayList (1);
63 Argument a = new Argument (e, Argument.AType.Expression);
65 // We need to resolve the arguments before sending them in !
66 if (!a.Resolve (ec, loc))
70 method = mg.OverloadResolve (
71 ec, args, false, loc);
76 return new StaticCallExpr ((MethodInfo) method, args, loc);
79 public override void EmitStatement (EmitContext ec)
82 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
83 ec.ig.Emit (OpCodes.Pop);
86 public MethodInfo Method {
91 public class ParenthesizedExpression : Expression
93 public Expression Expr;
95 public ParenthesizedExpression (Expression expr)
100 public override Expression DoResolve (EmitContext ec)
102 Expr = Expr.Resolve (ec);
106 public override void Emit (EmitContext ec)
108 throw new Exception ("Should not happen");
111 public override Location Location
114 return Expr.Location;
118 protected override void CloneTo (CloneContext clonectx, Expression t)
120 ParenthesizedExpression target = (ParenthesizedExpression) t;
122 target.Expr = Expr.Clone (clonectx);
127 /// Unary expressions.
131 /// Unary implements unary expressions. It derives from
132 /// ExpressionStatement becuase the pre/post increment/decrement
133 /// operators can be used in a statement context.
135 public class Unary : Expression {
136 public enum Operator : byte {
137 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
138 Indirection, AddressOf, TOP
141 public Operator Oper;
142 public Expression Expr;
144 public Unary (Operator op, Expression expr, Location loc)
152 /// Returns a stringified representation of the Operator
154 static public string OperName (Operator oper)
157 case Operator.UnaryPlus:
159 case Operator.UnaryNegation:
161 case Operator.LogicalNot:
163 case Operator.OnesComplement:
165 case Operator.AddressOf:
167 case Operator.Indirection:
171 return oper.ToString ();
174 public static readonly string [] oper_names;
178 oper_names = new string [(int)Operator.TOP];
180 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
181 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
182 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
183 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
184 oper_names [(int) Operator.Indirection] = "op_Indirection";
185 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
188 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
190 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
193 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
195 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
199 void Error23 (Type t)
201 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
205 // This routine will attempt to simplify the unary expression when the
206 // argument is a constant.
208 Constant TryReduceConstant (EmitContext ec, Constant e)
210 Type expr_type = e.Type;
213 case Operator.UnaryPlus:
214 // Unary numeric promotions
215 if (expr_type == TypeManager.byte_type)
216 return new IntConstant (((ByteConstant)e).Value, e.Location);
217 if (expr_type == TypeManager.sbyte_type)
218 return new IntConstant (((SByteConstant)e).Value, e.Location);
219 if (expr_type == TypeManager.short_type)
220 return new IntConstant (((ShortConstant)e).Value, e.Location);
221 if (expr_type == TypeManager.ushort_type)
222 return new IntConstant (((UShortConstant)e).Value, e.Location);
223 if (expr_type == TypeManager.char_type)
224 return new IntConstant (((CharConstant)e).Value, e.Location);
226 // Predefined operators
227 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
228 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
229 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
230 expr_type == TypeManager.decimal_type)
237 case Operator.UnaryNegation:
238 // Unary numeric promotions
239 if (expr_type == TypeManager.byte_type)
240 return new IntConstant (-((ByteConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.sbyte_type)
242 return new IntConstant (-((SByteConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.short_type)
244 return new IntConstant (-((ShortConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.ushort_type)
246 return new IntConstant (-((UShortConstant)e).Value, e.Location);
247 if (expr_type == TypeManager.char_type)
248 return new IntConstant (-((CharConstant)e).Value, e.Location);
250 // Predefined operators
251 if (expr_type == TypeManager.int32_type) {
252 int value = ((IntConstant)e).Value;
253 if (value == int.MinValue) {
254 if (ec.ConstantCheckState) {
255 ConstantFold.Error_CompileTimeOverflow (loc);
260 return new IntConstant (-value, e.Location);
262 if (expr_type == TypeManager.int64_type) {
263 long value = ((LongConstant)e).Value;
264 if (value == long.MinValue) {
265 if (ec.ConstantCheckState) {
266 ConstantFold.Error_CompileTimeOverflow (loc);
271 return new LongConstant (-value, e.Location);
274 if (expr_type == TypeManager.uint32_type) {
275 UIntLiteral uil = e as UIntLiteral;
277 if (uil.Value == 2147483648)
278 return new IntLiteral (int.MinValue, e.Location);
279 return new LongLiteral (-uil.Value, e.Location);
281 return new LongConstant (-((UIntConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.uint64_type) {
285 ULongLiteral ull = e as ULongLiteral;
286 if (ull != null && ull.Value == 9223372036854775808)
287 return new LongLiteral (long.MinValue, e.Location);
291 if (expr_type == TypeManager.float_type) {
292 FloatLiteral fl = e as FloatLiteral;
293 // For better error reporting
295 fl.Value = -fl.Value;
298 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
300 if (expr_type == TypeManager.double_type) {
301 DoubleLiteral dl = e as DoubleLiteral;
302 // For better error reporting
304 dl.Value = -dl.Value;
308 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
310 if (expr_type == TypeManager.decimal_type)
311 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
315 case Operator.LogicalNot:
316 if (expr_type != TypeManager.bool_type)
319 BoolConstant b = (BoolConstant) e;
320 return new BoolConstant (!(b.Value), b.Location);
322 case Operator.OnesComplement:
323 // Unary numeric promotions
324 if (expr_type == TypeManager.byte_type)
325 return new IntConstant (~((ByteConstant)e).Value, e.Location);
326 if (expr_type == TypeManager.sbyte_type)
327 return new IntConstant (~((SByteConstant)e).Value, e.Location);
328 if (expr_type == TypeManager.short_type)
329 return new IntConstant (~((ShortConstant)e).Value, e.Location);
330 if (expr_type == TypeManager.ushort_type)
331 return new IntConstant (~((UShortConstant)e).Value, e.Location);
332 if (expr_type == TypeManager.char_type)
333 return new IntConstant (~((CharConstant)e).Value, e.Location);
335 // Predefined operators
336 if (expr_type == TypeManager.int32_type)
337 return new IntConstant (~((IntConstant)e).Value, e.Location);
338 if (expr_type == TypeManager.uint32_type)
339 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
340 if (expr_type == TypeManager.int64_type)
341 return new LongConstant (~((LongConstant)e).Value, e.Location);
342 if (expr_type == TypeManager.uint64_type){
343 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
345 if (e is EnumConstant) {
346 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
348 e = new EnumConstant (e, expr_type);
353 case Operator.AddressOf:
356 case Operator.Indirection:
359 throw new Exception ("Can not constant fold: " + Oper.ToString());
362 Expression ResolveOperator (EmitContext ec)
365 // Step 1: Default operations on CLI native types.
368 // Attempt to use a constant folding operation.
369 Constant cexpr = Expr as Constant;
371 cexpr = TryReduceConstant (ec, cexpr);
378 // Step 2: Perform Operator Overload location
380 Type expr_type = Expr.Type;
381 string op_name = oper_names [(int) Oper];
383 Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
385 Expression e = StaticCallExpr.MakeSimpleCall (
386 ec, (MethodGroupExpr) mg, Expr, loc);
397 case Operator.LogicalNot:
398 if (expr_type != TypeManager.bool_type) {
399 Expr = ResolveBoolean (ec, Expr, loc);
406 type = TypeManager.bool_type;
409 case Operator.OnesComplement:
410 // Unary numeric promotions
411 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
412 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
413 expr_type == TypeManager.char_type)
415 type = TypeManager.int32_type;
416 return new EmptyCast (this, type);
419 // Predefined operators
420 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
421 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
422 TypeManager.IsEnumType (expr_type))
428 type = TypeManager.int32_type;
429 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
436 case Operator.AddressOf:
442 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
446 IVariable variable = Expr as IVariable;
447 bool is_fixed = variable != null && variable.VerifyFixed ();
449 if (!ec.InFixedInitializer && !is_fixed) {
450 Error (212, "You can only take the address of unfixed expression inside " +
451 "of a fixed statement initializer");
455 if (ec.InFixedInitializer && is_fixed) {
456 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
460 LocalVariableReference lr = Expr as LocalVariableReference;
462 if (lr.local_info.IsCaptured){
463 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
466 lr.local_info.AddressTaken = true;
467 lr.local_info.Used = true;
470 ParameterReference pr = Expr as ParameterReference;
471 if ((pr != null) && pr.Parameter.IsCaptured) {
472 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
476 // According to the specs, a variable is considered definitely assigned if you take
478 if ((variable != null) && (variable.VariableInfo != null)){
479 variable.VariableInfo.SetAssigned (ec);
482 type = TypeManager.GetPointerType (Expr.Type);
485 case Operator.Indirection:
491 if (!expr_type.IsPointer){
492 Error (193, "The * or -> operator must be applied to a pointer");
497 // We create an Indirection expression, because
498 // it can implement the IMemoryLocation.
500 return new Indirection (Expr, loc);
502 case Operator.UnaryPlus:
503 // Unary numeric promotions
504 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
505 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
506 expr_type == TypeManager.char_type)
508 return new EmptyCast (Expr, TypeManager.int32_type);
511 // Predefined operators
512 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
513 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
514 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
515 expr_type == TypeManager.decimal_type)
520 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
522 // Because we can completely ignore unary +
529 case Operator.UnaryNegation:
531 // transform - - expr into expr
533 Unary u = Expr as Unary;
534 if (u != null && u.Oper == Operator.UnaryNegation) {
538 // Unary numeric promotions
539 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
540 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
541 expr_type == TypeManager.char_type)
543 type = TypeManager.int32_type;
544 return new EmptyCast (this, type);
548 // Predefined operators
550 if (expr_type == TypeManager.uint32_type) {
551 type = TypeManager.int64_type;
552 Expr = Convert.ImplicitNumericConversion (Expr, type);
556 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
557 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
558 expr_type == TypeManager.decimal_type)
567 type = TypeManager.int32_type;
568 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
576 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
577 TypeManager.CSharpName (expr_type) + "'");
581 public override Expression DoResolve (EmitContext ec)
583 if (Oper == Operator.AddressOf) {
584 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
586 if (Expr == null || Expr.eclass != ExprClass.Variable){
587 Error (211, "Cannot take the address of the given expression");
592 Expr = Expr.Resolve (ec);
598 if (TypeManager.IsNullableValueType (Expr.Type))
599 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
602 eclass = ExprClass.Value;
603 return ResolveOperator (ec);
606 public override Expression DoResolveLValue (EmitContext ec, Expression right)
608 if (Oper == Operator.Indirection)
609 return DoResolve (ec);
614 public override void Emit (EmitContext ec)
616 ILGenerator ig = ec.ig;
619 case Operator.UnaryPlus:
620 throw new Exception ("This should be caught by Resolve");
622 case Operator.UnaryNegation:
623 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
624 ig.Emit (OpCodes.Ldc_I4_0);
625 if (type == TypeManager.int64_type)
626 ig.Emit (OpCodes.Conv_U8);
628 ig.Emit (OpCodes.Sub_Ovf);
631 ig.Emit (OpCodes.Neg);
636 case Operator.LogicalNot:
638 ig.Emit (OpCodes.Ldc_I4_0);
639 ig.Emit (OpCodes.Ceq);
642 case Operator.OnesComplement:
644 ig.Emit (OpCodes.Not);
647 case Operator.AddressOf:
648 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
652 throw new Exception ("This should not happen: Operator = "
657 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
659 if (Oper == Operator.LogicalNot)
660 Expr.EmitBranchable (ec, target, !onTrue);
662 base.EmitBranchable (ec, target, onTrue);
665 public override string ToString ()
667 return "Unary (" + Oper + ", " + Expr + ")";
670 protected override void CloneTo (CloneContext clonectx, Expression t)
672 Unary target = (Unary) t;
674 target.Expr = Expr.Clone (clonectx);
679 // Unary operators are turned into Indirection expressions
680 // after semantic analysis (this is so we can take the address
681 // of an indirection).
683 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
685 LocalTemporary temporary;
688 public Indirection (Expression expr, Location l)
691 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
692 eclass = ExprClass.Variable;
696 public override void Emit (EmitContext ec)
701 LoadFromPtr (ec.ig, Type);
704 public void Emit (EmitContext ec, bool leave_copy)
708 ec.ig.Emit (OpCodes.Dup);
709 temporary = new LocalTemporary (expr.Type);
710 temporary.Store (ec);
714 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
716 prepared = prepare_for_load;
720 if (prepare_for_load)
721 ec.ig.Emit (OpCodes.Dup);
725 ec.ig.Emit (OpCodes.Dup);
726 temporary = new LocalTemporary (expr.Type);
727 temporary.Store (ec);
730 StoreFromPtr (ec.ig, type);
732 if (temporary != null) {
734 temporary.Release (ec);
738 public void AddressOf (EmitContext ec, AddressOp Mode)
743 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
745 return DoResolve (ec);
748 public override Expression DoResolve (EmitContext ec)
751 // Born fully resolved
756 public override string ToString ()
758 return "*(" + expr + ")";
761 #region IVariable Members
763 public VariableInfo VariableInfo {
767 public bool VerifyFixed ()
769 // A pointer-indirection is always fixed.
777 /// Unary Mutator expressions (pre and post ++ and --)
781 /// UnaryMutator implements ++ and -- expressions. It derives from
782 /// ExpressionStatement becuase the pre/post increment/decrement
783 /// operators can be used in a statement context.
785 /// FIXME: Idea, we could split this up in two classes, one simpler
786 /// for the common case, and one with the extra fields for more complex
787 /// classes (indexers require temporary access; overloaded require method)
790 public class UnaryMutator : ExpressionStatement {
792 public enum Mode : byte {
799 PreDecrement = IsDecrement,
800 PostIncrement = IsPost,
801 PostDecrement = IsPost | IsDecrement
805 bool is_expr = false;
806 bool recurse = false;
811 // This is expensive for the simplest case.
813 StaticCallExpr method;
815 public UnaryMutator (Mode m, Expression e, Location l)
822 static string OperName (Mode mode)
824 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
829 /// Returns whether an object of type `t' can be incremented
830 /// or decremented with add/sub (ie, basically whether we can
831 /// use pre-post incr-decr operations on it, but it is not a
832 /// System.Decimal, which we require operator overloading to catch)
834 static bool IsIncrementableNumber (Type t)
836 return (t == TypeManager.sbyte_type) ||
837 (t == TypeManager.byte_type) ||
838 (t == TypeManager.short_type) ||
839 (t == TypeManager.ushort_type) ||
840 (t == TypeManager.int32_type) ||
841 (t == TypeManager.uint32_type) ||
842 (t == TypeManager.int64_type) ||
843 (t == TypeManager.uint64_type) ||
844 (t == TypeManager.char_type) ||
845 (t.IsSubclassOf (TypeManager.enum_type)) ||
846 (t == TypeManager.float_type) ||
847 (t == TypeManager.double_type) ||
848 (t.IsPointer && t != TypeManager.void_ptr_type);
851 Expression ResolveOperator (EmitContext ec)
853 Type expr_type = expr.Type;
856 // Step 1: Perform Operator Overload location
861 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
862 op_name = "op_Increment";
864 op_name = "op_Decrement";
866 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
869 method = StaticCallExpr.MakeSimpleCall (
870 ec, (MethodGroupExpr) mg, expr, loc);
873 } else if (!IsIncrementableNumber (expr_type)) {
874 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
875 TypeManager.CSharpName (expr_type) + "'");
880 // The operand of the prefix/postfix increment decrement operators
881 // should be an expression that is classified as a variable,
882 // a property access or an indexer access
885 if (expr.eclass == ExprClass.Variable){
886 LocalVariableReference var = expr as LocalVariableReference;
887 if ((var != null) && var.IsReadOnly) {
888 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
891 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
892 expr = expr.ResolveLValue (ec, this, Location);
896 if (expr.eclass == ExprClass.Value) {
897 Error_ValueAssignment (loc);
899 expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
907 public override Expression DoResolve (EmitContext ec)
909 expr = expr.Resolve (ec);
914 eclass = ExprClass.Value;
917 if (TypeManager.IsNullableValueType (expr.Type))
918 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
921 return ResolveOperator (ec);
924 static int PtrTypeSize (Type t)
926 return GetTypeSize (TypeManager.GetElementType (t));
930 // Loads the proper "1" into the stack based on the type, then it emits the
931 // opcode for the operation requested
933 void LoadOneAndEmitOp (EmitContext ec, Type t)
936 // Measure if getting the typecode and using that is more/less efficient
937 // that comparing types. t.GetTypeCode() is an internal call.
939 ILGenerator ig = ec.ig;
941 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
942 LongConstant.EmitLong (ig, 1);
943 else if (t == TypeManager.double_type)
944 ig.Emit (OpCodes.Ldc_R8, 1.0);
945 else if (t == TypeManager.float_type)
946 ig.Emit (OpCodes.Ldc_R4, 1.0F);
947 else if (t.IsPointer){
948 int n = PtrTypeSize (t);
951 ig.Emit (OpCodes.Sizeof, t);
953 IntConstant.EmitInt (ig, n);
955 ig.Emit (OpCodes.Ldc_I4_1);
958 // Now emit the operation
961 if (t == TypeManager.int32_type ||
962 t == TypeManager.int64_type){
963 if ((mode & Mode.IsDecrement) != 0)
964 ig.Emit (OpCodes.Sub_Ovf);
966 ig.Emit (OpCodes.Add_Ovf);
967 } else if (t == TypeManager.uint32_type ||
968 t == TypeManager.uint64_type){
969 if ((mode & Mode.IsDecrement) != 0)
970 ig.Emit (OpCodes.Sub_Ovf_Un);
972 ig.Emit (OpCodes.Add_Ovf_Un);
974 if ((mode & Mode.IsDecrement) != 0)
975 ig.Emit (OpCodes.Sub_Ovf);
977 ig.Emit (OpCodes.Add_Ovf);
980 if ((mode & Mode.IsDecrement) != 0)
981 ig.Emit (OpCodes.Sub);
983 ig.Emit (OpCodes.Add);
986 if (t == TypeManager.sbyte_type){
988 ig.Emit (OpCodes.Conv_Ovf_I1);
990 ig.Emit (OpCodes.Conv_I1);
991 } else if (t == TypeManager.byte_type){
993 ig.Emit (OpCodes.Conv_Ovf_U1);
995 ig.Emit (OpCodes.Conv_U1);
996 } else if (t == TypeManager.short_type){
998 ig.Emit (OpCodes.Conv_Ovf_I2);
1000 ig.Emit (OpCodes.Conv_I2);
1001 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1003 ig.Emit (OpCodes.Conv_Ovf_U2);
1005 ig.Emit (OpCodes.Conv_U2);
1010 void EmitCode (EmitContext ec, bool is_expr)
1013 this.is_expr = is_expr;
1014 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1017 public override void Emit (EmitContext ec)
1020 // We use recurse to allow ourselfs to be the source
1021 // of an assignment. This little hack prevents us from
1022 // having to allocate another expression
1025 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1027 LoadOneAndEmitOp (ec, expr.Type);
1029 ec.ig.Emit (OpCodes.Call, method.Method);
1034 EmitCode (ec, true);
1037 public override void EmitStatement (EmitContext ec)
1039 EmitCode (ec, false);
1042 protected override void CloneTo (CloneContext clonectx, Expression t)
1044 UnaryMutator target = (UnaryMutator) t;
1046 target.expr = expr.Clone (clonectx);
1051 /// Base class for the `Is' and `As' classes.
1055 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1058 public abstract class Probe : Expression {
1059 public Expression ProbeType;
1060 protected Expression expr;
1061 protected TypeExpr probe_type_expr;
1063 public Probe (Expression expr, Expression probe_type, Location l)
1065 ProbeType = probe_type;
1070 public Expression Expr {
1076 public override Expression DoResolve (EmitContext ec)
1078 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1079 if (probe_type_expr == null)
1082 expr = expr.Resolve (ec);
1086 if (expr.Type.IsPointer) {
1087 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1093 protected override void CloneTo (CloneContext clonectx, Expression t)
1095 Probe target = (Probe) t;
1097 target.expr = expr.Clone (clonectx);
1098 target.ProbeType = ProbeType.Clone (clonectx);
1104 /// Implementation of the `is' operator.
1106 public class Is : Probe {
1107 public Is (Expression expr, Expression probe_type, Location l)
1108 : base (expr, probe_type, l)
1113 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1118 public override void Emit (EmitContext ec)
1120 ILGenerator ig = ec.ig;
1125 case Action.AlwaysFalse:
1126 ig.Emit (OpCodes.Pop);
1127 IntConstant.EmitInt (ig, 0);
1129 case Action.AlwaysTrue:
1130 ig.Emit (OpCodes.Pop);
1131 IntConstant.EmitInt (ig, 1);
1133 case Action.LeaveOnStack:
1134 // the `e != null' rule.
1135 ig.Emit (OpCodes.Ldnull);
1136 ig.Emit (OpCodes.Ceq);
1137 ig.Emit (OpCodes.Ldc_I4_0);
1138 ig.Emit (OpCodes.Ceq);
1141 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1142 ig.Emit (OpCodes.Ldnull);
1143 ig.Emit (OpCodes.Cgt_Un);
1146 throw new Exception ("never reached");
1149 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1151 ILGenerator ig = ec.ig;
1154 case Action.AlwaysFalse:
1156 ig.Emit (OpCodes.Br, target);
1159 case Action.AlwaysTrue:
1161 ig.Emit (OpCodes.Br, target);
1164 case Action.LeaveOnStack:
1165 // the `e != null' rule.
1167 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1171 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1172 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1175 throw new Exception ("never reached");
1178 public override Expression DoResolve (EmitContext ec)
1180 Expression e = base.DoResolve (ec);
1182 if ((e == null) || (expr == null))
1185 Type etype = expr.Type;
1186 type = TypeManager.bool_type;
1187 eclass = ExprClass.Value;
1190 // First case, if at compile time, there is an implicit conversion
1191 // then e != null (objects) or true (value types)
1193 Type probe_type = probe_type_expr.Type;
1194 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1197 if (etype.IsValueType)
1198 action = Action.AlwaysTrue;
1200 action = Action.LeaveOnStack;
1202 Constant c = e as Constant;
1203 if (c != null && c.GetValue () == null) {
1204 action = Action.AlwaysFalse;
1205 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1206 TypeManager.CSharpName (probe_type));
1208 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1209 TypeManager.CSharpName (probe_type));
1214 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1215 if (TypeManager.IsGenericParameter (etype))
1216 expr = new BoxedCast (expr, etype);
1219 // Second case: explicit reference convresion
1221 if (expr is NullLiteral)
1222 action = Action.AlwaysFalse;
1224 action = Action.Probe;
1225 } else if (TypeManager.ContainsGenericParameters (etype) ||
1226 TypeManager.ContainsGenericParameters (probe_type)) {
1227 expr = new BoxedCast (expr, etype);
1228 action = Action.Probe;
1230 action = Action.AlwaysFalse;
1231 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1232 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1240 /// Implementation of the `as' operator.
1242 public class As : Probe {
1243 public As (Expression expr, Expression probe_type, Location l)
1244 : base (expr, probe_type, l)
1248 bool do_isinst = false;
1249 Expression resolved_type;
1251 public override void Emit (EmitContext ec)
1253 ILGenerator ig = ec.ig;
1258 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1261 static void Error_CannotConvertType (Type source, Type target, Location loc)
1263 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1264 TypeManager.CSharpName (source),
1265 TypeManager.CSharpName (target));
1268 public override Expression DoResolve (EmitContext ec)
1270 if (resolved_type == null) {
1271 resolved_type = base.DoResolve (ec);
1273 if (resolved_type == null)
1277 type = probe_type_expr.Type;
1278 eclass = ExprClass.Value;
1279 Type etype = expr.Type;
1281 if (type.IsValueType) {
1282 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1283 TypeManager.CSharpName (type) + "' is a value type)");
1290 // If the type is a type parameter, ensure
1291 // that it is constrained by a class
1293 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1295 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1298 if (constraints == null)
1301 if (!constraints.HasClassConstraint)
1302 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1306 Report.Error (413, loc,
1307 "The as operator requires that the `{0}' type parameter be constrained by a class",
1308 probe_type_expr.GetSignatureForError ());
1314 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1321 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1322 if (TypeManager.IsGenericParameter (etype))
1323 expr = new BoxedCast (expr, etype);
1329 if (TypeManager.ContainsGenericParameters (etype) ||
1330 TypeManager.ContainsGenericParameters (type)) {
1331 expr = new BoxedCast (expr, etype);
1336 Error_CannotConvertType (etype, type, loc);
1340 public override bool GetAttributableValue (Type valueType, out object value)
1342 return expr.GetAttributableValue (valueType, out value);
1347 /// This represents a typecast in the source language.
1349 /// FIXME: Cast expressions have an unusual set of parsing
1350 /// rules, we need to figure those out.
1352 public class Cast : Expression {
1353 Expression target_type;
1356 public Cast (Expression cast_type, Expression expr)
1357 : this (cast_type, expr, cast_type.Location)
1361 public Cast (Expression cast_type, Expression expr, Location loc)
1363 this.target_type = cast_type;
1367 if (target_type == TypeManager.system_void_expr)
1368 Error_VoidInvalidInTheContext (loc);
1371 public Expression TargetType {
1372 get { return target_type; }
1375 public Expression Expr {
1376 get { return expr; }
1377 set { expr = value; }
1380 public override Expression DoResolve (EmitContext ec)
1382 expr = expr.Resolve (ec);
1386 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1392 if (type.IsAbstract && type.IsSealed) {
1393 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1397 eclass = ExprClass.Value;
1399 Constant c = expr as Constant;
1401 c = c.TryReduce (ec, type, loc);
1406 if (type.IsPointer && !ec.InUnsafe) {
1410 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1414 public override void Emit (EmitContext ec)
1416 throw new Exception ("Should not happen");
1419 protected override void CloneTo (CloneContext clonectx, Expression t)
1421 Cast target = (Cast) t;
1423 target.target_type = target_type.Clone (clonectx);
1424 target.expr = expr.Clone (clonectx);
1429 /// Binary operators
1431 public class Binary : Expression {
1432 public enum Operator : byte {
1433 Multiply, Division, Modulus,
1434 Addition, Subtraction,
1435 LeftShift, RightShift,
1436 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1437 Equality, Inequality,
1447 Expression left, right;
1449 // This must be kept in sync with Operator!!!
1450 public static readonly string [] oper_names;
1454 oper_names = new string [(int) Operator.TOP];
1456 oper_names [(int) Operator.Multiply] = "op_Multiply";
1457 oper_names [(int) Operator.Division] = "op_Division";
1458 oper_names [(int) Operator.Modulus] = "op_Modulus";
1459 oper_names [(int) Operator.Addition] = "op_Addition";
1460 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1461 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1462 oper_names [(int) Operator.RightShift] = "op_RightShift";
1463 oper_names [(int) Operator.LessThan] = "op_LessThan";
1464 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1465 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1466 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1467 oper_names [(int) Operator.Equality] = "op_Equality";
1468 oper_names [(int) Operator.Inequality] = "op_Inequality";
1469 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1470 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1471 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1472 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1473 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1476 public Binary (Operator oper, Expression left, Expression right)
1481 this.loc = left.Location;
1484 public Operator Oper {
1493 public Expression Left {
1502 public Expression Right {
1513 /// Returns a stringified representation of the Operator
1515 public static string OperName (Operator oper)
1518 case Operator.Multiply:
1520 case Operator.Division:
1522 case Operator.Modulus:
1524 case Operator.Addition:
1526 case Operator.Subtraction:
1528 case Operator.LeftShift:
1530 case Operator.RightShift:
1532 case Operator.LessThan:
1534 case Operator.GreaterThan:
1536 case Operator.LessThanOrEqual:
1538 case Operator.GreaterThanOrEqual:
1540 case Operator.Equality:
1542 case Operator.Inequality:
1544 case Operator.BitwiseAnd:
1546 case Operator.BitwiseOr:
1548 case Operator.ExclusiveOr:
1550 case Operator.LogicalOr:
1552 case Operator.LogicalAnd:
1556 return oper.ToString ();
1559 public override string ToString ()
1561 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1562 right.ToString () + ")";
1565 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1567 if (expr.Type == target_type)
1570 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1573 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1576 34, loc, "Operator `" + OperName (oper)
1577 + "' is ambiguous on operands of type `"
1578 + TypeManager.CSharpName (l) + "' "
1579 + "and `" + TypeManager.CSharpName (r)
1583 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1585 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1588 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1590 if (!IsConvertible (ec, left, right, t))
1592 left = ForceConversion (ec, left, t);
1593 right = ForceConversion (ec, right, t);
1598 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1600 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1601 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1603 if (oper == Operator.Equality || oper == Operator.Inequality)
1605 if (oper == Operator.Addition)
1610 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1612 if (!IsApplicable_String (ec, left, right, oper))
1614 Type t = TypeManager.string_type;
1615 if (Convert.ImplicitConversionExists (ec, left, t))
1616 left = ForceConversion (ec, left, t);
1617 if (Convert.ImplicitConversionExists (ec, right, t))
1618 right = ForceConversion (ec, right, t);
1623 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1625 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1626 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1627 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1628 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1632 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1634 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1635 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1639 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1641 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1644 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1646 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1650 void Error_OperatorCannotBeApplied ()
1652 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1653 TypeManager.CSharpName(right.Type));
1656 static bool is_unsigned (Type t)
1658 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1659 t == TypeManager.short_type || t == TypeManager.byte_type);
1662 Expression Make32or64 (EmitContext ec, Expression e)
1666 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1667 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1669 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1672 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1675 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1678 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1684 Expression CheckShiftArguments (EmitContext ec)
1686 Expression new_left = Make32or64 (ec, left);
1687 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1688 if (new_left == null || new_right == null) {
1689 Error_OperatorCannotBeApplied ();
1692 type = new_left.Type;
1693 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1695 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1700 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1701 // i.e., not invoke op_Equality.
1703 static bool EqualsNullIsReferenceEquals (Type t)
1705 return t == TypeManager.object_type || t == TypeManager.string_type ||
1706 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1709 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1711 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1712 "Possible unintended reference comparison; to get a value comparison, " +
1713 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1716 Expression ResolveOperator (EmitContext ec)
1719 Type r = right.Type;
1721 if (oper == Operator.Equality || oper == Operator.Inequality){
1722 if (TypeManager.IsGenericParameter (l) && (right is NullLiteral)) {
1723 if (l.BaseType == TypeManager.value_type) {
1724 Error_OperatorCannotBeApplied ();
1728 left = new BoxedCast (left, TypeManager.object_type);
1729 Type = TypeManager.bool_type;
1733 if (TypeManager.IsGenericParameter (r) && (left is NullLiteral)) {
1734 if (r.BaseType == TypeManager.value_type) {
1735 Error_OperatorCannotBeApplied ();
1739 right = new BoxedCast (right, TypeManager.object_type);
1740 Type = TypeManager.bool_type;
1745 // Optimize out call to op_Equality in a few cases.
1747 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1748 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1749 Type = TypeManager.bool_type;
1754 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1755 Type = TypeManager.bool_type;
1761 // Do not perform operator overload resolution when both sides are
1764 Expression left_operators = null, right_operators = null;
1765 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1767 // Step 1: Perform Operator Overload location
1769 string op = oper_names [(int) oper];
1771 MethodGroupExpr union;
1772 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc);
1774 right_operators = MemberLookup (
1775 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc);
1776 union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
1778 union = (MethodGroupExpr) left_operators;
1780 if (union != null) {
1781 ArrayList args = new ArrayList (2);
1782 args.Add (new Argument (left, Argument.AType.Expression));
1783 args.Add (new Argument (right, Argument.AType.Expression));
1785 MethodBase method = union.OverloadResolve (ec, args, true, Location.Null);
1787 if (method != null) {
1788 MethodInfo mi = (MethodInfo) method;
1789 return new BinaryMethod (mi.ReturnType, method, args);
1795 // Step 0: String concatenation (because overloading will get this wrong)
1797 if (oper == Operator.Addition){
1799 // If any of the arguments is a string, cast to string
1802 // Simple constant folding
1803 if (left is StringConstant && right is StringConstant)
1804 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1806 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1808 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1809 Error_OperatorCannotBeApplied ();
1813 // try to fold it in on the left
1814 if (left is StringConcat) {
1817 // We have to test here for not-null, since we can be doubly-resolved
1818 // take care of not appending twice
1821 type = TypeManager.string_type;
1822 ((StringConcat) left).Append (ec, right);
1823 return left.Resolve (ec);
1829 // Otherwise, start a new concat expression
1830 return new StringConcat (ec, loc, left, right).Resolve (ec);
1834 // Transform a + ( - b) into a - b
1836 if (right is Unary){
1837 Unary right_unary = (Unary) right;
1839 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1840 oper = Operator.Subtraction;
1841 right = right_unary.Expr;
1847 if (oper == Operator.Equality || oper == Operator.Inequality){
1848 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1849 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1850 Error_OperatorCannotBeApplied ();
1854 type = TypeManager.bool_type;
1858 if (l.IsPointer || r.IsPointer) {
1859 if (l.IsPointer && r.IsPointer) {
1860 type = TypeManager.bool_type;
1864 if (l.IsPointer && r == TypeManager.null_type) {
1865 right = new EmptyCast (NullPointer.Null, l);
1866 type = TypeManager.bool_type;
1870 if (r.IsPointer && l == TypeManager.null_type) {
1871 left = new EmptyCast (NullPointer.Null, r);
1872 type = TypeManager.bool_type;
1878 if (l.IsGenericParameter && r.IsGenericParameter) {
1879 GenericConstraints l_gc, r_gc;
1881 l_gc = TypeManager.GetTypeParameterConstraints (l);
1882 r_gc = TypeManager.GetTypeParameterConstraints (r);
1884 if ((l_gc == null) || (r_gc == null) ||
1885 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1886 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1887 Error_OperatorCannotBeApplied ();
1895 // operator != (object a, object b)
1896 // operator == (object a, object b)
1898 // For this to be used, both arguments have to be reference-types.
1899 // Read the rationale on the spec (14.9.6)
1901 if (!(l.IsValueType || r.IsValueType)){
1902 type = TypeManager.bool_type;
1908 // Also, a standard conversion must exist from either one
1910 bool left_to_right =
1911 Convert.ImplicitStandardConversionExists (left, r);
1912 bool right_to_left = !left_to_right &&
1913 Convert.ImplicitStandardConversionExists (right, l);
1915 if (!left_to_right && !right_to_left) {
1916 Error_OperatorCannotBeApplied ();
1920 if (left_to_right && left_operators != null &&
1921 RootContext.WarningLevel >= 2) {
1922 ArrayList args = new ArrayList (2);
1923 args.Add (new Argument (left, Argument.AType.Expression));
1924 args.Add (new Argument (left, Argument.AType.Expression));
1925 MethodBase method = ((MethodGroupExpr)left_operators).OverloadResolve (
1926 ec, args, true, Location.Null);
1928 Warning_UnintendedReferenceComparison (loc, "right", l);
1931 if (right_to_left && right_operators != null &&
1932 RootContext.WarningLevel >= 2) {
1933 ArrayList args = new ArrayList (2);
1934 args.Add (new Argument (right, Argument.AType.Expression));
1935 args.Add (new Argument (right, Argument.AType.Expression));
1936 MethodBase method = ((MethodGroupExpr)right_operators).OverloadResolve (
1937 ec, args, true, Location.Null);
1939 Warning_UnintendedReferenceComparison (loc, "left", r);
1943 // We are going to have to convert to an object to compare
1945 if (l != TypeManager.object_type)
1946 left = new EmptyCast (left, TypeManager.object_type);
1947 if (r != TypeManager.object_type)
1948 right = new EmptyCast (right, TypeManager.object_type);
1954 // Only perform numeric promotions on:
1955 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1957 if (oper == Operator.Addition || oper == Operator.Subtraction) {
1958 if (TypeManager.IsDelegateType (l)){
1959 if (((right.eclass == ExprClass.MethodGroup) ||
1960 (r == TypeManager.anonymous_method_type))){
1961 if ((RootContext.Version != LanguageVersion.ISO_1)){
1962 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
1970 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
1972 ArrayList args = new ArrayList (2);
1974 args = new ArrayList (2);
1975 args.Add (new Argument (left, Argument.AType.Expression));
1976 args.Add (new Argument (right, Argument.AType.Expression));
1978 if (oper == Operator.Addition)
1979 method = TypeManager.delegate_combine_delegate_delegate;
1981 method = TypeManager.delegate_remove_delegate_delegate;
1983 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
1984 Error_OperatorCannotBeApplied ();
1988 return new BinaryDelegate (l, method, args);
1993 // Pointer arithmetic:
1995 // T* operator + (T* x, int y);
1996 // T* operator + (T* x, uint y);
1997 // T* operator + (T* x, long y);
1998 // T* operator + (T* x, ulong y);
2000 // T* operator + (int y, T* x);
2001 // T* operator + (uint y, T *x);
2002 // T* operator + (long y, T *x);
2003 // T* operator + (ulong y, T *x);
2005 // T* operator - (T* x, int y);
2006 // T* operator - (T* x, uint y);
2007 // T* operator - (T* x, long y);
2008 // T* operator - (T* x, ulong y);
2010 // long operator - (T* x, T *y)
2013 if (r.IsPointer && oper == Operator.Subtraction){
2015 return new PointerArithmetic (
2016 false, left, right, TypeManager.int64_type,
2019 Expression t = Make32or64 (ec, right);
2021 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2023 } else if (r.IsPointer && oper == Operator.Addition){
2024 Expression t = Make32or64 (ec, left);
2026 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2031 // Enumeration operators
2033 bool lie = TypeManager.IsEnumType (l);
2034 bool rie = TypeManager.IsEnumType (r);
2038 // U operator - (E e, E f)
2040 if (oper == Operator.Subtraction){
2042 type = TypeManager.EnumToUnderlying (l);
2045 Error_OperatorCannotBeApplied ();
2051 // operator + (E e, U x)
2052 // operator - (E e, U x)
2054 if (oper == Operator.Addition || oper == Operator.Subtraction){
2055 Type enum_type = lie ? l : r;
2056 Type other_type = lie ? r : l;
2057 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2059 if (underlying_type != other_type){
2060 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2070 Error_OperatorCannotBeApplied ();
2079 temp = Convert.ImplicitConversion (ec, right, l, loc);
2083 Error_OperatorCannotBeApplied ();
2087 temp = Convert.ImplicitConversion (ec, left, r, loc);
2092 Error_OperatorCannotBeApplied ();
2097 if (oper == Operator.Equality || oper == Operator.Inequality ||
2098 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2099 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2100 if (left.Type != right.Type){
2101 Error_OperatorCannotBeApplied ();
2104 type = TypeManager.bool_type;
2108 if (oper == Operator.BitwiseAnd ||
2109 oper == Operator.BitwiseOr ||
2110 oper == Operator.ExclusiveOr){
2111 if (left.Type != right.Type){
2112 Error_OperatorCannotBeApplied ();
2118 Error_OperatorCannotBeApplied ();
2122 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2123 return CheckShiftArguments (ec);
2125 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2126 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2127 type = TypeManager.bool_type;
2131 left_operators = l == TypeManager.bool_type ?
2132 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2133 right_operators = r == TypeManager.bool_type ?
2134 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2136 if (left_operators != null && right_operators != null) {
2137 left = left_operators;
2138 right = right_operators;
2139 type = TypeManager.bool_type;
2143 Expression e = new ConditionalLogicalOperator (
2144 oper == Operator.LogicalAnd, left, right, l, loc);
2145 return e.Resolve (ec);
2148 Expression orig_left = left;
2149 Expression orig_right = right;
2152 // operator & (bool x, bool y)
2153 // operator | (bool x, bool y)
2154 // operator ^ (bool x, bool y)
2156 if (oper == Operator.BitwiseAnd ||
2157 oper == Operator.BitwiseOr ||
2158 oper == Operator.ExclusiveOr) {
2159 if (OverloadResolve_PredefinedIntegral (ec)) {
2160 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2161 Error_OperatorAmbiguous (loc, oper, l, r);
2165 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2166 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2167 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2168 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2169 TypeManager.CSharpName (r));
2172 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2173 Error_OperatorCannotBeApplied ();
2180 // Pointer comparison
2182 if (l.IsPointer && r.IsPointer){
2183 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2184 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2185 type = TypeManager.bool_type;
2190 if (OverloadResolve_PredefinedIntegral (ec)) {
2191 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2192 Error_OperatorAmbiguous (loc, oper, l, r);
2195 } else if (OverloadResolve_PredefinedFloating (ec)) {
2196 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2197 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2198 Error_OperatorAmbiguous (loc, oper, l, r);
2201 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2202 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2203 Error_OperatorAmbiguous (loc, oper, l, r);
2206 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2207 Error_OperatorCannotBeApplied ();
2211 if (oper == Operator.Equality ||
2212 oper == Operator.Inequality ||
2213 oper == Operator.LessThanOrEqual ||
2214 oper == Operator.LessThan ||
2215 oper == Operator.GreaterThanOrEqual ||
2216 oper == Operator.GreaterThan)
2217 type = TypeManager.bool_type;
2222 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2224 if (r == TypeManager.string_type)
2226 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2227 ec.ContainerType, lookup, oper_names [(int) oper],
2228 MemberTypes.Method, AllBindingFlags, loc);
2229 ArrayList args = new ArrayList (2);
2230 args.Add (new Argument (left, Argument.AType.Expression));
2231 args.Add (new Argument (right, Argument.AType.Expression));
2232 MethodBase method = ops.OverloadResolve (ec, args, true, Location.Null);
2233 return new BinaryMethod (type, method, args);
2239 Constant EnumLiftUp (Constant left, Constant right)
2242 case Operator.BitwiseOr:
2243 case Operator.BitwiseAnd:
2244 case Operator.ExclusiveOr:
2245 case Operator.Equality:
2246 case Operator.Inequality:
2247 case Operator.LessThan:
2248 case Operator.LessThanOrEqual:
2249 case Operator.GreaterThan:
2250 case Operator.GreaterThanOrEqual:
2251 if (left is EnumConstant)
2254 if (left.IsZeroInteger)
2255 return new EnumConstant (left, right.Type);
2259 case Operator.Addition:
2260 case Operator.Subtraction:
2263 case Operator.Multiply:
2264 case Operator.Division:
2265 case Operator.Modulus:
2266 case Operator.LeftShift:
2267 case Operator.RightShift:
2268 if (right is EnumConstant || left is EnumConstant)
2272 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2276 public override Expression DoResolve (EmitContext ec)
2281 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2282 left = ((ParenthesizedExpression) left).Expr;
2283 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2287 if (left.eclass == ExprClass.Type) {
2288 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2292 left = left.Resolve (ec);
2297 Constant lc = left as Constant;
2298 if (lc != null && lc.Type == TypeManager.bool_type &&
2299 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2300 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2302 // TODO: make a sense to resolve unreachable expression as we do for statement
2303 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2307 right = right.Resolve (ec);
2311 eclass = ExprClass.Value;
2312 Constant rc = right as Constant;
2314 // The conversion rules are ignored in enum context but why
2315 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2316 left = lc = EnumLiftUp (lc, rc);
2320 right = rc = EnumLiftUp (rc, lc);
2325 if (oper == Operator.BitwiseAnd) {
2326 if (rc != null && rc.IsZeroInteger) {
2327 return lc is EnumConstant ?
2328 new EnumConstant (rc, lc.Type):
2332 if (lc != null && lc.IsZeroInteger) {
2333 return rc is EnumConstant ?
2334 new EnumConstant (lc, rc.Type):
2338 else if (oper == Operator.BitwiseOr) {
2339 if (lc is EnumConstant &&
2340 rc != null && rc.IsZeroInteger)
2342 if (rc is EnumConstant &&
2343 lc != null && lc.IsZeroInteger)
2345 } else if (oper == Operator.LogicalAnd) {
2346 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2348 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2352 if (rc != null && lc != null){
2353 int prev_e = Report.Errors;
2354 Expression e = ConstantFold.BinaryFold (
2355 ec, oper, lc, rc, loc);
2356 if (e != null || Report.Errors != prev_e)
2361 if ((left is NullLiteral || left.Type.IsValueType) &&
2362 (right is NullLiteral || right.Type.IsValueType) &&
2363 !(left is NullLiteral && right is NullLiteral) &&
2364 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2365 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2368 // Comparison warnings
2369 if (oper == Operator.Equality || oper == Operator.Inequality ||
2370 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2371 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2372 if (left.Equals (right)) {
2373 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2375 CheckUselessComparison (lc, right.Type);
2376 CheckUselessComparison (rc, left.Type);
2379 return ResolveOperator (ec);
2382 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2387 private void CheckUselessComparison (Constant c, Type type)
2389 if (c == null || !IsTypeIntegral (type)
2390 || c is StringConstant
2391 || c is BoolConstant
2392 || c is FloatConstant
2393 || c is DoubleConstant
2394 || c is DecimalConstant
2400 if (c is ULongConstant) {
2401 ulong uvalue = ((ULongConstant) c).Value;
2402 if (uvalue > long.MaxValue) {
2403 if (type == TypeManager.byte_type ||
2404 type == TypeManager.sbyte_type ||
2405 type == TypeManager.short_type ||
2406 type == TypeManager.ushort_type ||
2407 type == TypeManager.int32_type ||
2408 type == TypeManager.uint32_type ||
2409 type == TypeManager.int64_type ||
2410 type == TypeManager.char_type)
2411 WarnUselessComparison (type);
2414 value = (long) uvalue;
2416 else if (c is ByteConstant)
2417 value = ((ByteConstant) c).Value;
2418 else if (c is SByteConstant)
2419 value = ((SByteConstant) c).Value;
2420 else if (c is ShortConstant)
2421 value = ((ShortConstant) c).Value;
2422 else if (c is UShortConstant)
2423 value = ((UShortConstant) c).Value;
2424 else if (c is IntConstant)
2425 value = ((IntConstant) c).Value;
2426 else if (c is UIntConstant)
2427 value = ((UIntConstant) c).Value;
2428 else if (c is LongConstant)
2429 value = ((LongConstant) c).Value;
2430 else if (c is CharConstant)
2431 value = ((CharConstant)c).Value;
2436 if (IsValueOutOfRange (value, type))
2437 WarnUselessComparison (type);
2440 private bool IsValueOutOfRange (long value, Type type)
2442 if (IsTypeUnsigned (type) && value < 0)
2444 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2445 type == TypeManager.byte_type && value >= 0x100 ||
2446 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2447 type == TypeManager.ushort_type && value >= 0x10000 ||
2448 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2449 type == TypeManager.uint32_type && value >= 0x100000000;
2452 private static bool IsTypeIntegral (Type type)
2454 return type == TypeManager.uint64_type ||
2455 type == TypeManager.int64_type ||
2456 type == TypeManager.uint32_type ||
2457 type == TypeManager.int32_type ||
2458 type == TypeManager.ushort_type ||
2459 type == TypeManager.short_type ||
2460 type == TypeManager.sbyte_type ||
2461 type == TypeManager.byte_type ||
2462 type == TypeManager.char_type;
2465 private static bool IsTypeUnsigned (Type type)
2467 return type == TypeManager.uint64_type ||
2468 type == TypeManager.uint32_type ||
2469 type == TypeManager.ushort_type ||
2470 type == TypeManager.byte_type ||
2471 type == TypeManager.char_type;
2474 private void WarnUselessComparison (Type type)
2476 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}'",
2477 TypeManager.CSharpName (type));
2481 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2482 /// context of a conditional bool expression. This function will return
2483 /// false if it is was possible to use EmitBranchable, or true if it was.
2485 /// The expression's code is generated, and we will generate a branch to `target'
2486 /// if the resulting expression value is equal to isTrue
2488 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2490 ILGenerator ig = ec.ig;
2493 // This is more complicated than it looks, but its just to avoid
2494 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2495 // but on top of that we want for == and != to use a special path
2496 // if we are comparing against null
2498 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2499 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2502 // put the constant on the rhs, for simplicity
2504 if (left is Constant) {
2505 Expression swap = right;
2510 if (((Constant) right).IsZeroInteger) {
2513 ig.Emit (OpCodes.Brtrue, target);
2515 ig.Emit (OpCodes.Brfalse, target);
2518 } else if (right is BoolConstant) {
2520 if (my_on_true != ((BoolConstant) right).Value)
2521 ig.Emit (OpCodes.Brtrue, target);
2523 ig.Emit (OpCodes.Brfalse, target);
2528 } else if (oper == Operator.LogicalAnd) {
2531 Label tests_end = ig.DefineLabel ();
2533 left.EmitBranchable (ec, tests_end, false);
2534 right.EmitBranchable (ec, target, true);
2535 ig.MarkLabel (tests_end);
2538 // This optimizes code like this
2539 // if (true && i > 4)
2541 if (!(left is Constant))
2542 left.EmitBranchable (ec, target, false);
2544 if (!(right is Constant))
2545 right.EmitBranchable (ec, target, false);
2550 } else if (oper == Operator.LogicalOr){
2552 left.EmitBranchable (ec, target, true);
2553 right.EmitBranchable (ec, target, true);
2556 Label tests_end = ig.DefineLabel ();
2557 left.EmitBranchable (ec, tests_end, true);
2558 right.EmitBranchable (ec, target, false);
2559 ig.MarkLabel (tests_end);
2564 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2565 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2566 oper == Operator.Equality || oper == Operator.Inequality)) {
2567 base.EmitBranchable (ec, target, onTrue);
2575 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2578 case Operator.Equality:
2580 ig.Emit (OpCodes.Beq, target);
2582 ig.Emit (OpCodes.Bne_Un, target);
2585 case Operator.Inequality:
2587 ig.Emit (OpCodes.Bne_Un, target);
2589 ig.Emit (OpCodes.Beq, target);
2592 case Operator.LessThan:
2595 ig.Emit (OpCodes.Blt_Un, target);
2597 ig.Emit (OpCodes.Blt, target);
2600 ig.Emit (OpCodes.Bge_Un, target);
2602 ig.Emit (OpCodes.Bge, target);
2605 case Operator.GreaterThan:
2608 ig.Emit (OpCodes.Bgt_Un, target);
2610 ig.Emit (OpCodes.Bgt, target);
2613 ig.Emit (OpCodes.Ble_Un, target);
2615 ig.Emit (OpCodes.Ble, target);
2618 case Operator.LessThanOrEqual:
2621 ig.Emit (OpCodes.Ble_Un, target);
2623 ig.Emit (OpCodes.Ble, target);
2626 ig.Emit (OpCodes.Bgt_Un, target);
2628 ig.Emit (OpCodes.Bgt, target);
2632 case Operator.GreaterThanOrEqual:
2635 ig.Emit (OpCodes.Bge_Un, target);
2637 ig.Emit (OpCodes.Bge, target);
2640 ig.Emit (OpCodes.Blt_Un, target);
2642 ig.Emit (OpCodes.Blt, target);
2645 Console.WriteLine (oper);
2646 throw new Exception ("what is THAT");
2650 public override void Emit (EmitContext ec)
2652 ILGenerator ig = ec.ig;
2657 // Handle short-circuit operators differently
2660 if (oper == Operator.LogicalAnd) {
2661 Label load_zero = ig.DefineLabel ();
2662 Label end = ig.DefineLabel ();
2664 left.EmitBranchable (ec, load_zero, false);
2666 ig.Emit (OpCodes.Br, end);
2668 ig.MarkLabel (load_zero);
2669 ig.Emit (OpCodes.Ldc_I4_0);
2672 } else if (oper == Operator.LogicalOr) {
2673 Label load_one = ig.DefineLabel ();
2674 Label end = ig.DefineLabel ();
2676 left.EmitBranchable (ec, load_one, true);
2678 ig.Emit (OpCodes.Br, end);
2680 ig.MarkLabel (load_one);
2681 ig.Emit (OpCodes.Ldc_I4_1);
2689 bool isUnsigned = is_unsigned (left.Type);
2692 case Operator.Multiply:
2694 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2695 opcode = OpCodes.Mul_Ovf;
2696 else if (isUnsigned)
2697 opcode = OpCodes.Mul_Ovf_Un;
2699 opcode = OpCodes.Mul;
2701 opcode = OpCodes.Mul;
2705 case Operator.Division:
2707 opcode = OpCodes.Div_Un;
2709 opcode = OpCodes.Div;
2712 case Operator.Modulus:
2714 opcode = OpCodes.Rem_Un;
2716 opcode = OpCodes.Rem;
2719 case Operator.Addition:
2721 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2722 opcode = OpCodes.Add_Ovf;
2723 else if (isUnsigned)
2724 opcode = OpCodes.Add_Ovf_Un;
2726 opcode = OpCodes.Add;
2728 opcode = OpCodes.Add;
2731 case Operator.Subtraction:
2733 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2734 opcode = OpCodes.Sub_Ovf;
2735 else if (isUnsigned)
2736 opcode = OpCodes.Sub_Ovf_Un;
2738 opcode = OpCodes.Sub;
2740 opcode = OpCodes.Sub;
2743 case Operator.RightShift:
2745 opcode = OpCodes.Shr_Un;
2747 opcode = OpCodes.Shr;
2750 case Operator.LeftShift:
2751 opcode = OpCodes.Shl;
2754 case Operator.Equality:
2755 opcode = OpCodes.Ceq;
2758 case Operator.Inequality:
2759 ig.Emit (OpCodes.Ceq);
2760 ig.Emit (OpCodes.Ldc_I4_0);
2762 opcode = OpCodes.Ceq;
2765 case Operator.LessThan:
2767 opcode = OpCodes.Clt_Un;
2769 opcode = OpCodes.Clt;
2772 case Operator.GreaterThan:
2774 opcode = OpCodes.Cgt_Un;
2776 opcode = OpCodes.Cgt;
2779 case Operator.LessThanOrEqual:
2780 Type lt = left.Type;
2782 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2783 ig.Emit (OpCodes.Cgt_Un);
2785 ig.Emit (OpCodes.Cgt);
2786 ig.Emit (OpCodes.Ldc_I4_0);
2788 opcode = OpCodes.Ceq;
2791 case Operator.GreaterThanOrEqual:
2792 Type le = left.Type;
2794 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2795 ig.Emit (OpCodes.Clt_Un);
2797 ig.Emit (OpCodes.Clt);
2799 ig.Emit (OpCodes.Ldc_I4_0);
2801 opcode = OpCodes.Ceq;
2804 case Operator.BitwiseOr:
2805 opcode = OpCodes.Or;
2808 case Operator.BitwiseAnd:
2809 opcode = OpCodes.And;
2812 case Operator.ExclusiveOr:
2813 opcode = OpCodes.Xor;
2817 throw new Exception ("This should not happen: Operator = "
2818 + oper.ToString ());
2824 protected override void CloneTo (CloneContext clonectx, Expression t)
2826 Binary target = (Binary) t;
2828 target.left = left.Clone (clonectx);
2829 target.right = right.Clone (clonectx);
2834 // Object created by Binary when the binary operator uses an method instead of being
2835 // a binary operation that maps to a CIL binary operation.
2837 public class BinaryMethod : Expression {
2838 public MethodBase method;
2839 public ArrayList Arguments;
2841 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2846 eclass = ExprClass.Value;
2849 public override Expression DoResolve (EmitContext ec)
2854 public override void Emit (EmitContext ec)
2856 ILGenerator ig = ec.ig;
2858 if (Arguments != null)
2859 Invocation.EmitArguments (ec, method, Arguments, false, null);
2861 if (method is MethodInfo)
2862 ig.Emit (OpCodes.Call, (MethodInfo) method);
2864 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2869 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2870 // b, c, d... may be strings or objects.
2872 public class StringConcat : Expression {
2874 bool invalid = false;
2875 bool emit_conv_done = false;
2877 // Are we also concating objects?
2879 bool is_strings_only = true;
2881 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2884 type = TypeManager.string_type;
2885 eclass = ExprClass.Value;
2887 operands = new ArrayList (2);
2892 public override Expression DoResolve (EmitContext ec)
2900 public void Append (EmitContext ec, Expression operand)
2905 StringConstant sc = operand as StringConstant;
2907 // TODO: it will be better to do this silently as an optimalization
2909 // string s = "" + i;
2910 // because this code has poor performace
2911 // if (sc.Value.Length == 0)
2912 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2914 if (operands.Count != 0) {
2915 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2916 if (last_operand != null) {
2917 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2924 // Conversion to object
2926 if (operand.Type != TypeManager.string_type) {
2927 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2930 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2936 operands.Add (operand);
2939 public override void Emit (EmitContext ec)
2941 MethodInfo concat_method = null;
2944 // Do conversion to arguments; check for strings only
2947 // This can get called multiple times, so we have to deal with that.
2948 if (!emit_conv_done) {
2949 emit_conv_done = true;
2950 for (int i = 0; i < operands.Count; i ++) {
2951 Expression e = (Expression) operands [i];
2952 is_strings_only &= e.Type == TypeManager.string_type;
2955 for (int i = 0; i < operands.Count; i ++) {
2956 Expression e = (Expression) operands [i];
2958 if (! is_strings_only && e.Type == TypeManager.string_type) {
2959 // need to make sure this is an object, because the EmitParams
2960 // method might look at the type of this expression, see it is a
2961 // string and emit a string [] when we want an object [];
2963 e = new EmptyCast (e, TypeManager.object_type);
2965 operands [i] = new Argument (e, Argument.AType.Expression);
2970 // Find the right method
2972 switch (operands.Count) {
2975 // This should not be possible, because simple constant folding
2976 // is taken care of in the Binary code.
2978 throw new Exception ("how did you get here?");
2981 concat_method = is_strings_only ?
2982 TypeManager.string_concat_string_string :
2983 TypeManager.string_concat_object_object ;
2986 concat_method = is_strings_only ?
2987 TypeManager.string_concat_string_string_string :
2988 TypeManager.string_concat_object_object_object ;
2992 // There is not a 4 param overlaod for object (the one that there is
2993 // is actually a varargs methods, and is only in corlib because it was
2994 // introduced there before.).
2996 if (!is_strings_only)
2999 concat_method = TypeManager.string_concat_string_string_string_string;
3002 concat_method = is_strings_only ?
3003 TypeManager.string_concat_string_dot_dot_dot :
3004 TypeManager.string_concat_object_dot_dot_dot ;
3008 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3009 ec.ig.Emit (OpCodes.Call, concat_method);
3014 // Object created with +/= on delegates
3016 public class BinaryDelegate : Expression {
3020 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3025 eclass = ExprClass.Value;
3028 public override Expression DoResolve (EmitContext ec)
3033 public override void Emit (EmitContext ec)
3035 ILGenerator ig = ec.ig;
3037 Invocation.EmitArguments (ec, method, args, false, null);
3039 ig.Emit (OpCodes.Call, (MethodInfo) method);
3040 ig.Emit (OpCodes.Castclass, type);
3043 public Expression Right {
3045 Argument arg = (Argument) args [1];
3050 public bool IsAddition {
3052 return method == TypeManager.delegate_combine_delegate_delegate;
3058 // User-defined conditional logical operator
3059 public class ConditionalLogicalOperator : Expression {
3060 Expression left, right;
3063 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3066 eclass = ExprClass.Value;
3070 this.is_and = is_and;
3073 protected void Error19 ()
3075 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3078 protected void Error218 ()
3080 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3081 "declarations of operator true and operator false");
3084 Expression op_true, op_false, op;
3085 LocalTemporary left_temp;
3087 public override Expression DoResolve (EmitContext ec)
3090 Expression operator_group;
3092 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3093 if (operator_group == null) {
3098 left_temp = new LocalTemporary (type);
3100 ArrayList arguments = new ArrayList (2);
3101 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3102 arguments.Add (new Argument (right, Argument.AType.Expression));
3103 method = ((MethodGroupExpr) operator_group).OverloadResolve (
3104 ec, arguments, false, loc)
3106 if (method == null) {
3111 if (method.ReturnType != type) {
3112 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3113 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3117 op = new StaticCallExpr (method, arguments, loc);
3119 op_true = GetOperatorTrue (ec, left_temp, loc);
3120 op_false = GetOperatorFalse (ec, left_temp, loc);
3121 if ((op_true == null) || (op_false == null)) {
3129 public override void Emit (EmitContext ec)
3131 ILGenerator ig = ec.ig;
3132 Label false_target = ig.DefineLabel ();
3133 Label end_target = ig.DefineLabel ();
3136 left_temp.Store (ec);
3138 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3139 left_temp.Emit (ec);
3140 ig.Emit (OpCodes.Br, end_target);
3141 ig.MarkLabel (false_target);
3143 ig.MarkLabel (end_target);
3145 // We release 'left_temp' here since 'op' may refer to it too
3146 left_temp.Release (ec);
3150 public class PointerArithmetic : Expression {
3151 Expression left, right;
3155 // We assume that `l' is always a pointer
3157 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3163 is_add = is_addition;
3166 public override Expression DoResolve (EmitContext ec)
3168 eclass = ExprClass.Variable;
3170 if (left.Type == TypeManager.void_ptr_type) {
3171 Error (242, "The operation in question is undefined on void pointers");
3178 public override void Emit (EmitContext ec)
3180 Type op_type = left.Type;
3181 ILGenerator ig = ec.ig;
3183 // It must be either array or fixed buffer
3184 Type element = TypeManager.HasElementType (op_type) ?
3185 element = TypeManager.GetElementType (op_type) :
3186 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3188 int size = GetTypeSize (element);
3189 Type rtype = right.Type;
3191 if (rtype.IsPointer){
3193 // handle (pointer - pointer)
3197 ig.Emit (OpCodes.Sub);
3201 ig.Emit (OpCodes.Sizeof, element);
3203 IntLiteral.EmitInt (ig, size);
3204 ig.Emit (OpCodes.Div);
3206 ig.Emit (OpCodes.Conv_I8);
3209 // handle + and - on (pointer op int)
3212 ig.Emit (OpCodes.Conv_I);
3214 Constant right_const = right as Constant;
3215 if (right_const != null && size != 0) {
3216 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3224 ig.Emit (OpCodes.Sizeof, element);
3226 IntLiteral.EmitInt (ig, size);
3227 if (rtype == TypeManager.int64_type)
3228 ig.Emit (OpCodes.Conv_I8);
3229 else if (rtype == TypeManager.uint64_type)
3230 ig.Emit (OpCodes.Conv_U8);
3231 ig.Emit (OpCodes.Mul);
3235 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3236 ig.Emit (OpCodes.Conv_I);
3239 ig.Emit (OpCodes.Add);
3241 ig.Emit (OpCodes.Sub);
3247 /// Implements the ternary conditional operator (?:)
3249 public class Conditional : Expression {
3250 Expression expr, trueExpr, falseExpr;
3252 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3255 this.trueExpr = trueExpr;
3256 this.falseExpr = falseExpr;
3257 this.loc = expr.Location;
3260 public Expression Expr {
3266 public Expression TrueExpr {
3272 public Expression FalseExpr {
3278 public override Expression DoResolve (EmitContext ec)
3280 expr = expr.Resolve (ec);
3286 if (TypeManager.IsNullableValueType (expr.Type))
3287 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3290 if (expr.Type != TypeManager.bool_type){
3291 expr = Expression.ResolveBoolean (
3298 Assign ass = expr as Assign;
3299 if (ass != null && ass.Source is Constant) {
3300 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3303 trueExpr = trueExpr.Resolve (ec);
3304 falseExpr = falseExpr.Resolve (ec);
3306 if (trueExpr == null || falseExpr == null)
3309 eclass = ExprClass.Value;
3310 if (trueExpr.Type == falseExpr.Type) {
3311 type = trueExpr.Type;
3312 if (type == TypeManager.null_type) {
3313 // TODO: probably will have to implement ConditionalConstant
3314 // to call method without return constant as well
3315 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3320 Type true_type = trueExpr.Type;
3321 Type false_type = falseExpr.Type;
3324 // First, if an implicit conversion exists from trueExpr
3325 // to falseExpr, then the result type is of type falseExpr.Type
3327 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3330 // Check if both can convert implicitl to each other's type
3332 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3334 "Can not compute type of conditional expression " +
3335 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3336 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3337 "' convert implicitly to each other");
3342 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3346 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3347 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3352 // Dead code optimalization
3353 if (expr is BoolConstant){
3354 BoolConstant bc = (BoolConstant) expr;
3356 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3357 return bc.Value ? trueExpr : falseExpr;
3363 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3368 public override void Emit (EmitContext ec)
3370 ILGenerator ig = ec.ig;
3371 Label false_target = ig.DefineLabel ();
3372 Label end_target = ig.DefineLabel ();
3374 expr.EmitBranchable (ec, false_target, false);
3376 ig.Emit (OpCodes.Br, end_target);
3377 ig.MarkLabel (false_target);
3378 falseExpr.Emit (ec);
3379 ig.MarkLabel (end_target);
3382 protected override void CloneTo (CloneContext clonectx, Expression t)
3384 Conditional target = (Conditional) t;
3386 target.expr = expr.Clone (clonectx);
3387 target.trueExpr = trueExpr.Clone (clonectx);
3388 target.falseExpr = falseExpr.Clone (clonectx);
3392 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3394 LocalTemporary temp;
3396 public abstract Variable Variable {
3400 public abstract bool IsRef {
3404 public override void Emit (EmitContext ec)
3410 // This method is used by parameters that are references, that are
3411 // being passed as references: we only want to pass the pointer (that
3412 // is already stored in the parameter, not the address of the pointer,
3413 // and not the value of the variable).
3415 public void EmitLoad (EmitContext ec)
3417 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3419 Variable.EmitInstance (ec);
3423 public void Emit (EmitContext ec, bool leave_copy)
3425 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3431 ec.ig.Emit (OpCodes.Dup);
3434 // If we are a reference, we loaded on the stack a pointer
3435 // Now lets load the real value
3437 LoadFromPtr (ec.ig, type);
3441 ec.ig.Emit (OpCodes.Dup);
3443 if (IsRef || Variable.NeedsTemporary) {
3444 temp = new LocalTemporary (Type);
3450 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3451 bool prepare_for_load)
3453 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3456 ILGenerator ig = ec.ig;
3457 prepared = prepare_for_load;
3459 Variable.EmitInstance (ec);
3460 if (prepare_for_load && Variable.HasInstance)
3461 ig.Emit (OpCodes.Dup);
3462 else if (IsRef && !prepared)
3468 ig.Emit (OpCodes.Dup);
3469 if (IsRef || Variable.NeedsTemporary) {
3470 temp = new LocalTemporary (Type);
3476 StoreFromPtr (ig, type);
3478 Variable.EmitAssign (ec);
3486 public void AddressOf (EmitContext ec, AddressOp mode)
3488 Variable.EmitInstance (ec);
3489 Variable.EmitAddressOf (ec);
3496 public class LocalVariableReference : VariableReference, IVariable {
3497 public readonly string Name;
3499 public LocalInfo local_info;
3503 public LocalVariableReference (Block block, string name, Location l)
3508 eclass = ExprClass.Variable;
3512 // Setting `is_readonly' to false will allow you to create a writable
3513 // reference to a read-only variable. This is used by foreach and using.
3515 public LocalVariableReference (Block block, string name, Location l,
3516 LocalInfo local_info, bool is_readonly)
3517 : this (block, name, l)
3519 this.local_info = local_info;
3520 this.is_readonly = is_readonly;
3523 public VariableInfo VariableInfo {
3524 get { return local_info.VariableInfo; }
3527 public override bool IsRef {
3528 get { return false; }
3531 public bool IsReadOnly {
3532 get { return is_readonly; }
3535 public bool VerifyAssigned (EmitContext ec)
3537 VariableInfo variable_info = local_info.VariableInfo;
3538 return variable_info == null || variable_info.IsAssigned (ec, loc);
3541 void ResolveLocalInfo ()
3543 if (local_info == null) {
3544 local_info = Block.GetLocalInfo (Name);
3545 is_readonly = local_info.ReadOnly;
3549 protected Expression DoResolveBase (EmitContext ec)
3551 type = local_info.VariableType;
3553 Expression e = Block.GetConstantExpression (Name);
3555 return e.Resolve (ec);
3557 if (!VerifyAssigned (ec))
3561 // If we are referencing a variable from the external block
3562 // flag it for capturing
3564 if (ec.MustCaptureVariable (local_info)) {
3565 if (local_info.AddressTaken){
3566 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3570 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3571 variable = scope.AddLocal (local_info);
3572 type = variable.Type;
3578 public override Expression DoResolve (EmitContext ec)
3580 ResolveLocalInfo ();
3581 local_info.Used = true;
3582 return DoResolveBase (ec);
3585 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3587 ResolveLocalInfo ();
3592 if (right_side == EmptyExpression.OutAccess) {
3593 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3594 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3595 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3596 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3597 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3599 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3601 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3606 if (right_side == EmptyExpression.OutAccess)
3607 local_info.Used = true;
3609 if (VariableInfo != null)
3610 VariableInfo.SetAssigned (ec);
3612 return DoResolveBase (ec);
3615 public bool VerifyFixed ()
3617 // A local Variable is always fixed.
3621 public override int GetHashCode ()
3623 return Name.GetHashCode ();
3626 public override bool Equals (object obj)
3628 LocalVariableReference lvr = obj as LocalVariableReference;
3632 return Name == lvr.Name && Block == lvr.Block;
3635 public override Variable Variable {
3636 get { return variable != null ? variable : local_info.Variable; }
3639 public override string ToString ()
3641 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3644 protected override void CloneTo (CloneContext clonectx, Expression t)
3646 LocalVariableReference target = (LocalVariableReference) t;
3648 target.Block = clonectx.LookupBlock (Block);
3653 /// This represents a reference to a parameter in the intermediate
3656 public class ParameterReference : VariableReference, IVariable {
3662 public bool is_ref, is_out;
3670 public override bool IsRef {
3676 public string Name {
3682 public Parameter Parameter {
3690 public ParameterReference (Parameter par, Block block, int idx, Location loc)
3693 this.name = par.Name;
3697 eclass = ExprClass.Variable;
3700 public VariableInfo VariableInfo {
3704 public override Variable Variable {
3705 get { return variable != null ? variable : par.Variable; }
3708 public bool VerifyFixed ()
3710 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3711 return par.ModFlags == Parameter.Modifier.NONE;
3714 public bool IsAssigned (EmitContext ec, Location loc)
3716 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3719 Report.Error (269, loc,
3720 "Use of unassigned out parameter `{0}'", par.Name);
3724 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3726 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3729 Report.Error (170, loc,
3730 "Use of possibly unassigned field `" + field_name + "'");
3734 public void SetAssigned (EmitContext ec)
3736 if (is_out && ec.DoFlowAnalysis)
3737 ec.CurrentBranching.SetAssigned (vi);
3740 public void SetFieldAssigned (EmitContext ec, string field_name)
3742 if (is_out && ec.DoFlowAnalysis)
3743 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3746 protected bool DoResolveBase (EmitContext ec)
3748 if (!par.Resolve (ec)) {
3752 type = par.ParameterType;
3753 Parameter.Modifier mod = par.ModFlags;
3754 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3755 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3756 eclass = ExprClass.Variable;
3759 vi = block.ParameterMap [idx];
3761 AnonymousContainer am = ec.CurrentAnonymousMethod;
3765 if (is_ref && !block.Toplevel.IsLocalParameter (name)){
3766 Report.Error (1628, Location,
3767 "Cannot use ref or out parameter `{0}' inside an " +
3768 "anonymous method block", par.Name);
3772 if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
3775 ToplevelBlock toplevel = block.Toplevel;
3776 while (toplevel != null) {
3777 if (toplevel.IsLocalParameter (name))
3780 toplevel = toplevel.Container;
3783 ScopeInfo scope = toplevel.CreateScopeInfo ();
3784 variable = scope.AddParameter (par, idx);
3785 type = variable.Type;
3789 public override int GetHashCode()
3791 return name.GetHashCode ();
3794 public override bool Equals (object obj)
3796 ParameterReference pr = obj as ParameterReference;
3800 return name == pr.name && block == pr.block;
3804 // Notice that for ref/out parameters, the type exposed is not the
3805 // same type exposed externally.
3808 // externally we expose "int&"
3809 // here we expose "int".
3811 // We record this in "is_ref". This means that the type system can treat
3812 // the type as it is expected, but when we generate the code, we generate
3813 // the alternate kind of code.
3815 public override Expression DoResolve (EmitContext ec)
3817 if (!DoResolveBase (ec))
3820 if (is_out && ec.DoFlowAnalysis &&
3821 (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3827 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3829 if (!DoResolveBase (ec))
3837 static public void EmitLdArg (ILGenerator ig, int x)
3841 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3842 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3843 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3844 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3845 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3848 ig.Emit (OpCodes.Ldarg, x);
3851 public override string ToString ()
3853 return "ParameterReference[" + name + "]";
3858 /// Used for arguments to New(), Invocation()
3860 public class Argument {
3861 public enum AType : byte {
3868 public static readonly Argument[] Empty = new Argument [0];
3870 public readonly AType ArgType;
3871 public Expression Expr;
3873 public Argument (Expression expr, AType type)
3876 this.ArgType = type;
3879 public Argument (Expression expr)
3882 this.ArgType = AType.Expression;
3887 if (ArgType == AType.Ref || ArgType == AType.Out)
3888 return TypeManager.GetReferenceType (Expr.Type);
3894 public Parameter.Modifier Modifier
3899 return Parameter.Modifier.OUT;
3902 return Parameter.Modifier.REF;
3905 return Parameter.Modifier.NONE;
3910 public static string FullDesc (Argument a)
3912 if (a.ArgType == AType.ArgList)
3915 return (a.ArgType == AType.Ref ? "ref " :
3916 (a.ArgType == AType.Out ? "out " : "")) +
3917 TypeManager.CSharpName (a.Expr.Type);
3920 public bool ResolveMethodGroup (EmitContext ec)
3922 SimpleName sn = Expr as SimpleName;
3924 Expr = sn.GetMethodGroup ();
3926 // FIXME: csc doesn't report any error if you try to use `ref' or
3927 // `out' in a delegate creation expression.
3928 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3935 public bool Resolve (EmitContext ec, Location loc)
3937 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3938 // Verify that the argument is readable
3939 if (ArgType != AType.Out)
3940 Expr = Expr.Resolve (ec);
3942 // Verify that the argument is writeable
3943 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3944 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3946 return Expr != null;
3950 public void Emit (EmitContext ec)
3952 if (ArgType != AType.Ref && ArgType != AType.Out) {
3957 AddressOp mode = AddressOp.Store;
3958 if (ArgType == AType.Ref)
3959 mode |= AddressOp.Load;
3961 IMemoryLocation ml = (IMemoryLocation) Expr;
3962 ParameterReference pr = ml as ParameterReference;
3965 // ParameterReferences might already be references, so we want
3966 // to pass just the value
3968 if (pr != null && pr.IsRef)
3971 ml.AddressOf (ec, mode);
3974 public Argument Clone (CloneContext clonectx)
3976 return new Argument (Expr.Clone (clonectx), ArgType);
3981 /// Invocation of methods or delegates.
3983 public class Invocation : ExpressionStatement {
3984 public ArrayList Arguments;
3987 MethodBase method = null;
3990 // arguments is an ArrayList, but we do not want to typecast,
3991 // as it might be null.
3993 // FIXME: only allow expr to be a method invocation or a
3994 // delegate invocation (7.5.5)
3996 public Invocation (Expression expr, ArrayList arguments)
3999 Arguments = arguments;
4000 loc = expr.Location;
4003 public Expression Expr {
4009 public static string FullMethodDesc (MethodBase mb)
4015 if (mb is MethodInfo) {
4016 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4020 sb = new StringBuilder ();
4022 sb.Append (TypeManager.CSharpSignature (mb));
4023 return sb.ToString ();
4026 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4028 MemberInfo [] miset;
4029 MethodGroupExpr union;
4034 return (MethodGroupExpr) mg2;
4037 return (MethodGroupExpr) mg1;
4040 MethodGroupExpr left_set = null, right_set = null;
4041 int length1 = 0, length2 = 0;
4043 left_set = (MethodGroupExpr) mg1;
4044 length1 = left_set.Methods.Length;
4046 right_set = (MethodGroupExpr) mg2;
4047 length2 = right_set.Methods.Length;
4049 ArrayList common = new ArrayList ();
4051 foreach (MethodBase r in right_set.Methods){
4052 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4056 miset = new MemberInfo [length1 + length2 - common.Count];
4057 left_set.Methods.CopyTo (miset, 0);
4061 foreach (MethodBase r in right_set.Methods) {
4062 if (!common.Contains (r))
4066 union = new MethodGroupExpr (miset, loc);
4071 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4072 ArrayList arguments, int arg_count,
4073 ref MethodBase candidate)
4075 return IsParamsMethodApplicable (
4076 ec, me, arguments, arg_count, false, ref candidate) ||
4077 IsParamsMethodApplicable (
4078 ec, me, arguments, arg_count, true, ref candidate);
4083 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4084 ArrayList arguments, int arg_count,
4085 bool do_varargs, ref MethodBase candidate)
4088 if (!me.HasTypeArguments &&
4089 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4092 if (TypeManager.IsGenericMethodDefinition (candidate))
4093 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4096 return IsParamsMethodApplicable (
4097 ec, arguments, arg_count, candidate, do_varargs);
4101 /// Determines if the candidate method, if a params method, is applicable
4102 /// in its expanded form to the given set of arguments
4104 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4105 int arg_count, MethodBase candidate,
4108 ParameterData pd = TypeManager.GetParameterData (candidate);
4110 int pd_count = pd.Count;
4114 int count = pd_count - 1;
4116 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4118 if (pd_count != arg_count)
4121 if (!(((Argument) arguments [count]).Expr is Arglist))
4129 if (count > arg_count)
4132 if (pd_count == 1 && arg_count == 0)
4136 // If we have come this far, the case which
4137 // remains is when the number of parameters is
4138 // less than or equal to the argument count.
4140 int argument_index = 0;
4142 for (int i = 0; i < pd_count; ++i) {
4144 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4145 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4146 int params_args_count = arg_count - pd_count;
4147 if (params_args_count < 0)
4151 a = (Argument) arguments [argument_index++];
4153 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4155 } while (params_args_count-- > 0);
4159 a = (Argument) arguments [argument_index++];
4161 Parameter.Modifier a_mod = a.Modifier &
4162 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4163 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4164 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4166 if (a_mod == p_mod) {
4168 if (a_mod == Parameter.Modifier.NONE)
4169 if (!Convert.ImplicitConversionExists (ec,
4171 pd.ParameterType (i)))
4174 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4175 Type pt = pd.ParameterType (i);
4178 pt = TypeManager.GetReferenceType (pt);
4191 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4192 ArrayList arguments, int arg_count,
4193 ref MethodBase candidate)
4196 if (!me.HasTypeArguments &&
4197 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4200 if (TypeManager.IsGenericMethodDefinition (candidate))
4201 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4204 return IsApplicable (ec, arguments, arg_count, candidate);
4208 /// Determines if the candidate method is applicable (section 14.4.2.1)
4209 /// to the given set of arguments
4211 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4212 MethodBase candidate)
4214 ParameterData pd = TypeManager.GetParameterData (candidate);
4216 if (arg_count != pd.Count)
4219 for (int i = arg_count; i > 0; ) {
4222 Argument a = (Argument) arguments [i];
4224 Parameter.Modifier a_mod = a.Modifier &
4225 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4227 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4228 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4230 if (a_mod == p_mod) {
4231 Type pt = pd.ParameterType (i);
4232 EmitContext prevec = EmitContext.TempEc;
4233 EmitContext.TempEc = ec;
4236 if (a_mod == Parameter.Modifier.NONE) {
4237 if (!TypeManager.IsEqual (a.Type, pt) &&
4238 !Convert.ImplicitConversionExists (ec, a.Expr, pt))
4243 EmitContext.TempEc = prevec;
4255 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4257 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4258 name, arg_count.ToString ());
4261 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4262 Type delegate_type, Argument a, ParameterData expected_par)
4264 if (delegate_type == null)
4265 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4266 TypeManager.CSharpSignature (method));
4268 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4269 TypeManager.CSharpName (delegate_type));
4271 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4273 string index = (idx + 1).ToString ();
4274 if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4275 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4276 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4277 index, Parameter.GetModifierSignature (a.Modifier));
4279 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4280 index, Parameter.GetModifierSignature (mod));
4282 string p1 = Argument.FullDesc (a);
4283 string p2 = expected_par.ParameterDesc (idx);
4286 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4287 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4288 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4290 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'", index, p1, p2);
4294 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4295 int arg_count, MethodBase method,
4296 bool chose_params_expanded,
4297 Type delegate_type, bool may_fail,
4300 ParameterData pd = TypeManager.GetParameterData (method);
4304 for (j = 0; j < pd.Count; j++) {
4305 Type parameter_type = pd.ParameterType (j);
4306 Parameter.Modifier pm = pd.ParameterModifier (j);
4308 if (pm == Parameter.Modifier.ARGLIST) {
4309 a = (Argument) Arguments [a_idx];
4310 if (!(a.Expr is Arglist))
4316 int params_arg_count = 1;
4317 if (pm == Parameter.Modifier.PARAMS) {
4318 pm = Parameter.Modifier.NONE;
4319 params_arg_count = arg_count - pd.Count + 1;
4320 if (chose_params_expanded)
4321 parameter_type = TypeManager.GetElementType (parameter_type);
4324 while (params_arg_count > 0) {
4325 a = (Argument) Arguments [a_idx];
4326 if (pm != a.Modifier)
4329 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4330 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4333 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4337 // Update the argument with the implicit conversion
4345 if (params_arg_count > 0)
4348 if (parameter_type.IsPointer && !ec.InUnsafe) {
4355 if (a_idx == arg_count)
4359 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4363 private bool resolved = false;
4364 public override Expression DoResolve (EmitContext ec)
4367 return this.method == null ? null : this;
4371 // First, resolve the expression that is used to
4372 // trigger the invocation
4374 SimpleName sn = expr as SimpleName;
4376 expr = sn.GetMethodGroup ();
4378 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4379 if (expr_resolved == null)
4382 MethodGroupExpr mg = expr_resolved as MethodGroupExpr;
4384 Type expr_type = expr_resolved.Type;
4386 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4387 return (new DelegateInvocation (
4388 expr_resolved, Arguments, loc)).Resolve (ec);
4390 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4395 // Next, evaluate all the expressions in the argument list
4397 if (Arguments != null){
4398 foreach (Argument a in Arguments){
4399 if (!a.Resolve (ec, loc))
4404 MethodBase method = mg.OverloadExtensionResolve (ec, ref Arguments, ref mg, expr, loc);
4410 MethodInfo mi = method as MethodInfo;
4412 type = TypeManager.TypeToCoreType (mi.ReturnType);
4413 Expression iexpr = mg.InstanceExpression;
4415 if (iexpr == null ||
4416 iexpr is This || iexpr is EmptyExpression ||
4417 mg.IdenticalTypeName) {
4418 mg.InstanceExpression = null;
4420 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4424 if (iexpr == null || iexpr is EmptyExpression) {
4425 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
4431 if (type.IsPointer){
4439 // Only base will allow this invocation to happen.
4441 if (mg.IsBase && method.IsAbstract){
4442 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4446 if (Arguments == null && method.Name == "Finalize") {
4448 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4450 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4454 if (IsSpecialMethodInvocation (method)) {
4458 if (mg.InstanceExpression != null){
4459 mg.InstanceExpression.CheckMarshalByRefAccess ();
4462 // This is used to check that no methods are called in struct
4463 // constructors before all the fields on the struct have been
4466 if (!method.IsStatic){
4467 This mgthis = mg.InstanceExpression as This;
4468 if (mgthis != null){
4469 if (!mgthis.CheckThisUsage (ec))
4475 eclass = ExprClass.Value;
4476 this.method = method;
4480 bool IsSpecialMethodInvocation (MethodBase method)
4482 if (!TypeManager.IsSpecialMethod (method))
4485 Report.SymbolRelatedToPreviousError (method);
4486 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4487 TypeManager.CSharpSignature (method, true));
4493 // Emits the list of arguments as an array
4495 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4497 ILGenerator ig = ec.ig;
4499 for (int j = 0; j < count; j++){
4500 Argument a = (Argument) arguments [j + idx];
4503 IntConstant.EmitInt (ig, count);
4504 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4507 ig.Emit (OpCodes.Dup);
4508 IntConstant.EmitInt (ig, j);
4510 bool is_stobj, has_type_arg;
4511 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4513 ig.Emit (OpCodes.Ldelema, t);
4525 /// Emits a list of resolved Arguments that are in the arguments
4528 /// The MethodBase argument might be null if the
4529 /// emission of the arguments is known not to contain
4530 /// a `params' field (for example in constructors or other routines
4531 /// that keep their arguments in this structure)
4533 /// if `dup_args' is true, a copy of the arguments will be left
4534 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4535 /// which will be duplicated before any other args. Only EmitCall
4536 /// should be using this interface.
4538 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4540 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4542 LocalTemporary [] temps = null;
4544 if (dup_args && top != 0)
4545 temps = new LocalTemporary [top];
4547 int argument_index = 0;
4549 for (int i = 0; i < top; i++){
4551 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4552 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4553 int params_args_count = arguments == null ?
4554 0 : arguments.Count - top + 1;
4556 // Fill not provided argument
4557 if (params_args_count <= 0) {
4558 ILGenerator ig = ec.ig;
4559 IntConstant.EmitInt (ig, 0);
4560 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4565 // Special case if we are passing the same data as the
4566 // params argument, we do not need to recreate an array.
4568 a = (Argument) arguments [argument_index];
4569 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4575 EmitParams (ec, arguments, i, params_args_count);
4576 argument_index += params_args_count;
4581 a = (Argument) arguments [argument_index++];
4584 ec.ig.Emit (OpCodes.Dup);
4585 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4590 if (this_arg != null)
4593 for (int i = 0; i < top; i ++) {
4594 temps [i].Emit (ec);
4595 temps [i].Release (ec);
4600 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4602 ParameterData pd = TypeManager.GetParameterData (mb);
4604 if (arguments == null)
4605 return new Type [0];
4607 Argument a = (Argument) arguments [pd.Count - 1];
4608 Arglist list = (Arglist) a.Expr;
4610 return list.ArgumentTypes;
4614 /// This checks the ConditionalAttribute on the method
4616 static bool IsMethodExcluded (MethodBase method)
4618 if (method.IsConstructor)
4621 IMethodData md = TypeManager.GetMethod (method);
4623 return md.IsExcluded ();
4625 // For some methods (generated by delegate class) GetMethod returns null
4626 // because they are not included in builder_to_method table
4627 if (method.DeclaringType is TypeBuilder)
4630 return AttributeTester.IsConditionalMethodExcluded (method);
4634 /// is_base tells whether we want to force the use of the `call'
4635 /// opcode instead of using callvirt. Call is required to call
4636 /// a specific method, while callvirt will always use the most
4637 /// recent method in the vtable.
4639 /// is_static tells whether this is an invocation on a static method
4641 /// instance_expr is an expression that represents the instance
4642 /// it must be non-null if is_static is false.
4644 /// method is the method to invoke.
4646 /// Arguments is the list of arguments to pass to the method or constructor.
4648 public static void EmitCall (EmitContext ec, bool is_base,
4649 bool is_static, Expression instance_expr,
4650 MethodBase method, ArrayList Arguments, Location loc)
4652 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
4655 // `dup_args' leaves an extra copy of the arguments on the stack
4656 // `omit_args' does not leave any arguments at all.
4657 // So, basically, you could make one call with `dup_args' set to true,
4658 // and then another with `omit_args' set to true, and the two calls
4659 // would have the same set of arguments. However, each argument would
4660 // only have been evaluated once.
4661 public static void EmitCall (EmitContext ec, bool is_base,
4662 bool is_static, Expression instance_expr,
4663 MethodBase method, ArrayList Arguments, Location loc,
4664 bool dup_args, bool omit_args)
4666 ILGenerator ig = ec.ig;
4667 bool struct_call = false;
4668 bool this_call = false;
4669 LocalTemporary this_arg = null;
4671 Type decl_type = method.DeclaringType;
4673 if (!RootContext.StdLib) {
4674 // Replace any calls to the system's System.Array type with calls to
4675 // the newly created one.
4676 if (method == TypeManager.system_int_array_get_length)
4677 method = TypeManager.int_array_get_length;
4678 else if (method == TypeManager.system_int_array_get_rank)
4679 method = TypeManager.int_array_get_rank;
4680 else if (method == TypeManager.system_object_array_clone)
4681 method = TypeManager.object_array_clone;
4682 else if (method == TypeManager.system_int_array_get_length_int)
4683 method = TypeManager.int_array_get_length_int;
4684 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4685 method = TypeManager.int_array_get_lower_bound_int;
4686 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4687 method = TypeManager.int_array_get_upper_bound_int;
4688 else if (method == TypeManager.system_void_array_copyto_array_int)
4689 method = TypeManager.void_array_copyto_array_int;
4692 if (!ec.IsInObsoleteScope) {
4694 // This checks ObsoleteAttribute on the method and on the declaring type
4696 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4698 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4700 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4702 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4706 if (IsMethodExcluded (method))
4710 if (instance_expr == EmptyExpression.Null) {
4711 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4715 this_call = instance_expr is This;
4716 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4720 // If this is ourselves, push "this"
4724 Type iexpr_type = instance_expr.Type;
4727 // Push the instance expression
4729 if (TypeManager.IsValueType (iexpr_type)) {
4731 // Special case: calls to a function declared in a
4732 // reference-type with a value-type argument need
4733 // to have their value boxed.
4734 if (decl_type.IsValueType ||
4735 TypeManager.IsGenericParameter (iexpr_type)) {
4737 // If the expression implements IMemoryLocation, then
4738 // we can optimize and use AddressOf on the
4741 // If not we have to use some temporary storage for
4743 if (instance_expr is IMemoryLocation) {
4744 ((IMemoryLocation)instance_expr).
4745 AddressOf (ec, AddressOp.LoadStore);
4747 LocalTemporary temp = new LocalTemporary (iexpr_type);
4748 instance_expr.Emit (ec);
4750 temp.AddressOf (ec, AddressOp.Load);
4753 // avoid the overhead of doing this all the time.
4755 t = TypeManager.GetReferenceType (iexpr_type);
4757 instance_expr.Emit (ec);
4758 ig.Emit (OpCodes.Box, instance_expr.Type);
4759 t = TypeManager.object_type;
4762 instance_expr.Emit (ec);
4763 t = instance_expr.Type;
4767 ig.Emit (OpCodes.Dup);
4768 if (Arguments != null && Arguments.Count != 0) {
4769 this_arg = new LocalTemporary (t);
4770 this_arg.Store (ec);
4777 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4780 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4781 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4785 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4786 call_op = OpCodes.Call;
4788 call_op = OpCodes.Callvirt;
4790 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4791 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4792 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4799 // and DoFoo is not virtual, you can omit the callvirt,
4800 // because you don't need the null checking behavior.
4802 if (method is MethodInfo)
4803 ig.Emit (call_op, (MethodInfo) method);
4805 ig.Emit (call_op, (ConstructorInfo) method);
4808 public override void Emit (EmitContext ec)
4810 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4812 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4815 public override void EmitStatement (EmitContext ec)
4820 // Pop the return value if there is one
4822 if (method is MethodInfo){
4823 Type ret = ((MethodInfo)method).ReturnType;
4824 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4825 ec.ig.Emit (OpCodes.Pop);
4829 protected override void CloneTo (CloneContext clonectx, Expression t)
4831 Invocation target = (Invocation) t;
4833 if (Arguments != null){
4834 target.Arguments = new ArrayList ();
4835 foreach (Argument a in Arguments)
4836 target.Arguments.Add (a.Clone (clonectx));
4839 expr = expr.Clone (clonectx);
4843 public class InvocationOrCast : ExpressionStatement
4846 Expression argument;
4848 public InvocationOrCast (Expression expr, Expression argument)
4851 this.argument = argument;
4852 this.loc = expr.Location;
4855 public override Expression DoResolve (EmitContext ec)
4858 // First try to resolve it as a cast.
4860 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4861 if ((te != null) && (te.eclass == ExprClass.Type)) {
4862 Cast cast = new Cast (te, argument, loc);
4863 return cast.Resolve (ec);
4867 // This can either be a type or a delegate invocation.
4868 // Let's just resolve it and see what we'll get.
4870 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4875 // Ok, so it's a Cast.
4877 if (expr.eclass == ExprClass.Type) {
4878 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4879 return cast.Resolve (ec);
4883 // It's a delegate invocation.
4885 if (!TypeManager.IsDelegateType (expr.Type)) {
4886 Error (149, "Method name expected");
4890 ArrayList args = new ArrayList ();
4891 args.Add (new Argument (argument, Argument.AType.Expression));
4892 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4893 return invocation.Resolve (ec);
4896 public override ExpressionStatement ResolveStatement (EmitContext ec)
4899 // First try to resolve it as a cast.
4901 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4902 if ((te != null) && (te.eclass == ExprClass.Type)) {
4903 Error_InvalidExpressionStatement ();
4908 // This can either be a type or a delegate invocation.
4909 // Let's just resolve it and see what we'll get.
4911 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4912 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4913 Error_InvalidExpressionStatement ();
4918 // It's a delegate invocation.
4920 if (!TypeManager.IsDelegateType (expr.Type)) {
4921 Error (149, "Method name expected");
4925 ArrayList args = new ArrayList ();
4926 args.Add (new Argument (argument, Argument.AType.Expression));
4927 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4928 return invocation.ResolveStatement (ec);
4931 public override void Emit (EmitContext ec)
4933 throw new Exception ("Cannot happen");
4936 public override void EmitStatement (EmitContext ec)
4938 throw new Exception ("Cannot happen");
4941 protected override void CloneTo (CloneContext clonectx, Expression t)
4943 InvocationOrCast target = (InvocationOrCast) t;
4945 target.expr = expr.Clone (clonectx);
4946 target.argument = argument.Clone (clonectx);
4951 // This class is used to "disable" the code generation for the
4952 // temporary variable when initializing value types.
4954 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4955 public void AddressOf (EmitContext ec, AddressOp Mode)
4962 /// Implements the new expression
4964 public class New : ExpressionStatement, IMemoryLocation {
4965 public ArrayList Arguments;
4968 // During bootstrap, it contains the RequestedType,
4969 // but if `type' is not null, it *might* contain a NewDelegate
4970 // (because of field multi-initialization)
4972 public Expression RequestedType;
4974 MethodBase method = null;
4977 // If set, the new expression is for a value_target, and
4978 // we will not leave anything on the stack.
4980 Expression value_target;
4981 bool value_target_set = false;
4982 bool is_type_parameter = false;
4984 public New (Expression requested_type, ArrayList arguments, Location l)
4986 RequestedType = requested_type;
4987 Arguments = arguments;
4991 public bool SetValueTypeVariable (Expression value)
4993 value_target = value;
4994 value_target_set = true;
4995 if (!(value_target is IMemoryLocation)){
4996 Error_UnexpectedKind (null, "variable", loc);
5003 // This function is used to disable the following code sequence for
5004 // value type initialization:
5006 // AddressOf (temporary)
5010 // Instead the provide will have provided us with the address on the
5011 // stack to store the results.
5013 static Expression MyEmptyExpression;
5015 public void DisableTemporaryValueType ()
5017 if (MyEmptyExpression == null)
5018 MyEmptyExpression = new EmptyAddressOf ();
5021 // To enable this, look into:
5022 // test-34 and test-89 and self bootstrapping.
5024 // For instance, we can avoid a copy by using `newobj'
5025 // instead of Call + Push-temp on value types.
5026 // value_target = MyEmptyExpression;
5031 /// Converts complex core type syntax like 'new int ()' to simple constant
5033 public static Constant Constantify (Type t)
5035 if (t == TypeManager.int32_type)
5036 return new IntConstant (0, Location.Null);
5037 if (t == TypeManager.uint32_type)
5038 return new UIntConstant (0, Location.Null);
5039 if (t == TypeManager.int64_type)
5040 return new LongConstant (0, Location.Null);
5041 if (t == TypeManager.uint64_type)
5042 return new ULongConstant (0, Location.Null);
5043 if (t == TypeManager.float_type)
5044 return new FloatConstant (0, Location.Null);
5045 if (t == TypeManager.double_type)
5046 return new DoubleConstant (0, Location.Null);
5047 if (t == TypeManager.short_type)
5048 return new ShortConstant (0, Location.Null);
5049 if (t == TypeManager.ushort_type)
5050 return new UShortConstant (0, Location.Null);
5051 if (t == TypeManager.sbyte_type)
5052 return new SByteConstant (0, Location.Null);
5053 if (t == TypeManager.byte_type)
5054 return new ByteConstant (0, Location.Null);
5055 if (t == TypeManager.char_type)
5056 return new CharConstant ('\0', Location.Null);
5057 if (t == TypeManager.bool_type)
5058 return new BoolConstant (false, Location.Null);
5059 if (t == TypeManager.decimal_type)
5060 return new DecimalConstant (0, Location.Null);
5061 if (TypeManager.IsEnumType (t))
5062 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5068 // Checks whether the type is an interface that has the
5069 // [ComImport, CoClass] attributes and must be treated
5072 public Expression CheckComImport (EmitContext ec)
5074 if (!type.IsInterface)
5078 // Turn the call into:
5079 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5081 Type real_class = AttributeTester.GetCoClassAttribute (type);
5082 if (real_class == null)
5085 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5086 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5087 return cast.Resolve (ec);
5090 public override Expression DoResolve (EmitContext ec)
5093 // The New DoResolve might be called twice when initializing field
5094 // expressions (see EmitFieldInitializers, the call to
5095 // GetInitializerExpression will perform a resolve on the expression,
5096 // and later the assign will trigger another resolution
5098 // This leads to bugs (#37014)
5101 if (RequestedType is NewDelegate)
5102 return RequestedType;
5106 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5112 if (type == TypeManager.void_type) {
5113 Error_VoidInvalidInTheContext (loc);
5117 if (Arguments == null) {
5118 Expression c = Constantify (type);
5123 if (TypeManager.IsDelegateType (type)) {
5124 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5125 if (RequestedType != null)
5126 if (!(RequestedType is DelegateCreation))
5127 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5128 return RequestedType;
5132 if (type.IsGenericParameter) {
5133 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5135 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5136 Error (304, String.Format (
5137 "Cannot create an instance of the " +
5138 "variable type '{0}' because it " +
5139 "doesn't have the new() constraint",
5144 if ((Arguments != null) && (Arguments.Count != 0)) {
5145 Error (417, String.Format (
5146 "`{0}': cannot provide arguments " +
5147 "when creating an instance of a " +
5148 "variable type.", type));
5152 is_type_parameter = true;
5153 eclass = ExprClass.Value;
5158 if (type.IsAbstract && type.IsSealed) {
5159 Report.SymbolRelatedToPreviousError (type);
5160 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5164 if (type.IsInterface || type.IsAbstract){
5165 RequestedType = CheckComImport (ec);
5166 if (RequestedType != null)
5167 return RequestedType;
5169 Report.SymbolRelatedToPreviousError (type);
5170 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5174 bool is_struct = type.IsValueType;
5175 eclass = ExprClass.Value;
5178 // SRE returns a match for .ctor () on structs (the object constructor),
5179 // so we have to manually ignore it.
5181 if (is_struct && Arguments == null)
5184 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5185 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5186 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5191 MethodGroupExpr mg = ml as MethodGroupExpr;
5194 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5198 if (Arguments != null){
5199 foreach (Argument a in Arguments){
5200 if (!a.Resolve (ec, loc))
5205 method = mg.OverloadResolve (ec, Arguments, false, loc);
5206 if (method == null) {
5207 if (almostMatchedMembers.Count != 0)
5208 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5215 bool DoEmitTypeParameter (EmitContext ec)
5218 ILGenerator ig = ec.ig;
5220 ig.Emit (OpCodes.Ldtoken, type);
5221 ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5222 ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5223 ig.Emit (OpCodes.Unbox_Any, type);
5226 throw new InternalErrorException ();
5231 // This DoEmit can be invoked in two contexts:
5232 // * As a mechanism that will leave a value on the stack (new object)
5233 // * As one that wont (init struct)
5235 // You can control whether a value is required on the stack by passing
5236 // need_value_on_stack. The code *might* leave a value on the stack
5237 // so it must be popped manually
5239 // If we are dealing with a ValueType, we have a few
5240 // situations to deal with:
5242 // * The target is a ValueType, and we have been provided
5243 // the instance (this is easy, we are being assigned).
5245 // * The target of New is being passed as an argument,
5246 // to a boxing operation or a function that takes a
5249 // In this case, we need to create a temporary variable
5250 // that is the argument of New.
5252 // Returns whether a value is left on the stack
5254 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5256 bool is_value_type = TypeManager.IsValueType (type);
5257 ILGenerator ig = ec.ig;
5262 // Allow DoEmit() to be called multiple times.
5263 // We need to create a new LocalTemporary each time since
5264 // you can't share LocalBuilders among ILGeneators.
5265 if (!value_target_set)
5266 value_target = new LocalTemporary (type);
5268 ml = (IMemoryLocation) value_target;
5269 ml.AddressOf (ec, AddressOp.Store);
5273 Invocation.EmitArguments (ec, method, Arguments, false, null);
5277 ig.Emit (OpCodes.Initobj, type);
5279 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5280 if (need_value_on_stack){
5281 value_target.Emit (ec);
5286 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5291 public override void Emit (EmitContext ec)
5293 if (is_type_parameter)
5294 DoEmitTypeParameter (ec);
5299 public override void EmitStatement (EmitContext ec)
5301 if (is_type_parameter)
5302 throw new InvalidOperationException ();
5304 if (DoEmit (ec, false))
5305 ec.ig.Emit (OpCodes.Pop);
5308 public void AddressOf (EmitContext ec, AddressOp Mode)
5310 if (is_type_parameter)
5311 throw new InvalidOperationException ();
5313 if (!type.IsValueType){
5315 // We throw an exception. So far, I believe we only need to support
5317 // foreach (int j in new StructType ())
5320 throw new Exception ("AddressOf should not be used for classes");
5323 if (!value_target_set)
5324 value_target = new LocalTemporary (type);
5326 IMemoryLocation ml = (IMemoryLocation) value_target;
5327 ml.AddressOf (ec, AddressOp.Store);
5329 Invocation.EmitArguments (ec, method, Arguments, false, null);
5332 ec.ig.Emit (OpCodes.Initobj, type);
5334 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5336 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5339 protected override void CloneTo (CloneContext clonectx, Expression t)
5341 New target = (New) t;
5343 target.RequestedType = RequestedType.Clone (clonectx);
5344 if (Arguments != null){
5345 target.Arguments = new ArrayList ();
5346 foreach (Argument a in Arguments){
5347 target.Arguments.Add (a.Clone (clonectx));
5354 /// 14.5.10.2: Represents an array creation expression.
5358 /// There are two possible scenarios here: one is an array creation
5359 /// expression that specifies the dimensions and optionally the
5360 /// initialization data and the other which does not need dimensions
5361 /// specified but where initialization data is mandatory.
5363 public class ArrayCreation : Expression {
5364 Expression requested_base_type;
5365 ArrayList initializers;
5368 // The list of Argument types.
5369 // This is used to construct the `newarray' or constructor signature
5371 ArrayList arguments;
5374 // Method used to create the array object.
5376 MethodBase new_method = null;
5378 Type array_element_type;
5379 Type underlying_type;
5380 bool is_one_dimensional = false;
5381 bool is_builtin_type = false;
5382 bool expect_initializers = false;
5383 int num_arguments = 0;
5387 ArrayList array_data;
5391 // The number of constants in array initializers
5392 int const_initializers_count;
5393 bool only_constant_initializers;
5395 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5397 this.requested_base_type = requested_base_type;
5398 this.initializers = initializers;
5402 arguments = new ArrayList ();
5404 foreach (Expression e in exprs) {
5405 arguments.Add (new Argument (e, Argument.AType.Expression));
5410 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5412 this.requested_base_type = requested_base_type;
5413 this.initializers = initializers;
5417 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5419 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5421 //dimensions = tmp.Length - 1;
5422 expect_initializers = true;
5425 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5427 StringBuilder sb = new StringBuilder (rank);
5430 for (int i = 1; i < idx_count; i++)
5435 return new ComposedCast (base_type, sb.ToString (), loc);
5438 void Error_IncorrectArrayInitializer ()
5440 Error (178, "Invalid rank specifier: expected `,' or `]'");
5443 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5445 if (specified_dims) {
5446 Argument a = (Argument) arguments [idx];
5448 if (!a.Resolve (ec, loc))
5451 Constant c = a.Expr as Constant;
5453 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5457 Report.Error (150, a.Expr.Location, "A constant value is expected");
5461 int value = (int) c.GetValue ();
5463 if (value != probe.Count) {
5464 Error_IncorrectArrayInitializer ();
5468 bounds [idx] = value;
5471 int child_bounds = -1;
5472 only_constant_initializers = true;
5473 for (int i = 0; i < probe.Count; ++i) {
5474 object o = probe [i];
5475 if (o is ArrayList) {
5476 ArrayList sub_probe = o as ArrayList;
5477 int current_bounds = sub_probe.Count;
5479 if (child_bounds == -1)
5480 child_bounds = current_bounds;
5482 else if (child_bounds != current_bounds){
5483 Error_IncorrectArrayInitializer ();
5486 if (idx + 1 >= dimensions){
5487 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5491 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5495 if (child_bounds != -1){
5496 Error_IncorrectArrayInitializer ();
5500 Expression tmp = (Expression) o;
5501 tmp = tmp.Resolve (ec);
5505 Expression conv = Convert.ImplicitConversionRequired (
5506 ec, tmp, underlying_type, loc);
5511 // Initializers with the default values can be ignored
5512 Constant c = conv as Constant;
5514 if (c.IsDefaultInitializer (array_element_type)) {
5518 ++const_initializers_count;
5521 only_constant_initializers = false;
5524 array_data.Add (conv);
5531 public void UpdateIndices ()
5534 for (ArrayList probe = initializers; probe != null;) {
5535 if (probe.Count > 0 && probe [0] is ArrayList) {
5536 Expression e = new IntConstant (probe.Count, Location.Null);
5537 arguments.Add (new Argument (e, Argument.AType.Expression));
5539 bounds [i++] = probe.Count;
5541 probe = (ArrayList) probe [0];
5544 Expression e = new IntConstant (probe.Count, Location.Null);
5545 arguments.Add (new Argument (e, Argument.AType.Expression));
5547 bounds [i++] = probe.Count;
5554 bool ResolveInitializers (EmitContext ec)
5556 if (initializers == null) {
5557 return !expect_initializers;
5560 if (underlying_type == null)
5564 // We use this to store all the date values in the order in which we
5565 // will need to store them in the byte blob later
5567 array_data = new ArrayList ();
5568 bounds = new System.Collections.Specialized.HybridDictionary ();
5570 if (arguments != null)
5571 return CheckIndices (ec, initializers, 0, true);
5573 arguments = new ArrayList ();
5575 if (!CheckIndices (ec, initializers, 0, false))
5580 if (arguments.Count != dimensions) {
5581 Error_IncorrectArrayInitializer ();
5589 // Creates the type of the array
5591 bool LookupType (EmitContext ec)
5593 StringBuilder array_qualifier = new StringBuilder (rank);
5596 // `In the first form allocates an array instace of the type that results
5597 // from deleting each of the individual expression from the expression list'
5599 if (num_arguments > 0) {
5600 array_qualifier.Append ("[");
5601 for (int i = num_arguments-1; i > 0; i--)
5602 array_qualifier.Append (",");
5603 array_qualifier.Append ("]");
5609 TypeExpr array_type_expr;
5610 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5611 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5612 if (array_type_expr == null)
5615 type = array_type_expr.Type;
5616 underlying_type = TypeManager.GetElementType (type);
5617 dimensions = type.GetArrayRank ();
5622 public override Expression DoResolve (EmitContext ec)
5627 if (!LookupType (ec))
5630 array_element_type = TypeManager.GetElementType (type);
5631 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
5632 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
5637 // First step is to validate the initializers and fill
5638 // in any missing bits
5640 if (!ResolveInitializers (ec))
5644 if (arguments == null)
5647 arg_count = arguments.Count;
5648 foreach (Argument a in arguments){
5649 if (!a.Resolve (ec, loc))
5652 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5653 if (real_arg == null)
5660 if (arg_count == 1) {
5661 is_one_dimensional = true;
5662 eclass = ExprClass.Value;
5666 is_builtin_type = TypeManager.IsBuiltinType (type);
5668 if (is_builtin_type) {
5671 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
5672 AllBindingFlags, loc);
5674 if (!(ml is MethodGroupExpr)) {
5675 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5680 Error (-6, "New invocation: Can not find a constructor for " +
5681 "this argument list");
5685 new_method = ((MethodGroupExpr) ml).OverloadResolve (
5686 ec, arguments, false, loc);
5688 if (new_method == null) {
5689 Error (-6, "New invocation: Can not find a constructor for " +
5690 "this argument list");
5694 eclass = ExprClass.Value;
5697 ModuleBuilder mb = CodeGen.Module.Builder;
5698 ArrayList args = new ArrayList ();
5700 if (arguments != null) {
5701 for (int i = 0; i < arg_count; i++)
5702 args.Add (TypeManager.int32_type);
5705 Type [] arg_types = null;
5708 arg_types = new Type [args.Count];
5710 args.CopyTo (arg_types, 0);
5712 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5715 if (new_method == null) {
5716 Error (-6, "New invocation: Can not find a constructor for " +
5717 "this argument list");
5721 eclass = ExprClass.Value;
5726 byte [] MakeByteBlob ()
5731 int count = array_data.Count;
5733 if (underlying_type.IsEnum)
5734 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5736 factor = GetTypeSize (underlying_type);
5738 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5740 data = new byte [(count * factor + 4) & ~3];
5743 for (int i = 0; i < count; ++i) {
5744 object v = array_data [i];
5746 if (v is EnumConstant)
5747 v = ((EnumConstant) v).Child;
5749 if (v is Constant && !(v is StringConstant))
5750 v = ((Constant) v).GetValue ();
5756 if (underlying_type == TypeManager.int64_type){
5757 if (!(v is Expression)){
5758 long val = (long) v;
5760 for (int j = 0; j < factor; ++j) {
5761 data [idx + j] = (byte) (val & 0xFF);
5765 } else if (underlying_type == TypeManager.uint64_type){
5766 if (!(v is Expression)){
5767 ulong val = (ulong) v;
5769 for (int j = 0; j < factor; ++j) {
5770 data [idx + j] = (byte) (val & 0xFF);
5774 } else if (underlying_type == TypeManager.float_type) {
5775 if (!(v is Expression)){
5776 element = BitConverter.GetBytes ((float) v);
5778 for (int j = 0; j < factor; ++j)
5779 data [idx + j] = element [j];
5781 } else if (underlying_type == TypeManager.double_type) {
5782 if (!(v is Expression)){
5783 element = BitConverter.GetBytes ((double) v);
5785 for (int j = 0; j < factor; ++j)
5786 data [idx + j] = element [j];
5788 } else if (underlying_type == TypeManager.char_type){
5789 if (!(v is Expression)){
5790 int val = (int) ((char) v);
5792 data [idx] = (byte) (val & 0xff);
5793 data [idx+1] = (byte) (val >> 8);
5795 } else if (underlying_type == TypeManager.short_type){
5796 if (!(v is Expression)){
5797 int val = (int) ((short) v);
5799 data [idx] = (byte) (val & 0xff);
5800 data [idx+1] = (byte) (val >> 8);
5802 } else if (underlying_type == TypeManager.ushort_type){
5803 if (!(v is Expression)){
5804 int val = (int) ((ushort) v);
5806 data [idx] = (byte) (val & 0xff);
5807 data [idx+1] = (byte) (val >> 8);
5809 } else if (underlying_type == TypeManager.int32_type) {
5810 if (!(v is Expression)){
5813 data [idx] = (byte) (val & 0xff);
5814 data [idx+1] = (byte) ((val >> 8) & 0xff);
5815 data [idx+2] = (byte) ((val >> 16) & 0xff);
5816 data [idx+3] = (byte) (val >> 24);
5818 } else if (underlying_type == TypeManager.uint32_type) {
5819 if (!(v is Expression)){
5820 uint val = (uint) v;
5822 data [idx] = (byte) (val & 0xff);
5823 data [idx+1] = (byte) ((val >> 8) & 0xff);
5824 data [idx+2] = (byte) ((val >> 16) & 0xff);
5825 data [idx+3] = (byte) (val >> 24);
5827 } else if (underlying_type == TypeManager.sbyte_type) {
5828 if (!(v is Expression)){
5829 sbyte val = (sbyte) v;
5830 data [idx] = (byte) val;
5832 } else if (underlying_type == TypeManager.byte_type) {
5833 if (!(v is Expression)){
5834 byte val = (byte) v;
5835 data [idx] = (byte) val;
5837 } else if (underlying_type == TypeManager.bool_type) {
5838 if (!(v is Expression)){
5839 bool val = (bool) v;
5840 data [idx] = (byte) (val ? 1 : 0);
5842 } else if (underlying_type == TypeManager.decimal_type){
5843 if (!(v is Expression)){
5844 int [] bits = Decimal.GetBits ((decimal) v);
5847 // FIXME: For some reason, this doesn't work on the MS runtime.
5848 int [] nbits = new int [4];
5849 nbits [0] = bits [3];
5850 nbits [1] = bits [2];
5851 nbits [2] = bits [0];
5852 nbits [3] = bits [1];
5854 for (int j = 0; j < 4; j++){
5855 data [p++] = (byte) (nbits [j] & 0xff);
5856 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5857 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5858 data [p++] = (byte) (nbits [j] >> 24);
5862 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5871 // Emits the initializers for the array
5873 void EmitStaticInitializers (EmitContext ec)
5876 // First, the static data
5879 ILGenerator ig = ec.ig;
5881 byte [] data = MakeByteBlob ();
5883 fb = RootContext.MakeStaticData (data);
5885 ig.Emit (OpCodes.Dup);
5886 ig.Emit (OpCodes.Ldtoken, fb);
5887 ig.Emit (OpCodes.Call,
5888 TypeManager.void_initializearray_array_fieldhandle);
5892 // Emits pieces of the array that can not be computed at compile
5893 // time (variables and string locations).
5895 // This always expect the top value on the stack to be the array
5897 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5899 ILGenerator ig = ec.ig;
5900 int dims = bounds.Count;
5901 int [] current_pos = new int [dims];
5903 MethodInfo set = null;
5906 Type [] args = new Type [dims + 1];
5908 for (int j = 0; j < dims; j++)
5909 args [j] = TypeManager.int32_type;
5910 args [dims] = array_element_type;
5912 set = CodeGen.Module.Builder.GetArrayMethod (
5914 CallingConventions.HasThis | CallingConventions.Standard,
5915 TypeManager.void_type, args);
5918 for (int i = 0; i < array_data.Count; i++){
5920 Expression e = (Expression)array_data [i];
5922 // Constant can be initialized via StaticInitializer
5923 if (e != null && !(!emitConstants && e is Constant)) {
5924 Type etype = e.Type;
5926 ig.Emit (OpCodes.Dup);
5928 for (int idx = 0; idx < dims; idx++)
5929 IntConstant.EmitInt (ig, current_pos [idx]);
5932 // If we are dealing with a struct, get the
5933 // address of it, so we can store it.
5935 if ((dims == 1) && etype.IsValueType &&
5936 (!TypeManager.IsBuiltinOrEnum (etype) ||
5937 etype == TypeManager.decimal_type)) {
5942 // Let new know that we are providing
5943 // the address where to store the results
5945 n.DisableTemporaryValueType ();
5948 ig.Emit (OpCodes.Ldelema, etype);
5954 bool is_stobj, has_type_arg;
5955 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5957 ig.Emit (OpCodes.Stobj, etype);
5958 else if (has_type_arg)
5959 ig.Emit (op, etype);
5963 ig.Emit (OpCodes.Call, set);
5970 for (int j = dims - 1; j >= 0; j--){
5972 if (current_pos [j] < (int) bounds [j])
5974 current_pos [j] = 0;
5979 void EmitArrayArguments (EmitContext ec)
5981 ILGenerator ig = ec.ig;
5983 foreach (Argument a in arguments) {
5984 Type atype = a.Type;
5987 if (atype == TypeManager.uint64_type)
5988 ig.Emit (OpCodes.Conv_Ovf_U4);
5989 else if (atype == TypeManager.int64_type)
5990 ig.Emit (OpCodes.Conv_Ovf_I4);
5994 public override void Emit (EmitContext ec)
5996 ILGenerator ig = ec.ig;
5998 EmitArrayArguments (ec);
5999 if (is_one_dimensional)
6000 ig.Emit (OpCodes.Newarr, array_element_type);
6002 if (is_builtin_type)
6003 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6005 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6008 if (initializers == null)
6011 // Emit static initializer for arrays which have contain more than 4 items and
6012 // the static initializer will initialize at least 25% of array values.
6013 // NOTE: const_initializers_count does not contain default constant values.
6014 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6015 TypeManager.IsPrimitiveType (array_element_type)) {
6016 EmitStaticInitializers (ec);
6018 if (!only_constant_initializers)
6019 EmitDynamicInitializers (ec, false);
6021 EmitDynamicInitializers (ec, true);
6025 public override bool GetAttributableValue (Type valueType, out object value)
6027 if (!is_one_dimensional){
6028 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6029 return base.GetAttributableValue (null, out value);
6032 if (array_data == null) {
6033 Constant c = (Constant)((Argument)arguments [0]).Expr;
6034 if (c.IsDefaultValue) {
6035 value = Array.CreateInstance (array_element_type, 0);
6038 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6039 return base.GetAttributableValue (null, out value);
6042 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6043 object element_value;
6044 for (int i = 0; i < ret.Length; ++i)
6046 Expression e = (Expression)array_data [i];
6048 // Is null when an initializer is optimized (value == predefined value)
6052 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6056 ret.SetValue (element_value, i);
6062 protected override void CloneTo (CloneContext clonectx, Expression t)
6064 ArrayCreation target = (ArrayCreation) t;
6066 target.requested_base_type = requested_base_type.Clone (clonectx);
6067 target.arguments = new ArrayList ();
6068 foreach (Argument a in arguments)
6069 target.arguments.Add (a.Clone (clonectx));
6071 if (initializers != null){
6072 target.initializers = new ArrayList ();
6073 foreach (Expression initializer in initializers)
6074 target.initializers.Add (initializer.Clone (clonectx));
6079 public sealed class CompilerGeneratedThis : This
6081 public static This Instance = new CompilerGeneratedThis ();
6083 private CompilerGeneratedThis ()
6084 : base (Location.Null)
6088 public override Expression DoResolve (EmitContext ec)
6090 eclass = ExprClass.Variable;
6091 type = ec.ContainerType;
6092 variable = new SimpleThis (type);
6098 /// Represents the `this' construct
6101 public class This : VariableReference, IVariable
6104 VariableInfo variable_info;
6105 protected Variable variable;
6108 public This (Block block, Location loc)
6114 public This (Location loc)
6119 public VariableInfo VariableInfo {
6120 get { return variable_info; }
6123 public bool VerifyFixed ()
6125 return !TypeManager.IsValueType (Type);
6128 public override bool IsRef {
6129 get { return is_struct; }
6132 public override Variable Variable {
6133 get { return variable; }
6136 public bool ResolveBase (EmitContext ec)
6138 eclass = ExprClass.Variable;
6140 if (ec.TypeContainer.CurrentType != null)
6141 type = ec.TypeContainer.CurrentType;
6143 type = ec.ContainerType;
6145 is_struct = ec.TypeContainer is Struct;
6148 Error (26, "Keyword `this' is not valid in a static property, " +
6149 "static method, or static field initializer");
6153 if (block != null) {
6154 if (block.Toplevel.ThisVariable != null)
6155 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6157 AnonymousContainer am = ec.CurrentAnonymousMethod;
6158 if (is_struct && (am != null) && !am.IsIterator) {
6159 Report.Error (1673, loc, "Anonymous methods inside structs " +
6160 "cannot access instance members of `this'. " +
6161 "Consider copying `this' to a local variable " +
6162 "outside the anonymous method and using the " +
6167 RootScopeInfo host = block.Toplevel.RootScope;
6168 if ((host != null) && !ec.IsConstructor &&
6169 (!is_struct || host.IsIterator)) {
6170 variable = host.CaptureThis ();
6171 type = variable.Type;
6176 if (variable == null)
6177 variable = new SimpleThis (type);
6183 // Called from Invocation to check if the invocation is correct
6185 public bool CheckThisUsage (EmitContext ec)
6187 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6188 !variable_info.IsAssigned (ec)) {
6189 Error (188, "The `this' object cannot be used before all of its " +
6190 "fields are assigned to");
6191 variable_info.SetAssigned (ec);
6198 public override Expression DoResolve (EmitContext ec)
6200 if (!ResolveBase (ec))
6204 if (ec.IsFieldInitializer) {
6205 Error (27, "Keyword `this' is not available in the current context");
6212 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6214 if (!ResolveBase (ec))
6217 if (variable_info != null)
6218 variable_info.SetAssigned (ec);
6220 if (ec.TypeContainer is Class){
6221 Error (1604, "Cannot assign to 'this' because it is read-only");
6227 public override int GetHashCode()
6229 return block.GetHashCode ();
6232 public override bool Equals (object obj)
6234 This t = obj as This;
6238 return block == t.block;
6241 protected class SimpleThis : Variable
6245 public SimpleThis (Type type)
6250 public override Type Type {
6251 get { return type; }
6254 public override bool HasInstance {
6255 get { return false; }
6258 public override bool NeedsTemporary {
6259 get { return false; }
6262 public override void EmitInstance (EmitContext ec)
6267 public override void Emit (EmitContext ec)
6269 ec.ig.Emit (OpCodes.Ldarg_0);
6272 public override void EmitAssign (EmitContext ec)
6274 throw new InvalidOperationException ();
6277 public override void EmitAddressOf (EmitContext ec)
6279 ec.ig.Emit (OpCodes.Ldarg_0);
6283 protected override void CloneTo (CloneContext clonectx, Expression t)
6285 This target = (This) t;
6287 target.block = clonectx.LookupBlock (block);
6292 /// Represents the `__arglist' construct
6294 public class ArglistAccess : Expression
6296 public ArglistAccess (Location loc)
6301 public override Expression DoResolve (EmitContext ec)
6303 eclass = ExprClass.Variable;
6304 type = TypeManager.runtime_argument_handle_type;
6306 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6308 Error (190, "The __arglist construct is valid only within " +
6309 "a variable argument method");
6316 public override void Emit (EmitContext ec)
6318 ec.ig.Emit (OpCodes.Arglist);
6321 protected override void CloneTo (CloneContext clonectx, Expression target)
6328 /// Represents the `__arglist (....)' construct
6330 public class Arglist : Expression
6332 public Argument[] Arguments;
6334 public Arglist (Location loc)
6335 : this (Argument.Empty, loc)
6339 public Arglist (Argument[] args, Location l)
6345 public Type[] ArgumentTypes {
6347 Type[] retval = new Type [Arguments.Length];
6348 for (int i = 0; i < Arguments.Length; i++)
6349 retval [i] = Arguments [i].Type;
6354 public override Expression DoResolve (EmitContext ec)
6356 eclass = ExprClass.Variable;
6357 type = TypeManager.runtime_argument_handle_type;
6359 foreach (Argument arg in Arguments) {
6360 if (!arg.Resolve (ec, loc))
6367 public override void Emit (EmitContext ec)
6369 foreach (Argument arg in Arguments)
6373 protected override void CloneTo (CloneContext clonectx, Expression t)
6375 Arglist target = (Arglist) t;
6377 target.Arguments = new Argument [Arguments.Length];
6378 for (int i = 0; i < Arguments.Length; i++)
6379 target.Arguments [i] = Arguments [i].Clone (clonectx);
6384 // This produces the value that renders an instance, used by the iterators code
6386 public class ProxyInstance : Expression, IMemoryLocation {
6387 public override Expression DoResolve (EmitContext ec)
6389 eclass = ExprClass.Variable;
6390 type = ec.ContainerType;
6394 public override void Emit (EmitContext ec)
6396 ec.ig.Emit (OpCodes.Ldarg_0);
6400 public void AddressOf (EmitContext ec, AddressOp mode)
6402 ec.ig.Emit (OpCodes.Ldarg_0);
6407 /// Implements the typeof operator
6409 public class TypeOf : Expression {
6410 Expression QueriedType;
6411 protected Type typearg;
6413 public TypeOf (Expression queried_type, Location l)
6415 QueriedType = queried_type;
6419 public override Expression DoResolve (EmitContext ec)
6421 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6425 typearg = texpr.Type;
6427 if (typearg == TypeManager.void_type) {
6428 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6432 if (typearg.IsPointer && !ec.InUnsafe){
6437 type = TypeManager.type_type;
6438 // Even though what is returned is a type object, it's treated as a value by the compiler.
6439 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6440 eclass = ExprClass.Value;
6444 public override void Emit (EmitContext ec)
6446 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6447 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6450 public override bool GetAttributableValue (Type valueType, out object value)
6452 if (TypeManager.ContainsGenericParameters (typearg)) {
6453 Report.SymbolRelatedToPreviousError(typearg);
6454 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6455 TypeManager.CSharpName(typearg));
6460 if (valueType == TypeManager.object_type) {
6461 value = (object)typearg;
6468 public Type TypeArgument
6476 protected override void CloneTo (CloneContext clonectx, Expression t)
6478 TypeOf target = (TypeOf) t;
6480 target.QueriedType = QueriedType.Clone (clonectx);
6485 /// Implements the `typeof (void)' operator
6487 public class TypeOfVoid : TypeOf {
6488 public TypeOfVoid (Location l) : base (null, l)
6493 public override Expression DoResolve (EmitContext ec)
6495 type = TypeManager.type_type;
6496 typearg = TypeManager.void_type;
6497 // See description in TypeOf.
6498 eclass = ExprClass.Value;
6504 /// Implements the sizeof expression
6506 public class SizeOf : Expression {
6507 public Expression QueriedType;
6510 public SizeOf (Expression queried_type, Location l)
6512 this.QueriedType = queried_type;
6516 public override Expression DoResolve (EmitContext ec)
6518 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6523 if (texpr is TypeParameterExpr){
6524 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6529 type_queried = texpr.Type;
6530 if (type_queried.IsEnum)
6531 type_queried = TypeManager.EnumToUnderlying (type_queried);
6533 if (type_queried == TypeManager.void_type) {
6534 Expression.Error_VoidInvalidInTheContext (loc);
6538 int size_of = GetTypeSize (type_queried);
6540 return new IntConstant (size_of, loc);
6544 Report.Error (233, loc, "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
6545 TypeManager.CSharpName (type_queried));
6549 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6553 type = TypeManager.int32_type;
6554 eclass = ExprClass.Value;
6558 public override void Emit (EmitContext ec)
6560 int size = GetTypeSize (type_queried);
6563 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6565 IntConstant.EmitInt (ec.ig, size);
6568 protected override void CloneTo (CloneContext clonectx, Expression t)
6570 SizeOf target = (SizeOf) t;
6572 target.QueriedType = QueriedType.Clone (clonectx);
6577 /// Implements the qualified-alias-member (::) expression.
6579 public class QualifiedAliasMember : Expression
6581 string alias, identifier;
6583 public QualifiedAliasMember (string alias, string identifier, Location l)
6586 this.identifier = identifier;
6590 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6592 if (alias == "global")
6593 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6595 int errors = Report.Errors;
6596 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6598 if (errors == Report.Errors)
6599 Report.Error (432, loc, "Alias `{0}' not found", alias);
6602 if (fne.eclass != ExprClass.Namespace) {
6604 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6607 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6610 public override Expression DoResolve (EmitContext ec)
6612 FullNamedExpression fne;
6613 if (alias == "global") {
6614 fne = RootNamespace.Global;
6616 int errors = Report.Errors;
6617 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6619 if (errors == Report.Errors)
6620 Report.Error (432, loc, "Alias `{0}' not found", alias);
6625 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6629 if (!(retval is FullNamedExpression)) {
6630 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6634 // We defer this check till the end to match the behaviour of CSC
6635 if (fne.eclass != ExprClass.Namespace) {
6636 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6642 public override void Emit (EmitContext ec)
6644 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6648 public override string ToString ()
6650 return alias + "::" + identifier;
6653 public override string GetSignatureForError ()
6658 protected override void CloneTo (CloneContext clonectx, Expression t)
6665 /// Implements the member access expression
6667 public class MemberAccess : Expression {
6668 public readonly string Identifier;
6671 public MemberAccess (Expression expr, string id)
6672 : this (expr, id, expr.Location)
6676 public MemberAccess (Expression expr, string identifier, Location loc)
6679 Identifier = identifier;
6683 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6684 : this (expr, identifier, loc)
6691 public Expression Expr {
6692 get { return expr; }
6695 protected string LookupIdentifier {
6696 get { return MemberName.MakeName (Identifier, args); }
6699 // TODO: this method has very poor performace for Enum fields and
6700 // probably for other constants as well
6701 Expression DoResolve (EmitContext ec, Expression right_side)
6704 throw new Exception ();
6707 // Resolve the expression with flow analysis turned off, we'll do the definite
6708 // assignment checks later. This is because we don't know yet what the expression
6709 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6710 // definite assignment check on the actual field and not on the whole struct.
6713 SimpleName original = expr as SimpleName;
6714 Expression new_expr = expr.Resolve (ec,
6715 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6716 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6718 if (new_expr == null)
6721 if (new_expr is Namespace) {
6722 Namespace ns = (Namespace) new_expr;
6723 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6725 if ((retval != null) && (args != null))
6726 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6730 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6734 Type expr_type = new_expr.Type;
6735 if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
6736 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6739 if (expr_type == TypeManager.anonymous_method_type){
6740 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6744 Constant c = new_expr as Constant;
6745 if (c != null && c.GetValue () == null) {
6746 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6747 "System.NullReferenceException");
6750 Expression member_lookup;
6751 member_lookup = MemberLookup (
6752 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6754 if ((member_lookup == null) && (args != null)) {
6755 member_lookup = MemberLookup (
6756 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6759 if (member_lookup == null) {
6760 member_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6761 if (member_lookup != null)
6762 return member_lookup.DoResolve (ec);
6764 MemberLookupFailed (
6765 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6769 TypeExpr texpr = member_lookup as TypeExpr;
6770 if (texpr != null) {
6771 if (!(new_expr is TypeExpr) &&
6772 (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
6773 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6774 Identifier, member_lookup.GetSignatureForError ());
6778 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6779 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6780 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6785 ConstructedType ct = new_expr as ConstructedType;
6788 // When looking up a nested type in a generic instance
6789 // via reflection, we always get a generic type definition
6790 // and not a generic instance - so we have to do this here.
6792 // See gtest-172-lib.cs and gtest-172.cs for an example.
6794 ct = new ConstructedType (
6795 member_lookup.Type, ct.TypeArguments, loc);
6797 return ct.ResolveAsTypeStep (ec, false);
6800 return member_lookup;
6803 MemberExpr me = (MemberExpr) member_lookup;
6804 member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
6805 if (member_lookup == null)
6809 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6811 throw new InternalErrorException ();
6813 return mg.ResolveGeneric (ec, args);
6816 if (original != null && !TypeManager.IsValueType (expr_type)) {
6817 me = member_lookup as MemberExpr;
6818 if (me != null && me.IsInstance) {
6819 LocalVariableReference var = new_expr as LocalVariableReference;
6820 if (var != null && !var.VerifyAssigned (ec))
6825 // The following DoResolve/DoResolveLValue will do the definite assignment
6828 if (right_side != null)
6829 return member_lookup.DoResolveLValue (ec, right_side);
6831 return member_lookup.DoResolve (ec);
6834 public override Expression DoResolve (EmitContext ec)
6836 return DoResolve (ec, null);
6839 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6841 return DoResolve (ec, right_side);
6844 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6846 return ResolveNamespaceOrType (ec, silent);
6849 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6851 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6853 if (new_expr == null)
6856 if (new_expr is Namespace) {
6857 Namespace ns = (Namespace) new_expr;
6858 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6860 if ((retval != null) && (args != null))
6861 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6863 if (!silent && retval == null)
6864 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6868 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6869 if (tnew_expr == null)
6872 Type expr_type = tnew_expr.Type;
6874 if (expr_type.IsPointer){
6875 Error (23, "The `.' operator can not be applied to pointer operands (" +
6876 TypeManager.CSharpName (expr_type) + ")");
6880 Expression member_lookup = MemberLookup (
6881 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6882 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6883 if (member_lookup == null) {
6887 member_lookup = MemberLookup(
6888 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6889 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6891 if (member_lookup == null) {
6892 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6893 Identifier, new_expr.GetSignatureForError ());
6895 // TODO: Report.SymbolRelatedToPreviousError
6896 member_lookup.Error_UnexpectedKind (null, "type", loc);
6901 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6906 TypeArguments the_args = args;
6907 if (TypeManager.HasGenericArguments (expr_type)) {
6908 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6910 TypeArguments new_args = new TypeArguments (loc);
6911 foreach (Type decl in decl_args)
6912 new_args.Add (new TypeExpression (decl, loc));
6915 new_args.Add (args);
6917 the_args = new_args;
6920 if (the_args != null) {
6921 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6922 return ctype.ResolveAsTypeStep (rc, false);
6929 public override void Emit (EmitContext ec)
6931 throw new Exception ("Should not happen");
6934 public override string ToString ()
6936 return expr + "." + MemberName.MakeName (Identifier, args);
6939 public override string GetSignatureForError ()
6941 return expr.GetSignatureForError () + "." + Identifier;
6944 protected override void CloneTo (CloneContext clonectx, Expression t)
6946 MemberAccess target = (MemberAccess) t;
6948 target.expr = expr.Clone (clonectx);
6953 /// Implements checked expressions
6955 public class CheckedExpr : Expression {
6957 public Expression Expr;
6959 public CheckedExpr (Expression e, Location l)
6965 public override Expression DoResolve (EmitContext ec)
6967 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6968 Expr = Expr.Resolve (ec);
6973 if (Expr is Constant)
6976 eclass = Expr.eclass;
6981 public override void Emit (EmitContext ec)
6983 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6987 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6989 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6990 Expr.EmitBranchable (ec, target, onTrue);
6993 protected override void CloneTo (CloneContext clonectx, Expression t)
6995 CheckedExpr target = (CheckedExpr) t;
6997 target.Expr = Expr.Clone (clonectx);
7002 /// Implements the unchecked expression
7004 public class UnCheckedExpr : Expression {
7006 public Expression Expr;
7008 public UnCheckedExpr (Expression e, Location l)
7014 public override Expression DoResolve (EmitContext ec)
7016 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7017 Expr = Expr.Resolve (ec);
7022 if (Expr is Constant)
7025 eclass = Expr.eclass;
7030 public override void Emit (EmitContext ec)
7032 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7036 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7038 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7039 Expr.EmitBranchable (ec, target, onTrue);
7042 protected override void CloneTo (CloneContext clonectx, Expression t)
7044 UnCheckedExpr target = (UnCheckedExpr) t;
7046 target.Expr = Expr.Clone (clonectx);
7051 /// An Element Access expression.
7053 /// During semantic analysis these are transformed into
7054 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7056 public class ElementAccess : Expression {
7057 public ArrayList Arguments;
7058 public Expression Expr;
7060 public ElementAccess (Expression e, ArrayList e_list)
7069 Arguments = new ArrayList ();
7070 foreach (Expression tmp in e_list)
7071 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7075 bool CommonResolve (EmitContext ec)
7077 Expr = Expr.Resolve (ec);
7082 if (Arguments == null)
7085 foreach (Argument a in Arguments){
7086 if (!a.Resolve (ec, loc))
7093 Expression MakePointerAccess (EmitContext ec, Type t)
7095 if (t == TypeManager.void_ptr_type){
7096 Error (242, "The array index operation is not valid on void pointers");
7099 if (Arguments.Count != 1){
7100 Error (196, "A pointer must be indexed by only one value");
7105 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7108 return new Indirection (p, loc).Resolve (ec);
7111 public override Expression DoResolve (EmitContext ec)
7113 if (!CommonResolve (ec))
7117 // We perform some simple tests, and then to "split" the emit and store
7118 // code we create an instance of a different class, and return that.
7120 // I am experimenting with this pattern.
7124 if (t == TypeManager.array_type){
7125 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7130 return (new ArrayAccess (this, loc)).Resolve (ec);
7132 return MakePointerAccess (ec, Expr.Type);
7134 FieldExpr fe = Expr as FieldExpr;
7136 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7138 return MakePointerAccess (ec, ff.ElementType);
7141 return (new IndexerAccess (this, loc)).Resolve (ec);
7144 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7146 if (!CommonResolve (ec))
7151 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7154 return MakePointerAccess (ec, Expr.Type);
7156 FieldExpr fe = Expr as FieldExpr;
7158 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7160 if (!(fe.InstanceExpression is LocalVariableReference) &&
7161 !(fe.InstanceExpression is This)) {
7162 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7165 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7166 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7169 return MakePointerAccess (ec, ff.ElementType);
7172 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7175 public override void Emit (EmitContext ec)
7177 throw new Exception ("Should never be reached");
7180 protected override void CloneTo (CloneContext clonectx, Expression t)
7182 ElementAccess target = (ElementAccess) t;
7184 target.Expr = Expr.Clone (clonectx);
7185 target.Arguments = new ArrayList ();
7186 foreach (Argument a in Arguments)
7187 target.Arguments.Add (a.Clone (clonectx));
7192 /// Implements array access
7194 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7196 // Points to our "data" repository
7200 LocalTemporary temp;
7203 public ArrayAccess (ElementAccess ea_data, Location l)
7206 eclass = ExprClass.Variable;
7210 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7212 return DoResolve (ec);
7215 public override Expression DoResolve (EmitContext ec)
7218 ExprClass eclass = ea.Expr.eclass;
7220 // As long as the type is valid
7221 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7222 eclass == ExprClass.Value)) {
7223 ea.Expr.Error_UnexpectedKind ("variable or value");
7228 Type t = ea.Expr.Type;
7229 if (t.GetArrayRank () != ea.Arguments.Count){
7230 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7231 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7235 type = TypeManager.GetElementType (t);
7236 if (type.IsPointer && !ec.InUnsafe){
7237 UnsafeError (ea.Location);
7241 foreach (Argument a in ea.Arguments){
7242 Type argtype = a.Type;
7244 if (argtype == TypeManager.int32_type ||
7245 argtype == TypeManager.uint32_type ||
7246 argtype == TypeManager.int64_type ||
7247 argtype == TypeManager.uint64_type) {
7248 Constant c = a.Expr as Constant;
7249 if (c != null && c.IsNegative) {
7250 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7256 // Mhm. This is strage, because the Argument.Type is not the same as
7257 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7259 // Wonder if I will run into trouble for this.
7261 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7266 eclass = ExprClass.Variable;
7272 /// Emits the right opcode to load an object of Type `t'
7273 /// from an array of T
7275 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7277 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7278 ig.Emit (OpCodes.Ldelem_U1);
7279 else if (type == TypeManager.sbyte_type)
7280 ig.Emit (OpCodes.Ldelem_I1);
7281 else if (type == TypeManager.short_type)
7282 ig.Emit (OpCodes.Ldelem_I2);
7283 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7284 ig.Emit (OpCodes.Ldelem_U2);
7285 else if (type == TypeManager.int32_type)
7286 ig.Emit (OpCodes.Ldelem_I4);
7287 else if (type == TypeManager.uint32_type)
7288 ig.Emit (OpCodes.Ldelem_U4);
7289 else if (type == TypeManager.uint64_type)
7290 ig.Emit (OpCodes.Ldelem_I8);
7291 else if (type == TypeManager.int64_type)
7292 ig.Emit (OpCodes.Ldelem_I8);
7293 else if (type == TypeManager.float_type)
7294 ig.Emit (OpCodes.Ldelem_R4);
7295 else if (type == TypeManager.double_type)
7296 ig.Emit (OpCodes.Ldelem_R8);
7297 else if (type == TypeManager.intptr_type)
7298 ig.Emit (OpCodes.Ldelem_I);
7299 else if (TypeManager.IsEnumType (type)){
7300 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7301 } else if (type.IsValueType){
7302 ig.Emit (OpCodes.Ldelema, type);
7303 ig.Emit (OpCodes.Ldobj, type);
7305 } else if (type.IsGenericParameter) {
7307 ig.Emit (OpCodes.Ldelem, type);
7309 ig.Emit (OpCodes.Ldelem_Any, type);
7312 } else if (type.IsPointer)
7313 ig.Emit (OpCodes.Ldelem_I);
7315 ig.Emit (OpCodes.Ldelem_Ref);
7319 /// Returns the right opcode to store an object of Type `t'
7320 /// from an array of T.
7322 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7324 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7325 has_type_arg = false; is_stobj = false;
7326 t = TypeManager.TypeToCoreType (t);
7327 if (TypeManager.IsEnumType (t))
7328 t = TypeManager.EnumToUnderlying (t);
7329 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7330 t == TypeManager.bool_type)
7331 return OpCodes.Stelem_I1;
7332 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7333 t == TypeManager.char_type)
7334 return OpCodes.Stelem_I2;
7335 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7336 return OpCodes.Stelem_I4;
7337 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7338 return OpCodes.Stelem_I8;
7339 else if (t == TypeManager.float_type)
7340 return OpCodes.Stelem_R4;
7341 else if (t == TypeManager.double_type)
7342 return OpCodes.Stelem_R8;
7343 else if (t == TypeManager.intptr_type) {
7344 has_type_arg = true;
7346 return OpCodes.Stobj;
7347 } else if (t.IsValueType) {
7348 has_type_arg = true;
7350 return OpCodes.Stobj;
7352 } else if (t.IsGenericParameter) {
7353 has_type_arg = true;
7355 return OpCodes.Stelem;
7357 return OpCodes.Stelem_Any;
7361 } else if (t.IsPointer)
7362 return OpCodes.Stelem_I;
7364 return OpCodes.Stelem_Ref;
7367 MethodInfo FetchGetMethod ()
7369 ModuleBuilder mb = CodeGen.Module.Builder;
7370 int arg_count = ea.Arguments.Count;
7371 Type [] args = new Type [arg_count];
7374 for (int i = 0; i < arg_count; i++){
7375 //args [i++] = a.Type;
7376 args [i] = TypeManager.int32_type;
7379 get = mb.GetArrayMethod (
7380 ea.Expr.Type, "Get",
7381 CallingConventions.HasThis |
7382 CallingConventions.Standard,
7388 MethodInfo FetchAddressMethod ()
7390 ModuleBuilder mb = CodeGen.Module.Builder;
7391 int arg_count = ea.Arguments.Count;
7392 Type [] args = new Type [arg_count];
7396 ret_type = TypeManager.GetReferenceType (type);
7398 for (int i = 0; i < arg_count; i++){
7399 //args [i++] = a.Type;
7400 args [i] = TypeManager.int32_type;
7403 address = mb.GetArrayMethod (
7404 ea.Expr.Type, "Address",
7405 CallingConventions.HasThis |
7406 CallingConventions.Standard,
7413 // Load the array arguments into the stack.
7415 // If we have been requested to cache the values (cached_locations array
7416 // initialized), then load the arguments the first time and store them
7417 // in locals. otherwise load from local variables.
7419 void LoadArrayAndArguments (EmitContext ec)
7421 ILGenerator ig = ec.ig;
7424 foreach (Argument a in ea.Arguments){
7425 Type argtype = a.Expr.Type;
7429 if (argtype == TypeManager.int64_type)
7430 ig.Emit (OpCodes.Conv_Ovf_I);
7431 else if (argtype == TypeManager.uint64_type)
7432 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7436 public void Emit (EmitContext ec, bool leave_copy)
7438 int rank = ea.Expr.Type.GetArrayRank ();
7439 ILGenerator ig = ec.ig;
7442 LoadArrayAndArguments (ec);
7445 EmitLoadOpcode (ig, type);
7449 method = FetchGetMethod ();
7450 ig.Emit (OpCodes.Call, method);
7453 LoadFromPtr (ec.ig, this.type);
7456 ec.ig.Emit (OpCodes.Dup);
7457 temp = new LocalTemporary (this.type);
7462 public override void Emit (EmitContext ec)
7467 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7469 int rank = ea.Expr.Type.GetArrayRank ();
7470 ILGenerator ig = ec.ig;
7471 Type t = source.Type;
7472 prepared = prepare_for_load;
7474 if (prepare_for_load) {
7475 AddressOf (ec, AddressOp.LoadStore);
7476 ec.ig.Emit (OpCodes.Dup);
7479 ec.ig.Emit (OpCodes.Dup);
7480 temp = new LocalTemporary (this.type);
7483 StoreFromPtr (ec.ig, t);
7493 LoadArrayAndArguments (ec);
7496 bool is_stobj, has_type_arg;
7497 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7499 // The stobj opcode used by value types will need
7500 // an address on the stack, not really an array/array
7504 ig.Emit (OpCodes.Ldelema, t);
7508 ec.ig.Emit (OpCodes.Dup);
7509 temp = new LocalTemporary (this.type);
7514 ig.Emit (OpCodes.Stobj, t);
7515 else if (has_type_arg)
7520 ModuleBuilder mb = CodeGen.Module.Builder;
7521 int arg_count = ea.Arguments.Count;
7522 Type [] args = new Type [arg_count + 1];
7527 ec.ig.Emit (OpCodes.Dup);
7528 temp = new LocalTemporary (this.type);
7532 for (int i = 0; i < arg_count; i++){
7533 //args [i++] = a.Type;
7534 args [i] = TypeManager.int32_type;
7537 args [arg_count] = type;
7539 set = mb.GetArrayMethod (
7540 ea.Expr.Type, "Set",
7541 CallingConventions.HasThis |
7542 CallingConventions.Standard,
7543 TypeManager.void_type, args);
7545 ig.Emit (OpCodes.Call, set);
7554 public void AddressOf (EmitContext ec, AddressOp mode)
7556 int rank = ea.Expr.Type.GetArrayRank ();
7557 ILGenerator ig = ec.ig;
7559 LoadArrayAndArguments (ec);
7562 ig.Emit (OpCodes.Ldelema, type);
7564 MethodInfo address = FetchAddressMethod ();
7565 ig.Emit (OpCodes.Call, address);
7569 public void EmitGetLength (EmitContext ec, int dim)
7571 int rank = ea.Expr.Type.GetArrayRank ();
7572 ILGenerator ig = ec.ig;
7576 ig.Emit (OpCodes.Ldlen);
7577 ig.Emit (OpCodes.Conv_I4);
7579 IntLiteral.EmitInt (ig, dim);
7580 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7586 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7587 public readonly ArrayList Properties;
7588 static Indexers empty;
7590 public struct Indexer {
7591 public readonly PropertyInfo PropertyInfo;
7592 public readonly MethodInfo Getter, Setter;
7594 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7596 this.PropertyInfo = property_info;
7604 empty = new Indexers (null);
7607 Indexers (ArrayList array)
7612 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7617 foreach (PropertyInfo property in mi){
7618 MethodInfo get, set;
7620 get = property.GetGetMethod (true);
7621 set = property.GetSetMethod (true);
7622 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7624 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7626 if (get != null || set != null) {
7628 ix = new Indexers (new ArrayList ());
7629 ix.Properties.Add (new Indexer (property, get, set));
7634 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7636 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7638 return TypeManager.MemberLookup (
7639 caller_type, caller_type, lookup_type, MemberTypes.Property,
7640 BindingFlags.Public | BindingFlags.Instance |
7641 BindingFlags.DeclaredOnly, p_name, null);
7644 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7646 Indexers ix = empty;
7649 if (lookup_type.IsGenericParameter) {
7650 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7654 if (gc.HasClassConstraint)
7655 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7657 Type[] ifaces = gc.InterfaceConstraints;
7658 foreach (Type itype in ifaces)
7659 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7665 Type copy = lookup_type;
7666 while (copy != TypeManager.object_type && copy != null){
7667 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7668 copy = copy.BaseType;
7671 if (lookup_type.IsInterface) {
7672 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7673 if (ifaces != null) {
7674 foreach (Type itype in ifaces)
7675 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7684 /// Expressions that represent an indexer call.
7686 public class IndexerAccess : Expression, IAssignMethod {
7688 // Points to our "data" repository
7690 MethodInfo get, set;
7691 ArrayList set_arguments;
7692 bool is_base_indexer;
7694 protected Type indexer_type;
7695 protected Type current_type;
7696 protected Expression instance_expr;
7697 protected ArrayList arguments;
7699 public IndexerAccess (ElementAccess ea, Location loc)
7700 : this (ea.Expr, false, loc)
7702 this.arguments = ea.Arguments;
7705 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7708 this.instance_expr = instance_expr;
7709 this.is_base_indexer = is_base_indexer;
7710 this.eclass = ExprClass.Value;
7714 protected virtual bool CommonResolve (EmitContext ec)
7716 indexer_type = instance_expr.Type;
7717 current_type = ec.ContainerType;
7722 public override Expression DoResolve (EmitContext ec)
7724 if (!CommonResolve (ec))
7728 // Step 1: Query for all `Item' *properties*. Notice
7729 // that the actual methods are pointed from here.
7731 // This is a group of properties, piles of them.
7733 ArrayList AllGetters = null;
7735 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7736 if (ilist.Properties != null) {
7737 AllGetters = new ArrayList(ilist.Properties.Count);
7738 foreach (Indexers.Indexer ix in ilist.Properties) {
7739 if (ix.Getter != null)
7740 AllGetters.Add (ix.Getter);
7744 if (AllGetters == null) {
7745 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7746 TypeManager.CSharpName (indexer_type));
7750 if (AllGetters.Count == 0) {
7751 // FIXME: we cannot simply select first one as the error message is missleading when
7752 // multiple indexers exist
7753 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7754 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7755 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7759 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7760 arguments, false, loc);
7763 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7768 // Only base will allow this invocation to happen.
7770 if (get.IsAbstract && this is BaseIndexerAccess){
7771 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7775 type = get.ReturnType;
7776 if (type.IsPointer && !ec.InUnsafe){
7781 instance_expr.CheckMarshalByRefAccess ();
7783 eclass = ExprClass.IndexerAccess;
7787 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7789 if (right_side == EmptyExpression.OutAccess) {
7790 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7791 GetSignatureForError ());
7795 // if the indexer returns a value type, and we try to set a field in it
7796 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7797 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7798 GetSignatureForError ());
7802 ArrayList AllSetters = new ArrayList();
7803 if (!CommonResolve (ec))
7806 bool found_any = false, found_any_setters = false;
7808 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7809 if (ilist.Properties != null) {
7811 foreach (Indexers.Indexer ix in ilist.Properties) {
7812 if (ix.Setter != null)
7813 AllSetters.Add (ix.Setter);
7816 if (AllSetters.Count > 0) {
7817 found_any_setters = true;
7818 set_arguments = (ArrayList) arguments.Clone ();
7819 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7820 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7822 set_arguments, false, loc);
7826 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7827 TypeManager.CSharpName (indexer_type));
7831 if (!found_any_setters) {
7832 Error (154, "indexer can not be used in this context, because " +
7833 "it lacks a `set' accessor");
7838 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7843 // Only base will allow this invocation to happen.
7845 if (set.IsAbstract && this is BaseIndexerAccess){
7846 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7851 // Now look for the actual match in the list of indexers to set our "return" type
7853 type = TypeManager.void_type; // default value
7854 foreach (Indexers.Indexer ix in ilist.Properties){
7855 if (ix.Setter == set){
7856 type = ix.PropertyInfo.PropertyType;
7861 instance_expr.CheckMarshalByRefAccess ();
7863 eclass = ExprClass.IndexerAccess;
7867 bool prepared = false;
7868 LocalTemporary temp;
7870 public void Emit (EmitContext ec, bool leave_copy)
7872 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
7874 ec.ig.Emit (OpCodes.Dup);
7875 temp = new LocalTemporary (Type);
7881 // source is ignored, because we already have a copy of it from the
7882 // LValue resolution and we have already constructed a pre-cached
7883 // version of the arguments (ea.set_arguments);
7885 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7887 prepared = prepare_for_load;
7888 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7893 ec.ig.Emit (OpCodes.Dup);
7894 temp = new LocalTemporary (Type);
7897 } else if (leave_copy) {
7898 temp = new LocalTemporary (Type);
7904 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
7913 public override void Emit (EmitContext ec)
7918 public override string GetSignatureForError ()
7920 // FIXME: print the argument list of the indexer
7921 return instance_expr.GetSignatureForError () + ".this[...]";
7924 protected override void CloneTo (CloneContext clonectx, Expression t)
7926 IndexerAccess target = (IndexerAccess) t;
7928 if (arguments != null){
7929 target.arguments = new ArrayList ();
7930 foreach (Argument a in arguments)
7931 target.arguments.Add (a.Clone (clonectx));
7933 if (instance_expr != null)
7934 target.instance_expr = instance_expr.Clone (clonectx);
7939 /// The base operator for method names
7941 public class BaseAccess : Expression {
7942 public readonly string Identifier;
7945 public BaseAccess (string member, Location l)
7947 this.Identifier = member;
7951 public BaseAccess (string member, TypeArguments args, Location l)
7957 public override Expression DoResolve (EmitContext ec)
7959 Expression c = CommonResolve (ec);
7965 // MethodGroups use this opportunity to flag an error on lacking ()
7967 if (!(c is MethodGroupExpr))
7968 return c.Resolve (ec);
7972 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7974 Expression c = CommonResolve (ec);
7980 // MethodGroups use this opportunity to flag an error on lacking ()
7982 if (! (c is MethodGroupExpr))
7983 return c.DoResolveLValue (ec, right_side);
7988 Expression CommonResolve (EmitContext ec)
7990 Expression member_lookup;
7991 Type current_type = ec.ContainerType;
7992 Type base_type = current_type.BaseType;
7995 Error (1511, "Keyword `base' is not available in a static method");
7999 if (ec.IsFieldInitializer){
8000 Error (1512, "Keyword `base' is not available in the current context");
8004 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8005 AllMemberTypes, AllBindingFlags, loc);
8006 if (member_lookup == null) {
8007 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8014 left = new TypeExpression (base_type, loc);
8016 left = ec.GetThis (loc);
8018 MemberExpr me = (MemberExpr) member_lookup;
8020 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8022 if (e is PropertyExpr) {
8023 PropertyExpr pe = (PropertyExpr) e;
8028 MethodGroupExpr mg = e as MethodGroupExpr;
8034 return mg.ResolveGeneric (ec, args);
8036 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8044 public override void Emit (EmitContext ec)
8046 throw new Exception ("Should never be called");
8049 protected override void CloneTo (CloneContext clonectx, Expression t)
8051 BaseAccess target = (BaseAccess) t;
8053 target.args = args.Clone ();
8058 /// The base indexer operator
8060 public class BaseIndexerAccess : IndexerAccess {
8061 public BaseIndexerAccess (ArrayList args, Location loc)
8062 : base (null, true, loc)
8064 arguments = new ArrayList ();
8065 foreach (Expression tmp in args)
8066 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8069 protected override bool CommonResolve (EmitContext ec)
8071 instance_expr = ec.GetThis (loc);
8073 current_type = ec.ContainerType.BaseType;
8074 indexer_type = current_type;
8076 foreach (Argument a in arguments){
8077 if (!a.Resolve (ec, loc))
8086 /// This class exists solely to pass the Type around and to be a dummy
8087 /// that can be passed to the conversion functions (this is used by
8088 /// foreach implementation to typecast the object return value from
8089 /// get_Current into the proper type. All code has been generated and
8090 /// we only care about the side effect conversions to be performed
8092 /// This is also now used as a placeholder where a no-action expression
8093 /// is needed (the `New' class).
8095 public class EmptyExpression : Expression {
8096 public static readonly EmptyExpression Null = new EmptyExpression ();
8098 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8099 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8100 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8102 static EmptyExpression temp = new EmptyExpression ();
8103 public static EmptyExpression Grab ()
8105 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8110 public static void Release (EmptyExpression e)
8115 // TODO: should be protected
8116 public EmptyExpression ()
8118 type = TypeManager.object_type;
8119 eclass = ExprClass.Value;
8120 loc = Location.Null;
8123 public EmptyExpression (Type t)
8126 eclass = ExprClass.Value;
8127 loc = Location.Null;
8130 public override Expression DoResolve (EmitContext ec)
8135 public override void Emit (EmitContext ec)
8137 // nothing, as we only exist to not do anything.
8141 // This is just because we might want to reuse this bad boy
8142 // instead of creating gazillions of EmptyExpressions.
8143 // (CanImplicitConversion uses it)
8145 public void SetType (Type t)
8151 public class UserCast : Expression {
8155 public UserCast (MethodInfo method, Expression source, Location l)
8157 this.method = method;
8158 this.source = source;
8159 type = method.ReturnType;
8160 eclass = ExprClass.Value;
8164 public Expression Source {
8170 public override Expression DoResolve (EmitContext ec)
8173 // We are born fully resolved
8178 public override void Emit (EmitContext ec)
8180 ILGenerator ig = ec.ig;
8184 if (method is MethodInfo)
8185 ig.Emit (OpCodes.Call, (MethodInfo) method);
8187 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8193 // This class is used to "construct" the type during a typecast
8194 // operation. Since the Type.GetType class in .NET can parse
8195 // the type specification, we just use this to construct the type
8196 // one bit at a time.
8198 public class ComposedCast : TypeExpr {
8202 public ComposedCast (Expression left, string dim)
8203 : this (left, dim, left.Location)
8207 public ComposedCast (Expression left, string dim, Location l)
8215 public Expression RemoveNullable ()
8217 if (dim.EndsWith ("?")) {
8218 dim = dim.Substring (0, dim.Length - 1);
8227 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8229 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8233 Type ltype = lexpr.Type;
8234 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8235 Error_VoidInvalidInTheContext (loc);
8240 if ((dim.Length > 0) && (dim [0] == '?')) {
8241 TypeExpr nullable = new NullableType (left, loc);
8243 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8244 return nullable.ResolveAsTypeTerminal (ec, false);
8248 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8251 if (dim != "" && dim [0] == '[' &&
8252 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8253 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8258 type = TypeManager.GetConstructedType (ltype, dim);
8263 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8265 if (type.IsPointer && !ec.IsInUnsafeScope){
8270 eclass = ExprClass.Type;
8274 public override string Name {
8275 get { return left + dim; }
8278 public override string FullName {
8279 get { return type.FullName; }
8282 public override string GetSignatureForError ()
8284 return left.GetSignatureForError () + dim;
8287 protected override void CloneTo (CloneContext clonectx, Expression t)
8289 ComposedCast target = (ComposedCast) t;
8291 target.left = left.Clone (clonectx);
8295 public class FixedBufferPtr : Expression {
8298 public FixedBufferPtr (Expression array, Type array_type, Location l)
8303 type = TypeManager.GetPointerType (array_type);
8304 eclass = ExprClass.Value;
8307 public override void Emit(EmitContext ec)
8312 public override Expression DoResolve (EmitContext ec)
8315 // We are born fully resolved
8323 // This class is used to represent the address of an array, used
8324 // only by the Fixed statement, this generates "&a [0]" construct
8325 // for fixed (char *pa = a)
8327 public class ArrayPtr : FixedBufferPtr {
8330 public ArrayPtr (Expression array, Type array_type, Location l):
8331 base (array, array_type, l)
8333 this.array_type = array_type;
8336 public override void Emit (EmitContext ec)
8340 ILGenerator ig = ec.ig;
8341 IntLiteral.EmitInt (ig, 0);
8342 ig.Emit (OpCodes.Ldelema, array_type);
8347 // Used by the fixed statement
8349 public class StringPtr : Expression {
8352 public StringPtr (LocalBuilder b, Location l)
8355 eclass = ExprClass.Value;
8356 type = TypeManager.char_ptr_type;
8360 public override Expression DoResolve (EmitContext ec)
8362 // This should never be invoked, we are born in fully
8363 // initialized state.
8368 public override void Emit (EmitContext ec)
8370 ILGenerator ig = ec.ig;
8372 ig.Emit (OpCodes.Ldloc, b);
8373 ig.Emit (OpCodes.Conv_I);
8374 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8375 ig.Emit (OpCodes.Add);
8380 // Implements the `stackalloc' keyword
8382 public class StackAlloc : Expression {
8387 public StackAlloc (Expression type, Expression count, Location l)
8394 public override Expression DoResolve (EmitContext ec)
8396 count = count.Resolve (ec);
8400 if (count.Type != TypeManager.int32_type){
8401 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8406 Constant c = count as Constant;
8407 if (c != null && c.IsNegative) {
8408 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8412 if (ec.InCatch || ec.InFinally) {
8413 Error (255, "Cannot use stackalloc in finally or catch");
8417 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8423 if (!TypeManager.VerifyUnManaged (otype, loc))
8426 type = TypeManager.GetPointerType (otype);
8427 eclass = ExprClass.Value;
8432 public override void Emit (EmitContext ec)
8434 int size = GetTypeSize (otype);
8435 ILGenerator ig = ec.ig;
8438 ig.Emit (OpCodes.Sizeof, otype);
8440 IntConstant.EmitInt (ig, size);
8442 ig.Emit (OpCodes.Mul);
8443 ig.Emit (OpCodes.Localloc);
8446 protected override void CloneTo (CloneContext clonectx, Expression t)
8448 StackAlloc target = (StackAlloc) t;
8449 target.count = count.Clone (clonectx);
8450 target.t = t.Clone (clonectx);