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));
1207 } else if (etype.IsValueType) {
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 if (TypeManager.IsNullableType (type))
1262 ig.Emit (OpCodes.Unbox_Any, type);
1266 static void Error_CannotConvertType (Type source, Type target, Location loc)
1268 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1269 TypeManager.CSharpName (source),
1270 TypeManager.CSharpName (target));
1273 public override Expression DoResolve (EmitContext ec)
1275 if (resolved_type == null) {
1276 resolved_type = base.DoResolve (ec);
1278 if (resolved_type == null)
1282 type = probe_type_expr.Type;
1283 eclass = ExprClass.Value;
1284 Type etype = expr.Type;
1286 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1287 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1288 TypeManager.CSharpName (type) + "' is a value type)");
1295 // If the type is a type parameter, ensure
1296 // that it is constrained by a class
1298 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1300 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1303 if (constraints == null)
1306 if (!constraints.HasClassConstraint)
1307 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1311 Report.Error (413, loc,
1312 "The as operator requires that the `{0}' type parameter be constrained by a class",
1313 probe_type_expr.GetSignatureForError ());
1319 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1326 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1327 if (TypeManager.IsGenericParameter (etype))
1328 expr = new BoxedCast (expr, etype);
1334 if (TypeManager.ContainsGenericParameters (etype) ||
1335 TypeManager.ContainsGenericParameters (type)) {
1336 expr = new BoxedCast (expr, etype);
1341 Error_CannotConvertType (etype, type, loc);
1345 public override bool GetAttributableValue (Type valueType, out object value)
1347 return expr.GetAttributableValue (valueType, out value);
1352 /// This represents a typecast in the source language.
1354 /// FIXME: Cast expressions have an unusual set of parsing
1355 /// rules, we need to figure those out.
1357 public class Cast : Expression {
1358 Expression target_type;
1361 public Cast (Expression cast_type, Expression expr)
1362 : this (cast_type, expr, cast_type.Location)
1366 public Cast (Expression cast_type, Expression expr, Location loc)
1368 this.target_type = cast_type;
1372 if (target_type == TypeManager.system_void_expr)
1373 Error_VoidInvalidInTheContext (loc);
1376 public Expression TargetType {
1377 get { return target_type; }
1380 public Expression Expr {
1381 get { return expr; }
1382 set { expr = value; }
1385 public override Expression DoResolve (EmitContext ec)
1387 expr = expr.Resolve (ec);
1391 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1397 if (type.IsAbstract && type.IsSealed) {
1398 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1402 eclass = ExprClass.Value;
1404 Constant c = expr as Constant;
1406 c = c.TryReduce (ec, type, loc);
1411 if (type.IsPointer && !ec.InUnsafe) {
1415 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1419 public override void Emit (EmitContext ec)
1421 throw new Exception ("Should not happen");
1424 protected override void CloneTo (CloneContext clonectx, Expression t)
1426 Cast target = (Cast) t;
1428 target.target_type = target_type.Clone (clonectx);
1429 target.expr = expr.Clone (clonectx);
1434 /// Binary operators
1436 public class Binary : Expression {
1437 public enum Operator : byte {
1438 Multiply, Division, Modulus,
1439 Addition, Subtraction,
1440 LeftShift, RightShift,
1441 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1442 Equality, Inequality,
1452 Expression left, right;
1454 // This must be kept in sync with Operator!!!
1455 public static readonly string [] oper_names;
1459 oper_names = new string [(int) Operator.TOP];
1461 oper_names [(int) Operator.Multiply] = "op_Multiply";
1462 oper_names [(int) Operator.Division] = "op_Division";
1463 oper_names [(int) Operator.Modulus] = "op_Modulus";
1464 oper_names [(int) Operator.Addition] = "op_Addition";
1465 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1466 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1467 oper_names [(int) Operator.RightShift] = "op_RightShift";
1468 oper_names [(int) Operator.LessThan] = "op_LessThan";
1469 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1470 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1471 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1472 oper_names [(int) Operator.Equality] = "op_Equality";
1473 oper_names [(int) Operator.Inequality] = "op_Inequality";
1474 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1475 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1476 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1477 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1478 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1481 public Binary (Operator oper, Expression left, Expression right)
1486 this.loc = left.Location;
1489 public Operator Oper {
1498 public Expression Left {
1507 public Expression Right {
1518 /// Returns a stringified representation of the Operator
1520 public static string OperName (Operator oper)
1523 case Operator.Multiply:
1525 case Operator.Division:
1527 case Operator.Modulus:
1529 case Operator.Addition:
1531 case Operator.Subtraction:
1533 case Operator.LeftShift:
1535 case Operator.RightShift:
1537 case Operator.LessThan:
1539 case Operator.GreaterThan:
1541 case Operator.LessThanOrEqual:
1543 case Operator.GreaterThanOrEqual:
1545 case Operator.Equality:
1547 case Operator.Inequality:
1549 case Operator.BitwiseAnd:
1551 case Operator.BitwiseOr:
1553 case Operator.ExclusiveOr:
1555 case Operator.LogicalOr:
1557 case Operator.LogicalAnd:
1561 return oper.ToString ();
1564 public override string ToString ()
1566 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1567 right.ToString () + ")";
1570 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1572 if (expr.Type == target_type)
1575 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1578 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1581 34, loc, "Operator `" + OperName (oper)
1582 + "' is ambiguous on operands of type `"
1583 + TypeManager.CSharpName (l) + "' "
1584 + "and `" + TypeManager.CSharpName (r)
1588 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1590 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1593 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1595 if (!IsConvertible (ec, left, right, t))
1597 left = ForceConversion (ec, left, t);
1598 right = ForceConversion (ec, right, t);
1603 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1605 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1606 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1608 if (oper == Operator.Equality || oper == Operator.Inequality)
1610 if (oper == Operator.Addition)
1615 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1617 if (!IsApplicable_String (ec, left, right, oper))
1619 Type t = TypeManager.string_type;
1620 if (Convert.ImplicitConversionExists (ec, left, t))
1621 left = ForceConversion (ec, left, t);
1622 if (Convert.ImplicitConversionExists (ec, right, t))
1623 right = ForceConversion (ec, right, t);
1628 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1630 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1631 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1632 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1633 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1637 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1639 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1640 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1644 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1646 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1649 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1651 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1655 void Error_OperatorCannotBeApplied ()
1657 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1658 TypeManager.CSharpName(right.Type));
1661 static bool is_unsigned (Type t)
1663 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1664 t == TypeManager.short_type || t == TypeManager.byte_type);
1667 Expression Make32or64 (EmitContext ec, Expression e)
1671 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1672 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1674 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1677 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1680 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1683 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1689 Expression CheckShiftArguments (EmitContext ec)
1691 Expression new_left = Make32or64 (ec, left);
1692 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1693 if (new_left == null || new_right == null) {
1694 Error_OperatorCannotBeApplied ();
1697 type = new_left.Type;
1698 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1700 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1705 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1706 // i.e., not invoke op_Equality.
1708 static bool EqualsNullIsReferenceEquals (Type t)
1710 return t == TypeManager.object_type || t == TypeManager.string_type ||
1711 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1714 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1716 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1717 "Possible unintended reference comparison; to get a value comparison, " +
1718 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1721 Expression ResolveOperator (EmitContext ec)
1724 Type r = right.Type;
1726 if (oper == Operator.Equality || oper == Operator.Inequality){
1727 if (TypeManager.IsGenericParameter (l) && (right is NullLiteral)) {
1728 if (l.BaseType == TypeManager.value_type) {
1729 Error_OperatorCannotBeApplied ();
1733 left = new BoxedCast (left, TypeManager.object_type);
1734 Type = TypeManager.bool_type;
1738 if (TypeManager.IsGenericParameter (r) && (left is NullLiteral)) {
1739 if (r.BaseType == TypeManager.value_type) {
1740 Error_OperatorCannotBeApplied ();
1744 right = new BoxedCast (right, TypeManager.object_type);
1745 Type = TypeManager.bool_type;
1750 // Optimize out call to op_Equality in a few cases.
1752 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1753 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1754 Type = TypeManager.bool_type;
1759 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1760 Type = TypeManager.bool_type;
1766 // Delegate equality
1768 MethodGroupExpr mg = null;
1769 Type delegate_type = null;
1770 if (left.eclass == ExprClass.MethodGroup) {
1771 if (!TypeManager.IsDelegateType(r)) {
1772 Error_OperatorCannotBeApplied(Location, OperName(oper),
1773 left.ExprClassName, right.ExprClassName);
1776 mg = (MethodGroupExpr)left;
1778 } else if (right.eclass == ExprClass.MethodGroup) {
1779 if (!TypeManager.IsDelegateType(l)) {
1780 Error_OperatorCannotBeApplied(Location, OperName(oper),
1781 left.ExprClassName, right.ExprClassName);
1784 mg = (MethodGroupExpr)right;
1789 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1793 // Find operator method
1794 string op = oper_names[(int)oper];
1795 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1796 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1798 ArrayList args = new ArrayList(2);
1799 args.Add(new Argument(e, Argument.AType.Expression));
1800 if (delegate_type == l)
1801 args.Insert(0, new Argument(left, Argument.AType.Expression));
1803 args.Add(new Argument(right, Argument.AType.Expression));
1805 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1808 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1809 Error_OperatorCannotBeApplied(Location, OperName(oper),
1810 left.ExprClassName, right.ExprClassName);
1817 // Do not perform operator overload resolution when both sides are
1820 Expression left_operators = null, right_operators = null;
1821 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1823 // Step 1: Perform Operator Overload location
1825 string op = oper_names [(int) oper];
1827 MethodGroupExpr union;
1828 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc);
1830 right_operators = MemberLookup (
1831 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc);
1832 union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
1834 union = (MethodGroupExpr) left_operators;
1836 if (union != null) {
1837 ArrayList args = new ArrayList (2);
1838 args.Add (new Argument (left, Argument.AType.Expression));
1839 args.Add (new Argument (right, Argument.AType.Expression));
1841 MethodBase method = union.OverloadResolve (ec, args, true, Location.Null);
1843 if (method != null) {
1844 MethodInfo mi = (MethodInfo) method;
1845 return new BinaryMethod (mi.ReturnType, method, args);
1851 // Step 0: String concatenation (because overloading will get this wrong)
1853 if (oper == Operator.Addition){
1855 // If any of the arguments is a string, cast to string
1858 // Simple constant folding
1859 if (left is StringConstant && right is StringConstant)
1860 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1862 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1864 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1865 Error_OperatorCannotBeApplied ();
1869 // try to fold it in on the left
1870 if (left is StringConcat) {
1873 // We have to test here for not-null, since we can be doubly-resolved
1874 // take care of not appending twice
1877 type = TypeManager.string_type;
1878 ((StringConcat) left).Append (ec, right);
1879 return left.Resolve (ec);
1885 // Otherwise, start a new concat expression
1886 return new StringConcat (ec, loc, left, right).Resolve (ec);
1890 // Transform a + ( - b) into a - b
1892 if (right is Unary){
1893 Unary right_unary = (Unary) right;
1895 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1896 oper = Operator.Subtraction;
1897 right = right_unary.Expr;
1903 if (oper == Operator.Equality || oper == Operator.Inequality){
1904 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1905 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1906 Error_OperatorCannotBeApplied ();
1910 type = TypeManager.bool_type;
1914 if (l.IsPointer || r.IsPointer) {
1915 if (l.IsPointer && r.IsPointer) {
1916 type = TypeManager.bool_type;
1920 if (l.IsPointer && r == TypeManager.null_type) {
1921 right = new EmptyCast (NullPointer.Null, l);
1922 type = TypeManager.bool_type;
1926 if (r.IsPointer && l == TypeManager.null_type) {
1927 left = new EmptyCast (NullPointer.Null, r);
1928 type = TypeManager.bool_type;
1934 if (l.IsGenericParameter && r.IsGenericParameter) {
1935 GenericConstraints l_gc, r_gc;
1937 l_gc = TypeManager.GetTypeParameterConstraints (l);
1938 r_gc = TypeManager.GetTypeParameterConstraints (r);
1940 if ((l_gc == null) || (r_gc == null) ||
1941 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1942 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1943 Error_OperatorCannotBeApplied ();
1951 // operator != (object a, object b)
1952 // operator == (object a, object b)
1954 // For this to be used, both arguments have to be reference-types.
1955 // Read the rationale on the spec (14.9.6)
1957 if (!(l.IsValueType || r.IsValueType)){
1958 type = TypeManager.bool_type;
1964 // Also, a standard conversion must exist from either one
1966 bool left_to_right =
1967 Convert.ImplicitStandardConversionExists (left, r);
1968 bool right_to_left = !left_to_right &&
1969 Convert.ImplicitStandardConversionExists (right, l);
1971 if (!left_to_right && !right_to_left) {
1972 Error_OperatorCannotBeApplied ();
1976 if (left_to_right && left_operators != null &&
1977 RootContext.WarningLevel >= 2) {
1978 ArrayList args = new ArrayList (2);
1979 args.Add (new Argument (left, Argument.AType.Expression));
1980 args.Add (new Argument (left, Argument.AType.Expression));
1981 MethodBase method = ((MethodGroupExpr)left_operators).OverloadResolve (
1982 ec, args, true, Location.Null);
1984 Warning_UnintendedReferenceComparison (loc, "right", l);
1987 if (right_to_left && right_operators != null &&
1988 RootContext.WarningLevel >= 2) {
1989 ArrayList args = new ArrayList (2);
1990 args.Add (new Argument (right, Argument.AType.Expression));
1991 args.Add (new Argument (right, Argument.AType.Expression));
1992 MethodBase method = ((MethodGroupExpr)right_operators).OverloadResolve (
1993 ec, args, true, Location.Null);
1995 Warning_UnintendedReferenceComparison (loc, "left", r);
1999 // We are going to have to convert to an object to compare
2001 if (l != TypeManager.object_type)
2002 left = new EmptyCast (left, TypeManager.object_type);
2003 if (r != TypeManager.object_type)
2004 right = new EmptyCast (right, TypeManager.object_type);
2010 // Only perform numeric promotions on:
2011 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2013 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2014 if (TypeManager.IsDelegateType (l)){
2015 if (((right.eclass == ExprClass.MethodGroup) ||
2016 (r == TypeManager.anonymous_method_type))){
2017 if ((RootContext.Version != LanguageVersion.ISO_1)){
2018 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2026 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2028 ArrayList args = new ArrayList (2);
2030 args = new ArrayList (2);
2031 args.Add (new Argument (left, Argument.AType.Expression));
2032 args.Add (new Argument (right, Argument.AType.Expression));
2034 if (oper == Operator.Addition)
2035 method = TypeManager.delegate_combine_delegate_delegate;
2037 method = TypeManager.delegate_remove_delegate_delegate;
2039 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2040 Error_OperatorCannotBeApplied ();
2044 return new BinaryDelegate (l, method, args);
2049 // Pointer arithmetic:
2051 // T* operator + (T* x, int y);
2052 // T* operator + (T* x, uint y);
2053 // T* operator + (T* x, long y);
2054 // T* operator + (T* x, ulong y);
2056 // T* operator + (int y, T* x);
2057 // T* operator + (uint y, T *x);
2058 // T* operator + (long y, T *x);
2059 // T* operator + (ulong y, T *x);
2061 // T* operator - (T* x, int y);
2062 // T* operator - (T* x, uint y);
2063 // T* operator - (T* x, long y);
2064 // T* operator - (T* x, ulong y);
2066 // long operator - (T* x, T *y)
2069 if (r.IsPointer && oper == Operator.Subtraction){
2071 return new PointerArithmetic (
2072 false, left, right, TypeManager.int64_type,
2075 Expression t = Make32or64 (ec, right);
2077 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2079 } else if (r.IsPointer && oper == Operator.Addition){
2080 Expression t = Make32or64 (ec, left);
2082 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2087 // Enumeration operators
2089 bool lie = TypeManager.IsEnumType (l);
2090 bool rie = TypeManager.IsEnumType (r);
2094 // U operator - (E e, E f)
2096 if (oper == Operator.Subtraction){
2098 type = TypeManager.EnumToUnderlying (l);
2101 Error_OperatorCannotBeApplied ();
2107 // operator + (E e, U x)
2108 // operator - (E e, U x)
2110 if (oper == Operator.Addition || oper == Operator.Subtraction){
2111 Type enum_type = lie ? l : r;
2112 Type other_type = lie ? r : l;
2113 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2115 if (underlying_type != other_type){
2116 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2126 Error_OperatorCannotBeApplied ();
2135 temp = Convert.ImplicitConversion (ec, right, l, loc);
2139 Error_OperatorCannotBeApplied ();
2143 temp = Convert.ImplicitConversion (ec, left, r, loc);
2148 Error_OperatorCannotBeApplied ();
2153 if (oper == Operator.Equality || oper == Operator.Inequality ||
2154 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2155 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2156 if (left.Type != right.Type){
2157 Error_OperatorCannotBeApplied ();
2160 type = TypeManager.bool_type;
2164 if (oper == Operator.BitwiseAnd ||
2165 oper == Operator.BitwiseOr ||
2166 oper == Operator.ExclusiveOr){
2167 if (left.Type != right.Type){
2168 Error_OperatorCannotBeApplied ();
2174 Error_OperatorCannotBeApplied ();
2178 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2179 return CheckShiftArguments (ec);
2181 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2182 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2183 type = TypeManager.bool_type;
2187 left_operators = l == TypeManager.bool_type ?
2188 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2189 right_operators = r == TypeManager.bool_type ?
2190 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2192 if (left_operators != null && right_operators != null) {
2193 left = left_operators;
2194 right = right_operators;
2195 type = TypeManager.bool_type;
2199 Expression e = new ConditionalLogicalOperator (
2200 oper == Operator.LogicalAnd, left, right, l, loc);
2201 return e.Resolve (ec);
2204 Expression orig_left = left;
2205 Expression orig_right = right;
2208 // operator & (bool x, bool y)
2209 // operator | (bool x, bool y)
2210 // operator ^ (bool x, bool y)
2212 if (oper == Operator.BitwiseAnd ||
2213 oper == Operator.BitwiseOr ||
2214 oper == Operator.ExclusiveOr) {
2215 if (OverloadResolve_PredefinedIntegral (ec)) {
2216 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2217 Error_OperatorAmbiguous (loc, oper, l, r);
2221 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2222 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2223 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2224 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2225 TypeManager.CSharpName (r));
2228 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2229 Error_OperatorCannotBeApplied ();
2236 // Pointer comparison
2238 if (l.IsPointer && r.IsPointer){
2239 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2240 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2241 type = TypeManager.bool_type;
2246 if (OverloadResolve_PredefinedIntegral (ec)) {
2247 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2248 Error_OperatorAmbiguous (loc, oper, l, r);
2251 } else if (OverloadResolve_PredefinedFloating (ec)) {
2252 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2253 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2254 Error_OperatorAmbiguous (loc, oper, l, r);
2257 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2258 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2259 Error_OperatorAmbiguous (loc, oper, l, r);
2262 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2263 Error_OperatorCannotBeApplied ();
2267 if (oper == Operator.Equality ||
2268 oper == Operator.Inequality ||
2269 oper == Operator.LessThanOrEqual ||
2270 oper == Operator.LessThan ||
2271 oper == Operator.GreaterThanOrEqual ||
2272 oper == Operator.GreaterThan)
2273 type = TypeManager.bool_type;
2278 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2280 if (r == TypeManager.string_type)
2282 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2283 ec.ContainerType, lookup, oper_names [(int) oper],
2284 MemberTypes.Method, AllBindingFlags, loc);
2285 ArrayList args = new ArrayList (2);
2286 args.Add (new Argument (left, Argument.AType.Expression));
2287 args.Add (new Argument (right, Argument.AType.Expression));
2288 MethodBase method = ops.OverloadResolve (ec, args, true, Location.Null);
2289 return new BinaryMethod (type, method, args);
2295 Constant EnumLiftUp (Constant left, Constant right)
2298 case Operator.BitwiseOr:
2299 case Operator.BitwiseAnd:
2300 case Operator.ExclusiveOr:
2301 case Operator.Equality:
2302 case Operator.Inequality:
2303 case Operator.LessThan:
2304 case Operator.LessThanOrEqual:
2305 case Operator.GreaterThan:
2306 case Operator.GreaterThanOrEqual:
2307 if (left is EnumConstant)
2310 if (left.IsZeroInteger)
2311 return new EnumConstant (left, right.Type);
2315 case Operator.Addition:
2316 case Operator.Subtraction:
2319 case Operator.Multiply:
2320 case Operator.Division:
2321 case Operator.Modulus:
2322 case Operator.LeftShift:
2323 case Operator.RightShift:
2324 if (right is EnumConstant || left is EnumConstant)
2328 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2332 public override Expression DoResolve (EmitContext ec)
2337 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2338 left = ((ParenthesizedExpression) left).Expr;
2339 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2343 if (left.eclass == ExprClass.Type) {
2344 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2348 left = left.Resolve (ec);
2353 Constant lc = left as Constant;
2354 if (lc != null && lc.Type == TypeManager.bool_type &&
2355 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2356 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2358 // TODO: make a sense to resolve unreachable expression as we do for statement
2359 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2363 right = right.Resolve (ec);
2367 eclass = ExprClass.Value;
2368 Constant rc = right as Constant;
2370 // The conversion rules are ignored in enum context but why
2371 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2372 left = lc = EnumLiftUp (lc, rc);
2376 right = rc = EnumLiftUp (rc, lc);
2381 if (oper == Operator.BitwiseAnd) {
2382 if (rc != null && rc.IsZeroInteger) {
2383 return lc is EnumConstant ?
2384 new EnumConstant (rc, lc.Type):
2388 if (lc != null && lc.IsZeroInteger) {
2389 return rc is EnumConstant ?
2390 new EnumConstant (lc, rc.Type):
2394 else if (oper == Operator.BitwiseOr) {
2395 if (lc is EnumConstant &&
2396 rc != null && rc.IsZeroInteger)
2398 if (rc is EnumConstant &&
2399 lc != null && lc.IsZeroInteger)
2401 } else if (oper == Operator.LogicalAnd) {
2402 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2404 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2408 if (rc != null && lc != null){
2409 int prev_e = Report.Errors;
2410 Expression e = ConstantFold.BinaryFold (
2411 ec, oper, lc, rc, loc);
2412 if (e != null || Report.Errors != prev_e)
2417 if ((left is NullLiteral || left.Type.IsValueType) &&
2418 (right is NullLiteral || right.Type.IsValueType) &&
2419 !(left is NullLiteral && right is NullLiteral) &&
2420 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2421 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2424 // Comparison warnings
2425 if (oper == Operator.Equality || oper == Operator.Inequality ||
2426 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2427 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2428 if (left.Equals (right)) {
2429 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2431 CheckUselessComparison (lc, right.Type);
2432 CheckUselessComparison (rc, left.Type);
2435 return ResolveOperator (ec);
2438 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2443 private void CheckUselessComparison (Constant c, Type type)
2445 if (c == null || !IsTypeIntegral (type)
2446 || c is StringConstant
2447 || c is BoolConstant
2448 || c is FloatConstant
2449 || c is DoubleConstant
2450 || c is DecimalConstant
2456 if (c is ULongConstant) {
2457 ulong uvalue = ((ULongConstant) c).Value;
2458 if (uvalue > long.MaxValue) {
2459 if (type == TypeManager.byte_type ||
2460 type == TypeManager.sbyte_type ||
2461 type == TypeManager.short_type ||
2462 type == TypeManager.ushort_type ||
2463 type == TypeManager.int32_type ||
2464 type == TypeManager.uint32_type ||
2465 type == TypeManager.int64_type ||
2466 type == TypeManager.char_type)
2467 WarnUselessComparison (type);
2470 value = (long) uvalue;
2472 else if (c is ByteConstant)
2473 value = ((ByteConstant) c).Value;
2474 else if (c is SByteConstant)
2475 value = ((SByteConstant) c).Value;
2476 else if (c is ShortConstant)
2477 value = ((ShortConstant) c).Value;
2478 else if (c is UShortConstant)
2479 value = ((UShortConstant) c).Value;
2480 else if (c is IntConstant)
2481 value = ((IntConstant) c).Value;
2482 else if (c is UIntConstant)
2483 value = ((UIntConstant) c).Value;
2484 else if (c is LongConstant)
2485 value = ((LongConstant) c).Value;
2486 else if (c is CharConstant)
2487 value = ((CharConstant)c).Value;
2492 if (IsValueOutOfRange (value, type))
2493 WarnUselessComparison (type);
2496 private bool IsValueOutOfRange (long value, Type type)
2498 if (IsTypeUnsigned (type) && value < 0)
2500 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2501 type == TypeManager.byte_type && value >= 0x100 ||
2502 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2503 type == TypeManager.ushort_type && value >= 0x10000 ||
2504 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2505 type == TypeManager.uint32_type && value >= 0x100000000;
2508 private static bool IsTypeIntegral (Type type)
2510 return type == TypeManager.uint64_type ||
2511 type == TypeManager.int64_type ||
2512 type == TypeManager.uint32_type ||
2513 type == TypeManager.int32_type ||
2514 type == TypeManager.ushort_type ||
2515 type == TypeManager.short_type ||
2516 type == TypeManager.sbyte_type ||
2517 type == TypeManager.byte_type ||
2518 type == TypeManager.char_type;
2521 private static bool IsTypeUnsigned (Type type)
2523 return type == TypeManager.uint64_type ||
2524 type == TypeManager.uint32_type ||
2525 type == TypeManager.ushort_type ||
2526 type == TypeManager.byte_type ||
2527 type == TypeManager.char_type;
2530 private void WarnUselessComparison (Type type)
2532 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}'",
2533 TypeManager.CSharpName (type));
2537 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2538 /// context of a conditional bool expression. This function will return
2539 /// false if it is was possible to use EmitBranchable, or true if it was.
2541 /// The expression's code is generated, and we will generate a branch to `target'
2542 /// if the resulting expression value is equal to isTrue
2544 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2546 ILGenerator ig = ec.ig;
2549 // This is more complicated than it looks, but its just to avoid
2550 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2551 // but on top of that we want for == and != to use a special path
2552 // if we are comparing against null
2554 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2555 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2558 // put the constant on the rhs, for simplicity
2560 if (left is Constant) {
2561 Expression swap = right;
2566 if (((Constant) right).IsZeroInteger) {
2569 ig.Emit (OpCodes.Brtrue, target);
2571 ig.Emit (OpCodes.Brfalse, target);
2574 } else if (right is BoolConstant) {
2576 if (my_on_true != ((BoolConstant) right).Value)
2577 ig.Emit (OpCodes.Brtrue, target);
2579 ig.Emit (OpCodes.Brfalse, target);
2584 } else if (oper == Operator.LogicalAnd) {
2587 Label tests_end = ig.DefineLabel ();
2589 left.EmitBranchable (ec, tests_end, false);
2590 right.EmitBranchable (ec, target, true);
2591 ig.MarkLabel (tests_end);
2594 // This optimizes code like this
2595 // if (true && i > 4)
2597 if (!(left is Constant))
2598 left.EmitBranchable (ec, target, false);
2600 if (!(right is Constant))
2601 right.EmitBranchable (ec, target, false);
2606 } else if (oper == Operator.LogicalOr){
2608 left.EmitBranchable (ec, target, true);
2609 right.EmitBranchable (ec, target, true);
2612 Label tests_end = ig.DefineLabel ();
2613 left.EmitBranchable (ec, tests_end, true);
2614 right.EmitBranchable (ec, target, false);
2615 ig.MarkLabel (tests_end);
2620 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2621 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2622 oper == Operator.Equality || oper == Operator.Inequality)) {
2623 base.EmitBranchable (ec, target, onTrue);
2631 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2634 case Operator.Equality:
2636 ig.Emit (OpCodes.Beq, target);
2638 ig.Emit (OpCodes.Bne_Un, target);
2641 case Operator.Inequality:
2643 ig.Emit (OpCodes.Bne_Un, target);
2645 ig.Emit (OpCodes.Beq, target);
2648 case Operator.LessThan:
2651 ig.Emit (OpCodes.Blt_Un, target);
2653 ig.Emit (OpCodes.Blt, target);
2656 ig.Emit (OpCodes.Bge_Un, target);
2658 ig.Emit (OpCodes.Bge, target);
2661 case Operator.GreaterThan:
2664 ig.Emit (OpCodes.Bgt_Un, target);
2666 ig.Emit (OpCodes.Bgt, target);
2669 ig.Emit (OpCodes.Ble_Un, target);
2671 ig.Emit (OpCodes.Ble, target);
2674 case Operator.LessThanOrEqual:
2677 ig.Emit (OpCodes.Ble_Un, target);
2679 ig.Emit (OpCodes.Ble, target);
2682 ig.Emit (OpCodes.Bgt_Un, target);
2684 ig.Emit (OpCodes.Bgt, target);
2688 case Operator.GreaterThanOrEqual:
2691 ig.Emit (OpCodes.Bge_Un, target);
2693 ig.Emit (OpCodes.Bge, target);
2696 ig.Emit (OpCodes.Blt_Un, target);
2698 ig.Emit (OpCodes.Blt, target);
2701 Console.WriteLine (oper);
2702 throw new Exception ("what is THAT");
2706 public override void Emit (EmitContext ec)
2708 ILGenerator ig = ec.ig;
2713 // Handle short-circuit operators differently
2716 if (oper == Operator.LogicalAnd) {
2717 Label load_zero = ig.DefineLabel ();
2718 Label end = ig.DefineLabel ();
2720 left.EmitBranchable (ec, load_zero, false);
2722 ig.Emit (OpCodes.Br, end);
2724 ig.MarkLabel (load_zero);
2725 ig.Emit (OpCodes.Ldc_I4_0);
2728 } else if (oper == Operator.LogicalOr) {
2729 Label load_one = ig.DefineLabel ();
2730 Label end = ig.DefineLabel ();
2732 left.EmitBranchable (ec, load_one, true);
2734 ig.Emit (OpCodes.Br, end);
2736 ig.MarkLabel (load_one);
2737 ig.Emit (OpCodes.Ldc_I4_1);
2745 bool isUnsigned = is_unsigned (left.Type);
2748 case Operator.Multiply:
2750 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2751 opcode = OpCodes.Mul_Ovf;
2752 else if (isUnsigned)
2753 opcode = OpCodes.Mul_Ovf_Un;
2755 opcode = OpCodes.Mul;
2757 opcode = OpCodes.Mul;
2761 case Operator.Division:
2763 opcode = OpCodes.Div_Un;
2765 opcode = OpCodes.Div;
2768 case Operator.Modulus:
2770 opcode = OpCodes.Rem_Un;
2772 opcode = OpCodes.Rem;
2775 case Operator.Addition:
2777 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2778 opcode = OpCodes.Add_Ovf;
2779 else if (isUnsigned)
2780 opcode = OpCodes.Add_Ovf_Un;
2782 opcode = OpCodes.Add;
2784 opcode = OpCodes.Add;
2787 case Operator.Subtraction:
2789 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2790 opcode = OpCodes.Sub_Ovf;
2791 else if (isUnsigned)
2792 opcode = OpCodes.Sub_Ovf_Un;
2794 opcode = OpCodes.Sub;
2796 opcode = OpCodes.Sub;
2799 case Operator.RightShift:
2801 opcode = OpCodes.Shr_Un;
2803 opcode = OpCodes.Shr;
2806 case Operator.LeftShift:
2807 opcode = OpCodes.Shl;
2810 case Operator.Equality:
2811 opcode = OpCodes.Ceq;
2814 case Operator.Inequality:
2815 ig.Emit (OpCodes.Ceq);
2816 ig.Emit (OpCodes.Ldc_I4_0);
2818 opcode = OpCodes.Ceq;
2821 case Operator.LessThan:
2823 opcode = OpCodes.Clt_Un;
2825 opcode = OpCodes.Clt;
2828 case Operator.GreaterThan:
2830 opcode = OpCodes.Cgt_Un;
2832 opcode = OpCodes.Cgt;
2835 case Operator.LessThanOrEqual:
2836 Type lt = left.Type;
2838 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2839 ig.Emit (OpCodes.Cgt_Un);
2841 ig.Emit (OpCodes.Cgt);
2842 ig.Emit (OpCodes.Ldc_I4_0);
2844 opcode = OpCodes.Ceq;
2847 case Operator.GreaterThanOrEqual:
2848 Type le = left.Type;
2850 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2851 ig.Emit (OpCodes.Clt_Un);
2853 ig.Emit (OpCodes.Clt);
2855 ig.Emit (OpCodes.Ldc_I4_0);
2857 opcode = OpCodes.Ceq;
2860 case Operator.BitwiseOr:
2861 opcode = OpCodes.Or;
2864 case Operator.BitwiseAnd:
2865 opcode = OpCodes.And;
2868 case Operator.ExclusiveOr:
2869 opcode = OpCodes.Xor;
2873 throw new Exception ("This should not happen: Operator = "
2874 + oper.ToString ());
2880 protected override void CloneTo (CloneContext clonectx, Expression t)
2882 Binary target = (Binary) t;
2884 target.left = left.Clone (clonectx);
2885 target.right = right.Clone (clonectx);
2890 // Object created by Binary when the binary operator uses an method instead of being
2891 // a binary operation that maps to a CIL binary operation.
2893 public class BinaryMethod : Expression {
2894 public MethodBase method;
2895 public ArrayList Arguments;
2897 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2902 eclass = ExprClass.Value;
2905 public override Expression DoResolve (EmitContext ec)
2910 public override void Emit (EmitContext ec)
2912 ILGenerator ig = ec.ig;
2914 if (Arguments != null)
2915 Invocation.EmitArguments (ec, method, Arguments, false, null);
2917 if (method is MethodInfo)
2918 ig.Emit (OpCodes.Call, (MethodInfo) method);
2920 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2925 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2926 // b, c, d... may be strings or objects.
2928 public class StringConcat : Expression {
2930 bool invalid = false;
2931 bool emit_conv_done = false;
2933 // Are we also concating objects?
2935 bool is_strings_only = true;
2937 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2940 type = TypeManager.string_type;
2941 eclass = ExprClass.Value;
2943 operands = new ArrayList (2);
2948 public override Expression DoResolve (EmitContext ec)
2956 public void Append (EmitContext ec, Expression operand)
2961 StringConstant sc = operand as StringConstant;
2963 // TODO: it will be better to do this silently as an optimalization
2965 // string s = "" + i;
2966 // because this code has poor performace
2967 // if (sc.Value.Length == 0)
2968 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2970 if (operands.Count != 0) {
2971 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2972 if (last_operand != null) {
2973 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2980 // Conversion to object
2982 if (operand.Type != TypeManager.string_type) {
2983 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2986 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2992 operands.Add (operand);
2995 public override void Emit (EmitContext ec)
2997 MethodInfo concat_method = null;
3000 // Do conversion to arguments; check for strings only
3003 // This can get called multiple times, so we have to deal with that.
3004 if (!emit_conv_done) {
3005 emit_conv_done = true;
3006 for (int i = 0; i < operands.Count; i ++) {
3007 Expression e = (Expression) operands [i];
3008 is_strings_only &= e.Type == TypeManager.string_type;
3011 for (int i = 0; i < operands.Count; i ++) {
3012 Expression e = (Expression) operands [i];
3014 if (! is_strings_only && e.Type == TypeManager.string_type) {
3015 // need to make sure this is an object, because the EmitParams
3016 // method might look at the type of this expression, see it is a
3017 // string and emit a string [] when we want an object [];
3019 e = new EmptyCast (e, TypeManager.object_type);
3021 operands [i] = new Argument (e, Argument.AType.Expression);
3026 // Find the right method
3028 switch (operands.Count) {
3031 // This should not be possible, because simple constant folding
3032 // is taken care of in the Binary code.
3034 throw new Exception ("how did you get here?");
3037 concat_method = is_strings_only ?
3038 TypeManager.string_concat_string_string :
3039 TypeManager.string_concat_object_object ;
3042 concat_method = is_strings_only ?
3043 TypeManager.string_concat_string_string_string :
3044 TypeManager.string_concat_object_object_object ;
3048 // There is not a 4 param overlaod for object (the one that there is
3049 // is actually a varargs methods, and is only in corlib because it was
3050 // introduced there before.).
3052 if (!is_strings_only)
3055 concat_method = TypeManager.string_concat_string_string_string_string;
3058 concat_method = is_strings_only ?
3059 TypeManager.string_concat_string_dot_dot_dot :
3060 TypeManager.string_concat_object_dot_dot_dot ;
3064 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3065 ec.ig.Emit (OpCodes.Call, concat_method);
3070 // Object created with +/= on delegates
3072 public class BinaryDelegate : Expression {
3076 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3081 eclass = ExprClass.Value;
3084 public override Expression DoResolve (EmitContext ec)
3089 public override void Emit (EmitContext ec)
3091 ILGenerator ig = ec.ig;
3093 Invocation.EmitArguments (ec, method, args, false, null);
3095 ig.Emit (OpCodes.Call, (MethodInfo) method);
3096 ig.Emit (OpCodes.Castclass, type);
3099 public Expression Right {
3101 Argument arg = (Argument) args [1];
3106 public bool IsAddition {
3108 return method == TypeManager.delegate_combine_delegate_delegate;
3114 // User-defined conditional logical operator
3115 public class ConditionalLogicalOperator : Expression {
3116 Expression left, right;
3119 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3122 eclass = ExprClass.Value;
3126 this.is_and = is_and;
3129 protected void Error19 ()
3131 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3134 protected void Error218 ()
3136 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3137 "declarations of operator true and operator false");
3140 Expression op_true, op_false, op;
3141 LocalTemporary left_temp;
3143 public override Expression DoResolve (EmitContext ec)
3146 Expression operator_group;
3148 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3149 if (operator_group == null) {
3154 left_temp = new LocalTemporary (type);
3156 ArrayList arguments = new ArrayList (2);
3157 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3158 arguments.Add (new Argument (right, Argument.AType.Expression));
3159 method = ((MethodGroupExpr) operator_group).OverloadResolve (
3160 ec, arguments, false, loc)
3162 if (method == null) {
3167 if (method.ReturnType != type) {
3168 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3169 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3173 op = new StaticCallExpr (method, arguments, loc);
3175 op_true = GetOperatorTrue (ec, left_temp, loc);
3176 op_false = GetOperatorFalse (ec, left_temp, loc);
3177 if ((op_true == null) || (op_false == null)) {
3185 public override void Emit (EmitContext ec)
3187 ILGenerator ig = ec.ig;
3188 Label false_target = ig.DefineLabel ();
3189 Label end_target = ig.DefineLabel ();
3192 left_temp.Store (ec);
3194 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3195 left_temp.Emit (ec);
3196 ig.Emit (OpCodes.Br, end_target);
3197 ig.MarkLabel (false_target);
3199 ig.MarkLabel (end_target);
3201 // We release 'left_temp' here since 'op' may refer to it too
3202 left_temp.Release (ec);
3206 public class PointerArithmetic : Expression {
3207 Expression left, right;
3211 // We assume that `l' is always a pointer
3213 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3219 is_add = is_addition;
3222 public override Expression DoResolve (EmitContext ec)
3224 eclass = ExprClass.Variable;
3226 if (left.Type == TypeManager.void_ptr_type) {
3227 Error (242, "The operation in question is undefined on void pointers");
3234 public override void Emit (EmitContext ec)
3236 Type op_type = left.Type;
3237 ILGenerator ig = ec.ig;
3239 // It must be either array or fixed buffer
3240 Type element = TypeManager.HasElementType (op_type) ?
3241 element = TypeManager.GetElementType (op_type) :
3242 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3244 int size = GetTypeSize (element);
3245 Type rtype = right.Type;
3247 if (rtype.IsPointer){
3249 // handle (pointer - pointer)
3253 ig.Emit (OpCodes.Sub);
3257 ig.Emit (OpCodes.Sizeof, element);
3259 IntLiteral.EmitInt (ig, size);
3260 ig.Emit (OpCodes.Div);
3262 ig.Emit (OpCodes.Conv_I8);
3265 // handle + and - on (pointer op int)
3268 ig.Emit (OpCodes.Conv_I);
3270 Constant right_const = right as Constant;
3271 if (right_const != null && size != 0) {
3272 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3280 ig.Emit (OpCodes.Sizeof, element);
3282 IntLiteral.EmitInt (ig, size);
3283 if (rtype == TypeManager.int64_type)
3284 ig.Emit (OpCodes.Conv_I8);
3285 else if (rtype == TypeManager.uint64_type)
3286 ig.Emit (OpCodes.Conv_U8);
3287 ig.Emit (OpCodes.Mul);
3291 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3292 ig.Emit (OpCodes.Conv_I);
3295 ig.Emit (OpCodes.Add);
3297 ig.Emit (OpCodes.Sub);
3303 /// Implements the ternary conditional operator (?:)
3305 public class Conditional : Expression {
3306 Expression expr, trueExpr, falseExpr;
3308 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3311 this.trueExpr = trueExpr;
3312 this.falseExpr = falseExpr;
3313 this.loc = expr.Location;
3316 public Expression Expr {
3322 public Expression TrueExpr {
3328 public Expression FalseExpr {
3334 public override Expression DoResolve (EmitContext ec)
3336 expr = expr.Resolve (ec);
3342 if (TypeManager.IsNullableValueType (expr.Type))
3343 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3346 if (expr.Type != TypeManager.bool_type){
3347 expr = Expression.ResolveBoolean (
3354 Assign ass = expr as Assign;
3355 if (ass != null && ass.Source is Constant) {
3356 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3359 trueExpr = trueExpr.Resolve (ec);
3360 falseExpr = falseExpr.Resolve (ec);
3362 if (trueExpr == null || falseExpr == null)
3365 eclass = ExprClass.Value;
3366 if (trueExpr.Type == falseExpr.Type) {
3367 type = trueExpr.Type;
3368 if (type == TypeManager.null_type) {
3369 // TODO: probably will have to implement ConditionalConstant
3370 // to call method without return constant as well
3371 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3376 Type true_type = trueExpr.Type;
3377 Type false_type = falseExpr.Type;
3380 // First, if an implicit conversion exists from trueExpr
3381 // to falseExpr, then the result type is of type falseExpr.Type
3383 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3386 // Check if both can convert implicitl to each other's type
3388 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3390 "Can not compute type of conditional expression " +
3391 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3392 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3393 "' convert implicitly to each other");
3398 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3402 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3403 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3408 // Dead code optimalization
3409 if (expr is BoolConstant){
3410 BoolConstant bc = (BoolConstant) expr;
3412 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3413 return bc.Value ? trueExpr : falseExpr;
3419 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3424 public override void Emit (EmitContext ec)
3426 ILGenerator ig = ec.ig;
3427 Label false_target = ig.DefineLabel ();
3428 Label end_target = ig.DefineLabel ();
3430 expr.EmitBranchable (ec, false_target, false);
3432 ig.Emit (OpCodes.Br, end_target);
3433 ig.MarkLabel (false_target);
3434 falseExpr.Emit (ec);
3435 ig.MarkLabel (end_target);
3438 protected override void CloneTo (CloneContext clonectx, Expression t)
3440 Conditional target = (Conditional) t;
3442 target.expr = expr.Clone (clonectx);
3443 target.trueExpr = trueExpr.Clone (clonectx);
3444 target.falseExpr = falseExpr.Clone (clonectx);
3448 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3450 LocalTemporary temp;
3452 public abstract Variable Variable {
3456 public abstract bool IsRef {
3460 public override void Emit (EmitContext ec)
3466 // This method is used by parameters that are references, that are
3467 // being passed as references: we only want to pass the pointer (that
3468 // is already stored in the parameter, not the address of the pointer,
3469 // and not the value of the variable).
3471 public void EmitLoad (EmitContext ec)
3473 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3475 Variable.EmitInstance (ec);
3479 public void Emit (EmitContext ec, bool leave_copy)
3481 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3487 ec.ig.Emit (OpCodes.Dup);
3490 // If we are a reference, we loaded on the stack a pointer
3491 // Now lets load the real value
3493 LoadFromPtr (ec.ig, type);
3497 ec.ig.Emit (OpCodes.Dup);
3499 if (IsRef || Variable.NeedsTemporary) {
3500 temp = new LocalTemporary (Type);
3506 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3507 bool prepare_for_load)
3509 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3512 ILGenerator ig = ec.ig;
3513 prepared = prepare_for_load;
3515 Variable.EmitInstance (ec);
3516 if (prepare_for_load && Variable.HasInstance)
3517 ig.Emit (OpCodes.Dup);
3518 else if (IsRef && !prepared)
3524 ig.Emit (OpCodes.Dup);
3525 if (IsRef || Variable.NeedsTemporary) {
3526 temp = new LocalTemporary (Type);
3532 StoreFromPtr (ig, type);
3534 Variable.EmitAssign (ec);
3542 public void AddressOf (EmitContext ec, AddressOp mode)
3544 Variable.EmitInstance (ec);
3545 Variable.EmitAddressOf (ec);
3552 public class LocalVariableReference : VariableReference, IVariable {
3553 public readonly string Name;
3555 public LocalInfo local_info;
3559 public LocalVariableReference (Block block, string name, Location l)
3564 eclass = ExprClass.Variable;
3568 // Setting `is_readonly' to false will allow you to create a writable
3569 // reference to a read-only variable. This is used by foreach and using.
3571 public LocalVariableReference (Block block, string name, Location l,
3572 LocalInfo local_info, bool is_readonly)
3573 : this (block, name, l)
3575 this.local_info = local_info;
3576 this.is_readonly = is_readonly;
3579 public VariableInfo VariableInfo {
3580 get { return local_info.VariableInfo; }
3583 public override bool IsRef {
3584 get { return false; }
3587 public bool IsReadOnly {
3588 get { return is_readonly; }
3591 public bool VerifyAssigned (EmitContext ec)
3593 VariableInfo variable_info = local_info.VariableInfo;
3594 return variable_info == null || variable_info.IsAssigned (ec, loc);
3597 void ResolveLocalInfo ()
3599 if (local_info == null) {
3600 local_info = Block.GetLocalInfo (Name);
3601 is_readonly = local_info.ReadOnly;
3605 protected Expression DoResolveBase (EmitContext ec)
3607 type = local_info.VariableType;
3609 Expression e = Block.GetConstantExpression (Name);
3611 return e.Resolve (ec);
3613 if (!VerifyAssigned (ec))
3617 // If we are referencing a variable from the external block
3618 // flag it for capturing
3620 if (ec.MustCaptureVariable (local_info)) {
3621 if (local_info.AddressTaken){
3622 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3626 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3627 variable = scope.AddLocal (local_info);
3628 type = variable.Type;
3634 public override Expression DoResolve (EmitContext ec)
3636 ResolveLocalInfo ();
3637 local_info.Used = true;
3638 return DoResolveBase (ec);
3641 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3643 ResolveLocalInfo ();
3648 if (right_side == EmptyExpression.OutAccess) {
3649 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3650 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3651 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3652 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3653 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3655 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3657 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3662 if (right_side == EmptyExpression.OutAccess)
3663 local_info.Used = true;
3665 if (VariableInfo != null)
3666 VariableInfo.SetAssigned (ec);
3668 return DoResolveBase (ec);
3671 public bool VerifyFixed ()
3673 // A local Variable is always fixed.
3677 public override int GetHashCode ()
3679 return Name.GetHashCode ();
3682 public override bool Equals (object obj)
3684 LocalVariableReference lvr = obj as LocalVariableReference;
3688 return Name == lvr.Name && Block == lvr.Block;
3691 public override Variable Variable {
3692 get { return variable != null ? variable : local_info.Variable; }
3695 public override string ToString ()
3697 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3700 protected override void CloneTo (CloneContext clonectx, Expression t)
3702 LocalVariableReference target = (LocalVariableReference) t;
3704 target.Block = clonectx.LookupBlock (Block);
3709 /// This represents a reference to a parameter in the intermediate
3712 public class ParameterReference : VariableReference, IVariable {
3713 ToplevelParameterInfo pi;
3714 ToplevelBlock referenced;
3716 public bool is_ref, is_out;
3719 get { return is_out; }
3722 public override bool IsRef {
3723 get { return is_ref; }
3726 public string Name {
3727 get { return Parameter.Name; }
3730 public Parameter Parameter {
3731 get { return pi.Parameter; }
3736 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3739 this.referenced = referenced;
3741 eclass = ExprClass.Variable;
3744 public VariableInfo VariableInfo {
3745 get { return pi.VariableInfo; }
3748 public override Variable Variable {
3749 get { return variable != null ? variable : Parameter.Variable; }
3752 public bool VerifyFixed ()
3754 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3755 return Parameter.ModFlags == Parameter.Modifier.NONE;
3758 public bool IsAssigned (EmitContext ec, Location loc)
3760 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3763 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3767 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3769 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3772 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3776 public void SetAssigned (EmitContext ec)
3778 if (is_out && ec.DoFlowAnalysis)
3779 ec.CurrentBranching.SetAssigned (VariableInfo);
3782 public void SetFieldAssigned (EmitContext ec, string field_name)
3784 if (is_out && ec.DoFlowAnalysis)
3785 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3788 protected bool DoResolveBase (EmitContext ec)
3790 Parameter par = Parameter;
3791 if (!par.Resolve (ec)) {
3795 type = par.ParameterType;
3796 Parameter.Modifier mod = par.ModFlags;
3797 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3798 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3799 eclass = ExprClass.Variable;
3801 ToplevelBlock declared = pi.Block;
3803 AnonymousContainer am = ec.CurrentAnonymousMethod;
3807 if (is_ref && declared != referenced) {
3808 Report.Error (1628, Location,
3809 "Cannot use ref or out parameter `{0}' inside an " +
3810 "anonymous method block", par.Name);
3814 if (!am.IsIterator && declared == referenced)
3817 ScopeInfo scope = declared.CreateScopeInfo ();
3818 variable = scope.AddParameter (par, pi.Index);
3819 type = variable.Type;
3823 public override int GetHashCode ()
3825 return Name.GetHashCode ();
3828 public override bool Equals (object obj)
3830 ParameterReference pr = obj as ParameterReference;
3834 return Name == pr.Name && referenced == pr.referenced;
3838 // Notice that for ref/out parameters, the type exposed is not the
3839 // same type exposed externally.
3842 // externally we expose "int&"
3843 // here we expose "int".
3845 // We record this in "is_ref". This means that the type system can treat
3846 // the type as it is expected, but when we generate the code, we generate
3847 // the alternate kind of code.
3849 public override Expression DoResolve (EmitContext ec)
3851 if (!DoResolveBase (ec))
3854 if (is_out && ec.DoFlowAnalysis &&
3855 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3861 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3863 if (!DoResolveBase (ec))
3871 static public void EmitLdArg (ILGenerator ig, int x)
3875 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3876 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3877 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3878 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3879 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3882 ig.Emit (OpCodes.Ldarg, x);
3885 public override string ToString ()
3887 return "ParameterReference[" + Name + "]";
3892 /// Used for arguments to New(), Invocation()
3894 public class Argument {
3895 public enum AType : byte {
3902 public static readonly Argument[] Empty = new Argument [0];
3904 public readonly AType ArgType;
3905 public Expression Expr;
3907 public Argument (Expression expr, AType type)
3910 this.ArgType = type;
3913 public Argument (Expression expr)
3916 this.ArgType = AType.Expression;
3921 if (ArgType == AType.Ref || ArgType == AType.Out)
3922 return TypeManager.GetReferenceType (Expr.Type);
3928 public Parameter.Modifier Modifier
3933 return Parameter.Modifier.OUT;
3936 return Parameter.Modifier.REF;
3939 return Parameter.Modifier.NONE;
3944 public static string FullDesc (Argument a)
3946 if (a.ArgType == AType.ArgList)
3949 return (a.ArgType == AType.Ref ? "ref " :
3950 (a.ArgType == AType.Out ? "out " : "")) +
3951 TypeManager.CSharpName (a.Expr.Type);
3954 public bool ResolveMethodGroup (EmitContext ec)
3956 SimpleName sn = Expr as SimpleName;
3958 Expr = sn.GetMethodGroup ();
3960 // FIXME: csc doesn't report any error if you try to use `ref' or
3961 // `out' in a delegate creation expression.
3962 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3969 public bool Resolve (EmitContext ec, Location loc)
3971 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3972 // Verify that the argument is readable
3973 if (ArgType != AType.Out)
3974 Expr = Expr.Resolve (ec);
3976 // Verify that the argument is writeable
3977 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3978 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3980 return Expr != null;
3984 public void Emit (EmitContext ec)
3986 if (ArgType != AType.Ref && ArgType != AType.Out) {
3991 AddressOp mode = AddressOp.Store;
3992 if (ArgType == AType.Ref)
3993 mode |= AddressOp.Load;
3995 IMemoryLocation ml = (IMemoryLocation) Expr;
3996 ParameterReference pr = ml as ParameterReference;
3999 // ParameterReferences might already be references, so we want
4000 // to pass just the value
4002 if (pr != null && pr.IsRef)
4005 ml.AddressOf (ec, mode);
4008 public Argument Clone (CloneContext clonectx)
4010 return new Argument (Expr.Clone (clonectx), ArgType);
4015 /// Invocation of methods or delegates.
4017 public class Invocation : ExpressionStatement {
4018 public ArrayList Arguments;
4021 MethodBase method = null;
4024 // arguments is an ArrayList, but we do not want to typecast,
4025 // as it might be null.
4027 // FIXME: only allow expr to be a method invocation or a
4028 // delegate invocation (7.5.5)
4030 public Invocation (Expression expr, ArrayList arguments)
4033 Arguments = arguments;
4034 loc = expr.Location;
4037 public Expression Expr {
4043 public static string FullMethodDesc (MethodBase mb)
4049 if (mb is MethodInfo) {
4050 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4054 sb = new StringBuilder ();
4056 sb.Append (TypeManager.CSharpSignature (mb));
4057 return sb.ToString ();
4060 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4062 MemberInfo [] miset;
4063 MethodGroupExpr union;
4068 return (MethodGroupExpr) mg2;
4071 return (MethodGroupExpr) mg1;
4074 MethodGroupExpr left_set = null, right_set = null;
4075 int length1 = 0, length2 = 0;
4077 left_set = (MethodGroupExpr) mg1;
4078 length1 = left_set.Methods.Length;
4080 right_set = (MethodGroupExpr) mg2;
4081 length2 = right_set.Methods.Length;
4083 ArrayList common = new ArrayList ();
4085 foreach (MethodBase r in right_set.Methods){
4086 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4090 miset = new MemberInfo [length1 + length2 - common.Count];
4091 left_set.Methods.CopyTo (miset, 0);
4095 foreach (MethodBase r in right_set.Methods) {
4096 if (!common.Contains (r))
4100 union = new MethodGroupExpr (miset, loc);
4105 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4106 ArrayList arguments, int arg_count,
4107 ref MethodBase candidate)
4109 return IsParamsMethodApplicable (
4110 ec, me, arguments, arg_count, false, ref candidate) ||
4111 IsParamsMethodApplicable (
4112 ec, me, arguments, arg_count, true, ref candidate);
4117 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4118 ArrayList arguments, int arg_count,
4119 bool do_varargs, ref MethodBase candidate)
4122 if (!me.HasTypeArguments &&
4123 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4126 if (TypeManager.IsGenericMethodDefinition (candidate))
4127 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4130 return IsParamsMethodApplicable (
4131 ec, arguments, arg_count, candidate, do_varargs);
4135 /// Determines if the candidate method, if a params method, is applicable
4136 /// in its expanded form to the given set of arguments
4138 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4139 int arg_count, MethodBase candidate,
4142 ParameterData pd = TypeManager.GetParameterData (candidate);
4144 int pd_count = pd.Count;
4148 int count = pd_count - 1;
4150 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4152 if (pd_count != arg_count)
4155 if (!(((Argument) arguments [count]).Expr is Arglist))
4163 if (count > arg_count)
4166 if (pd_count == 1 && arg_count == 0)
4170 // If we have come this far, the case which
4171 // remains is when the number of parameters is
4172 // less than or equal to the argument count.
4174 int argument_index = 0;
4176 for (int i = 0; i < pd_count; ++i) {
4178 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4179 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4180 int params_args_count = arg_count - pd_count;
4181 if (params_args_count < 0)
4185 a = (Argument) arguments [argument_index++];
4187 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4189 } while (params_args_count-- > 0);
4193 a = (Argument) arguments [argument_index++];
4195 Parameter.Modifier a_mod = a.Modifier &
4196 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4197 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4198 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4200 if (a_mod == p_mod) {
4202 if (a_mod == Parameter.Modifier.NONE)
4203 if (!Convert.ImplicitConversionExists (ec,
4205 pd.ParameterType (i)))
4208 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4209 Type pt = pd.ParameterType (i);
4212 pt = TypeManager.GetReferenceType (pt);
4225 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4226 ArrayList arguments, int arg_count,
4227 ref MethodBase method)
4229 MethodBase candidate = method;
4232 if (!me.HasTypeArguments &&
4233 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4236 if (TypeManager.IsGenericMethodDefinition (candidate))
4237 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4240 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4249 /// Determines if the candidate method is applicable (section 14.4.2.1)
4250 /// to the given set of arguments
4252 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4253 MethodBase candidate)
4255 ParameterData pd = TypeManager.GetParameterData (candidate);
4257 if (arg_count != pd.Count)
4260 for (int i = arg_count; i > 0; ) {
4263 Argument a = (Argument) arguments [i];
4265 Parameter.Modifier a_mod = a.Modifier &
4266 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4268 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4269 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4271 if (a_mod == p_mod) {
4272 Type pt = pd.ParameterType (i);
4273 EmitContext prevec = EmitContext.TempEc;
4274 EmitContext.TempEc = ec;
4277 if (a_mod == Parameter.Modifier.NONE) {
4278 if (!TypeManager.IsEqual (a.Type, pt) &&
4279 !Convert.ImplicitConversionExists (ec, a.Expr, pt))
4284 EmitContext.TempEc = prevec;
4296 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4298 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4299 name, arg_count.ToString ());
4302 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4303 Type delegate_type, Argument a, ParameterData expected_par)
4305 if (delegate_type == null)
4306 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4307 TypeManager.CSharpSignature (method));
4309 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4310 TypeManager.CSharpName (delegate_type));
4312 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4314 string index = (idx + 1).ToString ();
4315 if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4316 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4317 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4318 index, Parameter.GetModifierSignature (a.Modifier));
4320 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4321 index, Parameter.GetModifierSignature (mod));
4323 string p1 = Argument.FullDesc (a);
4324 string p2 = expected_par.ParameterDesc (idx);
4327 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4328 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4329 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4331 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'", index, p1, p2);
4335 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4336 int arg_count, MethodBase method,
4337 bool chose_params_expanded,
4338 Type delegate_type, bool may_fail,
4341 ParameterData pd = TypeManager.GetParameterData (method);
4345 for (j = 0; j < pd.Count; j++) {
4346 Type parameter_type = pd.ParameterType (j);
4347 Parameter.Modifier pm = pd.ParameterModifier (j);
4349 if (pm == Parameter.Modifier.ARGLIST) {
4350 a = (Argument) Arguments [a_idx];
4351 if (!(a.Expr is Arglist))
4357 int params_arg_count = 1;
4358 if (pm == Parameter.Modifier.PARAMS) {
4359 pm = Parameter.Modifier.NONE;
4360 params_arg_count = arg_count - pd.Count + 1;
4361 if (chose_params_expanded)
4362 parameter_type = TypeManager.GetElementType (parameter_type);
4365 while (params_arg_count > 0) {
4366 a = (Argument) Arguments [a_idx];
4367 if (pm != a.Modifier)
4370 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4371 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4374 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4378 // Update the argument with the implicit conversion
4386 if (params_arg_count > 0)
4389 if (parameter_type.IsPointer && !ec.InUnsafe) {
4396 if (a_idx == arg_count)
4400 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4404 private bool resolved = false;
4405 public override Expression DoResolve (EmitContext ec)
4408 return this.method == null ? null : this;
4412 // First, resolve the expression that is used to
4413 // trigger the invocation
4415 SimpleName sn = expr as SimpleName;
4417 expr = sn.GetMethodGroup ();
4419 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4420 if (expr_resolved == null)
4423 MethodGroupExpr mg = expr_resolved as MethodGroupExpr;
4425 Type expr_type = expr_resolved.Type;
4427 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4428 return (new DelegateInvocation (
4429 expr_resolved, Arguments, loc)).Resolve (ec);
4431 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4436 // Next, evaluate all the expressions in the argument list
4438 if (Arguments != null){
4439 foreach (Argument a in Arguments){
4440 if (!a.Resolve (ec, loc))
4445 MethodBase method = mg.OverloadExtensionResolve (ec, ref Arguments, ref mg, expr, loc);
4451 MethodInfo mi = method as MethodInfo;
4453 type = TypeManager.TypeToCoreType (mi.ReturnType);
4454 Expression iexpr = mg.InstanceExpression;
4456 if (iexpr == null ||
4457 iexpr is This || iexpr is EmptyExpression ||
4458 mg.IdenticalTypeName) {
4459 mg.InstanceExpression = null;
4461 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4465 if (iexpr == null || iexpr is EmptyExpression) {
4466 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
4472 if (type.IsPointer){
4480 // Only base will allow this invocation to happen.
4482 if (mg.IsBase && method.IsAbstract){
4483 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4487 if (Arguments == null && method.Name == "Finalize") {
4489 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4491 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4495 if (IsSpecialMethodInvocation (method)) {
4499 if (mg.InstanceExpression != null){
4500 mg.InstanceExpression.CheckMarshalByRefAccess ();
4503 // This is used to check that no methods are called in struct
4504 // constructors before all the fields on the struct have been
4507 if (!method.IsStatic){
4508 This mgthis = mg.InstanceExpression as This;
4509 if (mgthis != null){
4510 if (!mgthis.CheckThisUsage (ec))
4516 eclass = ExprClass.Value;
4517 this.method = method;
4521 bool IsSpecialMethodInvocation (MethodBase method)
4523 if (!TypeManager.IsSpecialMethod (method))
4526 Report.SymbolRelatedToPreviousError (method);
4527 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4528 TypeManager.CSharpSignature (method, true));
4534 // Emits the list of arguments as an array
4536 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4538 ILGenerator ig = ec.ig;
4540 for (int j = 0; j < count; j++){
4541 Argument a = (Argument) arguments [j + idx];
4544 IntConstant.EmitInt (ig, count);
4545 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4548 ig.Emit (OpCodes.Dup);
4549 IntConstant.EmitInt (ig, j);
4551 bool is_stobj, has_type_arg;
4552 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4554 ig.Emit (OpCodes.Ldelema, t);
4566 /// Emits a list of resolved Arguments that are in the arguments
4569 /// The MethodBase argument might be null if the
4570 /// emission of the arguments is known not to contain
4571 /// a `params' field (for example in constructors or other routines
4572 /// that keep their arguments in this structure)
4574 /// if `dup_args' is true, a copy of the arguments will be left
4575 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4576 /// which will be duplicated before any other args. Only EmitCall
4577 /// should be using this interface.
4579 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4581 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4583 LocalTemporary [] temps = null;
4585 if (dup_args && top != 0)
4586 temps = new LocalTemporary [top];
4588 int argument_index = 0;
4590 for (int i = 0; i < top; i++){
4592 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4593 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4594 int params_args_count = arguments == null ?
4595 0 : arguments.Count - top + 1;
4597 // Fill not provided argument
4598 if (params_args_count <= 0) {
4599 ILGenerator ig = ec.ig;
4600 IntConstant.EmitInt (ig, 0);
4601 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4606 // Special case if we are passing the same data as the
4607 // params argument, we do not need to recreate an array.
4609 a = (Argument) arguments [argument_index];
4610 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4616 EmitParams (ec, arguments, i, params_args_count);
4617 argument_index += params_args_count;
4622 a = (Argument) arguments [argument_index++];
4625 ec.ig.Emit (OpCodes.Dup);
4626 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4631 if (this_arg != null)
4634 for (int i = 0; i < top; i ++) {
4635 temps [i].Emit (ec);
4636 temps [i].Release (ec);
4641 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4643 ParameterData pd = TypeManager.GetParameterData (mb);
4645 if (arguments == null)
4646 return new Type [0];
4648 Argument a = (Argument) arguments [pd.Count - 1];
4649 Arglist list = (Arglist) a.Expr;
4651 return list.ArgumentTypes;
4655 /// This checks the ConditionalAttribute on the method
4657 static bool IsMethodExcluded (MethodBase method)
4659 if (method.IsConstructor)
4662 IMethodData md = TypeManager.GetMethod (method);
4664 return md.IsExcluded ();
4666 // For some methods (generated by delegate class) GetMethod returns null
4667 // because they are not included in builder_to_method table
4668 if (method.DeclaringType is TypeBuilder)
4671 return AttributeTester.IsConditionalMethodExcluded (method);
4675 /// is_base tells whether we want to force the use of the `call'
4676 /// opcode instead of using callvirt. Call is required to call
4677 /// a specific method, while callvirt will always use the most
4678 /// recent method in the vtable.
4680 /// is_static tells whether this is an invocation on a static method
4682 /// instance_expr is an expression that represents the instance
4683 /// it must be non-null if is_static is false.
4685 /// method is the method to invoke.
4687 /// Arguments is the list of arguments to pass to the method or constructor.
4689 public static void EmitCall (EmitContext ec, bool is_base,
4690 bool is_static, Expression instance_expr,
4691 MethodBase method, ArrayList Arguments, Location loc)
4693 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
4696 // `dup_args' leaves an extra copy of the arguments on the stack
4697 // `omit_args' does not leave any arguments at all.
4698 // So, basically, you could make one call with `dup_args' set to true,
4699 // and then another with `omit_args' set to true, and the two calls
4700 // would have the same set of arguments. However, each argument would
4701 // only have been evaluated once.
4702 public static void EmitCall (EmitContext ec, bool is_base,
4703 bool is_static, Expression instance_expr,
4704 MethodBase method, ArrayList Arguments, Location loc,
4705 bool dup_args, bool omit_args)
4707 ILGenerator ig = ec.ig;
4708 bool struct_call = false;
4709 bool this_call = false;
4710 LocalTemporary this_arg = null;
4712 Type decl_type = method.DeclaringType;
4714 if (!RootContext.StdLib) {
4715 // Replace any calls to the system's System.Array type with calls to
4716 // the newly created one.
4717 if (method == TypeManager.system_int_array_get_length)
4718 method = TypeManager.int_array_get_length;
4719 else if (method == TypeManager.system_int_array_get_rank)
4720 method = TypeManager.int_array_get_rank;
4721 else if (method == TypeManager.system_object_array_clone)
4722 method = TypeManager.object_array_clone;
4723 else if (method == TypeManager.system_int_array_get_length_int)
4724 method = TypeManager.int_array_get_length_int;
4725 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4726 method = TypeManager.int_array_get_lower_bound_int;
4727 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4728 method = TypeManager.int_array_get_upper_bound_int;
4729 else if (method == TypeManager.system_void_array_copyto_array_int)
4730 method = TypeManager.void_array_copyto_array_int;
4733 if (!ec.IsInObsoleteScope) {
4735 // This checks ObsoleteAttribute on the method and on the declaring type
4737 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4739 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4741 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4743 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4747 if (IsMethodExcluded (method))
4751 if (instance_expr == EmptyExpression.Null) {
4752 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4756 this_call = instance_expr is This;
4757 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4761 // If this is ourselves, push "this"
4765 Type iexpr_type = instance_expr.Type;
4768 // Push the instance expression
4770 if (TypeManager.IsValueType (iexpr_type)) {
4772 // Special case: calls to a function declared in a
4773 // reference-type with a value-type argument need
4774 // to have their value boxed.
4775 if (decl_type.IsValueType ||
4776 TypeManager.IsGenericParameter (iexpr_type)) {
4778 // If the expression implements IMemoryLocation, then
4779 // we can optimize and use AddressOf on the
4782 // If not we have to use some temporary storage for
4784 if (instance_expr is IMemoryLocation) {
4785 ((IMemoryLocation)instance_expr).
4786 AddressOf (ec, AddressOp.LoadStore);
4788 LocalTemporary temp = new LocalTemporary (iexpr_type);
4789 instance_expr.Emit (ec);
4791 temp.AddressOf (ec, AddressOp.Load);
4794 // avoid the overhead of doing this all the time.
4796 t = TypeManager.GetReferenceType (iexpr_type);
4798 instance_expr.Emit (ec);
4799 ig.Emit (OpCodes.Box, instance_expr.Type);
4800 t = TypeManager.object_type;
4803 instance_expr.Emit (ec);
4804 t = instance_expr.Type;
4808 ig.Emit (OpCodes.Dup);
4809 if (Arguments != null && Arguments.Count != 0) {
4810 this_arg = new LocalTemporary (t);
4811 this_arg.Store (ec);
4818 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4821 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4822 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4826 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4827 call_op = OpCodes.Call;
4829 call_op = OpCodes.Callvirt;
4831 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4832 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4833 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4840 // and DoFoo is not virtual, you can omit the callvirt,
4841 // because you don't need the null checking behavior.
4843 if (method is MethodInfo)
4844 ig.Emit (call_op, (MethodInfo) method);
4846 ig.Emit (call_op, (ConstructorInfo) method);
4849 public override void Emit (EmitContext ec)
4851 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4853 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4856 public override void EmitStatement (EmitContext ec)
4861 // Pop the return value if there is one
4863 if (method is MethodInfo){
4864 Type ret = ((MethodInfo)method).ReturnType;
4865 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4866 ec.ig.Emit (OpCodes.Pop);
4870 protected override void CloneTo (CloneContext clonectx, Expression t)
4872 Invocation target = (Invocation) t;
4874 if (Arguments != null){
4875 target.Arguments = new ArrayList ();
4876 foreach (Argument a in Arguments)
4877 target.Arguments.Add (a.Clone (clonectx));
4880 expr = expr.Clone (clonectx);
4884 public class InvocationOrCast : ExpressionStatement
4887 Expression argument;
4889 public InvocationOrCast (Expression expr, Expression argument)
4892 this.argument = argument;
4893 this.loc = expr.Location;
4896 public override Expression DoResolve (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 Cast cast = new Cast (te, argument, loc);
4904 return cast.Resolve (ec);
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);
4916 // Ok, so it's a Cast.
4918 if (expr.eclass == ExprClass.Type) {
4919 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4920 return cast.Resolve (ec);
4924 // It's a delegate invocation.
4926 if (!TypeManager.IsDelegateType (expr.Type)) {
4927 Error (149, "Method name expected");
4931 ArrayList args = new ArrayList ();
4932 args.Add (new Argument (argument, Argument.AType.Expression));
4933 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4934 return invocation.Resolve (ec);
4937 public override ExpressionStatement ResolveStatement (EmitContext ec)
4940 // First try to resolve it as a cast.
4942 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4943 if ((te != null) && (te.eclass == ExprClass.Type)) {
4944 Error_InvalidExpressionStatement ();
4949 // This can either be a type or a delegate invocation.
4950 // Let's just resolve it and see what we'll get.
4952 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4953 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4954 Error_InvalidExpressionStatement ();
4959 // It's a delegate invocation.
4961 if (!TypeManager.IsDelegateType (expr.Type)) {
4962 Error (149, "Method name expected");
4966 ArrayList args = new ArrayList ();
4967 args.Add (new Argument (argument, Argument.AType.Expression));
4968 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4969 return invocation.ResolveStatement (ec);
4972 public override void Emit (EmitContext ec)
4974 throw new Exception ("Cannot happen");
4977 public override void EmitStatement (EmitContext ec)
4979 throw new Exception ("Cannot happen");
4982 protected override void CloneTo (CloneContext clonectx, Expression t)
4984 InvocationOrCast target = (InvocationOrCast) t;
4986 target.expr = expr.Clone (clonectx);
4987 target.argument = argument.Clone (clonectx);
4992 // This class is used to "disable" the code generation for the
4993 // temporary variable when initializing value types.
4995 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4996 public void AddressOf (EmitContext ec, AddressOp Mode)
5003 /// Implements the new expression
5005 public class New : ExpressionStatement, IMemoryLocation {
5006 public ArrayList Arguments;
5009 // During bootstrap, it contains the RequestedType,
5010 // but if `type' is not null, it *might* contain a NewDelegate
5011 // (because of field multi-initialization)
5013 public Expression RequestedType;
5015 MethodBase method = null;
5018 // If set, the new expression is for a value_target, and
5019 // we will not leave anything on the stack.
5021 Expression value_target;
5022 bool value_target_set = false;
5023 bool is_type_parameter = false;
5025 public New (Expression requested_type, ArrayList arguments, Location l)
5027 RequestedType = requested_type;
5028 Arguments = arguments;
5032 public bool SetValueTypeVariable (Expression value)
5034 value_target = value;
5035 value_target_set = true;
5036 if (!(value_target is IMemoryLocation)){
5037 Error_UnexpectedKind (null, "variable", loc);
5044 // This function is used to disable the following code sequence for
5045 // value type initialization:
5047 // AddressOf (temporary)
5051 // Instead the provide will have provided us with the address on the
5052 // stack to store the results.
5054 static Expression MyEmptyExpression;
5056 public void DisableTemporaryValueType ()
5058 if (MyEmptyExpression == null)
5059 MyEmptyExpression = new EmptyAddressOf ();
5062 // To enable this, look into:
5063 // test-34 and test-89 and self bootstrapping.
5065 // For instance, we can avoid a copy by using `newobj'
5066 // instead of Call + Push-temp on value types.
5067 // value_target = MyEmptyExpression;
5072 /// Converts complex core type syntax like 'new int ()' to simple constant
5074 public static Constant Constantify (Type t)
5076 if (t == TypeManager.int32_type)
5077 return new IntConstant (0, Location.Null);
5078 if (t == TypeManager.uint32_type)
5079 return new UIntConstant (0, Location.Null);
5080 if (t == TypeManager.int64_type)
5081 return new LongConstant (0, Location.Null);
5082 if (t == TypeManager.uint64_type)
5083 return new ULongConstant (0, Location.Null);
5084 if (t == TypeManager.float_type)
5085 return new FloatConstant (0, Location.Null);
5086 if (t == TypeManager.double_type)
5087 return new DoubleConstant (0, Location.Null);
5088 if (t == TypeManager.short_type)
5089 return new ShortConstant (0, Location.Null);
5090 if (t == TypeManager.ushort_type)
5091 return new UShortConstant (0, Location.Null);
5092 if (t == TypeManager.sbyte_type)
5093 return new SByteConstant (0, Location.Null);
5094 if (t == TypeManager.byte_type)
5095 return new ByteConstant (0, Location.Null);
5096 if (t == TypeManager.char_type)
5097 return new CharConstant ('\0', Location.Null);
5098 if (t == TypeManager.bool_type)
5099 return new BoolConstant (false, Location.Null);
5100 if (t == TypeManager.decimal_type)
5101 return new DecimalConstant (0, Location.Null);
5102 if (TypeManager.IsEnumType (t))
5103 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5109 // Checks whether the type is an interface that has the
5110 // [ComImport, CoClass] attributes and must be treated
5113 public Expression CheckComImport (EmitContext ec)
5115 if (!type.IsInterface)
5119 // Turn the call into:
5120 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5122 Type real_class = AttributeTester.GetCoClassAttribute (type);
5123 if (real_class == null)
5126 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5127 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5128 return cast.Resolve (ec);
5131 public override Expression DoResolve (EmitContext ec)
5134 // The New DoResolve might be called twice when initializing field
5135 // expressions (see EmitFieldInitializers, the call to
5136 // GetInitializerExpression will perform a resolve on the expression,
5137 // and later the assign will trigger another resolution
5139 // This leads to bugs (#37014)
5142 if (RequestedType is NewDelegate)
5143 return RequestedType;
5147 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5153 if (type == TypeManager.void_type) {
5154 Error_VoidInvalidInTheContext (loc);
5158 if (Arguments == null) {
5159 Expression c = Constantify (type);
5164 if (TypeManager.IsDelegateType (type)) {
5165 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5166 if (RequestedType != null)
5167 if (!(RequestedType is DelegateCreation))
5168 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5169 return RequestedType;
5173 if (type.IsGenericParameter) {
5174 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5176 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5177 Error (304, String.Format (
5178 "Cannot create an instance of the " +
5179 "variable type '{0}' because it " +
5180 "doesn't have the new() constraint",
5185 if ((Arguments != null) && (Arguments.Count != 0)) {
5186 Error (417, String.Format (
5187 "`{0}': cannot provide arguments " +
5188 "when creating an instance of a " +
5189 "variable type.", type));
5193 is_type_parameter = true;
5194 eclass = ExprClass.Value;
5199 if (type.IsAbstract && type.IsSealed) {
5200 Report.SymbolRelatedToPreviousError (type);
5201 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5205 if (type.IsInterface || type.IsAbstract){
5206 if (!TypeManager.IsGenericType (type)) {
5207 RequestedType = CheckComImport (ec);
5208 if (RequestedType != null)
5209 return RequestedType;
5212 Report.SymbolRelatedToPreviousError (type);
5213 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5217 bool is_struct = type.IsValueType;
5218 eclass = ExprClass.Value;
5221 // SRE returns a match for .ctor () on structs (the object constructor),
5222 // so we have to manually ignore it.
5224 if (is_struct && Arguments == null)
5227 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5228 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5229 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5234 MethodGroupExpr mg = ml as MethodGroupExpr;
5237 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5241 if (Arguments != null){
5242 foreach (Argument a in Arguments){
5243 if (!a.Resolve (ec, loc))
5248 method = mg.OverloadResolve (ec, Arguments, false, loc);
5249 if (method == null) {
5250 if (almostMatchedMembers.Count != 0)
5251 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5258 bool DoEmitTypeParameter (EmitContext ec)
5261 ILGenerator ig = ec.ig;
5264 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5265 new Type [] { type });
5267 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5268 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5269 ig.Emit (OpCodes.Call, ci);
5273 // Allow DoEmit() to be called multiple times.
5274 // We need to create a new LocalTemporary each time since
5275 // you can't share LocalBuilders among ILGeneators.
5276 LocalTemporary temp = new LocalTemporary (type);
5278 Label label_activator = ig.DefineLabel ();
5279 Label label_end = ig.DefineLabel ();
5281 temp.AddressOf (ec, AddressOp.Store);
5282 ig.Emit (OpCodes.Initobj, type);
5285 ig.Emit (OpCodes.Box, type);
5286 ig.Emit (OpCodes.Brfalse, label_activator);
5288 temp.AddressOf (ec, AddressOp.Store);
5289 ig.Emit (OpCodes.Initobj, type);
5291 ig.Emit (OpCodes.Br, label_end);
5293 ig.MarkLabel (label_activator);
5295 ig.Emit (OpCodes.Call, ci);
5296 ig.MarkLabel (label_end);
5299 throw new InternalErrorException ();
5304 // This DoEmit can be invoked in two contexts:
5305 // * As a mechanism that will leave a value on the stack (new object)
5306 // * As one that wont (init struct)
5308 // You can control whether a value is required on the stack by passing
5309 // need_value_on_stack. The code *might* leave a value on the stack
5310 // so it must be popped manually
5312 // If we are dealing with a ValueType, we have a few
5313 // situations to deal with:
5315 // * The target is a ValueType, and we have been provided
5316 // the instance (this is easy, we are being assigned).
5318 // * The target of New is being passed as an argument,
5319 // to a boxing operation or a function that takes a
5322 // In this case, we need to create a temporary variable
5323 // that is the argument of New.
5325 // Returns whether a value is left on the stack
5327 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5329 bool is_value_type = TypeManager.IsValueType (type);
5330 ILGenerator ig = ec.ig;
5335 // Allow DoEmit() to be called multiple times.
5336 // We need to create a new LocalTemporary each time since
5337 // you can't share LocalBuilders among ILGeneators.
5338 if (!value_target_set)
5339 value_target = new LocalTemporary (type);
5341 ml = (IMemoryLocation) value_target;
5342 ml.AddressOf (ec, AddressOp.Store);
5346 Invocation.EmitArguments (ec, method, Arguments, false, null);
5350 ig.Emit (OpCodes.Initobj, type);
5352 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5353 if (need_value_on_stack){
5354 value_target.Emit (ec);
5359 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5364 public override void Emit (EmitContext ec)
5366 if (is_type_parameter)
5367 DoEmitTypeParameter (ec);
5372 public override void EmitStatement (EmitContext ec)
5374 bool value_on_stack;
5376 if (is_type_parameter)
5377 value_on_stack = DoEmitTypeParameter (ec);
5379 value_on_stack = DoEmit (ec, false);
5382 ec.ig.Emit (OpCodes.Pop);
5386 public void AddressOf (EmitContext ec, AddressOp Mode)
5388 if (is_type_parameter) {
5389 LocalTemporary temp = new LocalTemporary (type);
5390 DoEmitTypeParameter (ec);
5392 temp.AddressOf (ec, Mode);
5396 if (!type.IsValueType){
5398 // We throw an exception. So far, I believe we only need to support
5400 // foreach (int j in new StructType ())
5403 throw new Exception ("AddressOf should not be used for classes");
5406 if (!value_target_set)
5407 value_target = new LocalTemporary (type);
5408 IMemoryLocation ml = (IMemoryLocation) value_target;
5410 ml.AddressOf (ec, AddressOp.Store);
5412 Invocation.EmitArguments (ec, method, Arguments, false, null);
5415 ec.ig.Emit (OpCodes.Initobj, type);
5417 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5419 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5422 protected override void CloneTo (CloneContext clonectx, Expression t)
5424 New target = (New) t;
5426 target.RequestedType = RequestedType.Clone (clonectx);
5427 if (Arguments != null){
5428 target.Arguments = new ArrayList ();
5429 foreach (Argument a in Arguments){
5430 target.Arguments.Add (a.Clone (clonectx));
5437 /// 14.5.10.2: Represents an array creation expression.
5441 /// There are two possible scenarios here: one is an array creation
5442 /// expression that specifies the dimensions and optionally the
5443 /// initialization data and the other which does not need dimensions
5444 /// specified but where initialization data is mandatory.
5446 public class ArrayCreation : Expression {
5447 Expression requested_base_type;
5448 ArrayList initializers;
5451 // The list of Argument types.
5452 // This is used to construct the `newarray' or constructor signature
5454 ArrayList arguments;
5457 // Method used to create the array object.
5459 MethodBase new_method = null;
5461 Type array_element_type;
5462 Type underlying_type;
5463 bool is_one_dimensional = false;
5464 bool is_builtin_type = false;
5465 bool expect_initializers = false;
5466 int num_arguments = 0;
5470 ArrayList array_data;
5474 // The number of constants in array initializers
5475 int const_initializers_count;
5476 bool only_constant_initializers;
5478 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5480 this.requested_base_type = requested_base_type;
5481 this.initializers = initializers;
5485 arguments = new ArrayList ();
5487 foreach (Expression e in exprs) {
5488 arguments.Add (new Argument (e, Argument.AType.Expression));
5493 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5495 this.requested_base_type = requested_base_type;
5496 this.initializers = initializers;
5500 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5502 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5504 //dimensions = tmp.Length - 1;
5505 expect_initializers = true;
5508 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5510 StringBuilder sb = new StringBuilder (rank);
5513 for (int i = 1; i < idx_count; i++)
5518 return new ComposedCast (base_type, sb.ToString (), loc);
5521 void Error_IncorrectArrayInitializer ()
5523 Error (178, "Invalid rank specifier: expected `,' or `]'");
5526 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5528 if (specified_dims) {
5529 Argument a = (Argument) arguments [idx];
5531 if (!a.Resolve (ec, loc))
5534 Constant c = a.Expr as Constant;
5536 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5540 Report.Error (150, a.Expr.Location, "A constant value is expected");
5544 int value = (int) c.GetValue ();
5546 if (value != probe.Count) {
5547 Error_IncorrectArrayInitializer ();
5551 bounds [idx] = value;
5554 int child_bounds = -1;
5555 only_constant_initializers = true;
5556 for (int i = 0; i < probe.Count; ++i) {
5557 object o = probe [i];
5558 if (o is ArrayList) {
5559 ArrayList sub_probe = o as ArrayList;
5560 int current_bounds = sub_probe.Count;
5562 if (child_bounds == -1)
5563 child_bounds = current_bounds;
5565 else if (child_bounds != current_bounds){
5566 Error_IncorrectArrayInitializer ();
5569 if (idx + 1 >= dimensions){
5570 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5574 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5578 if (child_bounds != -1){
5579 Error_IncorrectArrayInitializer ();
5583 Expression tmp = (Expression) o;
5584 tmp = tmp.Resolve (ec);
5588 Expression conv = Convert.ImplicitConversionRequired (
5589 ec, tmp, underlying_type, loc);
5594 // Initializers with the default values can be ignored
5595 Constant c = conv as Constant;
5597 if (c.IsDefaultInitializer (array_element_type)) {
5601 ++const_initializers_count;
5604 only_constant_initializers = false;
5607 array_data.Add (conv);
5614 public void UpdateIndices ()
5617 for (ArrayList probe = initializers; probe != null;) {
5618 if (probe.Count > 0 && probe [0] is ArrayList) {
5619 Expression e = new IntConstant (probe.Count, Location.Null);
5620 arguments.Add (new Argument (e, Argument.AType.Expression));
5622 bounds [i++] = probe.Count;
5624 probe = (ArrayList) probe [0];
5627 Expression e = new IntConstant (probe.Count, Location.Null);
5628 arguments.Add (new Argument (e, Argument.AType.Expression));
5630 bounds [i++] = probe.Count;
5637 bool ResolveInitializers (EmitContext ec)
5639 if (initializers == null) {
5640 return !expect_initializers;
5643 if (underlying_type == null)
5647 // We use this to store all the date values in the order in which we
5648 // will need to store them in the byte blob later
5650 array_data = new ArrayList ();
5651 bounds = new System.Collections.Specialized.HybridDictionary ();
5653 if (arguments != null)
5654 return CheckIndices (ec, initializers, 0, true);
5656 arguments = new ArrayList ();
5658 if (!CheckIndices (ec, initializers, 0, false))
5663 if (arguments.Count != dimensions) {
5664 Error_IncorrectArrayInitializer ();
5672 // Creates the type of the array
5674 bool LookupType (EmitContext ec)
5676 StringBuilder array_qualifier = new StringBuilder (rank);
5679 // `In the first form allocates an array instace of the type that results
5680 // from deleting each of the individual expression from the expression list'
5682 if (num_arguments > 0) {
5683 array_qualifier.Append ("[");
5684 for (int i = num_arguments-1; i > 0; i--)
5685 array_qualifier.Append (",");
5686 array_qualifier.Append ("]");
5692 TypeExpr array_type_expr;
5693 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5694 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5695 if (array_type_expr == null)
5698 type = array_type_expr.Type;
5699 underlying_type = TypeManager.GetElementType (type);
5700 dimensions = type.GetArrayRank ();
5705 public override Expression DoResolve (EmitContext ec)
5710 if (requested_base_type is VarExpr) {
5711 if (initializers == null || initializers.Count == 0) {
5712 Console.WriteLine ("Initializers required"); // FIXME proper error
5715 Expression e = ((Expression)initializers[0]).Resolve (ec);
5717 return null; // FIXME proper error
5718 requested_base_type = new TypeExpression (e.Type, loc);
5721 if (!LookupType (ec))
5724 array_element_type = TypeManager.GetElementType (type);
5725 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
5726 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
5731 // First step is to validate the initializers and fill
5732 // in any missing bits
5734 if (!ResolveInitializers (ec))
5738 if (arguments == null)
5741 arg_count = arguments.Count;
5742 foreach (Argument a in arguments){
5743 if (!a.Resolve (ec, loc))
5746 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5747 if (real_arg == null)
5754 if (arg_count == 1) {
5755 is_one_dimensional = true;
5756 eclass = ExprClass.Value;
5760 is_builtin_type = TypeManager.IsBuiltinType (type);
5762 if (is_builtin_type) {
5765 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
5766 AllBindingFlags, loc);
5768 if (!(ml is MethodGroupExpr)) {
5769 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5774 Error (-6, "New invocation: Can not find a constructor for " +
5775 "this argument list");
5779 new_method = ((MethodGroupExpr) ml).OverloadResolve (
5780 ec, arguments, false, loc);
5782 if (new_method == null) {
5783 Error (-6, "New invocation: Can not find a constructor for " +
5784 "this argument list");
5788 eclass = ExprClass.Value;
5791 ModuleBuilder mb = CodeGen.Module.Builder;
5792 ArrayList args = new ArrayList ();
5794 if (arguments != null) {
5795 for (int i = 0; i < arg_count; i++)
5796 args.Add (TypeManager.int32_type);
5799 Type [] arg_types = null;
5802 arg_types = new Type [args.Count];
5804 args.CopyTo (arg_types, 0);
5806 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5809 if (new_method == null) {
5810 Error (-6, "New invocation: Can not find a constructor for " +
5811 "this argument list");
5815 eclass = ExprClass.Value;
5820 byte [] MakeByteBlob ()
5825 int count = array_data.Count;
5827 if (underlying_type.IsEnum)
5828 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5830 factor = GetTypeSize (underlying_type);
5832 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5834 data = new byte [(count * factor + 4) & ~3];
5837 for (int i = 0; i < count; ++i) {
5838 object v = array_data [i];
5840 if (v is EnumConstant)
5841 v = ((EnumConstant) v).Child;
5843 if (v is Constant && !(v is StringConstant))
5844 v = ((Constant) v).GetValue ();
5850 if (underlying_type == TypeManager.int64_type){
5851 if (!(v is Expression)){
5852 long val = (long) v;
5854 for (int j = 0; j < factor; ++j) {
5855 data [idx + j] = (byte) (val & 0xFF);
5859 } else if (underlying_type == TypeManager.uint64_type){
5860 if (!(v is Expression)){
5861 ulong val = (ulong) v;
5863 for (int j = 0; j < factor; ++j) {
5864 data [idx + j] = (byte) (val & 0xFF);
5868 } else if (underlying_type == TypeManager.float_type) {
5869 if (!(v is Expression)){
5870 element = BitConverter.GetBytes ((float) v);
5872 for (int j = 0; j < factor; ++j)
5873 data [idx + j] = element [j];
5874 if (!BitConverter.IsLittleEndian)
5875 System.Array.Reverse (data, idx, 4);
5877 } else if (underlying_type == TypeManager.double_type) {
5878 if (!(v is Expression)){
5879 element = BitConverter.GetBytes ((double) v);
5881 for (int j = 0; j < factor; ++j)
5882 data [idx + j] = element [j];
5884 // FIXME: Handle the ARM float format.
5885 if (!BitConverter.IsLittleEndian)
5886 System.Array.Reverse (data, idx, 8);
5888 } else if (underlying_type == TypeManager.char_type){
5889 if (!(v is Expression)){
5890 int val = (int) ((char) v);
5892 data [idx] = (byte) (val & 0xff);
5893 data [idx+1] = (byte) (val >> 8);
5895 } else if (underlying_type == TypeManager.short_type){
5896 if (!(v is Expression)){
5897 int val = (int) ((short) v);
5899 data [idx] = (byte) (val & 0xff);
5900 data [idx+1] = (byte) (val >> 8);
5902 } else if (underlying_type == TypeManager.ushort_type){
5903 if (!(v is Expression)){
5904 int val = (int) ((ushort) v);
5906 data [idx] = (byte) (val & 0xff);
5907 data [idx+1] = (byte) (val >> 8);
5909 } else if (underlying_type == TypeManager.int32_type) {
5910 if (!(v is Expression)){
5913 data [idx] = (byte) (val & 0xff);
5914 data [idx+1] = (byte) ((val >> 8) & 0xff);
5915 data [idx+2] = (byte) ((val >> 16) & 0xff);
5916 data [idx+3] = (byte) (val >> 24);
5918 } else if (underlying_type == TypeManager.uint32_type) {
5919 if (!(v is Expression)){
5920 uint val = (uint) v;
5922 data [idx] = (byte) (val & 0xff);
5923 data [idx+1] = (byte) ((val >> 8) & 0xff);
5924 data [idx+2] = (byte) ((val >> 16) & 0xff);
5925 data [idx+3] = (byte) (val >> 24);
5927 } else if (underlying_type == TypeManager.sbyte_type) {
5928 if (!(v is Expression)){
5929 sbyte val = (sbyte) v;
5930 data [idx] = (byte) val;
5932 } else if (underlying_type == TypeManager.byte_type) {
5933 if (!(v is Expression)){
5934 byte val = (byte) v;
5935 data [idx] = (byte) val;
5937 } else if (underlying_type == TypeManager.bool_type) {
5938 if (!(v is Expression)){
5939 bool val = (bool) v;
5940 data [idx] = (byte) (val ? 1 : 0);
5942 } else if (underlying_type == TypeManager.decimal_type){
5943 if (!(v is Expression)){
5944 int [] bits = Decimal.GetBits ((decimal) v);
5947 // FIXME: For some reason, this doesn't work on the MS runtime.
5948 int [] nbits = new int [4];
5949 nbits [0] = bits [3];
5950 nbits [1] = bits [2];
5951 nbits [2] = bits [0];
5952 nbits [3] = bits [1];
5954 for (int j = 0; j < 4; j++){
5955 data [p++] = (byte) (nbits [j] & 0xff);
5956 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5957 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5958 data [p++] = (byte) (nbits [j] >> 24);
5962 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5971 // Emits the initializers for the array
5973 void EmitStaticInitializers (EmitContext ec)
5976 // First, the static data
5979 ILGenerator ig = ec.ig;
5981 byte [] data = MakeByteBlob ();
5983 fb = RootContext.MakeStaticData (data);
5985 ig.Emit (OpCodes.Dup);
5986 ig.Emit (OpCodes.Ldtoken, fb);
5987 ig.Emit (OpCodes.Call,
5988 TypeManager.void_initializearray_array_fieldhandle);
5992 // Emits pieces of the array that can not be computed at compile
5993 // time (variables and string locations).
5995 // This always expect the top value on the stack to be the array
5997 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5999 ILGenerator ig = ec.ig;
6000 int dims = bounds.Count;
6001 int [] current_pos = new int [dims];
6003 MethodInfo set = null;
6006 Type [] args = new Type [dims + 1];
6008 for (int j = 0; j < dims; j++)
6009 args [j] = TypeManager.int32_type;
6010 args [dims] = array_element_type;
6012 set = CodeGen.Module.Builder.GetArrayMethod (
6014 CallingConventions.HasThis | CallingConventions.Standard,
6015 TypeManager.void_type, args);
6018 for (int i = 0; i < array_data.Count; i++){
6020 Expression e = (Expression)array_data [i];
6022 // Constant can be initialized via StaticInitializer
6023 if (e != null && !(!emitConstants && e is Constant)) {
6024 Type etype = e.Type;
6026 ig.Emit (OpCodes.Dup);
6028 for (int idx = 0; idx < dims; idx++)
6029 IntConstant.EmitInt (ig, current_pos [idx]);
6032 // If we are dealing with a struct, get the
6033 // address of it, so we can store it.
6035 if ((dims == 1) && etype.IsValueType &&
6036 (!TypeManager.IsBuiltinOrEnum (etype) ||
6037 etype == TypeManager.decimal_type)) {
6042 // Let new know that we are providing
6043 // the address where to store the results
6045 n.DisableTemporaryValueType ();
6048 ig.Emit (OpCodes.Ldelema, etype);
6054 bool is_stobj, has_type_arg;
6055 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6057 ig.Emit (OpCodes.Stobj, etype);
6058 else if (has_type_arg)
6059 ig.Emit (op, etype);
6063 ig.Emit (OpCodes.Call, set);
6070 for (int j = dims - 1; j >= 0; j--){
6072 if (current_pos [j] < (int) bounds [j])
6074 current_pos [j] = 0;
6079 void EmitArrayArguments (EmitContext ec)
6081 ILGenerator ig = ec.ig;
6083 foreach (Argument a in arguments) {
6084 Type atype = a.Type;
6087 if (atype == TypeManager.uint64_type)
6088 ig.Emit (OpCodes.Conv_Ovf_U4);
6089 else if (atype == TypeManager.int64_type)
6090 ig.Emit (OpCodes.Conv_Ovf_I4);
6094 public override void Emit (EmitContext ec)
6096 ILGenerator ig = ec.ig;
6098 EmitArrayArguments (ec);
6099 if (is_one_dimensional)
6100 ig.Emit (OpCodes.Newarr, array_element_type);
6102 if (is_builtin_type)
6103 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6105 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6108 if (initializers == null)
6111 // Emit static initializer for arrays which have contain more than 4 items and
6112 // the static initializer will initialize at least 25% of array values.
6113 // NOTE: const_initializers_count does not contain default constant values.
6114 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6115 TypeManager.IsPrimitiveType (array_element_type)) {
6116 EmitStaticInitializers (ec);
6118 if (!only_constant_initializers)
6119 EmitDynamicInitializers (ec, false);
6121 EmitDynamicInitializers (ec, true);
6125 public override bool GetAttributableValue (Type valueType, out object value)
6127 if (!is_one_dimensional){
6128 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6129 return base.GetAttributableValue (null, out value);
6132 if (array_data == null) {
6133 Constant c = (Constant)((Argument)arguments [0]).Expr;
6134 if (c.IsDefaultValue) {
6135 value = Array.CreateInstance (array_element_type, 0);
6138 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6139 return base.GetAttributableValue (null, out value);
6142 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6143 object element_value;
6144 for (int i = 0; i < ret.Length; ++i)
6146 Expression e = (Expression)array_data [i];
6148 // Is null when an initializer is optimized (value == predefined value)
6152 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6156 ret.SetValue (element_value, i);
6162 protected override void CloneTo (CloneContext clonectx, Expression t)
6164 ArrayCreation target = (ArrayCreation) t;
6166 target.requested_base_type = requested_base_type.Clone (clonectx);
6167 target.arguments = new ArrayList ();
6168 foreach (Argument a in arguments)
6169 target.arguments.Add (a.Clone (clonectx));
6171 if (initializers != null){
6172 target.initializers = new ArrayList ();
6173 foreach (Expression initializer in initializers)
6174 target.initializers.Add (initializer.Clone (clonectx));
6179 public sealed class CompilerGeneratedThis : This
6181 public static This Instance = new CompilerGeneratedThis ();
6183 private CompilerGeneratedThis ()
6184 : base (Location.Null)
6188 public override Expression DoResolve (EmitContext ec)
6190 eclass = ExprClass.Variable;
6191 type = ec.ContainerType;
6192 variable = new SimpleThis (type);
6198 /// Represents the `this' construct
6201 public class This : VariableReference, IVariable
6204 VariableInfo variable_info;
6205 protected Variable variable;
6208 public This (Block block, Location loc)
6214 public This (Location loc)
6219 public VariableInfo VariableInfo {
6220 get { return variable_info; }
6223 public bool VerifyFixed ()
6225 return !TypeManager.IsValueType (Type);
6228 public override bool IsRef {
6229 get { return is_struct; }
6232 public override Variable Variable {
6233 get { return variable; }
6236 public bool ResolveBase (EmitContext ec)
6238 eclass = ExprClass.Variable;
6240 if (ec.TypeContainer.CurrentType != null)
6241 type = ec.TypeContainer.CurrentType;
6243 type = ec.ContainerType;
6245 is_struct = ec.TypeContainer is Struct;
6248 Error (26, "Keyword `this' is not valid in a static property, " +
6249 "static method, or static field initializer");
6253 if (block != null) {
6254 if (block.Toplevel.ThisVariable != null)
6255 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6257 AnonymousContainer am = ec.CurrentAnonymousMethod;
6258 if (is_struct && (am != null) && !am.IsIterator) {
6259 Report.Error (1673, loc, "Anonymous methods inside structs " +
6260 "cannot access instance members of `this'. " +
6261 "Consider copying `this' to a local variable " +
6262 "outside the anonymous method and using the " +
6267 RootScopeInfo host = block.Toplevel.RootScope;
6268 if ((host != null) && !ec.IsConstructor &&
6269 (!is_struct || host.IsIterator)) {
6270 variable = host.CaptureThis ();
6271 type = variable.Type;
6276 if (variable == null)
6277 variable = new SimpleThis (type);
6283 // Called from Invocation to check if the invocation is correct
6285 public bool CheckThisUsage (EmitContext ec)
6287 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6288 !variable_info.IsAssigned (ec)) {
6289 Error (188, "The `this' object cannot be used before all of its " +
6290 "fields are assigned to");
6291 variable_info.SetAssigned (ec);
6298 public override Expression DoResolve (EmitContext ec)
6300 if (!ResolveBase (ec))
6304 if (ec.IsFieldInitializer) {
6305 Error (27, "Keyword `this' is not available in the current context");
6312 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6314 if (!ResolveBase (ec))
6317 if (variable_info != null)
6318 variable_info.SetAssigned (ec);
6320 if (ec.TypeContainer is Class){
6321 Error (1604, "Cannot assign to 'this' because it is read-only");
6327 public override int GetHashCode()
6329 return block.GetHashCode ();
6332 public override bool Equals (object obj)
6334 This t = obj as This;
6338 return block == t.block;
6341 protected class SimpleThis : Variable
6345 public SimpleThis (Type type)
6350 public override Type Type {
6351 get { return type; }
6354 public override bool HasInstance {
6355 get { return false; }
6358 public override bool NeedsTemporary {
6359 get { return false; }
6362 public override void EmitInstance (EmitContext ec)
6367 public override void Emit (EmitContext ec)
6369 ec.ig.Emit (OpCodes.Ldarg_0);
6372 public override void EmitAssign (EmitContext ec)
6374 throw new InvalidOperationException ();
6377 public override void EmitAddressOf (EmitContext ec)
6379 ec.ig.Emit (OpCodes.Ldarg_0);
6383 protected override void CloneTo (CloneContext clonectx, Expression t)
6385 This target = (This) t;
6387 target.block = clonectx.LookupBlock (block);
6392 /// Represents the `__arglist' construct
6394 public class ArglistAccess : Expression
6396 public ArglistAccess (Location loc)
6401 public override Expression DoResolve (EmitContext ec)
6403 eclass = ExprClass.Variable;
6404 type = TypeManager.runtime_argument_handle_type;
6406 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6408 Error (190, "The __arglist construct is valid only within " +
6409 "a variable argument method");
6416 public override void Emit (EmitContext ec)
6418 ec.ig.Emit (OpCodes.Arglist);
6421 protected override void CloneTo (CloneContext clonectx, Expression target)
6428 /// Represents the `__arglist (....)' construct
6430 public class Arglist : Expression
6432 public Argument[] Arguments;
6434 public Arglist (Location loc)
6435 : this (Argument.Empty, loc)
6439 public Arglist (Argument[] args, Location l)
6445 public Type[] ArgumentTypes {
6447 Type[] retval = new Type [Arguments.Length];
6448 for (int i = 0; i < Arguments.Length; i++)
6449 retval [i] = Arguments [i].Type;
6454 public override Expression DoResolve (EmitContext ec)
6456 eclass = ExprClass.Variable;
6457 type = TypeManager.runtime_argument_handle_type;
6459 foreach (Argument arg in Arguments) {
6460 if (!arg.Resolve (ec, loc))
6467 public override void Emit (EmitContext ec)
6469 foreach (Argument arg in Arguments)
6473 protected override void CloneTo (CloneContext clonectx, Expression t)
6475 Arglist target = (Arglist) t;
6477 target.Arguments = new Argument [Arguments.Length];
6478 for (int i = 0; i < Arguments.Length; i++)
6479 target.Arguments [i] = Arguments [i].Clone (clonectx);
6484 // This produces the value that renders an instance, used by the iterators code
6486 public class ProxyInstance : Expression, IMemoryLocation {
6487 public override Expression DoResolve (EmitContext ec)
6489 eclass = ExprClass.Variable;
6490 type = ec.ContainerType;
6494 public override void Emit (EmitContext ec)
6496 ec.ig.Emit (OpCodes.Ldarg_0);
6500 public void AddressOf (EmitContext ec, AddressOp mode)
6502 ec.ig.Emit (OpCodes.Ldarg_0);
6507 /// Implements the typeof operator
6509 public class TypeOf : Expression {
6510 Expression QueriedType;
6511 protected Type typearg;
6513 public TypeOf (Expression queried_type, Location l)
6515 QueriedType = queried_type;
6519 public override Expression DoResolve (EmitContext ec)
6521 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6525 typearg = texpr.Type;
6527 if (typearg == TypeManager.void_type) {
6528 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6532 if (typearg.IsPointer && !ec.InUnsafe){
6537 type = TypeManager.type_type;
6538 // Even though what is returned is a type object, it's treated as a value by the compiler.
6539 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6540 eclass = ExprClass.Value;
6544 public override void Emit (EmitContext ec)
6546 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6547 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6550 public override bool GetAttributableValue (Type valueType, out object value)
6552 if (TypeManager.ContainsGenericParameters (typearg)) {
6553 Report.SymbolRelatedToPreviousError(typearg);
6554 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6555 TypeManager.CSharpName(typearg));
6560 if (valueType == TypeManager.object_type) {
6561 value = (object)typearg;
6568 public Type TypeArgument
6576 protected override void CloneTo (CloneContext clonectx, Expression t)
6578 TypeOf target = (TypeOf) t;
6580 target.QueriedType = QueriedType.Clone (clonectx);
6585 /// Implements the `typeof (void)' operator
6587 public class TypeOfVoid : TypeOf {
6588 public TypeOfVoid (Location l) : base (null, l)
6593 public override Expression DoResolve (EmitContext ec)
6595 type = TypeManager.type_type;
6596 typearg = TypeManager.void_type;
6597 // See description in TypeOf.
6598 eclass = ExprClass.Value;
6604 /// Implements the sizeof expression
6606 public class SizeOf : Expression {
6607 public Expression QueriedType;
6610 public SizeOf (Expression queried_type, Location l)
6612 this.QueriedType = queried_type;
6616 public override Expression DoResolve (EmitContext ec)
6618 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6623 if (texpr is TypeParameterExpr){
6624 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6629 type_queried = texpr.Type;
6630 if (type_queried.IsEnum)
6631 type_queried = TypeManager.EnumToUnderlying (type_queried);
6633 if (type_queried == TypeManager.void_type) {
6634 Expression.Error_VoidInvalidInTheContext (loc);
6638 int size_of = GetTypeSize (type_queried);
6640 return new IntConstant (size_of, loc);
6644 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)",
6645 TypeManager.CSharpName (type_queried));
6649 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6653 type = TypeManager.int32_type;
6654 eclass = ExprClass.Value;
6658 public override void Emit (EmitContext ec)
6660 int size = GetTypeSize (type_queried);
6663 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6665 IntConstant.EmitInt (ec.ig, size);
6668 protected override void CloneTo (CloneContext clonectx, Expression t)
6670 SizeOf target = (SizeOf) t;
6672 target.QueriedType = QueriedType.Clone (clonectx);
6677 /// Implements the qualified-alias-member (::) expression.
6679 public class QualifiedAliasMember : Expression
6681 string alias, identifier;
6683 public QualifiedAliasMember (string alias, string identifier, Location l)
6686 this.identifier = identifier;
6690 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6692 if (alias == "global")
6693 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6695 int errors = Report.Errors;
6696 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6698 if (errors == Report.Errors)
6699 Report.Error (432, loc, "Alias `{0}' not found", alias);
6702 if (fne.eclass != ExprClass.Namespace) {
6704 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6707 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6710 public override Expression DoResolve (EmitContext ec)
6712 FullNamedExpression fne;
6713 if (alias == "global") {
6714 fne = RootNamespace.Global;
6716 int errors = Report.Errors;
6717 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6719 if (errors == Report.Errors)
6720 Report.Error (432, loc, "Alias `{0}' not found", alias);
6725 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6729 if (!(retval is FullNamedExpression)) {
6730 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6734 // We defer this check till the end to match the behaviour of CSC
6735 if (fne.eclass != ExprClass.Namespace) {
6736 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6742 public override void Emit (EmitContext ec)
6744 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6748 public override string ToString ()
6750 return alias + "::" + identifier;
6753 public override string GetSignatureForError ()
6758 protected override void CloneTo (CloneContext clonectx, Expression t)
6765 /// Implements the member access expression
6767 public class MemberAccess : Expression {
6768 public readonly string Identifier;
6771 public MemberAccess (Expression expr, string id)
6772 : this (expr, id, expr.Location)
6776 public MemberAccess (Expression expr, string identifier, Location loc)
6779 Identifier = identifier;
6783 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6784 : this (expr, identifier, loc)
6791 public Expression Expr {
6792 get { return expr; }
6795 protected string LookupIdentifier {
6796 get { return MemberName.MakeName (Identifier, args); }
6799 // TODO: this method has very poor performace for Enum fields and
6800 // probably for other constants as well
6801 Expression DoResolve (EmitContext ec, Expression right_side)
6804 throw new Exception ();
6807 // Resolve the expression with flow analysis turned off, we'll do the definite
6808 // assignment checks later. This is because we don't know yet what the expression
6809 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6810 // definite assignment check on the actual field and not on the whole struct.
6813 SimpleName original = expr as SimpleName;
6814 expr = expr.Resolve (ec,
6815 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6816 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6821 if (expr is Namespace) {
6822 Namespace ns = (Namespace) expr;
6823 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6825 if ((retval != null) && (args != null))
6826 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6830 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6834 Type expr_type = expr.Type;
6835 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr is NullLiteral){
6836 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6839 if (expr_type == TypeManager.anonymous_method_type){
6840 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6844 Constant c = expr as Constant;
6845 if (c != null && c.GetValue () == null) {
6846 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6847 "System.NullReferenceException");
6850 Expression member_lookup;
6851 member_lookup = MemberLookup (
6852 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6854 if ((member_lookup == null) && (args != null)) {
6855 member_lookup = MemberLookup (
6856 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6859 if (member_lookup == null) {
6860 member_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6861 if (member_lookup != null)
6862 return member_lookup.DoResolve (ec);
6864 MemberLookupFailed (
6865 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6869 TypeExpr texpr = member_lookup as TypeExpr;
6870 if (texpr != null) {
6871 if (!(expr is TypeExpr) &&
6872 (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) {
6873 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6874 Identifier, member_lookup.GetSignatureForError ());
6878 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6879 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6880 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6885 ConstructedType ct = expr as ConstructedType;
6888 // When looking up a nested type in a generic instance
6889 // via reflection, we always get a generic type definition
6890 // and not a generic instance - so we have to do this here.
6892 // See gtest-172-lib.cs and gtest-172.cs for an example.
6894 ct = new ConstructedType (
6895 member_lookup.Type, ct.TypeArguments, loc);
6897 return ct.ResolveAsTypeStep (ec, false);
6900 return member_lookup;
6903 MemberExpr me = (MemberExpr) member_lookup;
6904 member_lookup = me.ResolveMemberAccess (ec, expr, loc, original);
6905 if (member_lookup == null)
6909 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6911 throw new InternalErrorException ();
6913 return mg.ResolveGeneric (ec, args);
6916 if (original != null && !TypeManager.IsValueType (expr_type)) {
6917 me = member_lookup as MemberExpr;
6918 if (me != null && me.IsInstance) {
6919 LocalVariableReference var = expr as LocalVariableReference;
6920 if (var != null && !var.VerifyAssigned (ec))
6925 // The following DoResolve/DoResolveLValue will do the definite assignment
6928 if (right_side != null)
6929 return member_lookup.DoResolveLValue (ec, right_side);
6931 return member_lookup.DoResolve (ec);
6934 public override Expression DoResolve (EmitContext ec)
6936 return DoResolve (ec, null);
6939 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6941 return DoResolve (ec, right_side);
6944 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6946 return ResolveNamespaceOrType (ec, silent);
6949 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6951 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6953 if (new_expr == null)
6956 if (new_expr is Namespace) {
6957 Namespace ns = (Namespace) new_expr;
6958 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6960 if ((retval != null) && (args != null))
6961 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6963 if (!silent && retval == null)
6964 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6968 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6969 if (tnew_expr == null)
6972 Type expr_type = tnew_expr.Type;
6974 if (expr_type.IsPointer){
6975 Error (23, "The `.' operator can not be applied to pointer operands (" +
6976 TypeManager.CSharpName (expr_type) + ")");
6980 Expression member_lookup = MemberLookup (
6981 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6982 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6983 if (member_lookup == null) {
6987 member_lookup = MemberLookup(
6988 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6989 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6991 if (member_lookup == null) {
6992 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6993 Identifier, new_expr.GetSignatureForError ());
6995 // TODO: Report.SymbolRelatedToPreviousError
6996 member_lookup.Error_UnexpectedKind (null, "type", loc);
7001 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7006 TypeArguments the_args = args;
7007 if (TypeManager.HasGenericArguments (expr_type)) {
7008 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7010 TypeArguments new_args = new TypeArguments (loc);
7011 foreach (Type decl in decl_args)
7012 new_args.Add (new TypeExpression (decl, loc));
7015 new_args.Add (args);
7017 the_args = new_args;
7020 if (the_args != null) {
7021 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7022 return ctype.ResolveAsTypeStep (rc, false);
7029 public override void Emit (EmitContext ec)
7031 throw new Exception ("Should not happen");
7034 public override string ToString ()
7036 return expr + "." + MemberName.MakeName (Identifier, args);
7039 public override string GetSignatureForError ()
7041 return expr.GetSignatureForError () + "." + Identifier;
7044 protected override void CloneTo (CloneContext clonectx, Expression t)
7046 MemberAccess target = (MemberAccess) t;
7048 target.expr = expr.Clone (clonectx);
7053 /// Implements checked expressions
7055 public class CheckedExpr : Expression {
7057 public Expression Expr;
7059 public CheckedExpr (Expression e, Location l)
7065 public override Expression DoResolve (EmitContext ec)
7067 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7068 Expr = Expr.Resolve (ec);
7073 if (Expr is Constant)
7076 eclass = Expr.eclass;
7081 public override void Emit (EmitContext ec)
7083 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7087 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7089 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7090 Expr.EmitBranchable (ec, target, onTrue);
7093 protected override void CloneTo (CloneContext clonectx, Expression t)
7095 CheckedExpr target = (CheckedExpr) t;
7097 target.Expr = Expr.Clone (clonectx);
7102 /// Implements the unchecked expression
7104 public class UnCheckedExpr : Expression {
7106 public Expression Expr;
7108 public UnCheckedExpr (Expression e, Location l)
7114 public override Expression DoResolve (EmitContext ec)
7116 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7117 Expr = Expr.Resolve (ec);
7122 if (Expr is Constant)
7125 eclass = Expr.eclass;
7130 public override void Emit (EmitContext ec)
7132 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7136 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7138 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7139 Expr.EmitBranchable (ec, target, onTrue);
7142 protected override void CloneTo (CloneContext clonectx, Expression t)
7144 UnCheckedExpr target = (UnCheckedExpr) t;
7146 target.Expr = Expr.Clone (clonectx);
7151 /// An Element Access expression.
7153 /// During semantic analysis these are transformed into
7154 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7156 public class ElementAccess : Expression {
7157 public ArrayList Arguments;
7158 public Expression Expr;
7160 public ElementAccess (Expression e, ArrayList e_list)
7169 Arguments = new ArrayList ();
7170 foreach (Expression tmp in e_list)
7171 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7175 bool CommonResolve (EmitContext ec)
7177 Expr = Expr.Resolve (ec);
7182 if (Arguments == null)
7185 foreach (Argument a in Arguments){
7186 if (!a.Resolve (ec, loc))
7193 Expression MakePointerAccess (EmitContext ec, Type t)
7195 if (t == TypeManager.void_ptr_type){
7196 Error (242, "The array index operation is not valid on void pointers");
7199 if (Arguments.Count != 1){
7200 Error (196, "A pointer must be indexed by only one value");
7205 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7208 return new Indirection (p, loc).Resolve (ec);
7211 public override Expression DoResolve (EmitContext ec)
7213 if (!CommonResolve (ec))
7217 // We perform some simple tests, and then to "split" the emit and store
7218 // code we create an instance of a different class, and return that.
7220 // I am experimenting with this pattern.
7224 if (t == TypeManager.array_type){
7225 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7230 return (new ArrayAccess (this, loc)).Resolve (ec);
7232 return MakePointerAccess (ec, Expr.Type);
7234 FieldExpr fe = Expr as FieldExpr;
7236 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7238 return MakePointerAccess (ec, ff.ElementType);
7241 return (new IndexerAccess (this, loc)).Resolve (ec);
7244 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7246 if (!CommonResolve (ec))
7251 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7254 return MakePointerAccess (ec, Expr.Type);
7256 FieldExpr fe = Expr as FieldExpr;
7258 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7260 if (!(fe.InstanceExpression is LocalVariableReference) &&
7261 !(fe.InstanceExpression is This)) {
7262 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7265 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7266 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7269 return MakePointerAccess (ec, ff.ElementType);
7272 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7275 public override void Emit (EmitContext ec)
7277 throw new Exception ("Should never be reached");
7280 protected override void CloneTo (CloneContext clonectx, Expression t)
7282 ElementAccess target = (ElementAccess) t;
7284 target.Expr = Expr.Clone (clonectx);
7285 target.Arguments = new ArrayList ();
7286 foreach (Argument a in Arguments)
7287 target.Arguments.Add (a.Clone (clonectx));
7292 /// Implements array access
7294 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7296 // Points to our "data" repository
7300 LocalTemporary temp;
7303 public ArrayAccess (ElementAccess ea_data, Location l)
7306 eclass = ExprClass.Variable;
7310 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7312 return DoResolve (ec);
7315 public override Expression DoResolve (EmitContext ec)
7318 ExprClass eclass = ea.Expr.eclass;
7320 // As long as the type is valid
7321 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7322 eclass == ExprClass.Value)) {
7323 ea.Expr.Error_UnexpectedKind ("variable or value");
7328 Type t = ea.Expr.Type;
7329 if (t.GetArrayRank () != ea.Arguments.Count){
7330 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7331 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7335 type = TypeManager.GetElementType (t);
7336 if (type.IsPointer && !ec.InUnsafe){
7337 UnsafeError (ea.Location);
7341 foreach (Argument a in ea.Arguments){
7342 Type argtype = a.Type;
7344 if (argtype == TypeManager.int32_type ||
7345 argtype == TypeManager.uint32_type ||
7346 argtype == TypeManager.int64_type ||
7347 argtype == TypeManager.uint64_type) {
7348 Constant c = a.Expr as Constant;
7349 if (c != null && c.IsNegative) {
7350 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7356 // Mhm. This is strage, because the Argument.Type is not the same as
7357 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7359 // Wonder if I will run into trouble for this.
7361 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7366 eclass = ExprClass.Variable;
7372 /// Emits the right opcode to load an object of Type `t'
7373 /// from an array of T
7375 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7377 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7378 ig.Emit (OpCodes.Ldelem_U1);
7379 else if (type == TypeManager.sbyte_type)
7380 ig.Emit (OpCodes.Ldelem_I1);
7381 else if (type == TypeManager.short_type)
7382 ig.Emit (OpCodes.Ldelem_I2);
7383 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7384 ig.Emit (OpCodes.Ldelem_U2);
7385 else if (type == TypeManager.int32_type)
7386 ig.Emit (OpCodes.Ldelem_I4);
7387 else if (type == TypeManager.uint32_type)
7388 ig.Emit (OpCodes.Ldelem_U4);
7389 else if (type == TypeManager.uint64_type)
7390 ig.Emit (OpCodes.Ldelem_I8);
7391 else if (type == TypeManager.int64_type)
7392 ig.Emit (OpCodes.Ldelem_I8);
7393 else if (type == TypeManager.float_type)
7394 ig.Emit (OpCodes.Ldelem_R4);
7395 else if (type == TypeManager.double_type)
7396 ig.Emit (OpCodes.Ldelem_R8);
7397 else if (type == TypeManager.intptr_type)
7398 ig.Emit (OpCodes.Ldelem_I);
7399 else if (TypeManager.IsEnumType (type)){
7400 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7401 } else if (type.IsValueType){
7402 ig.Emit (OpCodes.Ldelema, type);
7403 ig.Emit (OpCodes.Ldobj, type);
7405 } else if (type.IsGenericParameter) {
7406 ig.Emit (OpCodes.Ldelem, type);
7408 } else if (type.IsPointer)
7409 ig.Emit (OpCodes.Ldelem_I);
7411 ig.Emit (OpCodes.Ldelem_Ref);
7415 /// Returns the right opcode to store an object of Type `t'
7416 /// from an array of T.
7418 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7420 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7421 has_type_arg = false; is_stobj = false;
7422 t = TypeManager.TypeToCoreType (t);
7423 if (TypeManager.IsEnumType (t))
7424 t = TypeManager.EnumToUnderlying (t);
7425 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7426 t == TypeManager.bool_type)
7427 return OpCodes.Stelem_I1;
7428 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7429 t == TypeManager.char_type)
7430 return OpCodes.Stelem_I2;
7431 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7432 return OpCodes.Stelem_I4;
7433 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7434 return OpCodes.Stelem_I8;
7435 else if (t == TypeManager.float_type)
7436 return OpCodes.Stelem_R4;
7437 else if (t == TypeManager.double_type)
7438 return OpCodes.Stelem_R8;
7439 else if (t == TypeManager.intptr_type) {
7440 has_type_arg = true;
7442 return OpCodes.Stobj;
7443 } else if (t.IsValueType) {
7444 has_type_arg = true;
7446 return OpCodes.Stobj;
7448 } else if (t.IsGenericParameter) {
7449 has_type_arg = true;
7450 return OpCodes.Stelem;
7453 } else if (t.IsPointer)
7454 return OpCodes.Stelem_I;
7456 return OpCodes.Stelem_Ref;
7459 MethodInfo FetchGetMethod ()
7461 ModuleBuilder mb = CodeGen.Module.Builder;
7462 int arg_count = ea.Arguments.Count;
7463 Type [] args = new Type [arg_count];
7466 for (int i = 0; i < arg_count; i++){
7467 //args [i++] = a.Type;
7468 args [i] = TypeManager.int32_type;
7471 get = mb.GetArrayMethod (
7472 ea.Expr.Type, "Get",
7473 CallingConventions.HasThis |
7474 CallingConventions.Standard,
7480 MethodInfo FetchAddressMethod ()
7482 ModuleBuilder mb = CodeGen.Module.Builder;
7483 int arg_count = ea.Arguments.Count;
7484 Type [] args = new Type [arg_count];
7488 ret_type = TypeManager.GetReferenceType (type);
7490 for (int i = 0; i < arg_count; i++){
7491 //args [i++] = a.Type;
7492 args [i] = TypeManager.int32_type;
7495 address = mb.GetArrayMethod (
7496 ea.Expr.Type, "Address",
7497 CallingConventions.HasThis |
7498 CallingConventions.Standard,
7505 // Load the array arguments into the stack.
7507 // If we have been requested to cache the values (cached_locations array
7508 // initialized), then load the arguments the first time and store them
7509 // in locals. otherwise load from local variables.
7511 void LoadArrayAndArguments (EmitContext ec)
7513 ILGenerator ig = ec.ig;
7516 foreach (Argument a in ea.Arguments){
7517 Type argtype = a.Expr.Type;
7521 if (argtype == TypeManager.int64_type)
7522 ig.Emit (OpCodes.Conv_Ovf_I);
7523 else if (argtype == TypeManager.uint64_type)
7524 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7528 public void Emit (EmitContext ec, bool leave_copy)
7530 int rank = ea.Expr.Type.GetArrayRank ();
7531 ILGenerator ig = ec.ig;
7534 LoadArrayAndArguments (ec);
7537 EmitLoadOpcode (ig, type);
7541 method = FetchGetMethod ();
7542 ig.Emit (OpCodes.Call, method);
7545 LoadFromPtr (ec.ig, this.type);
7548 ec.ig.Emit (OpCodes.Dup);
7549 temp = new LocalTemporary (this.type);
7554 public override void Emit (EmitContext ec)
7559 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7561 int rank = ea.Expr.Type.GetArrayRank ();
7562 ILGenerator ig = ec.ig;
7563 Type t = source.Type;
7564 prepared = prepare_for_load;
7566 if (prepare_for_load) {
7567 AddressOf (ec, AddressOp.LoadStore);
7568 ec.ig.Emit (OpCodes.Dup);
7571 ec.ig.Emit (OpCodes.Dup);
7572 temp = new LocalTemporary (this.type);
7575 StoreFromPtr (ec.ig, t);
7585 LoadArrayAndArguments (ec);
7588 bool is_stobj, has_type_arg;
7589 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7591 // The stobj opcode used by value types will need
7592 // an address on the stack, not really an array/array
7596 ig.Emit (OpCodes.Ldelema, t);
7600 ec.ig.Emit (OpCodes.Dup);
7601 temp = new LocalTemporary (this.type);
7606 ig.Emit (OpCodes.Stobj, t);
7607 else if (has_type_arg)
7612 ModuleBuilder mb = CodeGen.Module.Builder;
7613 int arg_count = ea.Arguments.Count;
7614 Type [] args = new Type [arg_count + 1];
7619 ec.ig.Emit (OpCodes.Dup);
7620 temp = new LocalTemporary (this.type);
7624 for (int i = 0; i < arg_count; i++){
7625 //args [i++] = a.Type;
7626 args [i] = TypeManager.int32_type;
7629 args [arg_count] = type;
7631 set = mb.GetArrayMethod (
7632 ea.Expr.Type, "Set",
7633 CallingConventions.HasThis |
7634 CallingConventions.Standard,
7635 TypeManager.void_type, args);
7637 ig.Emit (OpCodes.Call, set);
7646 public void AddressOf (EmitContext ec, AddressOp mode)
7648 int rank = ea.Expr.Type.GetArrayRank ();
7649 ILGenerator ig = ec.ig;
7651 LoadArrayAndArguments (ec);
7654 ig.Emit (OpCodes.Ldelema, type);
7656 MethodInfo address = FetchAddressMethod ();
7657 ig.Emit (OpCodes.Call, address);
7661 public void EmitGetLength (EmitContext ec, int dim)
7663 int rank = ea.Expr.Type.GetArrayRank ();
7664 ILGenerator ig = ec.ig;
7668 ig.Emit (OpCodes.Ldlen);
7669 ig.Emit (OpCodes.Conv_I4);
7671 IntLiteral.EmitInt (ig, dim);
7672 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7678 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7679 public readonly ArrayList Properties;
7680 static Indexers empty;
7682 public struct Indexer {
7683 public readonly PropertyInfo PropertyInfo;
7684 public readonly MethodInfo Getter, Setter;
7686 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7688 this.PropertyInfo = property_info;
7696 empty = new Indexers (null);
7699 Indexers (ArrayList array)
7704 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7709 foreach (PropertyInfo property in mi){
7710 MethodInfo get, set;
7712 get = property.GetGetMethod (true);
7713 set = property.GetSetMethod (true);
7714 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7716 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7718 if (get != null || set != null) {
7720 ix = new Indexers (new ArrayList ());
7721 ix.Properties.Add (new Indexer (property, get, set));
7726 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7728 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7730 return TypeManager.MemberLookup (
7731 caller_type, caller_type, lookup_type, MemberTypes.Property,
7732 BindingFlags.Public | BindingFlags.Instance |
7733 BindingFlags.DeclaredOnly, p_name, null);
7736 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7738 Indexers ix = empty;
7741 if (lookup_type.IsGenericParameter) {
7742 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7746 if (gc.HasClassConstraint)
7747 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7749 Type[] ifaces = gc.InterfaceConstraints;
7750 foreach (Type itype in ifaces)
7751 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7757 Type copy = lookup_type;
7758 while (copy != TypeManager.object_type && copy != null){
7759 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7760 copy = copy.BaseType;
7763 if (lookup_type.IsInterface) {
7764 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7765 if (ifaces != null) {
7766 foreach (Type itype in ifaces)
7767 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7776 /// Expressions that represent an indexer call.
7778 public class IndexerAccess : Expression, IAssignMethod {
7780 // Points to our "data" repository
7782 MethodInfo get, set;
7783 ArrayList set_arguments;
7784 bool is_base_indexer;
7786 protected Type indexer_type;
7787 protected Type current_type;
7788 protected Expression instance_expr;
7789 protected ArrayList arguments;
7791 public IndexerAccess (ElementAccess ea, Location loc)
7792 : this (ea.Expr, false, loc)
7794 this.arguments = ea.Arguments;
7797 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7800 this.instance_expr = instance_expr;
7801 this.is_base_indexer = is_base_indexer;
7802 this.eclass = ExprClass.Value;
7806 protected virtual bool CommonResolve (EmitContext ec)
7808 indexer_type = instance_expr.Type;
7809 current_type = ec.ContainerType;
7814 public override Expression DoResolve (EmitContext ec)
7816 if (!CommonResolve (ec))
7820 // Step 1: Query for all `Item' *properties*. Notice
7821 // that the actual methods are pointed from here.
7823 // This is a group of properties, piles of them.
7825 ArrayList AllGetters = null;
7827 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7828 if (ilist.Properties != null) {
7829 AllGetters = new ArrayList(ilist.Properties.Count);
7830 foreach (Indexers.Indexer ix in ilist.Properties) {
7831 if (ix.Getter != null)
7832 AllGetters.Add (ix.Getter);
7836 if (AllGetters == null) {
7837 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7838 TypeManager.CSharpName (indexer_type));
7842 if (AllGetters.Count == 0) {
7843 // FIXME: we cannot simply select first one as the error message is missleading when
7844 // multiple indexers exist
7845 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7846 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7847 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7851 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7852 arguments, false, loc);
7855 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7860 // Only base will allow this invocation to happen.
7862 if (get.IsAbstract && this is BaseIndexerAccess){
7863 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7867 type = get.ReturnType;
7868 if (type.IsPointer && !ec.InUnsafe){
7873 instance_expr.CheckMarshalByRefAccess ();
7875 eclass = ExprClass.IndexerAccess;
7879 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7881 if (right_side == EmptyExpression.OutAccess) {
7882 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7883 GetSignatureForError ());
7887 // if the indexer returns a value type, and we try to set a field in it
7888 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7889 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7890 GetSignatureForError ());
7894 ArrayList AllSetters = new ArrayList();
7895 if (!CommonResolve (ec))
7898 bool found_any = false, found_any_setters = false;
7900 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7901 if (ilist.Properties != null) {
7903 foreach (Indexers.Indexer ix in ilist.Properties) {
7904 if (ix.Setter != null)
7905 AllSetters.Add (ix.Setter);
7908 if (AllSetters.Count > 0) {
7909 found_any_setters = true;
7910 set_arguments = (ArrayList) arguments.Clone ();
7911 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7912 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7914 set_arguments, false, loc);
7918 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7919 TypeManager.CSharpName (indexer_type));
7923 if (!found_any_setters) {
7924 Error (154, "indexer can not be used in this context, because " +
7925 "it lacks a `set' accessor");
7930 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7935 // Only base will allow this invocation to happen.
7937 if (set.IsAbstract && this is BaseIndexerAccess){
7938 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7943 // Now look for the actual match in the list of indexers to set our "return" type
7945 type = TypeManager.void_type; // default value
7946 foreach (Indexers.Indexer ix in ilist.Properties){
7947 if (ix.Setter == set){
7948 type = ix.PropertyInfo.PropertyType;
7953 instance_expr.CheckMarshalByRefAccess ();
7955 eclass = ExprClass.IndexerAccess;
7959 bool prepared = false;
7960 LocalTemporary temp;
7962 public void Emit (EmitContext ec, bool leave_copy)
7964 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
7966 ec.ig.Emit (OpCodes.Dup);
7967 temp = new LocalTemporary (Type);
7973 // source is ignored, because we already have a copy of it from the
7974 // LValue resolution and we have already constructed a pre-cached
7975 // version of the arguments (ea.set_arguments);
7977 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7979 prepared = prepare_for_load;
7980 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7985 ec.ig.Emit (OpCodes.Dup);
7986 temp = new LocalTemporary (Type);
7989 } else if (leave_copy) {
7990 temp = new LocalTemporary (Type);
7996 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8005 public override void Emit (EmitContext ec)
8010 public override string GetSignatureForError ()
8012 // FIXME: print the argument list of the indexer
8013 return instance_expr.GetSignatureForError () + ".this[...]";
8016 protected override void CloneTo (CloneContext clonectx, Expression t)
8018 IndexerAccess target = (IndexerAccess) t;
8020 if (arguments != null){
8021 target.arguments = new ArrayList ();
8022 foreach (Argument a in arguments)
8023 target.arguments.Add (a.Clone (clonectx));
8025 if (instance_expr != null)
8026 target.instance_expr = instance_expr.Clone (clonectx);
8031 /// The base operator for method names
8033 public class BaseAccess : Expression {
8034 public readonly string Identifier;
8037 public BaseAccess (string member, Location l)
8039 this.Identifier = member;
8043 public BaseAccess (string member, TypeArguments args, Location l)
8049 public override Expression DoResolve (EmitContext ec)
8051 Expression c = CommonResolve (ec);
8057 // MethodGroups use this opportunity to flag an error on lacking ()
8059 if (!(c is MethodGroupExpr))
8060 return c.Resolve (ec);
8064 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8066 Expression c = CommonResolve (ec);
8072 // MethodGroups use this opportunity to flag an error on lacking ()
8074 if (! (c is MethodGroupExpr))
8075 return c.DoResolveLValue (ec, right_side);
8080 Expression CommonResolve (EmitContext ec)
8082 Expression member_lookup;
8083 Type current_type = ec.ContainerType;
8084 Type base_type = current_type.BaseType;
8087 Error (1511, "Keyword `base' is not available in a static method");
8091 if (ec.IsFieldInitializer){
8092 Error (1512, "Keyword `base' is not available in the current context");
8096 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8097 AllMemberTypes, AllBindingFlags, loc);
8098 if (member_lookup == null) {
8099 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8106 left = new TypeExpression (base_type, loc);
8108 left = ec.GetThis (loc);
8110 MemberExpr me = (MemberExpr) member_lookup;
8112 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8114 if (e is PropertyExpr) {
8115 PropertyExpr pe = (PropertyExpr) e;
8120 MethodGroupExpr mg = e as MethodGroupExpr;
8126 return mg.ResolveGeneric (ec, args);
8128 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8136 public override void Emit (EmitContext ec)
8138 throw new Exception ("Should never be called");
8141 protected override void CloneTo (CloneContext clonectx, Expression t)
8143 BaseAccess target = (BaseAccess) t;
8145 target.args = args.Clone ();
8150 /// The base indexer operator
8152 public class BaseIndexerAccess : IndexerAccess {
8153 public BaseIndexerAccess (ArrayList args, Location loc)
8154 : base (null, true, loc)
8156 arguments = new ArrayList ();
8157 foreach (Expression tmp in args)
8158 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8161 protected override bool CommonResolve (EmitContext ec)
8163 instance_expr = ec.GetThis (loc);
8165 current_type = ec.ContainerType.BaseType;
8166 indexer_type = current_type;
8168 foreach (Argument a in arguments){
8169 if (!a.Resolve (ec, loc))
8178 /// This class exists solely to pass the Type around and to be a dummy
8179 /// that can be passed to the conversion functions (this is used by
8180 /// foreach implementation to typecast the object return value from
8181 /// get_Current into the proper type. All code has been generated and
8182 /// we only care about the side effect conversions to be performed
8184 /// This is also now used as a placeholder where a no-action expression
8185 /// is needed (the `New' class).
8187 public class EmptyExpression : Expression {
8188 public static readonly EmptyExpression Null = new EmptyExpression ();
8190 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8191 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8192 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8194 static EmptyExpression temp = new EmptyExpression ();
8195 public static EmptyExpression Grab ()
8197 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8202 public static void Release (EmptyExpression e)
8207 // TODO: should be protected
8208 public EmptyExpression ()
8210 type = TypeManager.object_type;
8211 eclass = ExprClass.Value;
8212 loc = Location.Null;
8215 public EmptyExpression (Type t)
8218 eclass = ExprClass.Value;
8219 loc = Location.Null;
8222 public override Expression DoResolve (EmitContext ec)
8227 public override void Emit (EmitContext ec)
8229 // nothing, as we only exist to not do anything.
8233 // This is just because we might want to reuse this bad boy
8234 // instead of creating gazillions of EmptyExpressions.
8235 // (CanImplicitConversion uses it)
8237 public void SetType (Type t)
8243 public class UserCast : Expression {
8247 public UserCast (MethodInfo method, Expression source, Location l)
8249 this.method = method;
8250 this.source = source;
8251 type = method.ReturnType;
8252 eclass = ExprClass.Value;
8256 public Expression Source {
8262 public override Expression DoResolve (EmitContext ec)
8265 // We are born fully resolved
8270 public override void Emit (EmitContext ec)
8272 ILGenerator ig = ec.ig;
8276 if (method is MethodInfo)
8277 ig.Emit (OpCodes.Call, (MethodInfo) method);
8279 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8285 // This class is used to "construct" the type during a typecast
8286 // operation. Since the Type.GetType class in .NET can parse
8287 // the type specification, we just use this to construct the type
8288 // one bit at a time.
8290 public class ComposedCast : TypeExpr {
8294 public ComposedCast (Expression left, string dim)
8295 : this (left, dim, left.Location)
8299 public ComposedCast (Expression left, string dim, Location l)
8307 public Expression RemoveNullable ()
8309 if (dim.EndsWith ("?")) {
8310 dim = dim.Substring (0, dim.Length - 1);
8319 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8321 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8325 Type ltype = lexpr.Type;
8326 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8327 Error_VoidInvalidInTheContext (loc);
8332 if ((dim.Length > 0) && (dim [0] == '?')) {
8333 TypeExpr nullable = new NullableType (left, loc);
8335 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8336 return nullable.ResolveAsTypeTerminal (ec, false);
8340 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8343 if (dim != "" && dim [0] == '[' &&
8344 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8345 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8350 type = TypeManager.GetConstructedType (ltype, dim);
8355 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8357 if (type.IsPointer && !ec.IsInUnsafeScope){
8362 eclass = ExprClass.Type;
8366 public override string Name {
8367 get { return left + dim; }
8370 public override string FullName {
8371 get { return type.FullName; }
8374 public override string GetSignatureForError ()
8376 return left.GetSignatureForError () + dim;
8379 protected override void CloneTo (CloneContext clonectx, Expression t)
8381 ComposedCast target = (ComposedCast) t;
8383 target.left = left.Clone (clonectx);
8387 public class FixedBufferPtr : Expression {
8390 public FixedBufferPtr (Expression array, Type array_type, Location l)
8395 type = TypeManager.GetPointerType (array_type);
8396 eclass = ExprClass.Value;
8399 public override void Emit(EmitContext ec)
8404 public override Expression DoResolve (EmitContext ec)
8407 // We are born fully resolved
8415 // This class is used to represent the address of an array, used
8416 // only by the Fixed statement, this generates "&a [0]" construct
8417 // for fixed (char *pa = a)
8419 public class ArrayPtr : FixedBufferPtr {
8422 public ArrayPtr (Expression array, Type array_type, Location l):
8423 base (array, array_type, l)
8425 this.array_type = array_type;
8428 public override void Emit (EmitContext ec)
8432 ILGenerator ig = ec.ig;
8433 IntLiteral.EmitInt (ig, 0);
8434 ig.Emit (OpCodes.Ldelema, array_type);
8439 // Used by the fixed statement
8441 public class StringPtr : Expression {
8444 public StringPtr (LocalBuilder b, Location l)
8447 eclass = ExprClass.Value;
8448 type = TypeManager.char_ptr_type;
8452 public override Expression DoResolve (EmitContext ec)
8454 // This should never be invoked, we are born in fully
8455 // initialized state.
8460 public override void Emit (EmitContext ec)
8462 ILGenerator ig = ec.ig;
8464 ig.Emit (OpCodes.Ldloc, b);
8465 ig.Emit (OpCodes.Conv_I);
8466 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8467 ig.Emit (OpCodes.Add);
8472 // Implements the `stackalloc' keyword
8474 public class StackAlloc : Expression {
8479 public StackAlloc (Expression type, Expression count, Location l)
8486 public override Expression DoResolve (EmitContext ec)
8488 count = count.Resolve (ec);
8492 if (count.Type != TypeManager.int32_type){
8493 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8498 Constant c = count as Constant;
8499 if (c != null && c.IsNegative) {
8500 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8504 if (ec.InCatch || ec.InFinally) {
8505 Error (255, "Cannot use stackalloc in finally or catch");
8509 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8515 if (!TypeManager.VerifyUnManaged (otype, loc))
8518 type = TypeManager.GetPointerType (otype);
8519 eclass = ExprClass.Value;
8524 public override void Emit (EmitContext ec)
8526 int size = GetTypeSize (otype);
8527 ILGenerator ig = ec.ig;
8530 ig.Emit (OpCodes.Sizeof, otype);
8532 IntConstant.EmitInt (ig, size);
8534 ig.Emit (OpCodes.Mul);
8535 ig.Emit (OpCodes.Localloc);
8538 protected override void CloneTo (CloneContext clonectx, Expression t)
8540 StackAlloc target = (StackAlloc) t;
8541 target.count = count.Clone (clonectx);
8542 target.t = t.Clone (clonectx);
8546 public interface IInitializable
8548 bool Initialize (EmitContext ec, Expression target);
8551 public class Initializer
8553 public readonly string Name;
8554 public readonly object Value;
8556 public Initializer (string name, Expression value)
8562 public Initializer (string name, IInitializable value)
8569 public class ObjectInitializer : IInitializable
8571 readonly ArrayList initializers;
8572 public ObjectInitializer (ArrayList initializers)
8574 this.initializers = initializers;
8577 public bool Initialize (EmitContext ec, Expression target)
8579 ArrayList initialized = new ArrayList (initializers.Count);
8580 for (int i = initializers.Count - 1; i >= 0; i--) {
8581 Initializer initializer = initializers[i] as Initializer;
8582 if (initialized.Contains (initializer.Name)) {
8583 //FIXME proper error
8584 Console.WriteLine ("Object member can only be initialized once");
8588 MemberAccess ma = new MemberAccess (target, initializer.Name);
8589 Expression expr = initializer.Value as Expression;
8590 // If it's an expresison, append the assign.
8592 Assign a = new Assign (ma, expr);
8593 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8595 // If it's another initializer (object or collection), initialize it.
8596 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8599 initialized.Add (initializer.Name);
8605 public class CollectionInitializer : IInitializable
8607 readonly ArrayList items;
8608 public CollectionInitializer (ArrayList items)
8613 bool CheckCollection (EmitContext ec, Expression e)
8615 if (e == null || e.Type == null)
8617 bool is_ienumerable = false;
8618 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8619 if (t == typeof (IEnumerable)) {
8620 is_ienumerable = true;
8624 if (!is_ienumerable)
8627 MethodGroupExpr mg = Expression.MemberLookup (
8628 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8629 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8634 foreach (MethodInfo mi in mg.Methods) {
8635 if (TypeManager.GetParameterData (mi).Count != 1)
8637 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8644 public bool Initialize (EmitContext ec, Expression target)
8646 if (!CheckCollection (ec, target.Resolve (ec))) {
8647 // FIXME throw proper error
8648 Console.WriteLine ("Error: This is not a collection");
8652 for (int i = items.Count - 1; i >= 0; i--) {
8653 MemberAccess ma = new MemberAccess (target, "Add");
8654 ArrayList array = new ArrayList ();
8655 array.Add (new Argument ((Expression)items[i]));
8656 Invocation invoke = new Invocation (ma, array);
8657 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8663 public class AnonymousTypeInitializer : IInitializable
8665 readonly ArrayList initializers;
8666 public AnonymousTypeInitializer (ArrayList initializers)
8668 this.initializers = initializers;
8671 public bool Initialize (EmitContext ec, Expression target)
8673 foreach (AnonymousTypeParameter p in initializers) {
8674 MemberAccess ma = new MemberAccess (target, p.Name);
8675 Assign a = p.Expression as Assign;
8676 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8677 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8683 public class NewInitialize : New, IInitializable
8685 IInitializable initializer;
8687 public bool Initialize (EmitContext ec, Expression target)
8689 return initializer.Initialize (ec, target);
8692 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8693 : base (requested_type, arguments, l)
8695 this.initializer = initializer;
8699 public class AnonymousType : Expression
8701 ArrayList parameters;
8702 TypeContainer parent;
8704 TypeContainer anonymous_type;
8706 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8708 this.parameters = parameters;
8709 this.parent = parent;
8713 public override Expression DoResolve (EmitContext ec)
8715 foreach (AnonymousTypeParameter p in parameters)
8718 anonymous_type = GetAnonymousType (ec);
8720 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8721 AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8722 return new NewInitialize (te, null, ati, loc).Resolve (ec);
8725 TypeContainer GetAnonymousType (EmitContext ec)
8727 // See if we already have an anonymous type with the right fields.
8728 // If not, create one.
8730 // Look through all availible pre-existing anonymous types:
8731 foreach (DictionaryEntry d in parent.AnonymousTypes) {
8732 ArrayList p = d.Key as ArrayList;
8733 if (p.Count != parameters.Count)
8736 // And for each of the fields we need...
8737 foreach (AnonymousTypeParameter atp in parameters) {
8738 // ... check each of the pre-existing A-type's fields.
8740 foreach (AnonymousTypeParameter a in p)
8741 if (atp.Equals(a)) {
8745 // If the pre-existing A-type doesn't have one of our fields, try the next one
8751 // If it's a match, return it.
8753 return d.Value as TypeContainer;
8755 // Otherwise, create a new type.
8756 return CreateAnonymousType (ec);
8759 TypeContainer CreateAnonymousType (EmitContext ec)
8761 TypeContainer type = new AnonymousClass (parent, loc);
8762 foreach (AnonymousTypeParameter p in parameters) {
8763 TypeExpression te = new TypeExpression (p.Type, loc);
8764 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8765 type.AddField (field);
8768 type.DefineMembers ();
8769 parent.AnonymousTypes.Add (parameters, type);
8773 public override void Emit (EmitContext ec)
8775 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8776 new New (te, null, loc).Emit(ec);
8780 public class AnonymousTypeParameter : Expression
8784 Expression expression;
8787 public LocatedToken Token {
8788 get { return token; }
8791 public string Name {
8792 get { return name; }
8796 get { return type; }
8799 public Expression Expression {
8800 get { return expression; }
8803 public override bool Equals (object o)
8805 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8806 return other != null && Name == other.Name && Type == other.Type;
8809 public override Expression DoResolve (EmitContext ec)
8811 Expression e = expression.Resolve(ec);
8816 public override void Emit (EmitContext ec)
8818 expression.Emit(ec);
8821 public AnonymousTypeParameter (Expression expression, string name)
8824 this.expression = expression;
8825 type = expression.Type;