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);
4274 Type pt = pd.ParameterType (i);
4275 EmitContext prevec = EmitContext.TempEc;
4276 EmitContext.TempEc = ec;
4279 if (a_mod == Parameter.Modifier.NONE) {
4280 // It is already done in ImplicitConversion need to measure the performance, it causes problem in MWF
4281 if (TypeManager.IsEqual (a.Type, pt))
4284 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4289 EmitContext.TempEc = prevec;
4299 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4301 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4302 name, arg_count.ToString ());
4305 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4306 Type delegate_type, Argument a, ParameterData expected_par)
4308 if (delegate_type == null)
4309 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4310 TypeManager.CSharpSignature (method));
4312 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4313 TypeManager.CSharpName (delegate_type));
4315 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4317 string index = (idx + 1).ToString ();
4318 if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4319 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4320 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4321 index, Parameter.GetModifierSignature (a.Modifier));
4323 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4324 index, Parameter.GetModifierSignature (mod));
4326 string p1 = Argument.FullDesc (a);
4327 string p2 = expected_par.ParameterDesc (idx);
4330 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4331 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4332 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4334 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'", index, p1, p2);
4338 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4339 int arg_count, MethodBase method,
4340 bool chose_params_expanded,
4341 Type delegate_type, bool may_fail,
4344 ParameterData pd = TypeManager.GetParameterData (method);
4348 for (j = 0; j < pd.Count; j++) {
4349 Type parameter_type = pd.ParameterType (j);
4350 Parameter.Modifier pm = pd.ParameterModifier (j);
4352 if (pm == Parameter.Modifier.ARGLIST) {
4353 a = (Argument) Arguments [a_idx];
4354 if (!(a.Expr is Arglist))
4360 int params_arg_count = 1;
4361 if (pm == Parameter.Modifier.PARAMS) {
4362 pm = Parameter.Modifier.NONE;
4363 params_arg_count = arg_count - pd.Count + 1;
4364 if (chose_params_expanded)
4365 parameter_type = TypeManager.GetElementType (parameter_type);
4368 while (params_arg_count > 0) {
4369 a = (Argument) Arguments [a_idx];
4370 if (pm != a.Modifier)
4373 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4374 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4377 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4381 // Update the argument with the implicit conversion
4389 if (params_arg_count > 0)
4392 if (parameter_type.IsPointer && !ec.InUnsafe) {
4399 if (a_idx == arg_count)
4403 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4407 private bool resolved = false;
4408 public override Expression DoResolve (EmitContext ec)
4411 return this.method == null ? null : this;
4415 // First, resolve the expression that is used to
4416 // trigger the invocation
4418 SimpleName sn = expr as SimpleName;
4420 expr = sn.GetMethodGroup ();
4422 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4423 if (expr_resolved == null)
4426 MethodGroupExpr mg = expr_resolved as MethodGroupExpr;
4428 Type expr_type = expr_resolved.Type;
4430 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4431 return (new DelegateInvocation (
4432 expr_resolved, Arguments, loc)).Resolve (ec);
4434 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4439 // Next, evaluate all the expressions in the argument list
4441 if (Arguments != null){
4442 foreach (Argument a in Arguments){
4443 if (!a.Resolve (ec, loc))
4448 MethodBase method = mg.OverloadExtensionResolve (ec, ref Arguments, ref mg, expr, loc);
4454 MethodInfo mi = method as MethodInfo;
4456 type = TypeManager.TypeToCoreType (mi.ReturnType);
4457 Expression iexpr = mg.InstanceExpression;
4459 if (iexpr == null ||
4460 iexpr is This || iexpr is EmptyExpression ||
4461 mg.IdenticalTypeName) {
4462 mg.InstanceExpression = null;
4464 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4468 if (iexpr == null || iexpr is EmptyExpression) {
4469 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
4475 if (type.IsPointer){
4483 // Only base will allow this invocation to happen.
4485 if (mg.IsBase && method.IsAbstract){
4486 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4490 if (Arguments == null && method.Name == "Finalize") {
4492 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4494 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4498 if (IsSpecialMethodInvocation (method)) {
4502 if (mg.InstanceExpression != null){
4503 mg.InstanceExpression.CheckMarshalByRefAccess ();
4506 // This is used to check that no methods are called in struct
4507 // constructors before all the fields on the struct have been
4510 if (!method.IsStatic){
4511 This mgthis = mg.InstanceExpression as This;
4512 if (mgthis != null){
4513 if (!mgthis.CheckThisUsage (ec))
4519 eclass = ExprClass.Value;
4520 this.method = method;
4524 bool IsSpecialMethodInvocation (MethodBase method)
4526 if (!TypeManager.IsSpecialMethod (method))
4529 Report.SymbolRelatedToPreviousError (method);
4530 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4531 TypeManager.CSharpSignature (method, true));
4537 // Emits the list of arguments as an array
4539 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4541 ILGenerator ig = ec.ig;
4543 for (int j = 0; j < count; j++){
4544 Argument a = (Argument) arguments [j + idx];
4547 IntConstant.EmitInt (ig, count);
4548 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4551 ig.Emit (OpCodes.Dup);
4552 IntConstant.EmitInt (ig, j);
4554 bool is_stobj, has_type_arg;
4555 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4557 ig.Emit (OpCodes.Ldelema, t);
4569 /// Emits a list of resolved Arguments that are in the arguments
4572 /// The MethodBase argument might be null if the
4573 /// emission of the arguments is known not to contain
4574 /// a `params' field (for example in constructors or other routines
4575 /// that keep their arguments in this structure)
4577 /// if `dup_args' is true, a copy of the arguments will be left
4578 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4579 /// which will be duplicated before any other args. Only EmitCall
4580 /// should be using this interface.
4582 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4584 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4586 LocalTemporary [] temps = null;
4588 if (dup_args && top != 0)
4589 temps = new LocalTemporary [top];
4591 int argument_index = 0;
4593 for (int i = 0; i < top; i++){
4595 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4596 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4597 int params_args_count = arguments == null ?
4598 0 : arguments.Count - top + 1;
4600 // Fill not provided argument
4601 if (params_args_count <= 0) {
4602 ILGenerator ig = ec.ig;
4603 IntConstant.EmitInt (ig, 0);
4604 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4609 // Special case if we are passing the same data as the
4610 // params argument, we do not need to recreate an array.
4612 a = (Argument) arguments [argument_index];
4613 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4619 EmitParams (ec, arguments, i, params_args_count);
4620 argument_index += params_args_count;
4625 a = (Argument) arguments [argument_index++];
4628 ec.ig.Emit (OpCodes.Dup);
4629 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4634 if (this_arg != null)
4637 for (int i = 0; i < top; i ++) {
4638 temps [i].Emit (ec);
4639 temps [i].Release (ec);
4644 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4646 ParameterData pd = TypeManager.GetParameterData (mb);
4648 if (arguments == null)
4649 return new Type [0];
4651 Argument a = (Argument) arguments [pd.Count - 1];
4652 Arglist list = (Arglist) a.Expr;
4654 return list.ArgumentTypes;
4658 /// This checks the ConditionalAttribute on the method
4660 static bool IsMethodExcluded (MethodBase method)
4662 if (method.IsConstructor)
4665 IMethodData md = TypeManager.GetMethod (method);
4667 return md.IsExcluded ();
4669 // For some methods (generated by delegate class) GetMethod returns null
4670 // because they are not included in builder_to_method table
4671 if (method.DeclaringType is TypeBuilder)
4674 return AttributeTester.IsConditionalMethodExcluded (method);
4678 /// is_base tells whether we want to force the use of the `call'
4679 /// opcode instead of using callvirt. Call is required to call
4680 /// a specific method, while callvirt will always use the most
4681 /// recent method in the vtable.
4683 /// is_static tells whether this is an invocation on a static method
4685 /// instance_expr is an expression that represents the instance
4686 /// it must be non-null if is_static is false.
4688 /// method is the method to invoke.
4690 /// Arguments is the list of arguments to pass to the method or constructor.
4692 public static void EmitCall (EmitContext ec, bool is_base,
4693 bool is_static, Expression instance_expr,
4694 MethodBase method, ArrayList Arguments, Location loc)
4696 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
4699 // `dup_args' leaves an extra copy of the arguments on the stack
4700 // `omit_args' does not leave any arguments at all.
4701 // So, basically, you could make one call with `dup_args' set to true,
4702 // and then another with `omit_args' set to true, and the two calls
4703 // would have the same set of arguments. However, each argument would
4704 // only have been evaluated once.
4705 public static void EmitCall (EmitContext ec, bool is_base,
4706 bool is_static, Expression instance_expr,
4707 MethodBase method, ArrayList Arguments, Location loc,
4708 bool dup_args, bool omit_args)
4710 ILGenerator ig = ec.ig;
4711 bool struct_call = false;
4712 bool this_call = false;
4713 LocalTemporary this_arg = null;
4715 Type decl_type = method.DeclaringType;
4717 if (!RootContext.StdLib) {
4718 // Replace any calls to the system's System.Array type with calls to
4719 // the newly created one.
4720 if (method == TypeManager.system_int_array_get_length)
4721 method = TypeManager.int_array_get_length;
4722 else if (method == TypeManager.system_int_array_get_rank)
4723 method = TypeManager.int_array_get_rank;
4724 else if (method == TypeManager.system_object_array_clone)
4725 method = TypeManager.object_array_clone;
4726 else if (method == TypeManager.system_int_array_get_length_int)
4727 method = TypeManager.int_array_get_length_int;
4728 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4729 method = TypeManager.int_array_get_lower_bound_int;
4730 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4731 method = TypeManager.int_array_get_upper_bound_int;
4732 else if (method == TypeManager.system_void_array_copyto_array_int)
4733 method = TypeManager.void_array_copyto_array_int;
4736 if (!ec.IsInObsoleteScope) {
4738 // This checks ObsoleteAttribute on the method and on the declaring type
4740 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4742 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4744 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4746 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4750 if (IsMethodExcluded (method))
4754 if (instance_expr == EmptyExpression.Null) {
4755 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4759 this_call = instance_expr is This;
4760 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4764 // If this is ourselves, push "this"
4768 Type iexpr_type = instance_expr.Type;
4771 // Push the instance expression
4773 if (TypeManager.IsValueType (iexpr_type)) {
4775 // Special case: calls to a function declared in a
4776 // reference-type with a value-type argument need
4777 // to have their value boxed.
4778 if (decl_type.IsValueType ||
4779 TypeManager.IsGenericParameter (iexpr_type)) {
4781 // If the expression implements IMemoryLocation, then
4782 // we can optimize and use AddressOf on the
4785 // If not we have to use some temporary storage for
4787 if (instance_expr is IMemoryLocation) {
4788 ((IMemoryLocation)instance_expr).
4789 AddressOf (ec, AddressOp.LoadStore);
4791 LocalTemporary temp = new LocalTemporary (iexpr_type);
4792 instance_expr.Emit (ec);
4794 temp.AddressOf (ec, AddressOp.Load);
4797 // avoid the overhead of doing this all the time.
4799 t = TypeManager.GetReferenceType (iexpr_type);
4801 instance_expr.Emit (ec);
4802 ig.Emit (OpCodes.Box, instance_expr.Type);
4803 t = TypeManager.object_type;
4806 instance_expr.Emit (ec);
4807 t = instance_expr.Type;
4811 ig.Emit (OpCodes.Dup);
4812 if (Arguments != null && Arguments.Count != 0) {
4813 this_arg = new LocalTemporary (t);
4814 this_arg.Store (ec);
4821 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4824 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4825 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4829 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4830 call_op = OpCodes.Call;
4832 call_op = OpCodes.Callvirt;
4834 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4835 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4836 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4843 // and DoFoo is not virtual, you can omit the callvirt,
4844 // because you don't need the null checking behavior.
4846 if (method is MethodInfo)
4847 ig.Emit (call_op, (MethodInfo) method);
4849 ig.Emit (call_op, (ConstructorInfo) method);
4852 public override void Emit (EmitContext ec)
4854 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4856 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4859 public override void EmitStatement (EmitContext ec)
4864 // Pop the return value if there is one
4866 if (method is MethodInfo){
4867 Type ret = ((MethodInfo)method).ReturnType;
4868 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4869 ec.ig.Emit (OpCodes.Pop);
4873 protected override void CloneTo (CloneContext clonectx, Expression t)
4875 Invocation target = (Invocation) t;
4877 if (Arguments != null){
4878 target.Arguments = new ArrayList ();
4879 foreach (Argument a in Arguments)
4880 target.Arguments.Add (a.Clone (clonectx));
4883 expr = expr.Clone (clonectx);
4887 public class InvocationOrCast : ExpressionStatement
4890 Expression argument;
4892 public InvocationOrCast (Expression expr, Expression argument)
4895 this.argument = argument;
4896 this.loc = expr.Location;
4899 public override Expression DoResolve (EmitContext ec)
4902 // First try to resolve it as a cast.
4904 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4905 if ((te != null) && (te.eclass == ExprClass.Type)) {
4906 Cast cast = new Cast (te, argument, loc);
4907 return cast.Resolve (ec);
4911 // This can either be a type or a delegate invocation.
4912 // Let's just resolve it and see what we'll get.
4914 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4919 // Ok, so it's a Cast.
4921 if (expr.eclass == ExprClass.Type) {
4922 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4923 return cast.Resolve (ec);
4927 // It's a delegate invocation.
4929 if (!TypeManager.IsDelegateType (expr.Type)) {
4930 Error (149, "Method name expected");
4934 ArrayList args = new ArrayList ();
4935 args.Add (new Argument (argument, Argument.AType.Expression));
4936 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4937 return invocation.Resolve (ec);
4940 public override ExpressionStatement ResolveStatement (EmitContext ec)
4943 // First try to resolve it as a cast.
4945 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4946 if ((te != null) && (te.eclass == ExprClass.Type)) {
4947 Error_InvalidExpressionStatement ();
4952 // This can either be a type or a delegate invocation.
4953 // Let's just resolve it and see what we'll get.
4955 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4956 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4957 Error_InvalidExpressionStatement ();
4962 // It's a delegate invocation.
4964 if (!TypeManager.IsDelegateType (expr.Type)) {
4965 Error (149, "Method name expected");
4969 ArrayList args = new ArrayList ();
4970 args.Add (new Argument (argument, Argument.AType.Expression));
4971 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4972 return invocation.ResolveStatement (ec);
4975 public override void Emit (EmitContext ec)
4977 throw new Exception ("Cannot happen");
4980 public override void EmitStatement (EmitContext ec)
4982 throw new Exception ("Cannot happen");
4985 protected override void CloneTo (CloneContext clonectx, Expression t)
4987 InvocationOrCast target = (InvocationOrCast) t;
4989 target.expr = expr.Clone (clonectx);
4990 target.argument = argument.Clone (clonectx);
4995 // This class is used to "disable" the code generation for the
4996 // temporary variable when initializing value types.
4998 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4999 public void AddressOf (EmitContext ec, AddressOp Mode)
5006 /// Implements the new expression
5008 public class New : ExpressionStatement, IMemoryLocation {
5009 public ArrayList Arguments;
5012 // During bootstrap, it contains the RequestedType,
5013 // but if `type' is not null, it *might* contain a NewDelegate
5014 // (because of field multi-initialization)
5016 public Expression RequestedType;
5018 MethodBase method = null;
5021 // If set, the new expression is for a value_target, and
5022 // we will not leave anything on the stack.
5024 Expression value_target;
5025 bool value_target_set = false;
5026 bool is_type_parameter = false;
5028 public New (Expression requested_type, ArrayList arguments, Location l)
5030 RequestedType = requested_type;
5031 Arguments = arguments;
5035 public bool SetValueTypeVariable (Expression value)
5037 value_target = value;
5038 value_target_set = true;
5039 if (!(value_target is IMemoryLocation)){
5040 Error_UnexpectedKind (null, "variable", loc);
5047 // This function is used to disable the following code sequence for
5048 // value type initialization:
5050 // AddressOf (temporary)
5054 // Instead the provide will have provided us with the address on the
5055 // stack to store the results.
5057 static Expression MyEmptyExpression;
5059 public void DisableTemporaryValueType ()
5061 if (MyEmptyExpression == null)
5062 MyEmptyExpression = new EmptyAddressOf ();
5065 // To enable this, look into:
5066 // test-34 and test-89 and self bootstrapping.
5068 // For instance, we can avoid a copy by using `newobj'
5069 // instead of Call + Push-temp on value types.
5070 // value_target = MyEmptyExpression;
5075 /// Converts complex core type syntax like 'new int ()' to simple constant
5077 public static Constant Constantify (Type t)
5079 if (t == TypeManager.int32_type)
5080 return new IntConstant (0, Location.Null);
5081 if (t == TypeManager.uint32_type)
5082 return new UIntConstant (0, Location.Null);
5083 if (t == TypeManager.int64_type)
5084 return new LongConstant (0, Location.Null);
5085 if (t == TypeManager.uint64_type)
5086 return new ULongConstant (0, Location.Null);
5087 if (t == TypeManager.float_type)
5088 return new FloatConstant (0, Location.Null);
5089 if (t == TypeManager.double_type)
5090 return new DoubleConstant (0, Location.Null);
5091 if (t == TypeManager.short_type)
5092 return new ShortConstant (0, Location.Null);
5093 if (t == TypeManager.ushort_type)
5094 return new UShortConstant (0, Location.Null);
5095 if (t == TypeManager.sbyte_type)
5096 return new SByteConstant (0, Location.Null);
5097 if (t == TypeManager.byte_type)
5098 return new ByteConstant (0, Location.Null);
5099 if (t == TypeManager.char_type)
5100 return new CharConstant ('\0', Location.Null);
5101 if (t == TypeManager.bool_type)
5102 return new BoolConstant (false, Location.Null);
5103 if (t == TypeManager.decimal_type)
5104 return new DecimalConstant (0, Location.Null);
5105 if (TypeManager.IsEnumType (t))
5106 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5112 // Checks whether the type is an interface that has the
5113 // [ComImport, CoClass] attributes and must be treated
5116 public Expression CheckComImport (EmitContext ec)
5118 if (!type.IsInterface)
5122 // Turn the call into:
5123 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5125 Type real_class = AttributeTester.GetCoClassAttribute (type);
5126 if (real_class == null)
5129 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5130 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5131 return cast.Resolve (ec);
5134 public override Expression DoResolve (EmitContext ec)
5137 // The New DoResolve might be called twice when initializing field
5138 // expressions (see EmitFieldInitializers, the call to
5139 // GetInitializerExpression will perform a resolve on the expression,
5140 // and later the assign will trigger another resolution
5142 // This leads to bugs (#37014)
5145 if (RequestedType is NewDelegate)
5146 return RequestedType;
5150 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5156 if (type == TypeManager.void_type) {
5157 Error_VoidInvalidInTheContext (loc);
5161 if (Arguments == null) {
5162 Expression c = Constantify (type);
5167 if (TypeManager.IsDelegateType (type)) {
5168 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5169 if (RequestedType != null)
5170 if (!(RequestedType is DelegateCreation))
5171 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5172 return RequestedType;
5176 if (type.IsGenericParameter) {
5177 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5179 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5180 Error (304, String.Format (
5181 "Cannot create an instance of the " +
5182 "variable type '{0}' because it " +
5183 "doesn't have the new() constraint",
5188 if ((Arguments != null) && (Arguments.Count != 0)) {
5189 Error (417, String.Format (
5190 "`{0}': cannot provide arguments " +
5191 "when creating an instance of a " +
5192 "variable type.", type));
5196 is_type_parameter = true;
5197 eclass = ExprClass.Value;
5202 if (type.IsAbstract && type.IsSealed) {
5203 Report.SymbolRelatedToPreviousError (type);
5204 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5208 if (type.IsInterface || type.IsAbstract){
5209 if (!TypeManager.IsGenericType (type)) {
5210 RequestedType = CheckComImport (ec);
5211 if (RequestedType != null)
5212 return RequestedType;
5215 Report.SymbolRelatedToPreviousError (type);
5216 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5220 bool is_struct = type.IsValueType;
5221 eclass = ExprClass.Value;
5224 // SRE returns a match for .ctor () on structs (the object constructor),
5225 // so we have to manually ignore it.
5227 if (is_struct && Arguments == null)
5230 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5231 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5232 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5237 MethodGroupExpr mg = ml as MethodGroupExpr;
5240 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5244 if (Arguments != null){
5245 foreach (Argument a in Arguments){
5246 if (!a.Resolve (ec, loc))
5251 method = mg.OverloadResolve (ec, Arguments, false, loc);
5252 if (method == null) {
5253 if (almostMatchedMembers.Count != 0)
5254 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5261 bool DoEmitTypeParameter (EmitContext ec)
5264 ILGenerator ig = ec.ig;
5265 // IMemoryLocation ml;
5267 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5268 new Type [] { type });
5270 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5271 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5272 ig.Emit (OpCodes.Call, ci);
5276 // Allow DoEmit() to be called multiple times.
5277 // We need to create a new LocalTemporary each time since
5278 // you can't share LocalBuilders among ILGeneators.
5279 LocalTemporary temp = new LocalTemporary (type);
5281 Label label_activator = ig.DefineLabel ();
5282 Label label_end = ig.DefineLabel ();
5284 temp.AddressOf (ec, AddressOp.Store);
5285 ig.Emit (OpCodes.Initobj, type);
5288 ig.Emit (OpCodes.Box, type);
5289 ig.Emit (OpCodes.Brfalse, label_activator);
5291 temp.AddressOf (ec, AddressOp.Store);
5292 ig.Emit (OpCodes.Initobj, type);
5294 ig.Emit (OpCodes.Br, label_end);
5296 ig.MarkLabel (label_activator);
5298 ig.Emit (OpCodes.Call, ci);
5299 ig.MarkLabel (label_end);
5302 throw new InternalErrorException ();
5307 // This DoEmit can be invoked in two contexts:
5308 // * As a mechanism that will leave a value on the stack (new object)
5309 // * As one that wont (init struct)
5311 // You can control whether a value is required on the stack by passing
5312 // need_value_on_stack. The code *might* leave a value on the stack
5313 // so it must be popped manually
5315 // If we are dealing with a ValueType, we have a few
5316 // situations to deal with:
5318 // * The target is a ValueType, and we have been provided
5319 // the instance (this is easy, we are being assigned).
5321 // * The target of New is being passed as an argument,
5322 // to a boxing operation or a function that takes a
5325 // In this case, we need to create a temporary variable
5326 // that is the argument of New.
5328 // Returns whether a value is left on the stack
5330 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5332 bool is_value_type = TypeManager.IsValueType (type);
5333 ILGenerator ig = ec.ig;
5338 // Allow DoEmit() to be called multiple times.
5339 // We need to create a new LocalTemporary each time since
5340 // you can't share LocalBuilders among ILGeneators.
5341 if (!value_target_set)
5342 value_target = new LocalTemporary (type);
5344 ml = (IMemoryLocation) value_target;
5345 ml.AddressOf (ec, AddressOp.Store);
5349 Invocation.EmitArguments (ec, method, Arguments, false, null);
5353 ig.Emit (OpCodes.Initobj, type);
5355 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5356 if (need_value_on_stack){
5357 value_target.Emit (ec);
5362 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5367 public override void Emit (EmitContext ec)
5369 if (is_type_parameter)
5370 DoEmitTypeParameter (ec);
5375 public override void EmitStatement (EmitContext ec)
5377 bool value_on_stack;
5379 if (is_type_parameter)
5380 value_on_stack = DoEmitTypeParameter (ec);
5382 value_on_stack = DoEmit (ec, false);
5385 ec.ig.Emit (OpCodes.Pop);
5389 public void AddressOf (EmitContext ec, AddressOp Mode)
5391 if (is_type_parameter) {
5392 LocalTemporary temp = new LocalTemporary (type);
5393 DoEmitTypeParameter (ec);
5395 temp.AddressOf (ec, Mode);
5399 if (!type.IsValueType){
5401 // We throw an exception. So far, I believe we only need to support
5403 // foreach (int j in new StructType ())
5406 throw new Exception ("AddressOf should not be used for classes");
5409 if (!value_target_set)
5410 value_target = new LocalTemporary (type);
5411 IMemoryLocation ml = (IMemoryLocation) value_target;
5413 ml.AddressOf (ec, AddressOp.Store);
5415 Invocation.EmitArguments (ec, method, Arguments, false, null);
5418 ec.ig.Emit (OpCodes.Initobj, type);
5420 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5422 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5425 protected override void CloneTo (CloneContext clonectx, Expression t)
5427 New target = (New) t;
5429 target.RequestedType = RequestedType.Clone (clonectx);
5430 if (Arguments != null){
5431 target.Arguments = new ArrayList ();
5432 foreach (Argument a in Arguments){
5433 target.Arguments.Add (a.Clone (clonectx));
5440 /// 14.5.10.2: Represents an array creation expression.
5444 /// There are two possible scenarios here: one is an array creation
5445 /// expression that specifies the dimensions and optionally the
5446 /// initialization data and the other which does not need dimensions
5447 /// specified but where initialization data is mandatory.
5449 public class ArrayCreation : Expression {
5450 Expression requested_base_type;
5451 ArrayList initializers;
5454 // The list of Argument types.
5455 // This is used to construct the `newarray' or constructor signature
5457 ArrayList arguments;
5460 // Method used to create the array object.
5462 MethodBase new_method = null;
5464 Type array_element_type;
5465 Type underlying_type;
5466 bool is_one_dimensional = false;
5467 bool is_builtin_type = false;
5468 bool expect_initializers = false;
5469 int num_arguments = 0;
5473 ArrayList array_data;
5477 // The number of constants in array initializers
5478 int const_initializers_count;
5479 bool only_constant_initializers;
5481 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5483 this.requested_base_type = requested_base_type;
5484 this.initializers = initializers;
5488 arguments = new ArrayList ();
5490 foreach (Expression e in exprs) {
5491 arguments.Add (new Argument (e, Argument.AType.Expression));
5496 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5498 this.requested_base_type = requested_base_type;
5499 this.initializers = initializers;
5503 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5505 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5507 //dimensions = tmp.Length - 1;
5508 expect_initializers = true;
5511 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5513 StringBuilder sb = new StringBuilder (rank);
5516 for (int i = 1; i < idx_count; i++)
5521 return new ComposedCast (base_type, sb.ToString (), loc);
5524 void Error_IncorrectArrayInitializer ()
5526 Error (178, "Invalid rank specifier: expected `,' or `]'");
5529 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5531 if (specified_dims) {
5532 Argument a = (Argument) arguments [idx];
5534 if (!a.Resolve (ec, loc))
5537 Constant c = a.Expr as Constant;
5539 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5543 Report.Error (150, a.Expr.Location, "A constant value is expected");
5547 int value = (int) c.GetValue ();
5549 if (value != probe.Count) {
5550 Error_IncorrectArrayInitializer ();
5554 bounds [idx] = value;
5557 int child_bounds = -1;
5558 only_constant_initializers = true;
5559 for (int i = 0; i < probe.Count; ++i) {
5560 object o = probe [i];
5561 if (o is ArrayList) {
5562 ArrayList sub_probe = o as ArrayList;
5563 int current_bounds = sub_probe.Count;
5565 if (child_bounds == -1)
5566 child_bounds = current_bounds;
5568 else if (child_bounds != current_bounds){
5569 Error_IncorrectArrayInitializer ();
5572 if (idx + 1 >= dimensions){
5573 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5577 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5581 if (child_bounds != -1){
5582 Error_IncorrectArrayInitializer ();
5586 Expression tmp = (Expression) o;
5587 tmp = tmp.Resolve (ec);
5591 Expression conv = Convert.ImplicitConversionRequired (
5592 ec, tmp, underlying_type, loc);
5597 // Initializers with the default values can be ignored
5598 Constant c = conv as Constant;
5600 if (c.IsDefaultInitializer (array_element_type)) {
5604 ++const_initializers_count;
5607 only_constant_initializers = false;
5610 array_data.Add (conv);
5617 public void UpdateIndices ()
5620 for (ArrayList probe = initializers; probe != null;) {
5621 if (probe.Count > 0 && probe [0] is ArrayList) {
5622 Expression e = new IntConstant (probe.Count, Location.Null);
5623 arguments.Add (new Argument (e, Argument.AType.Expression));
5625 bounds [i++] = probe.Count;
5627 probe = (ArrayList) probe [0];
5630 Expression e = new IntConstant (probe.Count, Location.Null);
5631 arguments.Add (new Argument (e, Argument.AType.Expression));
5633 bounds [i++] = probe.Count;
5640 bool ResolveInitializers (EmitContext ec)
5642 if (initializers == null) {
5643 return !expect_initializers;
5646 if (underlying_type == null)
5650 // We use this to store all the date values in the order in which we
5651 // will need to store them in the byte blob later
5653 array_data = new ArrayList ();
5654 bounds = new System.Collections.Specialized.HybridDictionary ();
5656 if (arguments != null)
5657 return CheckIndices (ec, initializers, 0, true);
5659 arguments = new ArrayList ();
5661 if (!CheckIndices (ec, initializers, 0, false))
5666 if (arguments.Count != dimensions) {
5667 Error_IncorrectArrayInitializer ();
5675 // Creates the type of the array
5677 bool LookupType (EmitContext ec)
5679 StringBuilder array_qualifier = new StringBuilder (rank);
5682 // `In the first form allocates an array instace of the type that results
5683 // from deleting each of the individual expression from the expression list'
5685 if (num_arguments > 0) {
5686 array_qualifier.Append ("[");
5687 for (int i = num_arguments-1; i > 0; i--)
5688 array_qualifier.Append (",");
5689 array_qualifier.Append ("]");
5695 TypeExpr array_type_expr;
5696 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5697 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5698 if (array_type_expr == null)
5701 type = array_type_expr.Type;
5702 underlying_type = TypeManager.GetElementType (type);
5703 dimensions = type.GetArrayRank ();
5708 public override Expression DoResolve (EmitContext ec)
5713 if (requested_base_type is VarExpr) {
5714 if (initializers == null || initializers.Count == 0) {
5715 Console.WriteLine ("Initializers required"); // FIXME proper error
5718 Expression e = ((Expression)initializers[0]).Resolve (ec);
5720 return null; // FIXME proper error
5721 requested_base_type = new TypeExpression (e.Type, loc);
5724 if (!LookupType (ec))
5727 array_element_type = TypeManager.GetElementType (type);
5728 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
5729 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
5734 // First step is to validate the initializers and fill
5735 // in any missing bits
5737 if (!ResolveInitializers (ec))
5741 if (arguments == null)
5744 arg_count = arguments.Count;
5745 foreach (Argument a in arguments){
5746 if (!a.Resolve (ec, loc))
5749 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5750 if (real_arg == null)
5757 if (arg_count == 1) {
5758 is_one_dimensional = true;
5759 eclass = ExprClass.Value;
5763 is_builtin_type = TypeManager.IsBuiltinType (type);
5765 if (is_builtin_type) {
5768 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
5769 AllBindingFlags, loc);
5771 if (!(ml is MethodGroupExpr)) {
5772 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5777 Error (-6, "New invocation: Can not find a constructor for " +
5778 "this argument list");
5782 new_method = ((MethodGroupExpr) ml).OverloadResolve (
5783 ec, arguments, false, loc);
5785 if (new_method == null) {
5786 Error (-6, "New invocation: Can not find a constructor for " +
5787 "this argument list");
5791 eclass = ExprClass.Value;
5794 ModuleBuilder mb = CodeGen.Module.Builder;
5795 ArrayList args = new ArrayList ();
5797 if (arguments != null) {
5798 for (int i = 0; i < arg_count; i++)
5799 args.Add (TypeManager.int32_type);
5802 Type [] arg_types = null;
5805 arg_types = new Type [args.Count];
5807 args.CopyTo (arg_types, 0);
5809 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5812 if (new_method == null) {
5813 Error (-6, "New invocation: Can not find a constructor for " +
5814 "this argument list");
5818 eclass = ExprClass.Value;
5823 byte [] MakeByteBlob ()
5828 int count = array_data.Count;
5830 if (underlying_type.IsEnum)
5831 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5833 factor = GetTypeSize (underlying_type);
5835 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5837 data = new byte [(count * factor + 4) & ~3];
5840 for (int i = 0; i < count; ++i) {
5841 object v = array_data [i];
5843 if (v is EnumConstant)
5844 v = ((EnumConstant) v).Child;
5846 if (v is Constant && !(v is StringConstant))
5847 v = ((Constant) v).GetValue ();
5853 if (underlying_type == TypeManager.int64_type){
5854 if (!(v is Expression)){
5855 long val = (long) v;
5857 for (int j = 0; j < factor; ++j) {
5858 data [idx + j] = (byte) (val & 0xFF);
5862 } else if (underlying_type == TypeManager.uint64_type){
5863 if (!(v is Expression)){
5864 ulong val = (ulong) v;
5866 for (int j = 0; j < factor; ++j) {
5867 data [idx + j] = (byte) (val & 0xFF);
5871 } else if (underlying_type == TypeManager.float_type) {
5872 if (!(v is Expression)){
5873 element = BitConverter.GetBytes ((float) v);
5875 for (int j = 0; j < factor; ++j)
5876 data [idx + j] = element [j];
5877 if (!BitConverter.IsLittleEndian)
5878 System.Array.Reverse (data, idx, 4);
5880 } else if (underlying_type == TypeManager.double_type) {
5881 if (!(v is Expression)){
5882 element = BitConverter.GetBytes ((double) v);
5884 for (int j = 0; j < factor; ++j)
5885 data [idx + j] = element [j];
5887 // FIXME: Handle the ARM float format.
5888 if (!BitConverter.IsLittleEndian)
5889 System.Array.Reverse (data, idx, 8);
5891 } else if (underlying_type == TypeManager.char_type){
5892 if (!(v is Expression)){
5893 int val = (int) ((char) v);
5895 data [idx] = (byte) (val & 0xff);
5896 data [idx+1] = (byte) (val >> 8);
5898 } else if (underlying_type == TypeManager.short_type){
5899 if (!(v is Expression)){
5900 int val = (int) ((short) v);
5902 data [idx] = (byte) (val & 0xff);
5903 data [idx+1] = (byte) (val >> 8);
5905 } else if (underlying_type == TypeManager.ushort_type){
5906 if (!(v is Expression)){
5907 int val = (int) ((ushort) v);
5909 data [idx] = (byte) (val & 0xff);
5910 data [idx+1] = (byte) (val >> 8);
5912 } else if (underlying_type == TypeManager.int32_type) {
5913 if (!(v is Expression)){
5916 data [idx] = (byte) (val & 0xff);
5917 data [idx+1] = (byte) ((val >> 8) & 0xff);
5918 data [idx+2] = (byte) ((val >> 16) & 0xff);
5919 data [idx+3] = (byte) (val >> 24);
5921 } else if (underlying_type == TypeManager.uint32_type) {
5922 if (!(v is Expression)){
5923 uint val = (uint) v;
5925 data [idx] = (byte) (val & 0xff);
5926 data [idx+1] = (byte) ((val >> 8) & 0xff);
5927 data [idx+2] = (byte) ((val >> 16) & 0xff);
5928 data [idx+3] = (byte) (val >> 24);
5930 } else if (underlying_type == TypeManager.sbyte_type) {
5931 if (!(v is Expression)){
5932 sbyte val = (sbyte) v;
5933 data [idx] = (byte) val;
5935 } else if (underlying_type == TypeManager.byte_type) {
5936 if (!(v is Expression)){
5937 byte val = (byte) v;
5938 data [idx] = (byte) val;
5940 } else if (underlying_type == TypeManager.bool_type) {
5941 if (!(v is Expression)){
5942 bool val = (bool) v;
5943 data [idx] = (byte) (val ? 1 : 0);
5945 } else if (underlying_type == TypeManager.decimal_type){
5946 if (!(v is Expression)){
5947 int [] bits = Decimal.GetBits ((decimal) v);
5950 // FIXME: For some reason, this doesn't work on the MS runtime.
5951 int [] nbits = new int [4];
5952 nbits [0] = bits [3];
5953 nbits [1] = bits [2];
5954 nbits [2] = bits [0];
5955 nbits [3] = bits [1];
5957 for (int j = 0; j < 4; j++){
5958 data [p++] = (byte) (nbits [j] & 0xff);
5959 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5960 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5961 data [p++] = (byte) (nbits [j] >> 24);
5965 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5974 // Emits the initializers for the array
5976 void EmitStaticInitializers (EmitContext ec)
5979 // First, the static data
5982 ILGenerator ig = ec.ig;
5984 byte [] data = MakeByteBlob ();
5986 fb = RootContext.MakeStaticData (data);
5988 ig.Emit (OpCodes.Dup);
5989 ig.Emit (OpCodes.Ldtoken, fb);
5990 ig.Emit (OpCodes.Call,
5991 TypeManager.void_initializearray_array_fieldhandle);
5995 // Emits pieces of the array that can not be computed at compile
5996 // time (variables and string locations).
5998 // This always expect the top value on the stack to be the array
6000 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6002 ILGenerator ig = ec.ig;
6003 int dims = bounds.Count;
6004 int [] current_pos = new int [dims];
6006 MethodInfo set = null;
6009 Type [] args = new Type [dims + 1];
6011 for (int j = 0; j < dims; j++)
6012 args [j] = TypeManager.int32_type;
6013 args [dims] = array_element_type;
6015 set = CodeGen.Module.Builder.GetArrayMethod (
6017 CallingConventions.HasThis | CallingConventions.Standard,
6018 TypeManager.void_type, args);
6021 for (int i = 0; i < array_data.Count; i++){
6023 Expression e = (Expression)array_data [i];
6025 // Constant can be initialized via StaticInitializer
6026 if (e != null && !(!emitConstants && e is Constant)) {
6027 Type etype = e.Type;
6029 ig.Emit (OpCodes.Dup);
6031 for (int idx = 0; idx < dims; idx++)
6032 IntConstant.EmitInt (ig, current_pos [idx]);
6035 // If we are dealing with a struct, get the
6036 // address of it, so we can store it.
6038 if ((dims == 1) && etype.IsValueType &&
6039 (!TypeManager.IsBuiltinOrEnum (etype) ||
6040 etype == TypeManager.decimal_type)) {
6045 // Let new know that we are providing
6046 // the address where to store the results
6048 n.DisableTemporaryValueType ();
6051 ig.Emit (OpCodes.Ldelema, etype);
6057 bool is_stobj, has_type_arg;
6058 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6060 ig.Emit (OpCodes.Stobj, etype);
6061 else if (has_type_arg)
6062 ig.Emit (op, etype);
6066 ig.Emit (OpCodes.Call, set);
6073 for (int j = dims - 1; j >= 0; j--){
6075 if (current_pos [j] < (int) bounds [j])
6077 current_pos [j] = 0;
6082 void EmitArrayArguments (EmitContext ec)
6084 ILGenerator ig = ec.ig;
6086 foreach (Argument a in arguments) {
6087 Type atype = a.Type;
6090 if (atype == TypeManager.uint64_type)
6091 ig.Emit (OpCodes.Conv_Ovf_U4);
6092 else if (atype == TypeManager.int64_type)
6093 ig.Emit (OpCodes.Conv_Ovf_I4);
6097 public override void Emit (EmitContext ec)
6099 ILGenerator ig = ec.ig;
6101 EmitArrayArguments (ec);
6102 if (is_one_dimensional)
6103 ig.Emit (OpCodes.Newarr, array_element_type);
6105 if (is_builtin_type)
6106 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6108 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6111 if (initializers == null)
6114 // Emit static initializer for arrays which have contain more than 4 items and
6115 // the static initializer will initialize at least 25% of array values.
6116 // NOTE: const_initializers_count does not contain default constant values.
6117 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6118 TypeManager.IsPrimitiveType (array_element_type)) {
6119 EmitStaticInitializers (ec);
6121 if (!only_constant_initializers)
6122 EmitDynamicInitializers (ec, false);
6124 EmitDynamicInitializers (ec, true);
6128 public override bool GetAttributableValue (Type valueType, out object value)
6130 if (!is_one_dimensional){
6131 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6132 return base.GetAttributableValue (null, out value);
6135 if (array_data == null) {
6136 Constant c = (Constant)((Argument)arguments [0]).Expr;
6137 if (c.IsDefaultValue) {
6138 value = Array.CreateInstance (array_element_type, 0);
6141 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6142 return base.GetAttributableValue (null, out value);
6145 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6146 object element_value;
6147 for (int i = 0; i < ret.Length; ++i)
6149 Expression e = (Expression)array_data [i];
6151 // Is null when an initializer is optimized (value == predefined value)
6155 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6159 ret.SetValue (element_value, i);
6165 protected override void CloneTo (CloneContext clonectx, Expression t)
6167 ArrayCreation target = (ArrayCreation) t;
6169 target.requested_base_type = requested_base_type.Clone (clonectx);
6170 target.arguments = new ArrayList ();
6171 foreach (Argument a in arguments)
6172 target.arguments.Add (a.Clone (clonectx));
6174 if (initializers != null){
6175 target.initializers = new ArrayList ();
6176 foreach (Expression initializer in initializers)
6177 target.initializers.Add (initializer.Clone (clonectx));
6182 public sealed class CompilerGeneratedThis : This
6184 public static This Instance = new CompilerGeneratedThis ();
6186 private CompilerGeneratedThis ()
6187 : base (Location.Null)
6191 public override Expression DoResolve (EmitContext ec)
6193 eclass = ExprClass.Variable;
6194 type = ec.ContainerType;
6195 variable = new SimpleThis (type);
6201 /// Represents the `this' construct
6204 public class This : VariableReference, IVariable
6207 VariableInfo variable_info;
6208 protected Variable variable;
6211 public This (Block block, Location loc)
6217 public This (Location loc)
6222 public VariableInfo VariableInfo {
6223 get { return variable_info; }
6226 public bool VerifyFixed ()
6228 return !TypeManager.IsValueType (Type);
6231 public override bool IsRef {
6232 get { return is_struct; }
6235 public override Variable Variable {
6236 get { return variable; }
6239 public bool ResolveBase (EmitContext ec)
6241 eclass = ExprClass.Variable;
6243 if (ec.TypeContainer.CurrentType != null)
6244 type = ec.TypeContainer.CurrentType;
6246 type = ec.ContainerType;
6248 is_struct = ec.TypeContainer is Struct;
6251 Error (26, "Keyword `this' is not valid in a static property, " +
6252 "static method, or static field initializer");
6256 if (block != null) {
6257 if (block.Toplevel.ThisVariable != null)
6258 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6260 AnonymousContainer am = ec.CurrentAnonymousMethod;
6261 if (is_struct && (am != null) && !am.IsIterator) {
6262 Report.Error (1673, loc, "Anonymous methods inside structs " +
6263 "cannot access instance members of `this'. " +
6264 "Consider copying `this' to a local variable " +
6265 "outside the anonymous method and using the " +
6270 RootScopeInfo host = block.Toplevel.RootScope;
6271 if ((host != null) && !ec.IsConstructor &&
6272 (!is_struct || host.IsIterator)) {
6273 variable = host.CaptureThis ();
6274 type = variable.Type;
6279 if (variable == null)
6280 variable = new SimpleThis (type);
6286 // Called from Invocation to check if the invocation is correct
6288 public bool CheckThisUsage (EmitContext ec)
6290 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6291 !variable_info.IsAssigned (ec)) {
6292 Error (188, "The `this' object cannot be used before all of its " +
6293 "fields are assigned to");
6294 variable_info.SetAssigned (ec);
6301 public override Expression DoResolve (EmitContext ec)
6303 if (!ResolveBase (ec))
6307 if (ec.IsFieldInitializer) {
6308 Error (27, "Keyword `this' is not available in the current context");
6315 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6317 if (!ResolveBase (ec))
6320 if (variable_info != null)
6321 variable_info.SetAssigned (ec);
6323 if (ec.TypeContainer is Class){
6324 Error (1604, "Cannot assign to 'this' because it is read-only");
6330 public override int GetHashCode()
6332 return block.GetHashCode ();
6335 public override bool Equals (object obj)
6337 This t = obj as This;
6341 return block == t.block;
6344 protected class SimpleThis : Variable
6348 public SimpleThis (Type type)
6353 public override Type Type {
6354 get { return type; }
6357 public override bool HasInstance {
6358 get { return false; }
6361 public override bool NeedsTemporary {
6362 get { return false; }
6365 public override void EmitInstance (EmitContext ec)
6370 public override void Emit (EmitContext ec)
6372 ec.ig.Emit (OpCodes.Ldarg_0);
6375 public override void EmitAssign (EmitContext ec)
6377 throw new InvalidOperationException ();
6380 public override void EmitAddressOf (EmitContext ec)
6382 ec.ig.Emit (OpCodes.Ldarg_0);
6386 protected override void CloneTo (CloneContext clonectx, Expression t)
6388 This target = (This) t;
6390 target.block = clonectx.LookupBlock (block);
6395 /// Represents the `__arglist' construct
6397 public class ArglistAccess : Expression
6399 public ArglistAccess (Location loc)
6404 public override Expression DoResolve (EmitContext ec)
6406 eclass = ExprClass.Variable;
6407 type = TypeManager.runtime_argument_handle_type;
6409 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6411 Error (190, "The __arglist construct is valid only within " +
6412 "a variable argument method");
6419 public override void Emit (EmitContext ec)
6421 ec.ig.Emit (OpCodes.Arglist);
6424 protected override void CloneTo (CloneContext clonectx, Expression target)
6431 /// Represents the `__arglist (....)' construct
6433 public class Arglist : Expression
6435 public Argument[] Arguments;
6437 public Arglist (Location loc)
6438 : this (Argument.Empty, loc)
6442 public Arglist (Argument[] args, Location l)
6448 public Type[] ArgumentTypes {
6450 Type[] retval = new Type [Arguments.Length];
6451 for (int i = 0; i < Arguments.Length; i++)
6452 retval [i] = Arguments [i].Type;
6457 public override Expression DoResolve (EmitContext ec)
6459 eclass = ExprClass.Variable;
6460 type = TypeManager.runtime_argument_handle_type;
6462 foreach (Argument arg in Arguments) {
6463 if (!arg.Resolve (ec, loc))
6470 public override void Emit (EmitContext ec)
6472 foreach (Argument arg in Arguments)
6476 protected override void CloneTo (CloneContext clonectx, Expression t)
6478 Arglist target = (Arglist) t;
6480 target.Arguments = new Argument [Arguments.Length];
6481 for (int i = 0; i < Arguments.Length; i++)
6482 target.Arguments [i] = Arguments [i].Clone (clonectx);
6487 // This produces the value that renders an instance, used by the iterators code
6489 public class ProxyInstance : Expression, IMemoryLocation {
6490 public override Expression DoResolve (EmitContext ec)
6492 eclass = ExprClass.Variable;
6493 type = ec.ContainerType;
6497 public override void Emit (EmitContext ec)
6499 ec.ig.Emit (OpCodes.Ldarg_0);
6503 public void AddressOf (EmitContext ec, AddressOp mode)
6505 ec.ig.Emit (OpCodes.Ldarg_0);
6510 /// Implements the typeof operator
6512 public class TypeOf : Expression {
6513 Expression QueriedType;
6514 protected Type typearg;
6516 public TypeOf (Expression queried_type, Location l)
6518 QueriedType = queried_type;
6522 public override Expression DoResolve (EmitContext ec)
6524 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6528 typearg = texpr.Type;
6530 if (typearg == TypeManager.void_type) {
6531 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6535 if (typearg.IsPointer && !ec.InUnsafe){
6540 type = TypeManager.type_type;
6541 // Even though what is returned is a type object, it's treated as a value by the compiler.
6542 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6543 eclass = ExprClass.Value;
6547 public override void Emit (EmitContext ec)
6549 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6550 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6553 public override bool GetAttributableValue (Type valueType, out object value)
6555 if (TypeManager.ContainsGenericParameters (typearg)) {
6556 Report.SymbolRelatedToPreviousError(typearg);
6557 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6558 TypeManager.CSharpName(typearg));
6563 if (valueType == TypeManager.object_type) {
6564 value = (object)typearg;
6571 public Type TypeArgument
6579 protected override void CloneTo (CloneContext clonectx, Expression t)
6581 TypeOf target = (TypeOf) t;
6583 target.QueriedType = QueriedType.Clone (clonectx);
6588 /// Implements the `typeof (void)' operator
6590 public class TypeOfVoid : TypeOf {
6591 public TypeOfVoid (Location l) : base (null, l)
6596 public override Expression DoResolve (EmitContext ec)
6598 type = TypeManager.type_type;
6599 typearg = TypeManager.void_type;
6600 // See description in TypeOf.
6601 eclass = ExprClass.Value;
6607 /// Implements the sizeof expression
6609 public class SizeOf : Expression {
6610 public Expression QueriedType;
6613 public SizeOf (Expression queried_type, Location l)
6615 this.QueriedType = queried_type;
6619 public override Expression DoResolve (EmitContext ec)
6621 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6626 if (texpr is TypeParameterExpr){
6627 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6632 type_queried = texpr.Type;
6633 if (type_queried.IsEnum)
6634 type_queried = TypeManager.EnumToUnderlying (type_queried);
6636 if (type_queried == TypeManager.void_type) {
6637 Expression.Error_VoidInvalidInTheContext (loc);
6641 int size_of = GetTypeSize (type_queried);
6643 return new IntConstant (size_of, loc);
6647 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)",
6648 TypeManager.CSharpName (type_queried));
6652 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6656 type = TypeManager.int32_type;
6657 eclass = ExprClass.Value;
6661 public override void Emit (EmitContext ec)
6663 int size = GetTypeSize (type_queried);
6666 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6668 IntConstant.EmitInt (ec.ig, size);
6671 protected override void CloneTo (CloneContext clonectx, Expression t)
6673 SizeOf target = (SizeOf) t;
6675 target.QueriedType = QueriedType.Clone (clonectx);
6680 /// Implements the qualified-alias-member (::) expression.
6682 public class QualifiedAliasMember : Expression
6684 string alias, identifier;
6686 public QualifiedAliasMember (string alias, string identifier, Location l)
6689 this.identifier = identifier;
6693 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6695 if (alias == "global")
6696 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6698 int errors = Report.Errors;
6699 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6701 if (errors == Report.Errors)
6702 Report.Error (432, loc, "Alias `{0}' not found", alias);
6705 if (fne.eclass != ExprClass.Namespace) {
6707 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6710 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6713 public override Expression DoResolve (EmitContext ec)
6715 FullNamedExpression fne;
6716 if (alias == "global") {
6717 fne = RootNamespace.Global;
6719 int errors = Report.Errors;
6720 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6722 if (errors == Report.Errors)
6723 Report.Error (432, loc, "Alias `{0}' not found", alias);
6728 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6732 if (!(retval is FullNamedExpression)) {
6733 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6737 // We defer this check till the end to match the behaviour of CSC
6738 if (fne.eclass != ExprClass.Namespace) {
6739 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6745 public override void Emit (EmitContext ec)
6747 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6751 public override string ToString ()
6753 return alias + "::" + identifier;
6756 public override string GetSignatureForError ()
6761 protected override void CloneTo (CloneContext clonectx, Expression t)
6768 /// Implements the member access expression
6770 public class MemberAccess : Expression {
6771 public readonly string Identifier;
6774 public MemberAccess (Expression expr, string id)
6775 : this (expr, id, expr.Location)
6779 public MemberAccess (Expression expr, string identifier, Location loc)
6782 Identifier = identifier;
6786 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6787 : this (expr, identifier, loc)
6794 public Expression Expr {
6795 get { return expr; }
6798 protected string LookupIdentifier {
6799 get { return MemberName.MakeName (Identifier, args); }
6802 // TODO: this method has very poor performace for Enum fields and
6803 // probably for other constants as well
6804 Expression DoResolve (EmitContext ec, Expression right_side)
6807 throw new Exception ();
6810 // Resolve the expression with flow analysis turned off, we'll do the definite
6811 // assignment checks later. This is because we don't know yet what the expression
6812 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6813 // definite assignment check on the actual field and not on the whole struct.
6816 SimpleName original = expr as SimpleName;
6817 expr = expr.Resolve (ec,
6818 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6819 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6824 if (expr is Namespace) {
6825 Namespace ns = (Namespace) expr;
6826 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6828 if ((retval != null) && (args != null))
6829 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6833 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6837 Type expr_type = expr.Type;
6838 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr is NullLiteral){
6839 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6842 if (expr_type == TypeManager.anonymous_method_type){
6843 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6847 Constant c = expr as Constant;
6848 if (c != null && c.GetValue () == null) {
6849 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6850 "System.NullReferenceException");
6853 Expression member_lookup;
6854 member_lookup = MemberLookup (
6855 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6857 if ((member_lookup == null) && (args != null)) {
6858 member_lookup = MemberLookup (
6859 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6862 if (member_lookup == null) {
6863 member_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6864 if (member_lookup != null)
6865 return member_lookup.DoResolve (ec);
6867 MemberLookupFailed (
6868 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6872 TypeExpr texpr = member_lookup as TypeExpr;
6873 if (texpr != null) {
6874 if (!(expr is TypeExpr) &&
6875 (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) {
6876 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6877 Identifier, member_lookup.GetSignatureForError ());
6881 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6882 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6883 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6888 ConstructedType ct = expr as ConstructedType;
6891 // When looking up a nested type in a generic instance
6892 // via reflection, we always get a generic type definition
6893 // and not a generic instance - so we have to do this here.
6895 // See gtest-172-lib.cs and gtest-172.cs for an example.
6897 ct = new ConstructedType (
6898 member_lookup.Type, ct.TypeArguments, loc);
6900 return ct.ResolveAsTypeStep (ec, false);
6903 return member_lookup;
6906 MemberExpr me = (MemberExpr) member_lookup;
6907 member_lookup = me.ResolveMemberAccess (ec, expr, loc, original);
6908 if (member_lookup == null)
6912 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6914 throw new InternalErrorException ();
6916 return mg.ResolveGeneric (ec, args);
6919 if (original != null && !TypeManager.IsValueType (expr_type)) {
6920 me = member_lookup as MemberExpr;
6921 if (me != null && me.IsInstance) {
6922 LocalVariableReference var = expr as LocalVariableReference;
6923 if (var != null && !var.VerifyAssigned (ec))
6928 // The following DoResolve/DoResolveLValue will do the definite assignment
6931 if (right_side != null)
6932 return member_lookup.DoResolveLValue (ec, right_side);
6934 return member_lookup.DoResolve (ec);
6937 public override Expression DoResolve (EmitContext ec)
6939 return DoResolve (ec, null);
6942 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6944 return DoResolve (ec, right_side);
6947 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6949 return ResolveNamespaceOrType (ec, silent);
6952 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6954 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6956 if (new_expr == null)
6959 if (new_expr is Namespace) {
6960 Namespace ns = (Namespace) new_expr;
6961 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6963 if ((retval != null) && (args != null))
6964 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6966 if (!silent && retval == null)
6967 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6971 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6972 if (tnew_expr == null)
6975 Type expr_type = tnew_expr.Type;
6977 if (expr_type.IsPointer){
6978 Error (23, "The `.' operator can not be applied to pointer operands (" +
6979 TypeManager.CSharpName (expr_type) + ")");
6983 Expression member_lookup = MemberLookup (
6984 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6985 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6986 if (member_lookup == null) {
6990 member_lookup = MemberLookup(
6991 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6992 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6994 if (member_lookup == null) {
6995 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6996 Identifier, new_expr.GetSignatureForError ());
6998 // TODO: Report.SymbolRelatedToPreviousError
6999 member_lookup.Error_UnexpectedKind (null, "type", loc);
7004 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7009 TypeArguments the_args = args;
7010 if (TypeManager.HasGenericArguments (expr_type)) {
7011 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7013 TypeArguments new_args = new TypeArguments (loc);
7014 foreach (Type decl in decl_args)
7015 new_args.Add (new TypeExpression (decl, loc));
7018 new_args.Add (args);
7020 the_args = new_args;
7023 if (the_args != null) {
7024 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7025 return ctype.ResolveAsTypeStep (rc, false);
7032 public override void Emit (EmitContext ec)
7034 throw new Exception ("Should not happen");
7037 public override string ToString ()
7039 return expr + "." + MemberName.MakeName (Identifier, args);
7042 public override string GetSignatureForError ()
7044 return expr.GetSignatureForError () + "." + Identifier;
7047 protected override void CloneTo (CloneContext clonectx, Expression t)
7049 MemberAccess target = (MemberAccess) t;
7051 target.expr = expr.Clone (clonectx);
7056 /// Implements checked expressions
7058 public class CheckedExpr : Expression {
7060 public Expression Expr;
7062 public CheckedExpr (Expression e, Location l)
7068 public override Expression DoResolve (EmitContext ec)
7070 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7071 Expr = Expr.Resolve (ec);
7076 if (Expr is Constant)
7079 eclass = Expr.eclass;
7084 public override void Emit (EmitContext ec)
7086 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7090 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7092 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7093 Expr.EmitBranchable (ec, target, onTrue);
7096 protected override void CloneTo (CloneContext clonectx, Expression t)
7098 CheckedExpr target = (CheckedExpr) t;
7100 target.Expr = Expr.Clone (clonectx);
7105 /// Implements the unchecked expression
7107 public class UnCheckedExpr : Expression {
7109 public Expression Expr;
7111 public UnCheckedExpr (Expression e, Location l)
7117 public override Expression DoResolve (EmitContext ec)
7119 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7120 Expr = Expr.Resolve (ec);
7125 if (Expr is Constant)
7128 eclass = Expr.eclass;
7133 public override void Emit (EmitContext ec)
7135 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7139 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7141 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7142 Expr.EmitBranchable (ec, target, onTrue);
7145 protected override void CloneTo (CloneContext clonectx, Expression t)
7147 UnCheckedExpr target = (UnCheckedExpr) t;
7149 target.Expr = Expr.Clone (clonectx);
7154 /// An Element Access expression.
7156 /// During semantic analysis these are transformed into
7157 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7159 public class ElementAccess : Expression {
7160 public ArrayList Arguments;
7161 public Expression Expr;
7163 public ElementAccess (Expression e, ArrayList e_list)
7172 Arguments = new ArrayList ();
7173 foreach (Expression tmp in e_list)
7174 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7178 bool CommonResolve (EmitContext ec)
7180 Expr = Expr.Resolve (ec);
7185 if (Arguments == null)
7188 foreach (Argument a in Arguments){
7189 if (!a.Resolve (ec, loc))
7196 Expression MakePointerAccess (EmitContext ec, Type t)
7198 if (t == TypeManager.void_ptr_type){
7199 Error (242, "The array index operation is not valid on void pointers");
7202 if (Arguments.Count != 1){
7203 Error (196, "A pointer must be indexed by only one value");
7208 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7211 return new Indirection (p, loc).Resolve (ec);
7214 public override Expression DoResolve (EmitContext ec)
7216 if (!CommonResolve (ec))
7220 // We perform some simple tests, and then to "split" the emit and store
7221 // code we create an instance of a different class, and return that.
7223 // I am experimenting with this pattern.
7227 if (t == TypeManager.array_type){
7228 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7233 return (new ArrayAccess (this, loc)).Resolve (ec);
7235 return MakePointerAccess (ec, Expr.Type);
7237 FieldExpr fe = Expr as FieldExpr;
7239 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7241 return MakePointerAccess (ec, ff.ElementType);
7244 return (new IndexerAccess (this, loc)).Resolve (ec);
7247 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7249 if (!CommonResolve (ec))
7254 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7257 return MakePointerAccess (ec, Expr.Type);
7259 FieldExpr fe = Expr as FieldExpr;
7261 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7263 if (!(fe.InstanceExpression is LocalVariableReference) &&
7264 !(fe.InstanceExpression is This)) {
7265 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7268 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7269 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7272 return MakePointerAccess (ec, ff.ElementType);
7275 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7278 public override void Emit (EmitContext ec)
7280 throw new Exception ("Should never be reached");
7283 protected override void CloneTo (CloneContext clonectx, Expression t)
7285 ElementAccess target = (ElementAccess) t;
7287 target.Expr = Expr.Clone (clonectx);
7288 target.Arguments = new ArrayList ();
7289 foreach (Argument a in Arguments)
7290 target.Arguments.Add (a.Clone (clonectx));
7295 /// Implements array access
7297 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7299 // Points to our "data" repository
7303 LocalTemporary temp;
7306 public ArrayAccess (ElementAccess ea_data, Location l)
7309 eclass = ExprClass.Variable;
7313 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7315 return DoResolve (ec);
7318 public override Expression DoResolve (EmitContext ec)
7321 ExprClass eclass = ea.Expr.eclass;
7323 // As long as the type is valid
7324 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7325 eclass == ExprClass.Value)) {
7326 ea.Expr.Error_UnexpectedKind ("variable or value");
7331 Type t = ea.Expr.Type;
7332 if (t.GetArrayRank () != ea.Arguments.Count){
7333 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7334 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7338 type = TypeManager.GetElementType (t);
7339 if (type.IsPointer && !ec.InUnsafe){
7340 UnsafeError (ea.Location);
7344 foreach (Argument a in ea.Arguments){
7345 Type argtype = a.Type;
7347 if (argtype == TypeManager.int32_type ||
7348 argtype == TypeManager.uint32_type ||
7349 argtype == TypeManager.int64_type ||
7350 argtype == TypeManager.uint64_type) {
7351 Constant c = a.Expr as Constant;
7352 if (c != null && c.IsNegative) {
7353 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7359 // Mhm. This is strage, because the Argument.Type is not the same as
7360 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7362 // Wonder if I will run into trouble for this.
7364 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7369 eclass = ExprClass.Variable;
7375 /// Emits the right opcode to load an object of Type `t'
7376 /// from an array of T
7378 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7380 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7381 ig.Emit (OpCodes.Ldelem_U1);
7382 else if (type == TypeManager.sbyte_type)
7383 ig.Emit (OpCodes.Ldelem_I1);
7384 else if (type == TypeManager.short_type)
7385 ig.Emit (OpCodes.Ldelem_I2);
7386 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7387 ig.Emit (OpCodes.Ldelem_U2);
7388 else if (type == TypeManager.int32_type)
7389 ig.Emit (OpCodes.Ldelem_I4);
7390 else if (type == TypeManager.uint32_type)
7391 ig.Emit (OpCodes.Ldelem_U4);
7392 else if (type == TypeManager.uint64_type)
7393 ig.Emit (OpCodes.Ldelem_I8);
7394 else if (type == TypeManager.int64_type)
7395 ig.Emit (OpCodes.Ldelem_I8);
7396 else if (type == TypeManager.float_type)
7397 ig.Emit (OpCodes.Ldelem_R4);
7398 else if (type == TypeManager.double_type)
7399 ig.Emit (OpCodes.Ldelem_R8);
7400 else if (type == TypeManager.intptr_type)
7401 ig.Emit (OpCodes.Ldelem_I);
7402 else if (TypeManager.IsEnumType (type)){
7403 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7404 } else if (type.IsValueType){
7405 ig.Emit (OpCodes.Ldelema, type);
7406 ig.Emit (OpCodes.Ldobj, type);
7408 } else if (type.IsGenericParameter) {
7409 ig.Emit (OpCodes.Ldelem, type);
7411 } else if (type.IsPointer)
7412 ig.Emit (OpCodes.Ldelem_I);
7414 ig.Emit (OpCodes.Ldelem_Ref);
7418 /// Returns the right opcode to store an object of Type `t'
7419 /// from an array of T.
7421 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7423 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7424 has_type_arg = false; is_stobj = false;
7425 t = TypeManager.TypeToCoreType (t);
7426 if (TypeManager.IsEnumType (t))
7427 t = TypeManager.EnumToUnderlying (t);
7428 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7429 t == TypeManager.bool_type)
7430 return OpCodes.Stelem_I1;
7431 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7432 t == TypeManager.char_type)
7433 return OpCodes.Stelem_I2;
7434 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7435 return OpCodes.Stelem_I4;
7436 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7437 return OpCodes.Stelem_I8;
7438 else if (t == TypeManager.float_type)
7439 return OpCodes.Stelem_R4;
7440 else if (t == TypeManager.double_type)
7441 return OpCodes.Stelem_R8;
7442 else if (t == TypeManager.intptr_type) {
7443 has_type_arg = true;
7445 return OpCodes.Stobj;
7446 } else if (t.IsValueType) {
7447 has_type_arg = true;
7449 return OpCodes.Stobj;
7451 } else if (t.IsGenericParameter) {
7452 has_type_arg = true;
7453 return OpCodes.Stelem;
7456 } else if (t.IsPointer)
7457 return OpCodes.Stelem_I;
7459 return OpCodes.Stelem_Ref;
7462 MethodInfo FetchGetMethod ()
7464 ModuleBuilder mb = CodeGen.Module.Builder;
7465 int arg_count = ea.Arguments.Count;
7466 Type [] args = new Type [arg_count];
7469 for (int i = 0; i < arg_count; i++){
7470 //args [i++] = a.Type;
7471 args [i] = TypeManager.int32_type;
7474 get = mb.GetArrayMethod (
7475 ea.Expr.Type, "Get",
7476 CallingConventions.HasThis |
7477 CallingConventions.Standard,
7483 MethodInfo FetchAddressMethod ()
7485 ModuleBuilder mb = CodeGen.Module.Builder;
7486 int arg_count = ea.Arguments.Count;
7487 Type [] args = new Type [arg_count];
7491 ret_type = TypeManager.GetReferenceType (type);
7493 for (int i = 0; i < arg_count; i++){
7494 //args [i++] = a.Type;
7495 args [i] = TypeManager.int32_type;
7498 address = mb.GetArrayMethod (
7499 ea.Expr.Type, "Address",
7500 CallingConventions.HasThis |
7501 CallingConventions.Standard,
7508 // Load the array arguments into the stack.
7510 // If we have been requested to cache the values (cached_locations array
7511 // initialized), then load the arguments the first time and store them
7512 // in locals. otherwise load from local variables.
7514 void LoadArrayAndArguments (EmitContext ec)
7516 ILGenerator ig = ec.ig;
7519 foreach (Argument a in ea.Arguments){
7520 Type argtype = a.Expr.Type;
7524 if (argtype == TypeManager.int64_type)
7525 ig.Emit (OpCodes.Conv_Ovf_I);
7526 else if (argtype == TypeManager.uint64_type)
7527 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7531 public void Emit (EmitContext ec, bool leave_copy)
7533 int rank = ea.Expr.Type.GetArrayRank ();
7534 ILGenerator ig = ec.ig;
7537 LoadArrayAndArguments (ec);
7540 EmitLoadOpcode (ig, type);
7544 method = FetchGetMethod ();
7545 ig.Emit (OpCodes.Call, method);
7548 LoadFromPtr (ec.ig, this.type);
7551 ec.ig.Emit (OpCodes.Dup);
7552 temp = new LocalTemporary (this.type);
7557 public override void Emit (EmitContext ec)
7562 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7564 int rank = ea.Expr.Type.GetArrayRank ();
7565 ILGenerator ig = ec.ig;
7566 Type t = source.Type;
7567 prepared = prepare_for_load;
7569 if (prepare_for_load) {
7570 AddressOf (ec, AddressOp.LoadStore);
7571 ec.ig.Emit (OpCodes.Dup);
7574 ec.ig.Emit (OpCodes.Dup);
7575 temp = new LocalTemporary (this.type);
7578 StoreFromPtr (ec.ig, t);
7588 LoadArrayAndArguments (ec);
7591 bool is_stobj, has_type_arg;
7592 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7594 // The stobj opcode used by value types will need
7595 // an address on the stack, not really an array/array
7599 ig.Emit (OpCodes.Ldelema, t);
7603 ec.ig.Emit (OpCodes.Dup);
7604 temp = new LocalTemporary (this.type);
7609 ig.Emit (OpCodes.Stobj, t);
7610 else if (has_type_arg)
7615 ModuleBuilder mb = CodeGen.Module.Builder;
7616 int arg_count = ea.Arguments.Count;
7617 Type [] args = new Type [arg_count + 1];
7622 ec.ig.Emit (OpCodes.Dup);
7623 temp = new LocalTemporary (this.type);
7627 for (int i = 0; i < arg_count; i++){
7628 //args [i++] = a.Type;
7629 args [i] = TypeManager.int32_type;
7632 args [arg_count] = type;
7634 set = mb.GetArrayMethod (
7635 ea.Expr.Type, "Set",
7636 CallingConventions.HasThis |
7637 CallingConventions.Standard,
7638 TypeManager.void_type, args);
7640 ig.Emit (OpCodes.Call, set);
7649 public void AddressOf (EmitContext ec, AddressOp mode)
7651 int rank = ea.Expr.Type.GetArrayRank ();
7652 ILGenerator ig = ec.ig;
7654 LoadArrayAndArguments (ec);
7657 ig.Emit (OpCodes.Ldelema, type);
7659 MethodInfo address = FetchAddressMethod ();
7660 ig.Emit (OpCodes.Call, address);
7664 public void EmitGetLength (EmitContext ec, int dim)
7666 int rank = ea.Expr.Type.GetArrayRank ();
7667 ILGenerator ig = ec.ig;
7671 ig.Emit (OpCodes.Ldlen);
7672 ig.Emit (OpCodes.Conv_I4);
7674 IntLiteral.EmitInt (ig, dim);
7675 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7681 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7682 public readonly ArrayList Properties;
7683 static Indexers empty;
7685 public struct Indexer {
7686 public readonly PropertyInfo PropertyInfo;
7687 public readonly MethodInfo Getter, Setter;
7689 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7691 this.PropertyInfo = property_info;
7699 empty = new Indexers (null);
7702 Indexers (ArrayList array)
7707 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7712 foreach (PropertyInfo property in mi){
7713 MethodInfo get, set;
7715 get = property.GetGetMethod (true);
7716 set = property.GetSetMethod (true);
7717 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7719 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7721 if (get != null || set != null) {
7723 ix = new Indexers (new ArrayList ());
7724 ix.Properties.Add (new Indexer (property, get, set));
7729 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7731 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7733 return TypeManager.MemberLookup (
7734 caller_type, caller_type, lookup_type, MemberTypes.Property,
7735 BindingFlags.Public | BindingFlags.Instance |
7736 BindingFlags.DeclaredOnly, p_name, null);
7739 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7741 Indexers ix = empty;
7744 if (lookup_type.IsGenericParameter) {
7745 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7749 if (gc.HasClassConstraint)
7750 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7752 Type[] ifaces = gc.InterfaceConstraints;
7753 foreach (Type itype in ifaces)
7754 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7760 Type copy = lookup_type;
7761 while (copy != TypeManager.object_type && copy != null){
7762 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7763 copy = copy.BaseType;
7766 if (lookup_type.IsInterface) {
7767 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7768 if (ifaces != null) {
7769 foreach (Type itype in ifaces)
7770 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7779 /// Expressions that represent an indexer call.
7781 public class IndexerAccess : Expression, IAssignMethod {
7783 // Points to our "data" repository
7785 MethodInfo get, set;
7786 ArrayList set_arguments;
7787 bool is_base_indexer;
7789 protected Type indexer_type;
7790 protected Type current_type;
7791 protected Expression instance_expr;
7792 protected ArrayList arguments;
7794 public IndexerAccess (ElementAccess ea, Location loc)
7795 : this (ea.Expr, false, loc)
7797 this.arguments = ea.Arguments;
7800 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7803 this.instance_expr = instance_expr;
7804 this.is_base_indexer = is_base_indexer;
7805 this.eclass = ExprClass.Value;
7809 protected virtual bool CommonResolve (EmitContext ec)
7811 indexer_type = instance_expr.Type;
7812 current_type = ec.ContainerType;
7817 public override Expression DoResolve (EmitContext ec)
7819 if (!CommonResolve (ec))
7823 // Step 1: Query for all `Item' *properties*. Notice
7824 // that the actual methods are pointed from here.
7826 // This is a group of properties, piles of them.
7828 ArrayList AllGetters = null;
7830 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7831 if (ilist.Properties != null) {
7832 AllGetters = new ArrayList(ilist.Properties.Count);
7833 foreach (Indexers.Indexer ix in ilist.Properties) {
7834 if (ix.Getter != null)
7835 AllGetters.Add (ix.Getter);
7839 if (AllGetters == null) {
7840 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7841 TypeManager.CSharpName (indexer_type));
7845 if (AllGetters.Count == 0) {
7846 // FIXME: we cannot simply select first one as the error message is missleading when
7847 // multiple indexers exist
7848 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7849 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7850 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7854 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7855 arguments, false, loc);
7858 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7863 // Only base will allow this invocation to happen.
7865 if (get.IsAbstract && this is BaseIndexerAccess){
7866 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7870 type = get.ReturnType;
7871 if (type.IsPointer && !ec.InUnsafe){
7876 instance_expr.CheckMarshalByRefAccess ();
7878 eclass = ExprClass.IndexerAccess;
7882 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7884 if (right_side == EmptyExpression.OutAccess) {
7885 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7886 GetSignatureForError ());
7890 // if the indexer returns a value type, and we try to set a field in it
7891 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7892 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7893 GetSignatureForError ());
7897 ArrayList AllSetters = new ArrayList();
7898 if (!CommonResolve (ec))
7901 bool found_any = false, found_any_setters = false;
7903 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7904 if (ilist.Properties != null) {
7906 foreach (Indexers.Indexer ix in ilist.Properties) {
7907 if (ix.Setter != null)
7908 AllSetters.Add (ix.Setter);
7911 if (AllSetters.Count > 0) {
7912 found_any_setters = true;
7913 set_arguments = (ArrayList) arguments.Clone ();
7914 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7915 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7917 set_arguments, false, loc);
7921 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7922 TypeManager.CSharpName (indexer_type));
7926 if (!found_any_setters) {
7927 Error (154, "indexer can not be used in this context, because " +
7928 "it lacks a `set' accessor");
7933 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7938 // Only base will allow this invocation to happen.
7940 if (set.IsAbstract && this is BaseIndexerAccess){
7941 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7946 // Now look for the actual match in the list of indexers to set our "return" type
7948 type = TypeManager.void_type; // default value
7949 foreach (Indexers.Indexer ix in ilist.Properties){
7950 if (ix.Setter == set){
7951 type = ix.PropertyInfo.PropertyType;
7956 instance_expr.CheckMarshalByRefAccess ();
7958 eclass = ExprClass.IndexerAccess;
7962 bool prepared = false;
7963 LocalTemporary temp;
7965 public void Emit (EmitContext ec, bool leave_copy)
7967 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
7969 ec.ig.Emit (OpCodes.Dup);
7970 temp = new LocalTemporary (Type);
7976 // source is ignored, because we already have a copy of it from the
7977 // LValue resolution and we have already constructed a pre-cached
7978 // version of the arguments (ea.set_arguments);
7980 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7982 prepared = prepare_for_load;
7983 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7988 ec.ig.Emit (OpCodes.Dup);
7989 temp = new LocalTemporary (Type);
7992 } else if (leave_copy) {
7993 temp = new LocalTemporary (Type);
7999 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8008 public override void Emit (EmitContext ec)
8013 public override string GetSignatureForError ()
8015 // FIXME: print the argument list of the indexer
8016 return instance_expr.GetSignatureForError () + ".this[...]";
8019 protected override void CloneTo (CloneContext clonectx, Expression t)
8021 IndexerAccess target = (IndexerAccess) t;
8023 if (arguments != null){
8024 target.arguments = new ArrayList ();
8025 foreach (Argument a in arguments)
8026 target.arguments.Add (a.Clone (clonectx));
8028 if (instance_expr != null)
8029 target.instance_expr = instance_expr.Clone (clonectx);
8034 /// The base operator for method names
8036 public class BaseAccess : Expression {
8037 public readonly string Identifier;
8040 public BaseAccess (string member, Location l)
8042 this.Identifier = member;
8046 public BaseAccess (string member, TypeArguments args, Location l)
8052 public override Expression DoResolve (EmitContext ec)
8054 Expression c = CommonResolve (ec);
8060 // MethodGroups use this opportunity to flag an error on lacking ()
8062 if (!(c is MethodGroupExpr))
8063 return c.Resolve (ec);
8067 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8069 Expression c = CommonResolve (ec);
8075 // MethodGroups use this opportunity to flag an error on lacking ()
8077 if (! (c is MethodGroupExpr))
8078 return c.DoResolveLValue (ec, right_side);
8083 Expression CommonResolve (EmitContext ec)
8085 Expression member_lookup;
8086 Type current_type = ec.ContainerType;
8087 Type base_type = current_type.BaseType;
8090 Error (1511, "Keyword `base' is not available in a static method");
8094 if (ec.IsFieldInitializer){
8095 Error (1512, "Keyword `base' is not available in the current context");
8099 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8100 AllMemberTypes, AllBindingFlags, loc);
8101 if (member_lookup == null) {
8102 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8109 left = new TypeExpression (base_type, loc);
8111 left = ec.GetThis (loc);
8113 MemberExpr me = (MemberExpr) member_lookup;
8115 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8117 if (e is PropertyExpr) {
8118 PropertyExpr pe = (PropertyExpr) e;
8123 MethodGroupExpr mg = e as MethodGroupExpr;
8129 return mg.ResolveGeneric (ec, args);
8131 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8139 public override void Emit (EmitContext ec)
8141 throw new Exception ("Should never be called");
8144 protected override void CloneTo (CloneContext clonectx, Expression t)
8146 BaseAccess target = (BaseAccess) t;
8148 target.args = args.Clone ();
8153 /// The base indexer operator
8155 public class BaseIndexerAccess : IndexerAccess {
8156 public BaseIndexerAccess (ArrayList args, Location loc)
8157 : base (null, true, loc)
8159 arguments = new ArrayList ();
8160 foreach (Expression tmp in args)
8161 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8164 protected override bool CommonResolve (EmitContext ec)
8166 instance_expr = ec.GetThis (loc);
8168 current_type = ec.ContainerType.BaseType;
8169 indexer_type = current_type;
8171 foreach (Argument a in arguments){
8172 if (!a.Resolve (ec, loc))
8181 /// This class exists solely to pass the Type around and to be a dummy
8182 /// that can be passed to the conversion functions (this is used by
8183 /// foreach implementation to typecast the object return value from
8184 /// get_Current into the proper type. All code has been generated and
8185 /// we only care about the side effect conversions to be performed
8187 /// This is also now used as a placeholder where a no-action expression
8188 /// is needed (the `New' class).
8190 public class EmptyExpression : Expression {
8191 public static readonly EmptyExpression Null = new EmptyExpression ();
8193 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8194 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8195 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8197 static EmptyExpression temp = new EmptyExpression ();
8198 public static EmptyExpression Grab ()
8200 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8205 public static void Release (EmptyExpression e)
8210 // TODO: should be protected
8211 public EmptyExpression ()
8213 type = TypeManager.object_type;
8214 eclass = ExprClass.Value;
8215 loc = Location.Null;
8218 public EmptyExpression (Type t)
8221 eclass = ExprClass.Value;
8222 loc = Location.Null;
8225 public override Expression DoResolve (EmitContext ec)
8230 public override void Emit (EmitContext ec)
8232 // nothing, as we only exist to not do anything.
8236 // This is just because we might want to reuse this bad boy
8237 // instead of creating gazillions of EmptyExpressions.
8238 // (CanImplicitConversion uses it)
8240 public void SetType (Type t)
8246 public class UserCast : Expression {
8250 public UserCast (MethodInfo method, Expression source, Location l)
8252 this.method = method;
8253 this.source = source;
8254 type = method.ReturnType;
8255 eclass = ExprClass.Value;
8259 public Expression Source {
8265 public override Expression DoResolve (EmitContext ec)
8268 // We are born fully resolved
8273 public override void Emit (EmitContext ec)
8275 ILGenerator ig = ec.ig;
8279 if (method is MethodInfo)
8280 ig.Emit (OpCodes.Call, (MethodInfo) method);
8282 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8288 // This class is used to "construct" the type during a typecast
8289 // operation. Since the Type.GetType class in .NET can parse
8290 // the type specification, we just use this to construct the type
8291 // one bit at a time.
8293 public class ComposedCast : TypeExpr {
8297 public ComposedCast (Expression left, string dim)
8298 : this (left, dim, left.Location)
8302 public ComposedCast (Expression left, string dim, Location l)
8310 public Expression RemoveNullable ()
8312 if (dim.EndsWith ("?")) {
8313 dim = dim.Substring (0, dim.Length - 1);
8322 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8324 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8328 Type ltype = lexpr.Type;
8329 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8330 Error_VoidInvalidInTheContext (loc);
8335 if ((dim.Length > 0) && (dim [0] == '?')) {
8336 TypeExpr nullable = new NullableType (left, loc);
8338 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8339 return nullable.ResolveAsTypeTerminal (ec, false);
8343 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8346 if (dim != "" && dim [0] == '[' &&
8347 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8348 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8353 type = TypeManager.GetConstructedType (ltype, dim);
8358 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8360 if (type.IsPointer && !ec.IsInUnsafeScope){
8365 eclass = ExprClass.Type;
8369 public override string Name {
8370 get { return left + dim; }
8373 public override string FullName {
8374 get { return type.FullName; }
8377 public override string GetSignatureForError ()
8379 return left.GetSignatureForError () + dim;
8382 protected override void CloneTo (CloneContext clonectx, Expression t)
8384 ComposedCast target = (ComposedCast) t;
8386 target.left = left.Clone (clonectx);
8390 public class FixedBufferPtr : Expression {
8393 public FixedBufferPtr (Expression array, Type array_type, Location l)
8398 type = TypeManager.GetPointerType (array_type);
8399 eclass = ExprClass.Value;
8402 public override void Emit(EmitContext ec)
8407 public override Expression DoResolve (EmitContext ec)
8410 // We are born fully resolved
8418 // This class is used to represent the address of an array, used
8419 // only by the Fixed statement, this generates "&a [0]" construct
8420 // for fixed (char *pa = a)
8422 public class ArrayPtr : FixedBufferPtr {
8425 public ArrayPtr (Expression array, Type array_type, Location l):
8426 base (array, array_type, l)
8428 this.array_type = array_type;
8431 public override void Emit (EmitContext ec)
8435 ILGenerator ig = ec.ig;
8436 IntLiteral.EmitInt (ig, 0);
8437 ig.Emit (OpCodes.Ldelema, array_type);
8442 // Used by the fixed statement
8444 public class StringPtr : Expression {
8447 public StringPtr (LocalBuilder b, Location l)
8450 eclass = ExprClass.Value;
8451 type = TypeManager.char_ptr_type;
8455 public override Expression DoResolve (EmitContext ec)
8457 // This should never be invoked, we are born in fully
8458 // initialized state.
8463 public override void Emit (EmitContext ec)
8465 ILGenerator ig = ec.ig;
8467 ig.Emit (OpCodes.Ldloc, b);
8468 ig.Emit (OpCodes.Conv_I);
8469 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8470 ig.Emit (OpCodes.Add);
8475 // Implements the `stackalloc' keyword
8477 public class StackAlloc : Expression {
8482 public StackAlloc (Expression type, Expression count, Location l)
8489 public override Expression DoResolve (EmitContext ec)
8491 count = count.Resolve (ec);
8495 if (count.Type != TypeManager.int32_type){
8496 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8501 Constant c = count as Constant;
8502 if (c != null && c.IsNegative) {
8503 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8507 if (ec.InCatch || ec.InFinally) {
8508 Error (255, "Cannot use stackalloc in finally or catch");
8512 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8518 if (!TypeManager.VerifyUnManaged (otype, loc))
8521 type = TypeManager.GetPointerType (otype);
8522 eclass = ExprClass.Value;
8527 public override void Emit (EmitContext ec)
8529 int size = GetTypeSize (otype);
8530 ILGenerator ig = ec.ig;
8533 ig.Emit (OpCodes.Sizeof, otype);
8535 IntConstant.EmitInt (ig, size);
8537 ig.Emit (OpCodes.Mul);
8538 ig.Emit (OpCodes.Localloc);
8541 protected override void CloneTo (CloneContext clonectx, Expression t)
8543 StackAlloc target = (StackAlloc) t;
8544 target.count = count.Clone (clonectx);
8545 target.t = t.Clone (clonectx);
8549 public interface IInitializable
8551 bool Initialize (EmitContext ec, Expression target);
8554 public class Initializer
8556 public readonly string Name;
8557 public readonly object Value;
8559 public Initializer (string name, Expression value)
8565 public Initializer (string name, IInitializable value)
8572 public class ObjectInitializer : IInitializable
8574 readonly ArrayList initializers;
8575 public ObjectInitializer (ArrayList initializers)
8577 this.initializers = initializers;
8580 public bool Initialize (EmitContext ec, Expression target)
8582 ArrayList initialized = new ArrayList (initializers.Count);
8583 for (int i = initializers.Count - 1; i >= 0; i--) {
8584 Initializer initializer = initializers[i] as Initializer;
8585 if (initialized.Contains (initializer.Name)) {
8586 //FIXME proper error
8587 Console.WriteLine ("Object member can only be initialized once");
8591 MemberAccess ma = new MemberAccess (target, initializer.Name);
8592 Expression expr = initializer.Value as Expression;
8593 // If it's an expresison, append the assign.
8595 Assign a = new Assign (ma, expr);
8596 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8598 // If it's another initializer (object or collection), initialize it.
8599 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8602 initialized.Add (initializer.Name);
8608 public class CollectionInitializer : IInitializable
8610 readonly ArrayList items;
8611 public CollectionInitializer (ArrayList items)
8616 bool CheckCollection (EmitContext ec, Expression e)
8618 if (e == null || e.Type == null)
8620 bool is_ienumerable = false;
8621 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8622 if (t == typeof (IEnumerable)) {
8623 is_ienumerable = true;
8627 if (!is_ienumerable)
8630 MethodGroupExpr mg = Expression.MemberLookup (
8631 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8632 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8637 foreach (MethodInfo mi in mg.Methods) {
8638 if (TypeManager.GetParameterData (mi).Count != 1)
8640 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8647 public bool Initialize (EmitContext ec, Expression target)
8649 if (!CheckCollection (ec, target.Resolve (ec))) {
8650 // FIXME throw proper error
8651 Console.WriteLine ("Error: This is not a collection");
8655 for (int i = items.Count - 1; i >= 0; i--) {
8656 MemberAccess ma = new MemberAccess (target, "Add");
8657 ArrayList array = new ArrayList ();
8658 array.Add (new Argument ((Expression)items[i]));
8659 Invocation invoke = new Invocation (ma, array);
8660 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8666 public class AnonymousTypeInitializer : IInitializable
8668 readonly ArrayList initializers;
8669 public AnonymousTypeInitializer (ArrayList initializers)
8671 this.initializers = initializers;
8674 public bool Initialize (EmitContext ec, Expression target)
8676 foreach (AnonymousTypeParameter p in initializers) {
8677 MemberAccess ma = new MemberAccess (target, p.Name);
8678 Assign a = p.Expression as Assign;
8679 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8680 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8686 public class NewInitialize : New, IInitializable
8688 IInitializable initializer;
8690 public bool Initialize (EmitContext ec, Expression target)
8692 return initializer.Initialize (ec, target);
8695 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8696 : base (requested_type, arguments, l)
8698 this.initializer = initializer;
8702 public class AnonymousType : Expression
8704 ArrayList parameters;
8705 TypeContainer parent;
8706 TypeContainer anonymous_type;
8708 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8710 this.parameters = parameters;
8711 this.parent = parent;
8715 public override Expression DoResolve (EmitContext ec)
8717 foreach (AnonymousTypeParameter p in parameters)
8720 anonymous_type = GetAnonymousType (ec);
8722 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8723 AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8724 return new NewInitialize (te, null, ati, loc).Resolve (ec);
8727 TypeContainer GetAnonymousType (EmitContext ec)
8729 // See if we already have an anonymous type with the right fields.
8730 // If not, create one.
8732 // Look through all availible pre-existing anonymous types:
8733 foreach (DictionaryEntry d in parent.AnonymousTypes) {
8734 ArrayList p = d.Key as ArrayList;
8735 if (p.Count != parameters.Count)
8738 // And for each of the fields we need...
8739 foreach (AnonymousTypeParameter atp in parameters) {
8740 // ... check each of the pre-existing A-type's fields.
8742 foreach (AnonymousTypeParameter a in p)
8743 if (atp.Equals(a)) {
8747 // If the pre-existing A-type doesn't have one of our fields, try the next one
8753 // If it's a match, return it.
8755 return d.Value as TypeContainer;
8757 // Otherwise, create a new type.
8758 return CreateAnonymousType (ec);
8761 TypeContainer CreateAnonymousType (EmitContext ec)
8763 TypeContainer type = new AnonymousClass (parent, loc);
8764 foreach (AnonymousTypeParameter p in parameters) {
8765 TypeExpression te = new TypeExpression (p.Type, loc);
8766 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8767 type.AddField (field);
8770 type.DefineMembers ();
8771 parent.AnonymousTypes.Add (parameters, type);
8775 public override void Emit (EmitContext ec)
8777 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8778 new New (te, null, loc).Emit(ec);
8782 public class AnonymousTypeParameter : Expression
8786 Expression expression;
8788 public LocatedToken Token {
8789 get { return token; }
8792 public string Name {
8793 get { return name; }
8796 public Expression Expression {
8797 get { return expression; }
8800 public override bool Equals (object o)
8802 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8803 return other != null && Name == other.Name && Type == other.Type;
8806 public override int GetHashCode ()
8808 return name.GetHashCode ();
8811 public override Expression DoResolve (EmitContext ec)
8813 Expression e = expression.Resolve(ec);
8818 public override void Emit (EmitContext ec)
8820 expression.Emit(ec);
8823 public AnonymousTypeParameter (Expression expression, string name)
8826 this.expression = expression;
8827 type = expression.Type;