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)
61 args = new ArrayList (1);
62 Argument a = new Argument (e, Argument.AType.Expression);
64 // We need to resolve the arguments before sending them in !
65 if (!a.Resolve (ec, loc))
69 mg = mg.OverloadResolve (ec, args, false, loc);
74 return new StaticCallExpr ((MethodInfo) mg, args, loc);
77 public override void EmitStatement (EmitContext ec)
80 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
81 ec.ig.Emit (OpCodes.Pop);
84 public MethodInfo Method {
89 public class ParenthesizedExpression : Expression
91 public Expression Expr;
93 public ParenthesizedExpression (Expression expr)
98 public override Expression DoResolve (EmitContext ec)
100 Expr = Expr.Resolve (ec);
104 public override void Emit (EmitContext ec)
106 throw new Exception ("Should not happen");
109 public override Location Location
112 return Expr.Location;
116 protected override void CloneTo (CloneContext clonectx, Expression t)
118 ParenthesizedExpression target = (ParenthesizedExpression) t;
120 target.Expr = Expr.Clone (clonectx);
125 /// Unary expressions.
129 /// Unary implements unary expressions. It derives from
130 /// ExpressionStatement becuase the pre/post increment/decrement
131 /// operators can be used in a statement context.
133 public class Unary : Expression {
134 public enum Operator : byte {
135 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
136 Indirection, AddressOf, TOP
139 public readonly Operator Oper;
140 public Expression Expr;
142 public Unary (Operator op, Expression expr, Location loc)
150 /// Returns a stringified representation of the Operator
152 static public string OperName (Operator oper)
155 case Operator.UnaryPlus:
157 case Operator.UnaryNegation:
159 case Operator.LogicalNot:
161 case Operator.OnesComplement:
163 case Operator.AddressOf:
165 case Operator.Indirection:
169 return oper.ToString ();
172 public static readonly string [] oper_names;
176 oper_names = new string [(int)Operator.TOP];
178 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
179 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
180 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
181 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
182 oper_names [(int) Operator.Indirection] = "op_Indirection";
183 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
186 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
188 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
191 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
193 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
197 void Error23 (Type t)
199 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
203 // This routine will attempt to simplify the unary expression when the
204 // argument is a constant.
206 Constant TryReduceConstant (EmitContext ec, Constant e)
208 Type expr_type = e.Type;
211 case Operator.UnaryPlus:
212 // Unary numeric promotions
213 if (expr_type == TypeManager.byte_type)
214 return new IntConstant (((ByteConstant)e).Value, e.Location);
215 if (expr_type == TypeManager.sbyte_type)
216 return new IntConstant (((SByteConstant)e).Value, e.Location);
217 if (expr_type == TypeManager.short_type)
218 return new IntConstant (((ShortConstant)e).Value, e.Location);
219 if (expr_type == TypeManager.ushort_type)
220 return new IntConstant (((UShortConstant)e).Value, e.Location);
221 if (expr_type == TypeManager.char_type)
222 return new IntConstant (((CharConstant)e).Value, e.Location);
224 // Predefined operators
225 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
226 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
227 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
228 expr_type == TypeManager.decimal_type)
235 case Operator.UnaryNegation:
236 // Unary numeric promotions
237 if (expr_type == TypeManager.byte_type)
238 return new IntConstant (-((ByteConstant)e).Value, e.Location);
239 if (expr_type == TypeManager.sbyte_type)
240 return new IntConstant (-((SByteConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.short_type)
242 return new IntConstant (-((ShortConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.ushort_type)
244 return new IntConstant (-((UShortConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.char_type)
246 return new IntConstant (-((CharConstant)e).Value, e.Location);
248 // Predefined operators
249 if (expr_type == TypeManager.int32_type) {
250 int value = ((IntConstant)e).Value;
251 if (value == int.MinValue) {
252 if (ec.ConstantCheckState) {
253 ConstantFold.Error_CompileTimeOverflow (loc);
258 return new IntConstant (-value, e.Location);
260 if (expr_type == TypeManager.int64_type) {
261 long value = ((LongConstant)e).Value;
262 if (value == long.MinValue) {
263 if (ec.ConstantCheckState) {
264 ConstantFold.Error_CompileTimeOverflow (loc);
269 return new LongConstant (-value, e.Location);
272 if (expr_type == TypeManager.uint32_type) {
273 UIntLiteral uil = e as UIntLiteral;
275 if (uil.Value == 2147483648)
276 return new IntLiteral (int.MinValue, e.Location);
277 return new LongLiteral (-uil.Value, e.Location);
279 return new LongConstant (-((UIntConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.uint64_type) {
283 ULongLiteral ull = e as ULongLiteral;
284 if (ull != null && ull.Value == 9223372036854775808)
285 return new LongLiteral (long.MinValue, e.Location);
289 if (expr_type == TypeManager.float_type) {
290 FloatLiteral fl = e as FloatLiteral;
291 // For better error reporting
293 fl.Value = -fl.Value;
296 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
298 if (expr_type == TypeManager.double_type) {
299 DoubleLiteral dl = e as DoubleLiteral;
300 // For better error reporting
302 dl.Value = -dl.Value;
306 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
308 if (expr_type == TypeManager.decimal_type)
309 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
313 case Operator.LogicalNot:
314 if (expr_type != TypeManager.bool_type)
317 BoolConstant b = (BoolConstant) e;
318 return new BoolConstant (!(b.Value), b.Location);
320 case Operator.OnesComplement:
321 // Unary numeric promotions
322 if (expr_type == TypeManager.byte_type)
323 return new IntConstant (~((ByteConstant)e).Value, e.Location);
324 if (expr_type == TypeManager.sbyte_type)
325 return new IntConstant (~((SByteConstant)e).Value, e.Location);
326 if (expr_type == TypeManager.short_type)
327 return new IntConstant (~((ShortConstant)e).Value, e.Location);
328 if (expr_type == TypeManager.ushort_type)
329 return new IntConstant (~((UShortConstant)e).Value, e.Location);
330 if (expr_type == TypeManager.char_type)
331 return new IntConstant (~((CharConstant)e).Value, e.Location);
333 // Predefined operators
334 if (expr_type == TypeManager.int32_type)
335 return new IntConstant (~((IntConstant)e).Value, e.Location);
336 if (expr_type == TypeManager.uint32_type)
337 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
338 if (expr_type == TypeManager.int64_type)
339 return new LongConstant (~((LongConstant)e).Value, e.Location);
340 if (expr_type == TypeManager.uint64_type){
341 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
343 if (e is EnumConstant) {
344 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
346 e = new EnumConstant (e, expr_type);
351 case Operator.AddressOf:
354 case Operator.Indirection:
357 throw new Exception ("Can not constant fold: " + Oper.ToString());
360 Expression ResolveOperator (EmitContext ec)
363 // Step 1: Default operations on CLI native types.
366 // Attempt to use a constant folding operation.
367 Constant cexpr = Expr as Constant;
369 cexpr = TryReduceConstant (ec, cexpr);
376 // Step 2: Perform Operator Overload location
378 Type expr_type = Expr.Type;
379 string op_name = oper_names [(int) Oper];
381 Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
383 Expression e = StaticCallExpr.MakeSimpleCall (
384 ec, (MethodGroupExpr) mg, Expr, loc);
395 case Operator.LogicalNot:
396 if (expr_type != TypeManager.bool_type) {
397 Expr = ResolveBoolean (ec, Expr, loc);
404 type = TypeManager.bool_type;
407 case Operator.OnesComplement:
408 // Unary numeric promotions
409 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
410 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
411 expr_type == TypeManager.char_type)
413 type = TypeManager.int32_type;
414 return new EmptyCast (this, type);
417 // Predefined operators
418 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
419 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
420 TypeManager.IsEnumType (expr_type))
426 type = TypeManager.int32_type;
427 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
434 case Operator.AddressOf:
440 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
444 IVariable variable = Expr as IVariable;
445 bool is_fixed = variable != null && variable.VerifyFixed ();
447 if (!ec.InFixedInitializer && !is_fixed) {
448 Error (212, "You can only take the address of unfixed expression inside " +
449 "of a fixed statement initializer");
453 if (ec.InFixedInitializer && is_fixed) {
454 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
458 LocalVariableReference lr = Expr as LocalVariableReference;
460 if (lr.local_info.IsCaptured){
461 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
464 lr.local_info.AddressTaken = true;
465 lr.local_info.Used = true;
468 ParameterReference pr = Expr as ParameterReference;
469 if ((pr != null) && pr.Parameter.IsCaptured) {
470 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
474 // According to the specs, a variable is considered definitely assigned if you take
476 if ((variable != null) && (variable.VariableInfo != null)){
477 variable.VariableInfo.SetAssigned (ec);
480 type = TypeManager.GetPointerType (Expr.Type);
483 case Operator.Indirection:
489 if (!expr_type.IsPointer){
490 Error (193, "The * or -> operator must be applied to a pointer");
495 // We create an Indirection expression, because
496 // it can implement the IMemoryLocation.
498 return new Indirection (Expr, loc);
500 case Operator.UnaryPlus:
501 // Unary numeric promotions
502 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
503 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
504 expr_type == TypeManager.char_type)
506 return new EmptyCast (Expr, TypeManager.int32_type);
509 // Predefined operators
510 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
511 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
512 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
513 expr_type == TypeManager.decimal_type)
518 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
520 // Because we can completely ignore unary +
527 case Operator.UnaryNegation:
529 // transform - - expr into expr
531 Unary u = Expr as Unary;
532 if (u != null && u.Oper == Operator.UnaryNegation) {
536 // Unary numeric promotions
537 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
538 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
539 expr_type == TypeManager.char_type)
541 type = TypeManager.int32_type;
542 return new EmptyCast (this, type);
546 // Predefined operators
548 if (expr_type == TypeManager.uint32_type) {
549 type = TypeManager.int64_type;
550 Expr = Convert.ImplicitNumericConversion (Expr, type);
554 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
555 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
556 expr_type == TypeManager.decimal_type)
565 type = TypeManager.int32_type;
566 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
574 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
575 TypeManager.CSharpName (expr_type) + "'");
579 public override Expression DoResolve (EmitContext ec)
581 if (Oper == Operator.AddressOf) {
582 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
584 if (Expr == null || Expr.eclass != ExprClass.Variable){
585 Error (211, "Cannot take the address of the given expression");
590 Expr = Expr.Resolve (ec);
596 if (TypeManager.IsNullableValueType (Expr.Type))
597 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
600 eclass = ExprClass.Value;
601 return ResolveOperator (ec);
604 public override Expression DoResolveLValue (EmitContext ec, Expression right)
606 if (Oper == Operator.Indirection)
607 return DoResolve (ec);
612 public override void Emit (EmitContext ec)
614 ILGenerator ig = ec.ig;
617 case Operator.UnaryPlus:
618 throw new Exception ("This should be caught by Resolve");
620 case Operator.UnaryNegation:
621 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
622 ig.Emit (OpCodes.Ldc_I4_0);
623 if (type == TypeManager.int64_type)
624 ig.Emit (OpCodes.Conv_U8);
626 ig.Emit (OpCodes.Sub_Ovf);
629 ig.Emit (OpCodes.Neg);
634 case Operator.LogicalNot:
636 ig.Emit (OpCodes.Ldc_I4_0);
637 ig.Emit (OpCodes.Ceq);
640 case Operator.OnesComplement:
642 ig.Emit (OpCodes.Not);
645 case Operator.AddressOf:
646 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
650 throw new Exception ("This should not happen: Operator = "
655 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
657 if (Oper == Operator.LogicalNot)
658 Expr.EmitBranchable (ec, target, !onTrue);
660 base.EmitBranchable (ec, target, onTrue);
663 public override string ToString ()
665 return "Unary (" + Oper + ", " + Expr + ")";
668 protected override void CloneTo (CloneContext clonectx, Expression t)
670 Unary target = (Unary) t;
672 target.Expr = Expr.Clone (clonectx);
677 // Unary operators are turned into Indirection expressions
678 // after semantic analysis (this is so we can take the address
679 // of an indirection).
681 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
683 LocalTemporary temporary;
686 public Indirection (Expression expr, Location l)
689 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
690 eclass = ExprClass.Variable;
694 public override void Emit (EmitContext ec)
699 LoadFromPtr (ec.ig, Type);
702 public void Emit (EmitContext ec, bool leave_copy)
706 ec.ig.Emit (OpCodes.Dup);
707 temporary = new LocalTemporary (expr.Type);
708 temporary.Store (ec);
712 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
714 prepared = prepare_for_load;
718 if (prepare_for_load)
719 ec.ig.Emit (OpCodes.Dup);
723 ec.ig.Emit (OpCodes.Dup);
724 temporary = new LocalTemporary (expr.Type);
725 temporary.Store (ec);
728 StoreFromPtr (ec.ig, type);
730 if (temporary != null) {
732 temporary.Release (ec);
736 public void AddressOf (EmitContext ec, AddressOp Mode)
741 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
743 return DoResolve (ec);
746 public override Expression DoResolve (EmitContext ec)
749 // Born fully resolved
754 public override string ToString ()
756 return "*(" + expr + ")";
759 #region IVariable Members
761 public VariableInfo VariableInfo {
765 public bool VerifyFixed ()
767 // A pointer-indirection is always fixed.
775 /// Unary Mutator expressions (pre and post ++ and --)
779 /// UnaryMutator implements ++ and -- expressions. It derives from
780 /// ExpressionStatement becuase the pre/post increment/decrement
781 /// operators can be used in a statement context.
783 /// FIXME: Idea, we could split this up in two classes, one simpler
784 /// for the common case, and one with the extra fields for more complex
785 /// classes (indexers require temporary access; overloaded require method)
788 public class UnaryMutator : ExpressionStatement {
790 public enum Mode : byte {
797 PreDecrement = IsDecrement,
798 PostIncrement = IsPost,
799 PostDecrement = IsPost | IsDecrement
803 bool is_expr = false;
804 bool recurse = false;
809 // This is expensive for the simplest case.
811 StaticCallExpr method;
813 public UnaryMutator (Mode m, Expression e, Location l)
820 static string OperName (Mode mode)
822 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
827 /// Returns whether an object of type `t' can be incremented
828 /// or decremented with add/sub (ie, basically whether we can
829 /// use pre-post incr-decr operations on it, but it is not a
830 /// System.Decimal, which we require operator overloading to catch)
832 static bool IsIncrementableNumber (Type t)
834 return (t == TypeManager.sbyte_type) ||
835 (t == TypeManager.byte_type) ||
836 (t == TypeManager.short_type) ||
837 (t == TypeManager.ushort_type) ||
838 (t == TypeManager.int32_type) ||
839 (t == TypeManager.uint32_type) ||
840 (t == TypeManager.int64_type) ||
841 (t == TypeManager.uint64_type) ||
842 (t == TypeManager.char_type) ||
843 (t.IsSubclassOf (TypeManager.enum_type)) ||
844 (t == TypeManager.float_type) ||
845 (t == TypeManager.double_type) ||
846 (t.IsPointer && t != TypeManager.void_ptr_type);
849 Expression ResolveOperator (EmitContext ec)
851 Type expr_type = expr.Type;
854 // Step 1: Perform Operator Overload location
859 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
860 op_name = "op_Increment";
862 op_name = "op_Decrement";
864 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
867 method = StaticCallExpr.MakeSimpleCall (
868 ec, (MethodGroupExpr) mg, expr, loc);
871 } else if (!IsIncrementableNumber (expr_type)) {
872 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
873 TypeManager.CSharpName (expr_type) + "'");
878 // The operand of the prefix/postfix increment decrement operators
879 // should be an expression that is classified as a variable,
880 // a property access or an indexer access
883 if (expr.eclass == ExprClass.Variable){
884 LocalVariableReference var = expr as LocalVariableReference;
885 if ((var != null) && var.IsReadOnly) {
886 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
889 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
890 expr = expr.ResolveLValue (ec, this, Location);
894 if (expr.eclass == ExprClass.Value) {
895 Error_ValueAssignment (loc);
897 expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
905 public override Expression DoResolve (EmitContext ec)
907 expr = expr.Resolve (ec);
912 eclass = ExprClass.Value;
915 if (TypeManager.IsNullableValueType (expr.Type))
916 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
919 return ResolveOperator (ec);
922 static int PtrTypeSize (Type t)
924 return GetTypeSize (TypeManager.GetElementType (t));
928 // Loads the proper "1" into the stack based on the type, then it emits the
929 // opcode for the operation requested
931 void LoadOneAndEmitOp (EmitContext ec, Type t)
934 // Measure if getting the typecode and using that is more/less efficient
935 // that comparing types. t.GetTypeCode() is an internal call.
937 ILGenerator ig = ec.ig;
939 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
940 LongConstant.EmitLong (ig, 1);
941 else if (t == TypeManager.double_type)
942 ig.Emit (OpCodes.Ldc_R8, 1.0);
943 else if (t == TypeManager.float_type)
944 ig.Emit (OpCodes.Ldc_R4, 1.0F);
945 else if (t.IsPointer){
946 int n = PtrTypeSize (t);
949 ig.Emit (OpCodes.Sizeof, t);
951 IntConstant.EmitInt (ig, n);
953 ig.Emit (OpCodes.Ldc_I4_1);
956 // Now emit the operation
959 if (t == TypeManager.int32_type ||
960 t == TypeManager.int64_type){
961 if ((mode & Mode.IsDecrement) != 0)
962 ig.Emit (OpCodes.Sub_Ovf);
964 ig.Emit (OpCodes.Add_Ovf);
965 } else if (t == TypeManager.uint32_type ||
966 t == TypeManager.uint64_type){
967 if ((mode & Mode.IsDecrement) != 0)
968 ig.Emit (OpCodes.Sub_Ovf_Un);
970 ig.Emit (OpCodes.Add_Ovf_Un);
972 if ((mode & Mode.IsDecrement) != 0)
973 ig.Emit (OpCodes.Sub_Ovf);
975 ig.Emit (OpCodes.Add_Ovf);
978 if ((mode & Mode.IsDecrement) != 0)
979 ig.Emit (OpCodes.Sub);
981 ig.Emit (OpCodes.Add);
984 if (t == TypeManager.sbyte_type){
986 ig.Emit (OpCodes.Conv_Ovf_I1);
988 ig.Emit (OpCodes.Conv_I1);
989 } else if (t == TypeManager.byte_type){
991 ig.Emit (OpCodes.Conv_Ovf_U1);
993 ig.Emit (OpCodes.Conv_U1);
994 } else if (t == TypeManager.short_type){
996 ig.Emit (OpCodes.Conv_Ovf_I2);
998 ig.Emit (OpCodes.Conv_I2);
999 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1001 ig.Emit (OpCodes.Conv_Ovf_U2);
1003 ig.Emit (OpCodes.Conv_U2);
1008 void EmitCode (EmitContext ec, bool is_expr)
1011 this.is_expr = is_expr;
1012 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1015 public override void Emit (EmitContext ec)
1018 // We use recurse to allow ourselfs to be the source
1019 // of an assignment. This little hack prevents us from
1020 // having to allocate another expression
1023 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1025 LoadOneAndEmitOp (ec, expr.Type);
1027 ec.ig.Emit (OpCodes.Call, method.Method);
1032 EmitCode (ec, true);
1035 public override void EmitStatement (EmitContext ec)
1037 EmitCode (ec, false);
1040 protected override void CloneTo (CloneContext clonectx, Expression t)
1042 UnaryMutator target = (UnaryMutator) t;
1044 target.expr = expr.Clone (clonectx);
1049 /// Base class for the `Is' and `As' classes.
1053 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1056 public abstract class Probe : Expression {
1057 public Expression ProbeType;
1058 protected Expression expr;
1059 protected TypeExpr probe_type_expr;
1061 public Probe (Expression expr, Expression probe_type, Location l)
1063 ProbeType = probe_type;
1068 public Expression Expr {
1074 public override Expression DoResolve (EmitContext ec)
1076 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1077 if (probe_type_expr == null)
1080 expr = expr.Resolve (ec);
1084 if (expr.Type.IsPointer) {
1085 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1091 protected override void CloneTo (CloneContext clonectx, Expression t)
1093 Probe target = (Probe) t;
1095 target.expr = expr.Clone (clonectx);
1096 target.ProbeType = ProbeType.Clone (clonectx);
1102 /// Implementation of the `is' operator.
1104 public class Is : Probe {
1105 public Is (Expression expr, Expression probe_type, Location l)
1106 : base (expr, probe_type, l)
1111 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1116 public override void Emit (EmitContext ec)
1118 ILGenerator ig = ec.ig;
1123 case Action.AlwaysFalse:
1124 ig.Emit (OpCodes.Pop);
1125 IntConstant.EmitInt (ig, 0);
1127 case Action.AlwaysTrue:
1128 ig.Emit (OpCodes.Pop);
1129 IntConstant.EmitInt (ig, 1);
1131 case Action.LeaveOnStack:
1132 // the `e != null' rule.
1133 ig.Emit (OpCodes.Ldnull);
1134 ig.Emit (OpCodes.Ceq);
1135 ig.Emit (OpCodes.Ldc_I4_0);
1136 ig.Emit (OpCodes.Ceq);
1139 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1140 ig.Emit (OpCodes.Ldnull);
1141 ig.Emit (OpCodes.Cgt_Un);
1144 throw new Exception ("never reached");
1147 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1149 ILGenerator ig = ec.ig;
1152 case Action.AlwaysFalse:
1154 ig.Emit (OpCodes.Br, target);
1157 case Action.AlwaysTrue:
1159 ig.Emit (OpCodes.Br, target);
1162 case Action.LeaveOnStack:
1163 // the `e != null' rule.
1165 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1169 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1170 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1173 throw new Exception ("never reached");
1176 public override Expression DoResolve (EmitContext ec)
1178 Expression e = base.DoResolve (ec);
1180 if ((e == null) || (expr == null))
1183 Type etype = expr.Type;
1184 type = TypeManager.bool_type;
1185 eclass = ExprClass.Value;
1188 // First case, if at compile time, there is an implicit conversion
1189 // then e != null (objects) or true (value types)
1191 Type probe_type = probe_type_expr.Type;
1192 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1195 if (etype.IsValueType)
1196 action = Action.AlwaysTrue;
1198 action = Action.LeaveOnStack;
1200 Constant c = e as Constant;
1201 if (c != null && c.GetValue () == null) {
1202 action = Action.AlwaysFalse;
1203 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1204 TypeManager.CSharpName (probe_type));
1205 } else if (etype.IsValueType) {
1206 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1207 TypeManager.CSharpName (probe_type));
1212 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1213 if (TypeManager.IsGenericParameter (etype))
1214 expr = new BoxedCast (expr, etype);
1217 // Second case: explicit reference convresion
1219 if (expr is NullLiteral)
1220 action = Action.AlwaysFalse;
1222 action = Action.Probe;
1223 } else if (TypeManager.ContainsGenericParameters (etype) ||
1224 TypeManager.ContainsGenericParameters (probe_type)) {
1225 expr = new BoxedCast (expr, etype);
1226 action = Action.Probe;
1228 action = Action.AlwaysFalse;
1229 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1230 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1238 /// Implementation of the `as' operator.
1240 public class As : Probe {
1241 public As (Expression expr, Expression probe_type, Location l)
1242 : base (expr, probe_type, l)
1246 bool do_isinst = false;
1247 Expression resolved_type;
1249 public override void Emit (EmitContext ec)
1251 ILGenerator ig = ec.ig;
1256 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1259 if (TypeManager.IsNullableType (type))
1260 ig.Emit (OpCodes.Unbox_Any, type);
1264 static void Error_CannotConvertType (Type source, Type target, Location loc)
1266 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1267 TypeManager.CSharpName (source),
1268 TypeManager.CSharpName (target));
1271 public override Expression DoResolve (EmitContext ec)
1273 if (resolved_type == null) {
1274 resolved_type = base.DoResolve (ec);
1276 if (resolved_type == null)
1280 type = probe_type_expr.Type;
1281 eclass = ExprClass.Value;
1282 Type etype = expr.Type;
1284 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1285 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1286 TypeManager.CSharpName (type) + "' is a value type)");
1293 // If the type is a type parameter, ensure
1294 // that it is constrained by a class
1296 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1298 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1301 if (constraints == null)
1304 if (!constraints.HasClassConstraint)
1305 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1309 Report.Error (413, loc,
1310 "The as operator requires that the `{0}' type parameter be constrained by a class",
1311 probe_type_expr.GetSignatureForError ());
1317 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1324 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1325 if (TypeManager.IsGenericParameter (etype))
1326 expr = new BoxedCast (expr, etype);
1332 if (TypeManager.ContainsGenericParameters (etype) ||
1333 TypeManager.ContainsGenericParameters (type)) {
1334 expr = new BoxedCast (expr, etype);
1339 Error_CannotConvertType (etype, type, loc);
1343 public override bool GetAttributableValue (Type valueType, out object value)
1345 return expr.GetAttributableValue (valueType, out value);
1350 /// This represents a typecast in the source language.
1352 /// FIXME: Cast expressions have an unusual set of parsing
1353 /// rules, we need to figure those out.
1355 public class Cast : Expression {
1356 Expression target_type;
1359 public Cast (Expression cast_type, Expression expr)
1360 : this (cast_type, expr, cast_type.Location)
1364 public Cast (Expression cast_type, Expression expr, Location loc)
1366 this.target_type = cast_type;
1370 if (target_type == TypeManager.system_void_expr)
1371 Error_VoidInvalidInTheContext (loc);
1374 public Expression TargetType {
1375 get { return target_type; }
1378 public Expression Expr {
1379 get { return expr; }
1382 public override Expression DoResolve (EmitContext ec)
1384 expr = expr.Resolve (ec);
1388 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1394 if (type.IsAbstract && type.IsSealed) {
1395 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1399 eclass = ExprClass.Value;
1401 Constant c = expr as Constant;
1403 c = c.TryReduce (ec, type, loc);
1408 if (type.IsPointer && !ec.InUnsafe) {
1412 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1416 public override void Emit (EmitContext ec)
1418 throw new Exception ("Should not happen");
1421 protected override void CloneTo (CloneContext clonectx, Expression t)
1423 Cast target = (Cast) t;
1425 target.target_type = target_type.Clone (clonectx);
1426 target.expr = expr.Clone (clonectx);
1431 /// Binary operators
1433 public class Binary : Expression {
1434 public enum Operator : byte {
1435 Multiply, Division, Modulus,
1436 Addition, Subtraction,
1437 LeftShift, RightShift,
1438 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1439 Equality, Inequality,
1448 readonly Operator oper;
1449 Expression left, right;
1451 // This must be kept in sync with Operator!!!
1452 public static readonly string [] oper_names;
1456 oper_names = new string [(int) Operator.TOP];
1458 oper_names [(int) Operator.Multiply] = "op_Multiply";
1459 oper_names [(int) Operator.Division] = "op_Division";
1460 oper_names [(int) Operator.Modulus] = "op_Modulus";
1461 oper_names [(int) Operator.Addition] = "op_Addition";
1462 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1463 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1464 oper_names [(int) Operator.RightShift] = "op_RightShift";
1465 oper_names [(int) Operator.LessThan] = "op_LessThan";
1466 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1467 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1468 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1469 oper_names [(int) Operator.Equality] = "op_Equality";
1470 oper_names [(int) Operator.Inequality] = "op_Inequality";
1471 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1472 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1473 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1474 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1475 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1478 public Binary (Operator oper, Expression left, Expression right)
1483 this.loc = left.Location;
1486 public Operator Oper {
1493 /// Returns a stringified representation of the Operator
1495 public static string OperName (Operator oper)
1498 case Operator.Multiply:
1500 case Operator.Division:
1502 case Operator.Modulus:
1504 case Operator.Addition:
1506 case Operator.Subtraction:
1508 case Operator.LeftShift:
1510 case Operator.RightShift:
1512 case Operator.LessThan:
1514 case Operator.GreaterThan:
1516 case Operator.LessThanOrEqual:
1518 case Operator.GreaterThanOrEqual:
1520 case Operator.Equality:
1522 case Operator.Inequality:
1524 case Operator.BitwiseAnd:
1526 case Operator.BitwiseOr:
1528 case Operator.ExclusiveOr:
1530 case Operator.LogicalOr:
1532 case Operator.LogicalAnd:
1536 return oper.ToString ();
1539 public override string ToString ()
1541 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1542 right.ToString () + ")";
1545 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1547 if (expr.Type == target_type)
1550 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1553 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1556 34, loc, "Operator `" + OperName (oper)
1557 + "' is ambiguous on operands of type `"
1558 + TypeManager.CSharpName (l) + "' "
1559 + "and `" + TypeManager.CSharpName (r)
1563 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1565 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1568 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1570 if (!IsConvertible (ec, left, right, t))
1572 left = ForceConversion (ec, left, t);
1573 right = ForceConversion (ec, right, t);
1578 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1580 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1581 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1583 if (oper == Operator.Equality || oper == Operator.Inequality)
1585 if (oper == Operator.Addition)
1590 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1592 if (!IsApplicable_String (ec, left, right, oper))
1594 Type t = TypeManager.string_type;
1595 if (Convert.ImplicitConversionExists (ec, left, t))
1596 left = ForceConversion (ec, left, t);
1597 if (Convert.ImplicitConversionExists (ec, right, t))
1598 right = ForceConversion (ec, right, t);
1603 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1605 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1606 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1607 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1608 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1612 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1614 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1615 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1619 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1621 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1624 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1626 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1630 void Error_OperatorCannotBeApplied ()
1632 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1633 TypeManager.CSharpName(right.Type));
1636 static bool is_unsigned (Type t)
1638 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1639 t == TypeManager.short_type || t == TypeManager.byte_type);
1642 Expression Make32or64 (EmitContext ec, Expression e)
1646 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1647 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1649 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1652 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1655 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1658 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1664 Expression CheckShiftArguments (EmitContext ec)
1666 Expression new_left = Make32or64 (ec, left);
1667 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1668 if (new_left == null || new_right == null) {
1669 Error_OperatorCannotBeApplied ();
1672 type = new_left.Type;
1673 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1675 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1680 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1681 // i.e., not invoke op_Equality.
1683 static bool EqualsNullIsReferenceEquals (Type t)
1685 return t == TypeManager.object_type || t == TypeManager.string_type ||
1686 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1689 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1691 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1692 "Possible unintended reference comparison; to get a value comparison, " +
1693 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1696 static void Warning_Constant_Result (Location loc, bool result, Type type)
1698 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1699 "This operation is undocumented and it is temporary supported for compatibility reasons only",
1700 TypeManager.CSharpName (type), result ? "true" : "false");
1703 Expression ResolveOperator (EmitContext ec)
1706 Type r = right.Type;
1708 if (oper == Operator.Equality || oper == Operator.Inequality){
1709 if (right.Type == TypeManager.null_type){
1710 if (TypeManager.IsGenericParameter (l)){
1711 if (l.BaseType == TypeManager.value_type) {
1712 Error_OperatorCannotBeApplied ();
1716 left = new BoxedCast (left, TypeManager.object_type);
1717 Type = TypeManager.bool_type;
1722 // CSC 2 has this behavior, it allows structs to be compared
1723 // with the null literal *outside* of a generics context and
1724 // inlines that as true or false.
1726 // This is, in my opinion, completely wrong.
1728 if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType){
1729 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1730 return new BoolLiteral (oper == Operator.Inequality, loc);
1734 if (left is NullLiteral){
1735 if (TypeManager.IsGenericParameter (r)){
1736 if (r.BaseType == TypeManager.value_type) {
1737 Error_OperatorCannotBeApplied ();
1741 right = new BoxedCast (right, TypeManager.object_type);
1742 Type = TypeManager.bool_type;
1747 // CSC 2 has this behavior, it allows structs to be compared
1748 // with the null literal *outside* of a generics context and
1749 // inlines that as true or false.
1751 // This is, in my opinion, completely wrong.
1753 if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1754 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1755 return new BoolLiteral (oper == Operator.Inequality, loc);
1760 // Optimize out call to op_Equality in a few cases.
1762 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1763 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1764 Type = TypeManager.bool_type;
1769 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1770 Type = TypeManager.bool_type;
1776 // Delegate equality
1778 MethodGroupExpr mg = null;
1779 Type delegate_type = null;
1780 if (left.eclass == ExprClass.MethodGroup) {
1781 if (!TypeManager.IsDelegateType(r)) {
1782 Error_OperatorCannotBeApplied(Location, OperName(oper),
1783 left.ExprClassName, right.ExprClassName);
1786 mg = (MethodGroupExpr)left;
1788 } else if (right.eclass == ExprClass.MethodGroup) {
1789 if (!TypeManager.IsDelegateType(l)) {
1790 Error_OperatorCannotBeApplied(Location, OperName(oper),
1791 left.ExprClassName, right.ExprClassName);
1794 mg = (MethodGroupExpr)right;
1799 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1803 // Find operator method
1804 string op = oper_names[(int)oper];
1805 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1806 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1808 ArrayList args = new ArrayList(2);
1809 args.Add(new Argument(e, Argument.AType.Expression));
1810 if (delegate_type == l)
1811 args.Insert(0, new Argument(left, Argument.AType.Expression));
1813 args.Add(new Argument(right, Argument.AType.Expression));
1815 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1818 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1819 Error_OperatorCannotBeApplied(Location, OperName(oper),
1820 left.ExprClassName, right.ExprClassName);
1827 // Do not perform operator overload resolution when both sides are
1830 MethodGroupExpr left_operators = null, right_operators = null;
1831 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1833 // Step 1: Perform Operator Overload location
1835 string op = oper_names [(int) oper];
1837 MethodGroupExpr union;
1838 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1840 right_operators = MemberLookup (
1841 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1842 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
1844 union = left_operators;
1846 if (union != null) {
1847 ArrayList args = new ArrayList (2);
1848 args.Add (new Argument (left, Argument.AType.Expression));
1849 args.Add (new Argument (right, Argument.AType.Expression));
1851 union = union.OverloadResolve (ec, args, true, Location.Null);
1853 if (union != null) {
1854 MethodInfo mi = (MethodInfo) union;
1855 return new BinaryMethod (mi.ReturnType, mi, args);
1861 // Step 0: String concatenation (because overloading will get this wrong)
1863 if (oper == Operator.Addition){
1865 // If any of the arguments is a string, cast to string
1868 // Simple constant folding
1869 if (left is StringConstant && right is StringConstant)
1870 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1872 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1874 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1875 Error_OperatorCannotBeApplied ();
1879 // try to fold it in on the left
1880 if (left is StringConcat) {
1883 // We have to test here for not-null, since we can be doubly-resolved
1884 // take care of not appending twice
1887 type = TypeManager.string_type;
1888 ((StringConcat) left).Append (ec, right);
1889 return left.Resolve (ec);
1895 // Otherwise, start a new concat expression
1896 return new StringConcat (ec, loc, left, right).Resolve (ec);
1900 // Transform a + ( - b) into a - b
1902 if (right is Unary){
1903 Unary right_unary = (Unary) right;
1905 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1906 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
1911 if (oper == Operator.Equality || oper == Operator.Inequality){
1912 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1913 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1914 Error_OperatorCannotBeApplied ();
1918 type = TypeManager.bool_type;
1922 if (l.IsPointer || r.IsPointer) {
1923 if (l.IsPointer && r.IsPointer) {
1924 type = TypeManager.bool_type;
1928 if (l.IsPointer && r == TypeManager.null_type) {
1929 right = new EmptyCast (NullPointer.Null, l);
1930 type = TypeManager.bool_type;
1934 if (r.IsPointer && l == TypeManager.null_type) {
1935 left = new EmptyCast (NullPointer.Null, r);
1936 type = TypeManager.bool_type;
1942 if (l.IsGenericParameter && r.IsGenericParameter) {
1943 GenericConstraints l_gc, r_gc;
1945 l_gc = TypeManager.GetTypeParameterConstraints (l);
1946 r_gc = TypeManager.GetTypeParameterConstraints (r);
1948 if ((l_gc == null) || (r_gc == null) ||
1949 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1950 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1951 Error_OperatorCannotBeApplied ();
1959 // operator != (object a, object b)
1960 // operator == (object a, object b)
1962 // For this to be used, both arguments have to be reference-types.
1963 // Read the rationale on the spec (14.9.6)
1965 if (!(l.IsValueType || r.IsValueType)){
1966 type = TypeManager.bool_type;
1972 // Also, a standard conversion must exist from either one
1974 bool left_to_right =
1975 Convert.ImplicitStandardConversionExists (left, r);
1976 bool right_to_left = !left_to_right &&
1977 Convert.ImplicitStandardConversionExists (right, l);
1979 if (!left_to_right && !right_to_left) {
1980 Error_OperatorCannotBeApplied ();
1984 if (left_to_right && left_operators != null &&
1985 Report.WarningLevel >= 2) {
1986 ArrayList args = new ArrayList (2);
1987 args.Add (new Argument (left, Argument.AType.Expression));
1988 args.Add (new Argument (left, Argument.AType.Expression));
1989 if (left_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1990 Warning_UnintendedReferenceComparison (loc, "right", l);
1993 if (right_to_left && right_operators != null &&
1994 Report.WarningLevel >= 2) {
1995 ArrayList args = new ArrayList (2);
1996 args.Add (new Argument (right, Argument.AType.Expression));
1997 args.Add (new Argument (right, Argument.AType.Expression));
1998 if (right_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1999 Warning_UnintendedReferenceComparison (loc, "left", r);
2003 // We are going to have to convert to an object to compare
2005 if (l != TypeManager.object_type)
2006 left = new EmptyCast (left, TypeManager.object_type);
2007 if (r != TypeManager.object_type)
2008 right = new EmptyCast (right, TypeManager.object_type);
2014 // Only perform numeric promotions on:
2015 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2017 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2018 if (TypeManager.IsDelegateType (l)){
2019 if (((right.eclass == ExprClass.MethodGroup) ||
2020 (r == TypeManager.anonymous_method_type))){
2021 if ((RootContext.Version != LanguageVersion.ISO_1)){
2022 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2030 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2032 ArrayList args = new ArrayList (2);
2034 args = new ArrayList (2);
2035 args.Add (new Argument (left, Argument.AType.Expression));
2036 args.Add (new Argument (right, Argument.AType.Expression));
2038 if (oper == Operator.Addition)
2039 method = TypeManager.delegate_combine_delegate_delegate;
2041 method = TypeManager.delegate_remove_delegate_delegate;
2043 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2044 Error_OperatorCannotBeApplied ();
2048 return new BinaryDelegate (l, method, args);
2053 // Pointer arithmetic:
2055 // T* operator + (T* x, int y);
2056 // T* operator + (T* x, uint y);
2057 // T* operator + (T* x, long y);
2058 // T* operator + (T* x, ulong y);
2060 // T* operator + (int y, T* x);
2061 // T* operator + (uint y, T *x);
2062 // T* operator + (long y, T *x);
2063 // T* operator + (ulong y, T *x);
2065 // T* operator - (T* x, int y);
2066 // T* operator - (T* x, uint y);
2067 // T* operator - (T* x, long y);
2068 // T* operator - (T* x, ulong y);
2070 // long operator - (T* x, T *y)
2073 if (r.IsPointer && oper == Operator.Subtraction){
2075 return new PointerArithmetic (
2076 false, left, right, TypeManager.int64_type,
2079 Expression t = Make32or64 (ec, right);
2081 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2083 } else if (r.IsPointer && oper == Operator.Addition){
2084 Expression t = Make32or64 (ec, left);
2086 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2091 // Enumeration operators
2093 bool lie = TypeManager.IsEnumType (l);
2094 bool rie = TypeManager.IsEnumType (r);
2098 // U operator - (E e, E f)
2100 if (oper == Operator.Subtraction){
2102 type = TypeManager.EnumToUnderlying (l);
2105 Error_OperatorCannotBeApplied ();
2111 // operator + (E e, U x)
2112 // operator - (E e, U x)
2114 if (oper == Operator.Addition || oper == Operator.Subtraction){
2115 Type enum_type = lie ? l : r;
2116 Type other_type = lie ? r : l;
2117 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2119 if (underlying_type != other_type){
2120 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2130 Error_OperatorCannotBeApplied ();
2139 temp = Convert.ImplicitConversion (ec, right, l, loc);
2143 Error_OperatorCannotBeApplied ();
2147 temp = Convert.ImplicitConversion (ec, left, r, loc);
2152 Error_OperatorCannotBeApplied ();
2157 if (oper == Operator.Equality || oper == Operator.Inequality ||
2158 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2159 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2160 if (left.Type != right.Type){
2161 Error_OperatorCannotBeApplied ();
2164 type = TypeManager.bool_type;
2168 if (oper == Operator.BitwiseAnd ||
2169 oper == Operator.BitwiseOr ||
2170 oper == Operator.ExclusiveOr){
2171 if (left.Type != right.Type){
2172 Error_OperatorCannotBeApplied ();
2178 Error_OperatorCannotBeApplied ();
2182 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2183 return CheckShiftArguments (ec);
2185 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2186 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2187 type = TypeManager.bool_type;
2191 Expression left_operators_e = l == TypeManager.bool_type ?
2192 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2193 Expression right_operators_e = r == TypeManager.bool_type ?
2194 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2196 if (left_operators_e != null && right_operators_e != null) {
2197 left = left_operators_e;
2198 right = right_operators_e;
2199 type = TypeManager.bool_type;
2203 Expression e = new ConditionalLogicalOperator (
2204 oper == Operator.LogicalAnd, left, right, l, loc);
2205 return e.Resolve (ec);
2208 Expression orig_left = left;
2209 Expression orig_right = right;
2212 // operator & (bool x, bool y)
2213 // operator | (bool x, bool y)
2214 // operator ^ (bool x, bool y)
2216 if (oper == Operator.BitwiseAnd ||
2217 oper == Operator.BitwiseOr ||
2218 oper == Operator.ExclusiveOr) {
2219 if (OverloadResolve_PredefinedIntegral (ec)) {
2220 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2221 Error_OperatorAmbiguous (loc, oper, l, r);
2225 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2226 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2227 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2228 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2229 TypeManager.CSharpName (r));
2232 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2233 Error_OperatorCannotBeApplied ();
2240 // Pointer comparison
2242 if (l.IsPointer && r.IsPointer){
2243 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2244 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2245 type = TypeManager.bool_type;
2250 if (OverloadResolve_PredefinedIntegral (ec)) {
2251 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2252 Error_OperatorAmbiguous (loc, oper, l, r);
2255 } else if (OverloadResolve_PredefinedFloating (ec)) {
2256 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2257 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2258 Error_OperatorAmbiguous (loc, oper, l, r);
2261 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2262 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2263 Error_OperatorAmbiguous (loc, oper, l, r);
2266 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2267 Error_OperatorCannotBeApplied ();
2271 if (oper == Operator.Equality ||
2272 oper == Operator.Inequality ||
2273 oper == Operator.LessThanOrEqual ||
2274 oper == Operator.LessThan ||
2275 oper == Operator.GreaterThanOrEqual ||
2276 oper == Operator.GreaterThan)
2277 type = TypeManager.bool_type;
2282 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2284 if (r == TypeManager.string_type)
2286 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2287 ec.ContainerType, lookup, oper_names [(int) oper],
2288 MemberTypes.Method, AllBindingFlags, loc);
2289 ArrayList args = new ArrayList (2);
2290 args.Add (new Argument (left, Argument.AType.Expression));
2291 args.Add (new Argument (right, Argument.AType.Expression));
2292 ops = ops.OverloadResolve (ec, args, true, Location.Null);
2293 return new BinaryMethod (type, (MethodInfo)ops, args);
2299 Constant EnumLiftUp (Constant left, Constant right)
2302 case Operator.BitwiseOr:
2303 case Operator.BitwiseAnd:
2304 case Operator.ExclusiveOr:
2305 case Operator.Equality:
2306 case Operator.Inequality:
2307 case Operator.LessThan:
2308 case Operator.LessThanOrEqual:
2309 case Operator.GreaterThan:
2310 case Operator.GreaterThanOrEqual:
2311 if (left is EnumConstant)
2314 if (left.IsZeroInteger)
2315 return new EnumConstant (left, right.Type);
2319 case Operator.Addition:
2320 case Operator.Subtraction:
2323 case Operator.Multiply:
2324 case Operator.Division:
2325 case Operator.Modulus:
2326 case Operator.LeftShift:
2327 case Operator.RightShift:
2328 if (right is EnumConstant || left is EnumConstant)
2332 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2336 public override Expression DoResolve (EmitContext ec)
2341 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2342 left = ((ParenthesizedExpression) left).Expr;
2343 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2347 if (left.eclass == ExprClass.Type) {
2348 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2352 left = left.Resolve (ec);
2357 Constant lc = left as Constant;
2358 if (lc != null && lc.Type == TypeManager.bool_type &&
2359 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2360 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2362 // TODO: make a sense to resolve unreachable expression as we do for statement
2363 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2367 right = right.Resolve (ec);
2371 eclass = ExprClass.Value;
2372 Constant rc = right as Constant;
2374 // The conversion rules are ignored in enum context but why
2375 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2376 left = lc = EnumLiftUp (lc, rc);
2380 right = rc = EnumLiftUp (rc, lc);
2385 if (oper == Operator.BitwiseAnd) {
2386 if (rc != null && rc.IsZeroInteger) {
2387 return lc is EnumConstant ?
2388 new EnumConstant (rc, lc.Type):
2392 if (lc != null && lc.IsZeroInteger) {
2393 return rc is EnumConstant ?
2394 new EnumConstant (lc, rc.Type):
2398 else if (oper == Operator.BitwiseOr) {
2399 if (lc is EnumConstant &&
2400 rc != null && rc.IsZeroInteger)
2402 if (rc is EnumConstant &&
2403 lc != null && lc.IsZeroInteger)
2405 } else if (oper == Operator.LogicalAnd) {
2406 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2408 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2412 if (rc != null && lc != null){
2413 int prev_e = Report.Errors;
2414 Expression e = ConstantFold.BinaryFold (
2415 ec, oper, lc, rc, loc);
2416 if (e != null || Report.Errors != prev_e)
2421 if ((left is NullLiteral || left.Type.IsValueType) &&
2422 (right is NullLiteral || right.Type.IsValueType) &&
2423 !(left is NullLiteral && right is NullLiteral) &&
2424 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2425 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2428 // Comparison warnings
2429 if (oper == Operator.Equality || oper == Operator.Inequality ||
2430 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2431 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2432 if (left.Equals (right)) {
2433 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2435 CheckUselessComparison (lc, right.Type);
2436 CheckUselessComparison (rc, left.Type);
2439 return ResolveOperator (ec);
2442 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2447 private void CheckUselessComparison (Constant c, Type type)
2449 if (c == null || !IsTypeIntegral (type)
2450 || c is StringConstant
2451 || c is BoolConstant
2452 || c is FloatConstant
2453 || c is DoubleConstant
2454 || c is DecimalConstant
2460 if (c is ULongConstant) {
2461 ulong uvalue = ((ULongConstant) c).Value;
2462 if (uvalue > long.MaxValue) {
2463 if (type == TypeManager.byte_type ||
2464 type == TypeManager.sbyte_type ||
2465 type == TypeManager.short_type ||
2466 type == TypeManager.ushort_type ||
2467 type == TypeManager.int32_type ||
2468 type == TypeManager.uint32_type ||
2469 type == TypeManager.int64_type ||
2470 type == TypeManager.char_type)
2471 WarnUselessComparison (type);
2474 value = (long) uvalue;
2476 else if (c is ByteConstant)
2477 value = ((ByteConstant) c).Value;
2478 else if (c is SByteConstant)
2479 value = ((SByteConstant) c).Value;
2480 else if (c is ShortConstant)
2481 value = ((ShortConstant) c).Value;
2482 else if (c is UShortConstant)
2483 value = ((UShortConstant) c).Value;
2484 else if (c is IntConstant)
2485 value = ((IntConstant) c).Value;
2486 else if (c is UIntConstant)
2487 value = ((UIntConstant) c).Value;
2488 else if (c is LongConstant)
2489 value = ((LongConstant) c).Value;
2490 else if (c is CharConstant)
2491 value = ((CharConstant)c).Value;
2496 if (IsValueOutOfRange (value, type))
2497 WarnUselessComparison (type);
2500 private bool IsValueOutOfRange (long value, Type type)
2502 if (IsTypeUnsigned (type) && value < 0)
2504 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2505 type == TypeManager.byte_type && value >= 0x100 ||
2506 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2507 type == TypeManager.ushort_type && value >= 0x10000 ||
2508 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2509 type == TypeManager.uint32_type && value >= 0x100000000;
2512 private static bool IsTypeIntegral (Type type)
2514 return type == TypeManager.uint64_type ||
2515 type == TypeManager.int64_type ||
2516 type == TypeManager.uint32_type ||
2517 type == TypeManager.int32_type ||
2518 type == TypeManager.ushort_type ||
2519 type == TypeManager.short_type ||
2520 type == TypeManager.sbyte_type ||
2521 type == TypeManager.byte_type ||
2522 type == TypeManager.char_type;
2525 private static bool IsTypeUnsigned (Type type)
2527 return type == TypeManager.uint64_type ||
2528 type == TypeManager.uint32_type ||
2529 type == TypeManager.ushort_type ||
2530 type == TypeManager.byte_type ||
2531 type == TypeManager.char_type;
2534 private void WarnUselessComparison (Type type)
2536 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}'",
2537 TypeManager.CSharpName (type));
2541 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2542 /// context of a conditional bool expression. This function will return
2543 /// false if it is was possible to use EmitBranchable, or true if it was.
2545 /// The expression's code is generated, and we will generate a branch to `target'
2546 /// if the resulting expression value is equal to isTrue
2548 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2550 ILGenerator ig = ec.ig;
2553 // This is more complicated than it looks, but its just to avoid
2554 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2555 // but on top of that we want for == and != to use a special path
2556 // if we are comparing against null
2558 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2559 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2562 // put the constant on the rhs, for simplicity
2564 if (left is Constant) {
2565 Expression swap = right;
2570 if (((Constant) right).IsZeroInteger) {
2573 ig.Emit (OpCodes.Brtrue, target);
2575 ig.Emit (OpCodes.Brfalse, target);
2578 } else if (right is BoolConstant) {
2580 if (my_on_true != ((BoolConstant) right).Value)
2581 ig.Emit (OpCodes.Brtrue, target);
2583 ig.Emit (OpCodes.Brfalse, target);
2588 } else if (oper == Operator.LogicalAnd) {
2591 Label tests_end = ig.DefineLabel ();
2593 left.EmitBranchable (ec, tests_end, false);
2594 right.EmitBranchable (ec, target, true);
2595 ig.MarkLabel (tests_end);
2598 // This optimizes code like this
2599 // if (true && i > 4)
2601 if (!(left is Constant))
2602 left.EmitBranchable (ec, target, false);
2604 if (!(right is Constant))
2605 right.EmitBranchable (ec, target, false);
2610 } else if (oper == Operator.LogicalOr){
2612 left.EmitBranchable (ec, target, true);
2613 right.EmitBranchable (ec, target, true);
2616 Label tests_end = ig.DefineLabel ();
2617 left.EmitBranchable (ec, tests_end, true);
2618 right.EmitBranchable (ec, target, false);
2619 ig.MarkLabel (tests_end);
2624 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2625 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2626 oper == Operator.Equality || oper == Operator.Inequality)) {
2627 base.EmitBranchable (ec, target, onTrue);
2635 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2638 case Operator.Equality:
2640 ig.Emit (OpCodes.Beq, target);
2642 ig.Emit (OpCodes.Bne_Un, target);
2645 case Operator.Inequality:
2647 ig.Emit (OpCodes.Bne_Un, target);
2649 ig.Emit (OpCodes.Beq, target);
2652 case Operator.LessThan:
2655 ig.Emit (OpCodes.Blt_Un, target);
2657 ig.Emit (OpCodes.Blt, target);
2660 ig.Emit (OpCodes.Bge_Un, target);
2662 ig.Emit (OpCodes.Bge, target);
2665 case Operator.GreaterThan:
2668 ig.Emit (OpCodes.Bgt_Un, target);
2670 ig.Emit (OpCodes.Bgt, target);
2673 ig.Emit (OpCodes.Ble_Un, target);
2675 ig.Emit (OpCodes.Ble, target);
2678 case Operator.LessThanOrEqual:
2681 ig.Emit (OpCodes.Ble_Un, target);
2683 ig.Emit (OpCodes.Ble, target);
2686 ig.Emit (OpCodes.Bgt_Un, target);
2688 ig.Emit (OpCodes.Bgt, target);
2692 case Operator.GreaterThanOrEqual:
2695 ig.Emit (OpCodes.Bge_Un, target);
2697 ig.Emit (OpCodes.Bge, target);
2700 ig.Emit (OpCodes.Blt_Un, target);
2702 ig.Emit (OpCodes.Blt, target);
2705 Console.WriteLine (oper);
2706 throw new Exception ("what is THAT");
2710 public override void Emit (EmitContext ec)
2712 ILGenerator ig = ec.ig;
2717 // Handle short-circuit operators differently
2720 if (oper == Operator.LogicalAnd) {
2721 Label load_zero = ig.DefineLabel ();
2722 Label end = ig.DefineLabel ();
2724 left.EmitBranchable (ec, load_zero, false);
2726 ig.Emit (OpCodes.Br, end);
2728 ig.MarkLabel (load_zero);
2729 ig.Emit (OpCodes.Ldc_I4_0);
2732 } else if (oper == Operator.LogicalOr) {
2733 Label load_one = ig.DefineLabel ();
2734 Label end = ig.DefineLabel ();
2736 left.EmitBranchable (ec, load_one, true);
2738 ig.Emit (OpCodes.Br, end);
2740 ig.MarkLabel (load_one);
2741 ig.Emit (OpCodes.Ldc_I4_1);
2749 bool isUnsigned = is_unsigned (left.Type);
2752 case Operator.Multiply:
2754 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2755 opcode = OpCodes.Mul_Ovf;
2756 else if (isUnsigned)
2757 opcode = OpCodes.Mul_Ovf_Un;
2759 opcode = OpCodes.Mul;
2761 opcode = OpCodes.Mul;
2765 case Operator.Division:
2767 opcode = OpCodes.Div_Un;
2769 opcode = OpCodes.Div;
2772 case Operator.Modulus:
2774 opcode = OpCodes.Rem_Un;
2776 opcode = OpCodes.Rem;
2779 case Operator.Addition:
2781 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2782 opcode = OpCodes.Add_Ovf;
2783 else if (isUnsigned)
2784 opcode = OpCodes.Add_Ovf_Un;
2786 opcode = OpCodes.Add;
2788 opcode = OpCodes.Add;
2791 case Operator.Subtraction:
2793 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2794 opcode = OpCodes.Sub_Ovf;
2795 else if (isUnsigned)
2796 opcode = OpCodes.Sub_Ovf_Un;
2798 opcode = OpCodes.Sub;
2800 opcode = OpCodes.Sub;
2803 case Operator.RightShift:
2805 opcode = OpCodes.Shr_Un;
2807 opcode = OpCodes.Shr;
2810 case Operator.LeftShift:
2811 opcode = OpCodes.Shl;
2814 case Operator.Equality:
2815 opcode = OpCodes.Ceq;
2818 case Operator.Inequality:
2819 ig.Emit (OpCodes.Ceq);
2820 ig.Emit (OpCodes.Ldc_I4_0);
2822 opcode = OpCodes.Ceq;
2825 case Operator.LessThan:
2827 opcode = OpCodes.Clt_Un;
2829 opcode = OpCodes.Clt;
2832 case Operator.GreaterThan:
2834 opcode = OpCodes.Cgt_Un;
2836 opcode = OpCodes.Cgt;
2839 case Operator.LessThanOrEqual:
2840 Type lt = left.Type;
2842 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2843 ig.Emit (OpCodes.Cgt_Un);
2845 ig.Emit (OpCodes.Cgt);
2846 ig.Emit (OpCodes.Ldc_I4_0);
2848 opcode = OpCodes.Ceq;
2851 case Operator.GreaterThanOrEqual:
2852 Type le = left.Type;
2854 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2855 ig.Emit (OpCodes.Clt_Un);
2857 ig.Emit (OpCodes.Clt);
2859 ig.Emit (OpCodes.Ldc_I4_0);
2861 opcode = OpCodes.Ceq;
2864 case Operator.BitwiseOr:
2865 opcode = OpCodes.Or;
2868 case Operator.BitwiseAnd:
2869 opcode = OpCodes.And;
2872 case Operator.ExclusiveOr:
2873 opcode = OpCodes.Xor;
2877 throw new Exception ("This should not happen: Operator = "
2878 + oper.ToString ());
2884 protected override void CloneTo (CloneContext clonectx, Expression t)
2886 Binary target = (Binary) t;
2888 target.left = left.Clone (clonectx);
2889 target.right = right.Clone (clonectx);
2894 // Object created by Binary when the binary operator uses an method instead of being
2895 // a binary operation that maps to a CIL binary operation.
2897 public class BinaryMethod : Expression {
2898 public MethodBase method;
2899 public ArrayList Arguments;
2901 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2906 eclass = ExprClass.Value;
2909 public override Expression DoResolve (EmitContext ec)
2914 public override void Emit (EmitContext ec)
2916 ILGenerator ig = ec.ig;
2918 if (Arguments != null)
2919 Invocation.EmitArguments (ec, method, Arguments, false, null);
2921 if (method is MethodInfo)
2922 ig.Emit (OpCodes.Call, (MethodInfo) method);
2924 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2929 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2930 // b, c, d... may be strings or objects.
2932 public class StringConcat : Expression {
2934 bool invalid = false;
2935 bool emit_conv_done = false;
2937 // Are we also concating objects?
2939 bool is_strings_only = true;
2941 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2944 type = TypeManager.string_type;
2945 eclass = ExprClass.Value;
2947 operands = new ArrayList (2);
2952 public override Expression DoResolve (EmitContext ec)
2960 public void Append (EmitContext ec, Expression operand)
2965 StringConstant sc = operand as StringConstant;
2967 // TODO: it will be better to do this silently as an optimalization
2969 // string s = "" + i;
2970 // because this code has poor performace
2971 // if (sc.Value.Length == 0)
2972 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2974 if (operands.Count != 0) {
2975 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2976 if (last_operand != null) {
2977 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2985 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
2987 StringConcat concat_oper = operand as StringConcat;
2988 if (concat_oper != null) {
2989 operands.AddRange (concat_oper.operands);
2994 // Conversion to object
2996 if (operand.Type != TypeManager.string_type) {
2997 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3000 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3006 operands.Add (operand);
3009 public override void Emit (EmitContext ec)
3011 MethodInfo concat_method = null;
3014 // Do conversion to arguments; check for strings only
3017 // This can get called multiple times, so we have to deal with that.
3018 if (!emit_conv_done) {
3019 emit_conv_done = true;
3020 for (int i = 0; i < operands.Count; i ++) {
3021 Expression e = (Expression) operands [i];
3022 is_strings_only &= e.Type == TypeManager.string_type;
3025 for (int i = 0; i < operands.Count; i ++) {
3026 Expression e = (Expression) operands [i];
3028 if (! is_strings_only && e.Type == TypeManager.string_type) {
3029 // need to make sure this is an object, because the EmitParams
3030 // method might look at the type of this expression, see it is a
3031 // string and emit a string [] when we want an object [];
3033 e = new EmptyCast (e, TypeManager.object_type);
3035 operands [i] = new Argument (e, Argument.AType.Expression);
3040 // Find the right method
3042 switch (operands.Count) {
3045 // This should not be possible, because simple constant folding
3046 // is taken care of in the Binary code.
3048 throw new Exception ("how did you get here?");
3051 concat_method = is_strings_only ?
3052 TypeManager.string_concat_string_string :
3053 TypeManager.string_concat_object_object ;
3056 concat_method = is_strings_only ?
3057 TypeManager.string_concat_string_string_string :
3058 TypeManager.string_concat_object_object_object ;
3062 // There is not a 4 param overlaod for object (the one that there is
3063 // is actually a varargs methods, and is only in corlib because it was
3064 // introduced there before.).
3066 if (!is_strings_only)
3069 concat_method = TypeManager.string_concat_string_string_string_string;
3072 concat_method = is_strings_only ?
3073 TypeManager.string_concat_string_dot_dot_dot :
3074 TypeManager.string_concat_object_dot_dot_dot ;
3078 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3079 ec.ig.Emit (OpCodes.Call, concat_method);
3084 // Object created with +/= on delegates
3086 public class BinaryDelegate : Expression {
3090 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3095 eclass = ExprClass.Value;
3098 public override Expression DoResolve (EmitContext ec)
3103 public override void Emit (EmitContext ec)
3105 ILGenerator ig = ec.ig;
3107 Invocation.EmitArguments (ec, method, args, false, null);
3109 ig.Emit (OpCodes.Call, (MethodInfo) method);
3110 ig.Emit (OpCodes.Castclass, type);
3113 public Expression Right {
3115 Argument arg = (Argument) args [1];
3120 public bool IsAddition {
3122 return method == TypeManager.delegate_combine_delegate_delegate;
3128 // User-defined conditional logical operator
3129 public class ConditionalLogicalOperator : Expression {
3130 Expression left, right;
3133 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3136 eclass = ExprClass.Value;
3140 this.is_and = is_and;
3143 protected void Error19 ()
3145 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3148 protected void Error218 ()
3150 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3151 "declarations of operator true and operator false");
3154 Expression op_true, op_false, op;
3155 LocalTemporary left_temp;
3157 public override Expression DoResolve (EmitContext ec)
3159 MethodGroupExpr operator_group;
3161 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3162 if (operator_group == null) {
3167 left_temp = new LocalTemporary (type);
3169 ArrayList arguments = new ArrayList (2);
3170 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3171 arguments.Add (new Argument (right, Argument.AType.Expression));
3172 operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3173 if (operator_group == null) {
3178 MethodInfo method = (MethodInfo)operator_group;
3179 if (method.ReturnType != type) {
3180 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3181 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3185 op = new StaticCallExpr (method, arguments, loc);
3187 op_true = GetOperatorTrue (ec, left_temp, loc);
3188 op_false = GetOperatorFalse (ec, left_temp, loc);
3189 if ((op_true == null) || (op_false == null)) {
3197 public override void Emit (EmitContext ec)
3199 ILGenerator ig = ec.ig;
3200 Label false_target = ig.DefineLabel ();
3201 Label end_target = ig.DefineLabel ();
3204 left_temp.Store (ec);
3206 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3207 left_temp.Emit (ec);
3208 ig.Emit (OpCodes.Br, end_target);
3209 ig.MarkLabel (false_target);
3211 ig.MarkLabel (end_target);
3213 // We release 'left_temp' here since 'op' may refer to it too
3214 left_temp.Release (ec);
3218 public class PointerArithmetic : Expression {
3219 Expression left, right;
3223 // We assume that `l' is always a pointer
3225 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3231 is_add = is_addition;
3234 public override Expression DoResolve (EmitContext ec)
3236 eclass = ExprClass.Variable;
3238 if (left.Type == TypeManager.void_ptr_type) {
3239 Error (242, "The operation in question is undefined on void pointers");
3246 public override void Emit (EmitContext ec)
3248 Type op_type = left.Type;
3249 ILGenerator ig = ec.ig;
3251 // It must be either array or fixed buffer
3252 Type element = TypeManager.HasElementType (op_type) ?
3253 element = TypeManager.GetElementType (op_type) :
3254 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3256 int size = GetTypeSize (element);
3257 Type rtype = right.Type;
3259 if (rtype.IsPointer){
3261 // handle (pointer - pointer)
3265 ig.Emit (OpCodes.Sub);
3269 ig.Emit (OpCodes.Sizeof, element);
3271 IntLiteral.EmitInt (ig, size);
3272 ig.Emit (OpCodes.Div);
3274 ig.Emit (OpCodes.Conv_I8);
3277 // handle + and - on (pointer op int)
3280 ig.Emit (OpCodes.Conv_I);
3282 Constant right_const = right as Constant;
3283 if (right_const != null && size != 0) {
3284 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3292 ig.Emit (OpCodes.Sizeof, element);
3294 IntLiteral.EmitInt (ig, size);
3295 if (rtype == TypeManager.int64_type)
3296 ig.Emit (OpCodes.Conv_I8);
3297 else if (rtype == TypeManager.uint64_type)
3298 ig.Emit (OpCodes.Conv_U8);
3299 ig.Emit (OpCodes.Mul);
3303 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3304 ig.Emit (OpCodes.Conv_I);
3307 ig.Emit (OpCodes.Add);
3309 ig.Emit (OpCodes.Sub);
3315 /// Implements the ternary conditional operator (?:)
3317 public class Conditional : Expression {
3318 Expression expr, trueExpr, falseExpr;
3320 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3323 this.trueExpr = trueExpr;
3324 this.falseExpr = falseExpr;
3325 this.loc = expr.Location;
3328 public Expression Expr {
3334 public Expression TrueExpr {
3340 public Expression FalseExpr {
3346 public override Expression DoResolve (EmitContext ec)
3348 expr = expr.Resolve (ec);
3354 if (TypeManager.IsNullableValueType (expr.Type))
3355 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3358 if (expr.Type != TypeManager.bool_type){
3359 expr = Expression.ResolveBoolean (
3366 Assign ass = expr as Assign;
3367 if (ass != null && ass.Source is Constant) {
3368 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3371 trueExpr = trueExpr.Resolve (ec);
3372 falseExpr = falseExpr.Resolve (ec);
3374 if (trueExpr == null || falseExpr == null)
3377 eclass = ExprClass.Value;
3378 if (trueExpr.Type == falseExpr.Type) {
3379 type = trueExpr.Type;
3380 if (type == TypeManager.null_type) {
3381 // TODO: probably will have to implement ConditionalConstant
3382 // to call method without return constant as well
3383 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3388 Type true_type = trueExpr.Type;
3389 Type false_type = falseExpr.Type;
3392 // First, if an implicit conversion exists from trueExpr
3393 // to falseExpr, then the result type is of type falseExpr.Type
3395 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3398 // Check if both can convert implicitl to each other's type
3400 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3402 "Can not compute type of conditional expression " +
3403 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3404 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3405 "' convert implicitly to each other");
3410 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3414 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3415 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3420 // Dead code optimalization
3421 if (expr is BoolConstant){
3422 BoolConstant bc = (BoolConstant) expr;
3424 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3425 return bc.Value ? trueExpr : falseExpr;
3431 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3436 public override void Emit (EmitContext ec)
3438 ILGenerator ig = ec.ig;
3439 Label false_target = ig.DefineLabel ();
3440 Label end_target = ig.DefineLabel ();
3442 expr.EmitBranchable (ec, false_target, false);
3444 ig.Emit (OpCodes.Br, end_target);
3445 ig.MarkLabel (false_target);
3446 falseExpr.Emit (ec);
3447 ig.MarkLabel (end_target);
3450 protected override void CloneTo (CloneContext clonectx, Expression t)
3452 Conditional target = (Conditional) t;
3454 target.expr = expr.Clone (clonectx);
3455 target.trueExpr = trueExpr.Clone (clonectx);
3456 target.falseExpr = falseExpr.Clone (clonectx);
3460 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3462 LocalTemporary temp;
3464 public abstract Variable Variable {
3468 public abstract bool IsRef {
3472 public override void Emit (EmitContext ec)
3478 // This method is used by parameters that are references, that are
3479 // being passed as references: we only want to pass the pointer (that
3480 // is already stored in the parameter, not the address of the pointer,
3481 // and not the value of the variable).
3483 public void EmitLoad (EmitContext ec)
3485 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3487 Variable.EmitInstance (ec);
3491 public void Emit (EmitContext ec, bool leave_copy)
3493 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3499 ec.ig.Emit (OpCodes.Dup);
3502 // If we are a reference, we loaded on the stack a pointer
3503 // Now lets load the real value
3505 LoadFromPtr (ec.ig, type);
3509 ec.ig.Emit (OpCodes.Dup);
3511 if (IsRef || Variable.NeedsTemporary) {
3512 temp = new LocalTemporary (Type);
3518 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3519 bool prepare_for_load)
3521 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3524 ILGenerator ig = ec.ig;
3525 prepared = prepare_for_load;
3527 Variable.EmitInstance (ec);
3528 if (prepare_for_load && Variable.HasInstance)
3529 ig.Emit (OpCodes.Dup);
3530 else if (IsRef && !prepared)
3536 ig.Emit (OpCodes.Dup);
3537 if (IsRef || Variable.NeedsTemporary) {
3538 temp = new LocalTemporary (Type);
3544 StoreFromPtr (ig, type);
3546 Variable.EmitAssign (ec);
3554 public void AddressOf (EmitContext ec, AddressOp mode)
3556 Variable.EmitInstance (ec);
3557 Variable.EmitAddressOf (ec);
3564 public class LocalVariableReference : VariableReference, IVariable {
3565 public readonly string Name;
3567 public LocalInfo local_info;
3571 public LocalVariableReference (Block block, string name, Location l)
3576 eclass = ExprClass.Variable;
3580 // Setting `is_readonly' to false will allow you to create a writable
3581 // reference to a read-only variable. This is used by foreach and using.
3583 public LocalVariableReference (Block block, string name, Location l,
3584 LocalInfo local_info, bool is_readonly)
3585 : this (block, name, l)
3587 this.local_info = local_info;
3588 this.is_readonly = is_readonly;
3591 public VariableInfo VariableInfo {
3592 get { return local_info.VariableInfo; }
3595 public override bool IsRef {
3596 get { return false; }
3599 public bool IsReadOnly {
3600 get { return is_readonly; }
3603 public bool VerifyAssigned (EmitContext ec)
3605 VariableInfo variable_info = local_info.VariableInfo;
3606 return variable_info == null || variable_info.IsAssigned (ec, loc);
3609 void ResolveLocalInfo ()
3611 if (local_info == null) {
3612 local_info = Block.GetLocalInfo (Name);
3613 type = local_info.VariableType;
3614 is_readonly = local_info.ReadOnly;
3618 protected Expression DoResolveBase (EmitContext ec)
3620 type = local_info.VariableType;
3622 Expression e = Block.GetConstantExpression (Name);
3624 return e.Resolve (ec);
3626 if (!VerifyAssigned (ec))
3630 // If we are referencing a variable from the external block
3631 // flag it for capturing
3633 if (ec.MustCaptureVariable (local_info)) {
3634 if (local_info.AddressTaken){
3635 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3639 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3640 variable = scope.AddLocal (local_info);
3641 type = variable.Type;
3647 public override Expression DoResolve (EmitContext ec)
3649 ResolveLocalInfo ();
3650 local_info.Used = true;
3652 if (type == null && local_info.Type is VarExpr) {
3653 local_info.VariableType = TypeManager.object_type;
3654 Error_VariableIsUsedBeforeItIsDeclared (Name);
3658 return DoResolveBase (ec);
3661 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3663 ResolveLocalInfo ();
3666 if (right_side == EmptyExpression.OutAccess)
3667 local_info.Used = true;
3669 // Infer implicitly typed local variable
3671 VarExpr ve = local_info.Type as VarExpr;
3673 ve.DoResolveLValue (ec, right_side);
3674 type = local_info.VariableType = ve.Type;
3681 if (right_side == EmptyExpression.OutAccess) {
3682 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3683 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3684 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3685 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3686 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3688 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3690 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3694 if (VariableInfo != null)
3695 VariableInfo.SetAssigned (ec);
3697 return DoResolveBase (ec);
3700 public bool VerifyFixed ()
3702 // A local Variable is always fixed.
3706 public override int GetHashCode ()
3708 return Name.GetHashCode ();
3711 public override bool Equals (object obj)
3713 LocalVariableReference lvr = obj as LocalVariableReference;
3717 return Name == lvr.Name && Block == lvr.Block;
3720 public override Variable Variable {
3721 get { return variable != null ? variable : local_info.Variable; }
3724 public override string ToString ()
3726 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3729 protected override void CloneTo (CloneContext clonectx, Expression t)
3731 LocalVariableReference target = (LocalVariableReference) t;
3733 target.Block = clonectx.LookupBlock (Block);
3734 if (local_info != null)
3735 target.local_info = clonectx.LookupVariable (local_info);
3740 /// This represents a reference to a parameter in the intermediate
3743 public class ParameterReference : VariableReference, IVariable {
3744 readonly ToplevelParameterInfo pi;
3745 readonly ToplevelBlock referenced;
3748 public bool is_ref, is_out;
3751 get { return is_out; }
3754 public override bool IsRef {
3755 get { return is_ref; }
3758 public string Name {
3759 get { return Parameter.Name; }
3762 public Parameter Parameter {
3763 get { return pi.Parameter; }
3766 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3769 this.referenced = referenced;
3771 eclass = ExprClass.Variable;
3774 public VariableInfo VariableInfo {
3775 get { return pi.VariableInfo; }
3778 public override Variable Variable {
3779 get { return variable != null ? variable : Parameter.Variable; }
3782 public bool VerifyFixed ()
3784 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3785 return Parameter.ModFlags == Parameter.Modifier.NONE;
3788 public bool IsAssigned (EmitContext ec, Location loc)
3790 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3793 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3797 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3799 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3802 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3806 public void SetAssigned (EmitContext ec)
3808 if (is_out && ec.DoFlowAnalysis)
3809 ec.CurrentBranching.SetAssigned (VariableInfo);
3812 public void SetFieldAssigned (EmitContext ec, string field_name)
3814 if (is_out && ec.DoFlowAnalysis)
3815 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3818 protected bool DoResolveBase (EmitContext ec)
3820 Parameter par = Parameter;
3821 if (!par.Resolve (ec)) {
3825 type = par.ParameterType;
3826 Parameter.Modifier mod = par.ModFlags;
3827 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3828 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3829 eclass = ExprClass.Variable;
3831 AnonymousContainer am = ec.CurrentAnonymousMethod;
3835 ToplevelBlock declared = pi.Block;
3836 if (is_ref && declared != referenced) {
3837 Report.Error (1628, Location,
3838 "Cannot use ref or out parameter `{0}' inside an " +
3839 "anonymous method block", par.Name);
3843 if (!am.IsIterator && declared == referenced)
3846 // Don't capture aruments when the probing is on
3847 if (!ec.IsInProbingMode) {
3848 ScopeInfo scope = declared.CreateScopeInfo ();
3849 variable = scope.AddParameter (par, pi.Index);
3850 type = variable.Type;
3855 public override int GetHashCode ()
3857 return Name.GetHashCode ();
3860 public override bool Equals (object obj)
3862 ParameterReference pr = obj as ParameterReference;
3866 return Name == pr.Name && referenced == pr.referenced;
3870 // Notice that for ref/out parameters, the type exposed is not the
3871 // same type exposed externally.
3874 // externally we expose "int&"
3875 // here we expose "int".
3877 // We record this in "is_ref". This means that the type system can treat
3878 // the type as it is expected, but when we generate the code, we generate
3879 // the alternate kind of code.
3881 public override Expression DoResolve (EmitContext ec)
3883 if (!DoResolveBase (ec))
3886 if (is_out && ec.DoFlowAnalysis &&
3887 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3893 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3895 if (!DoResolveBase (ec))
3898 // HACK: parameters are not captured when probing is on
3899 if (!ec.IsInProbingMode)
3905 static public void EmitLdArg (ILGenerator ig, int x)
3909 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3910 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3911 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3912 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3913 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3916 ig.Emit (OpCodes.Ldarg, x);
3919 public override string ToString ()
3921 return "ParameterReference[" + Name + "]";
3926 /// Used for arguments to New(), Invocation()
3928 public class Argument {
3929 public enum AType : byte {
3936 public static readonly Argument[] Empty = new Argument [0];
3938 public readonly AType ArgType;
3939 public Expression Expr;
3941 public Argument (Expression expr, AType type)
3944 this.ArgType = type;
3947 public Argument (Expression expr)
3950 this.ArgType = AType.Expression;
3955 if (ArgType == AType.Ref || ArgType == AType.Out)
3956 return TypeManager.GetReferenceType (Expr.Type);
3962 public Parameter.Modifier Modifier
3967 return Parameter.Modifier.OUT;
3970 return Parameter.Modifier.REF;
3973 return Parameter.Modifier.NONE;
3978 public static string FullDesc (Argument a)
3980 if (a.ArgType == AType.ArgList)
3983 return (a.ArgType == AType.Ref ? "ref " :
3984 (a.ArgType == AType.Out ? "out " : "")) +
3985 TypeManager.CSharpName (a.Expr.Type);
3988 public bool ResolveMethodGroup (EmitContext ec)
3990 SimpleName sn = Expr as SimpleName;
3992 Expr = sn.GetMethodGroup ();
3994 // FIXME: csc doesn't report any error if you try to use `ref' or
3995 // `out' in a delegate creation expression.
3996 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4003 public bool Resolve (EmitContext ec, Location loc)
4005 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4006 // Verify that the argument is readable
4007 if (ArgType != AType.Out)
4008 Expr = Expr.Resolve (ec);
4010 // Verify that the argument is writeable
4011 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4012 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4014 return Expr != null;
4018 public void Emit (EmitContext ec)
4020 if (ArgType != AType.Ref && ArgType != AType.Out) {
4025 AddressOp mode = AddressOp.Store;
4026 if (ArgType == AType.Ref)
4027 mode |= AddressOp.Load;
4029 IMemoryLocation ml = (IMemoryLocation) Expr;
4030 ParameterReference pr = ml as ParameterReference;
4033 // ParameterReferences might already be references, so we want
4034 // to pass just the value
4036 if (pr != null && pr.IsRef)
4039 ml.AddressOf (ec, mode);
4042 public Argument Clone (CloneContext clonectx)
4044 return new Argument (Expr.Clone (clonectx), ArgType);
4049 /// Invocation of methods or delegates.
4051 public class Invocation : ExpressionStatement {
4052 ArrayList Arguments;
4057 // arguments is an ArrayList, but we do not want to typecast,
4058 // as it might be null.
4060 public Invocation (Expression expr, ArrayList arguments)
4062 SimpleName sn = expr as SimpleName;
4064 this.expr = sn.GetMethodGroup ();
4068 Arguments = arguments;
4069 loc = expr.Location;
4072 public static string FullMethodDesc (MethodBase mb)
4078 if (mb is MethodInfo) {
4079 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4083 sb = new StringBuilder ();
4085 sb.Append (TypeManager.CSharpSignature (mb));
4086 return sb.ToString ();
4089 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4090 ArrayList arguments, int arg_count,
4091 ref MethodBase candidate)
4093 return IsParamsMethodApplicable (
4094 ec, me, arguments, arg_count, false, ref candidate) ||
4095 IsParamsMethodApplicable (
4096 ec, me, arguments, arg_count, true, ref candidate);
4101 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4102 ArrayList arguments, int arg_count,
4103 bool do_varargs, ref MethodBase candidate)
4106 if (!me.HasTypeArguments &&
4107 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4110 if (TypeManager.IsGenericMethodDefinition (candidate))
4111 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4114 return IsParamsMethodApplicable (
4115 ec, arguments, arg_count, candidate, do_varargs);
4119 /// Determines if the candidate method, if a params method, is applicable
4120 /// in its expanded form to the given set of arguments
4122 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4123 int arg_count, MethodBase candidate,
4126 ParameterData pd = TypeManager.GetParameterData (candidate);
4128 int pd_count = pd.Count;
4132 int count = pd_count - 1;
4134 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4136 if (pd_count != arg_count)
4139 if (!(((Argument) arguments [count]).Expr is Arglist))
4147 if (count > arg_count)
4150 if (pd_count == 1 && arg_count == 0)
4154 // If we have come this far, the case which
4155 // remains is when the number of parameters is
4156 // less than or equal to the argument count.
4158 int argument_index = 0;
4160 for (int i = 0; i < pd_count; ++i) {
4162 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4163 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4164 int params_args_count = arg_count - pd_count;
4165 if (params_args_count < 0)
4169 a = (Argument) arguments [argument_index++];
4171 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4173 } while (params_args_count-- > 0);
4177 a = (Argument) arguments [argument_index++];
4179 Parameter.Modifier a_mod = a.Modifier &
4180 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4181 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4182 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4184 if (a_mod == p_mod) {
4186 if (a_mod == Parameter.Modifier.NONE)
4187 if (!Convert.ImplicitConversionExists (ec,
4189 pd.ParameterType (i)))
4192 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4193 Type pt = pd.ParameterType (i);
4196 pt = TypeManager.GetReferenceType (pt);
4209 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4210 ArrayList arguments, int arg_count,
4211 ref MethodBase method)
4213 MethodBase candidate = method;
4216 if (!me.HasTypeArguments &&
4217 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4220 if (TypeManager.IsGenericMethodDefinition (candidate))
4221 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4224 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4233 /// Determines if the candidate method is applicable (section 14.4.2.1)
4234 /// to the given set of arguments
4236 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4237 MethodBase candidate)
4239 ParameterData pd = TypeManager.GetParameterData (candidate);
4241 if (arg_count != pd.Count)
4244 for (int i = arg_count; i > 0; ) {
4247 Argument a = (Argument) arguments [i];
4249 Parameter.Modifier a_mod = a.Modifier &
4250 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4252 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4253 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4258 Type pt = pd.ParameterType (i);
4260 if (TypeManager.IsEqual (pt, a.Type))
4263 if (a_mod != Parameter.Modifier.NONE)
4266 // FIXME: Kill this abomination (EmitContext.TempEc)
4267 EmitContext prevec = EmitContext.TempEc;
4268 EmitContext.TempEc = ec;
4270 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4273 EmitContext.TempEc = prevec;
4280 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4282 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4283 name, arg_count.ToString ());
4286 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4287 Type delegate_type, Argument a, ParameterData expected_par)
4289 if (delegate_type == null)
4290 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4291 TypeManager.CSharpSignature (method));
4293 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4294 TypeManager.CSharpName (delegate_type));
4296 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4298 string index = (idx + 1).ToString ();
4299 if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4300 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4301 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4302 index, Parameter.GetModifierSignature (a.Modifier));
4304 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4305 index, Parameter.GetModifierSignature (mod));
4307 string p1 = Argument.FullDesc (a);
4308 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4311 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4312 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4313 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4315 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4319 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4320 int arg_count, MethodBase method,
4321 bool chose_params_expanded,
4322 Type delegate_type, bool may_fail,
4325 ParameterData pd = TypeManager.GetParameterData (method);
4329 for (j = 0; j < pd.Count; j++) {
4330 Type parameter_type = pd.ParameterType (j);
4331 Parameter.Modifier pm = pd.ParameterModifier (j);
4333 if (pm == Parameter.Modifier.ARGLIST) {
4334 a = (Argument) Arguments [a_idx];
4335 if (!(a.Expr is Arglist))
4341 int params_arg_count = 1;
4342 if (pm == Parameter.Modifier.PARAMS) {
4343 pm = Parameter.Modifier.NONE;
4344 params_arg_count = arg_count - pd.Count + 1;
4345 if (chose_params_expanded)
4346 parameter_type = TypeManager.GetElementType (parameter_type);
4349 while (params_arg_count > 0) {
4350 a = (Argument) Arguments [a_idx];
4351 if (pm != a.Modifier)
4354 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4355 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4358 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4362 // Update the argument with the implicit conversion
4370 if (params_arg_count > 0)
4373 if (parameter_type.IsPointer && !ec.InUnsafe) {
4380 if (a_idx == arg_count)
4384 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4388 public override Expression DoResolve (EmitContext ec)
4390 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4391 if (expr_resolved == null)
4394 mg = expr_resolved as MethodGroupExpr;
4396 Type expr_type = expr_resolved.Type;
4398 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4399 return (new DelegateInvocation (
4400 expr_resolved, Arguments, loc)).Resolve (ec);
4402 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4407 // Next, evaluate all the expressions in the argument list
4409 if (Arguments != null){
4410 foreach (Argument a in Arguments){
4411 if (!a.Resolve (ec, loc))
4416 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4420 MethodInfo method = (MethodInfo)mg;
4421 if (method != null) {
4422 type = TypeManager.TypeToCoreType (method.ReturnType);
4423 Expression iexpr = mg.InstanceExpression;
4424 if (method.IsStatic) {
4425 if (iexpr == null ||
4426 iexpr is This || iexpr is EmptyExpression ||
4427 mg.IdenticalTypeName) {
4428 mg.InstanceExpression = null;
4430 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4434 if (iexpr == null || iexpr is EmptyExpression) {
4435 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4441 if (type.IsPointer){
4449 // Only base will allow this invocation to happen.
4451 if (mg.IsBase && method.IsAbstract){
4452 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4456 if (Arguments == null && method.Name == "Finalize") {
4458 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4460 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4464 if (IsSpecialMethodInvocation (method)) {
4468 if (mg.InstanceExpression != null){
4469 mg.InstanceExpression.CheckMarshalByRefAccess ();
4472 // This is used to check that no methods are called in struct
4473 // constructors before all the fields on the struct have been
4476 if (!method.IsStatic){
4477 This mgthis = mg.InstanceExpression as This;
4478 if (mgthis != null){
4479 if (!mgthis.CheckThisUsage (ec))
4485 eclass = ExprClass.Value;
4489 bool IsSpecialMethodInvocation (MethodBase method)
4491 if (!TypeManager.IsSpecialMethod (method))
4494 Report.SymbolRelatedToPreviousError (method);
4495 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4496 TypeManager.CSharpSignature (method, true));
4502 // Emits the list of arguments as an array
4504 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4506 ILGenerator ig = ec.ig;
4508 for (int j = 0; j < count; j++){
4509 Argument a = (Argument) arguments [j + idx];
4512 IntConstant.EmitInt (ig, count);
4513 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4516 ig.Emit (OpCodes.Dup);
4517 IntConstant.EmitInt (ig, j);
4519 bool is_stobj, has_type_arg;
4520 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4522 ig.Emit (OpCodes.Ldelema, t);
4534 /// Emits a list of resolved Arguments that are in the arguments
4537 /// The MethodBase argument might be null if the
4538 /// emission of the arguments is known not to contain
4539 /// a `params' field (for example in constructors or other routines
4540 /// that keep their arguments in this structure)
4542 /// if `dup_args' is true, a copy of the arguments will be left
4543 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4544 /// which will be duplicated before any other args. Only EmitCall
4545 /// should be using this interface.
4547 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4549 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4551 LocalTemporary [] temps = null;
4553 if (dup_args && top != 0)
4554 temps = new LocalTemporary [top];
4556 int argument_index = 0;
4558 for (int i = 0; i < top; i++){
4560 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4561 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4562 int params_args_count = arguments == null ?
4563 0 : arguments.Count - top + 1;
4565 // Fill not provided argument
4566 if (params_args_count <= 0) {
4567 ILGenerator ig = ec.ig;
4568 IntConstant.EmitInt (ig, 0);
4569 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4574 // Special case if we are passing the same data as the
4575 // params argument, we do not need to recreate an array.
4577 a = (Argument) arguments [argument_index];
4578 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4584 EmitParams (ec, arguments, i, params_args_count);
4585 argument_index += params_args_count;
4590 a = (Argument) arguments [argument_index++];
4593 ec.ig.Emit (OpCodes.Dup);
4594 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4599 if (this_arg != null)
4602 for (int i = 0; i < top; i ++) {
4603 temps [i].Emit (ec);
4604 temps [i].Release (ec);
4609 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4611 ParameterData pd = TypeManager.GetParameterData (mb);
4613 if (arguments == null)
4614 return new Type [0];
4616 Argument a = (Argument) arguments [pd.Count - 1];
4617 Arglist list = (Arglist) a.Expr;
4619 return list.ArgumentTypes;
4623 /// This checks the ConditionalAttribute on the method
4625 static bool IsMethodExcluded (MethodBase method)
4627 if (method.IsConstructor)
4630 IMethodData md = TypeManager.GetMethod (method);
4632 return md.IsExcluded ();
4634 // For some methods (generated by delegate class) GetMethod returns null
4635 // because they are not included in builder_to_method table
4636 if (method.DeclaringType is TypeBuilder)
4639 return AttributeTester.IsConditionalMethodExcluded (method);
4643 /// is_base tells whether we want to force the use of the `call'
4644 /// opcode instead of using callvirt. Call is required to call
4645 /// a specific method, while callvirt will always use the most
4646 /// recent method in the vtable.
4648 /// is_static tells whether this is an invocation on a static method
4650 /// instance_expr is an expression that represents the instance
4651 /// it must be non-null if is_static is false.
4653 /// method is the method to invoke.
4655 /// Arguments is the list of arguments to pass to the method or constructor.
4657 public static void EmitCall (EmitContext ec, bool is_base,
4658 Expression instance_expr,
4659 MethodBase method, ArrayList Arguments, Location loc)
4661 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4664 // `dup_args' leaves an extra copy of the arguments on the stack
4665 // `omit_args' does not leave any arguments at all.
4666 // So, basically, you could make one call with `dup_args' set to true,
4667 // and then another with `omit_args' set to true, and the two calls
4668 // would have the same set of arguments. However, each argument would
4669 // only have been evaluated once.
4670 public static void EmitCall (EmitContext ec, bool is_base,
4671 Expression instance_expr,
4672 MethodBase method, ArrayList Arguments, Location loc,
4673 bool dup_args, bool omit_args)
4675 ILGenerator ig = ec.ig;
4676 bool struct_call = false;
4677 bool this_call = false;
4678 LocalTemporary this_arg = null;
4680 Type decl_type = method.DeclaringType;
4682 if (!RootContext.StdLib) {
4683 // Replace any calls to the system's System.Array type with calls to
4684 // the newly created one.
4685 if (method == TypeManager.system_int_array_get_length)
4686 method = TypeManager.int_array_get_length;
4687 else if (method == TypeManager.system_int_array_get_rank)
4688 method = TypeManager.int_array_get_rank;
4689 else if (method == TypeManager.system_object_array_clone)
4690 method = TypeManager.object_array_clone;
4691 else if (method == TypeManager.system_int_array_get_length_int)
4692 method = TypeManager.int_array_get_length_int;
4693 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4694 method = TypeManager.int_array_get_lower_bound_int;
4695 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4696 method = TypeManager.int_array_get_upper_bound_int;
4697 else if (method == TypeManager.system_void_array_copyto_array_int)
4698 method = TypeManager.void_array_copyto_array_int;
4701 if (!ec.IsInObsoleteScope) {
4703 // This checks ObsoleteAttribute on the method and on the declaring type
4705 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4707 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4709 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4711 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4715 if (IsMethodExcluded (method))
4718 bool is_static = method.IsStatic;
4720 if (instance_expr == EmptyExpression.Null) {
4721 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4725 this_call = instance_expr is This;
4726 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4730 // If this is ourselves, push "this"
4734 Type iexpr_type = instance_expr.Type;
4737 // Push the instance expression
4739 if (TypeManager.IsValueType (iexpr_type)) {
4741 // Special case: calls to a function declared in a
4742 // reference-type with a value-type argument need
4743 // to have their value boxed.
4744 if (decl_type.IsValueType ||
4745 TypeManager.IsGenericParameter (iexpr_type)) {
4747 // If the expression implements IMemoryLocation, then
4748 // we can optimize and use AddressOf on the
4751 // If not we have to use some temporary storage for
4753 if (instance_expr is IMemoryLocation) {
4754 ((IMemoryLocation)instance_expr).
4755 AddressOf (ec, AddressOp.LoadStore);
4757 LocalTemporary temp = new LocalTemporary (iexpr_type);
4758 instance_expr.Emit (ec);
4760 temp.AddressOf (ec, AddressOp.Load);
4763 // avoid the overhead of doing this all the time.
4765 t = TypeManager.GetReferenceType (iexpr_type);
4767 instance_expr.Emit (ec);
4768 ig.Emit (OpCodes.Box, instance_expr.Type);
4769 t = TypeManager.object_type;
4772 instance_expr.Emit (ec);
4773 t = instance_expr.Type;
4777 ig.Emit (OpCodes.Dup);
4778 if (Arguments != null && Arguments.Count != 0) {
4779 this_arg = new LocalTemporary (t);
4780 this_arg.Store (ec);
4787 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4790 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4791 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4795 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4796 call_op = OpCodes.Call;
4798 call_op = OpCodes.Callvirt;
4800 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4801 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4802 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4809 // and DoFoo is not virtual, you can omit the callvirt,
4810 // because you don't need the null checking behavior.
4812 if (method is MethodInfo)
4813 ig.Emit (call_op, (MethodInfo) method);
4815 ig.Emit (call_op, (ConstructorInfo) method);
4818 public override void Emit (EmitContext ec)
4820 mg.EmitCall (ec, Arguments);
4823 public override void EmitStatement (EmitContext ec)
4828 // Pop the return value if there is one
4830 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4831 ec.ig.Emit (OpCodes.Pop);
4834 protected override void CloneTo (CloneContext clonectx, Expression t)
4836 Invocation target = (Invocation) t;
4838 if (Arguments != null) {
4839 target.Arguments = new ArrayList (Arguments.Count);
4840 foreach (Argument a in Arguments)
4841 target.Arguments.Add (a.Clone (clonectx));
4844 target.expr = expr.Clone (clonectx);
4848 public class InvocationOrCast : ExpressionStatement
4851 Expression argument;
4853 public InvocationOrCast (Expression expr, Expression argument)
4856 this.argument = argument;
4857 this.loc = expr.Location;
4860 public override Expression DoResolve (EmitContext ec)
4863 // First try to resolve it as a cast.
4865 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4866 if ((te != null) && (te.eclass == ExprClass.Type)) {
4867 Cast cast = new Cast (te, argument, loc);
4868 return cast.Resolve (ec);
4872 // This can either be a type or a delegate invocation.
4873 // Let's just resolve it and see what we'll get.
4875 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4880 // Ok, so it's a Cast.
4882 if (expr.eclass == ExprClass.Type) {
4883 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4884 return cast.Resolve (ec);
4888 // It's a delegate invocation.
4890 if (!TypeManager.IsDelegateType (expr.Type)) {
4891 Error (149, "Method name expected");
4895 ArrayList args = new ArrayList ();
4896 args.Add (new Argument (argument, Argument.AType.Expression));
4897 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4898 return invocation.Resolve (ec);
4901 public override ExpressionStatement ResolveStatement (EmitContext ec)
4904 // First try to resolve it as a cast.
4906 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4907 if ((te != null) && (te.eclass == ExprClass.Type)) {
4908 Error_InvalidExpressionStatement ();
4913 // This can either be a type or a delegate invocation.
4914 // Let's just resolve it and see what we'll get.
4916 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4917 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4918 Error_InvalidExpressionStatement ();
4923 // It's a delegate invocation.
4925 if (!TypeManager.IsDelegateType (expr.Type)) {
4926 Error (149, "Method name expected");
4930 ArrayList args = new ArrayList ();
4931 args.Add (new Argument (argument, Argument.AType.Expression));
4932 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4933 return invocation.ResolveStatement (ec);
4936 public override void Emit (EmitContext ec)
4938 throw new Exception ("Cannot happen");
4941 public override void EmitStatement (EmitContext ec)
4943 throw new Exception ("Cannot happen");
4946 protected override void CloneTo (CloneContext clonectx, Expression t)
4948 InvocationOrCast target = (InvocationOrCast) t;
4950 target.expr = expr.Clone (clonectx);
4951 target.argument = argument.Clone (clonectx);
4956 // This class is used to "disable" the code generation for the
4957 // temporary variable when initializing value types.
4959 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4960 public void AddressOf (EmitContext ec, AddressOp Mode)
4967 /// Implements the new expression
4969 public class New : ExpressionStatement, IMemoryLocation {
4970 ArrayList Arguments;
4973 // During bootstrap, it contains the RequestedType,
4974 // but if `type' is not null, it *might* contain a NewDelegate
4975 // (because of field multi-initialization)
4977 public Expression RequestedType;
4979 MethodGroupExpr method;
4982 // If set, the new expression is for a value_target, and
4983 // we will not leave anything on the stack.
4985 Expression value_target;
4986 bool value_target_set = false;
4987 bool is_type_parameter = false;
4989 public New (Expression requested_type, ArrayList arguments, Location l)
4991 RequestedType = requested_type;
4992 Arguments = arguments;
4996 public bool SetValueTypeVariable (Expression value)
4998 value_target = value;
4999 value_target_set = true;
5000 if (!(value_target is IMemoryLocation)){
5001 Error_UnexpectedKind (null, "variable", loc);
5008 // This function is used to disable the following code sequence for
5009 // value type initialization:
5011 // AddressOf (temporary)
5015 // Instead the provide will have provided us with the address on the
5016 // stack to store the results.
5018 static Expression MyEmptyExpression;
5020 public void DisableTemporaryValueType ()
5022 if (MyEmptyExpression == null)
5023 MyEmptyExpression = new EmptyAddressOf ();
5026 // To enable this, look into:
5027 // test-34 and test-89 and self bootstrapping.
5029 // For instance, we can avoid a copy by using `newobj'
5030 // instead of Call + Push-temp on value types.
5031 // value_target = MyEmptyExpression;
5036 /// Converts complex core type syntax like 'new int ()' to simple constant
5038 public static Constant Constantify (Type t)
5040 if (t == TypeManager.int32_type)
5041 return new IntConstant (0, Location.Null);
5042 if (t == TypeManager.uint32_type)
5043 return new UIntConstant (0, Location.Null);
5044 if (t == TypeManager.int64_type)
5045 return new LongConstant (0, Location.Null);
5046 if (t == TypeManager.uint64_type)
5047 return new ULongConstant (0, Location.Null);
5048 if (t == TypeManager.float_type)
5049 return new FloatConstant (0, Location.Null);
5050 if (t == TypeManager.double_type)
5051 return new DoubleConstant (0, Location.Null);
5052 if (t == TypeManager.short_type)
5053 return new ShortConstant (0, Location.Null);
5054 if (t == TypeManager.ushort_type)
5055 return new UShortConstant (0, Location.Null);
5056 if (t == TypeManager.sbyte_type)
5057 return new SByteConstant (0, Location.Null);
5058 if (t == TypeManager.byte_type)
5059 return new ByteConstant (0, Location.Null);
5060 if (t == TypeManager.char_type)
5061 return new CharConstant ('\0', Location.Null);
5062 if (t == TypeManager.bool_type)
5063 return new BoolConstant (false, Location.Null);
5064 if (t == TypeManager.decimal_type)
5065 return new DecimalConstant (0, Location.Null);
5066 if (TypeManager.IsEnumType (t))
5067 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5073 // Checks whether the type is an interface that has the
5074 // [ComImport, CoClass] attributes and must be treated
5077 public Expression CheckComImport (EmitContext ec)
5079 if (!type.IsInterface)
5083 // Turn the call into:
5084 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5086 Type real_class = AttributeTester.GetCoClassAttribute (type);
5087 if (real_class == null)
5090 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5091 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5092 return cast.Resolve (ec);
5095 public override Expression DoResolve (EmitContext ec)
5098 // The New DoResolve might be called twice when initializing field
5099 // expressions (see EmitFieldInitializers, the call to
5100 // GetInitializerExpression will perform a resolve on the expression,
5101 // and later the assign will trigger another resolution
5103 // This leads to bugs (#37014)
5106 if (RequestedType is NewDelegate)
5107 return RequestedType;
5111 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5117 if (type == TypeManager.void_type) {
5118 Error_VoidInvalidInTheContext (loc);
5122 if (Arguments == null) {
5123 Expression c = Constantify (type);
5128 if (TypeManager.IsDelegateType (type)) {
5129 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5130 if (RequestedType != null)
5131 if (!(RequestedType is DelegateCreation))
5132 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5133 return RequestedType;
5137 if (type.IsGenericParameter) {
5138 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5140 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5141 Error (304, String.Format (
5142 "Cannot create an instance of the " +
5143 "variable type '{0}' because it " +
5144 "doesn't have the new() constraint",
5149 if ((Arguments != null) && (Arguments.Count != 0)) {
5150 Error (417, String.Format (
5151 "`{0}': cannot provide arguments " +
5152 "when creating an instance of a " +
5153 "variable type.", type));
5157 is_type_parameter = true;
5158 eclass = ExprClass.Value;
5163 if (type.IsAbstract && type.IsSealed) {
5164 Report.SymbolRelatedToPreviousError (type);
5165 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5169 if (type.IsInterface || type.IsAbstract){
5170 if (!TypeManager.IsGenericType (type)) {
5171 RequestedType = CheckComImport (ec);
5172 if (RequestedType != null)
5173 return RequestedType;
5176 Report.SymbolRelatedToPreviousError (type);
5177 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5181 bool is_struct = type.IsValueType;
5182 eclass = ExprClass.Value;
5185 // SRE returns a match for .ctor () on structs (the object constructor),
5186 // so we have to manually ignore it.
5188 if (is_struct && Arguments == null)
5191 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5192 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5193 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5198 method = ml as MethodGroupExpr;
5200 if (method == null) {
5201 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5205 if (Arguments != null){
5206 foreach (Argument a in Arguments){
5207 if (!a.Resolve (ec, loc))
5212 method = method.OverloadResolve (ec, Arguments, false, loc);
5213 if (method == null) {
5214 if (almostMatchedMembers.Count != 0)
5215 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5222 bool DoEmitTypeParameter (EmitContext ec)
5225 ILGenerator ig = ec.ig;
5226 // IMemoryLocation ml;
5228 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5229 new Type [] { type });
5231 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5232 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5233 ig.Emit (OpCodes.Call, ci);
5237 // Allow DoEmit() to be called multiple times.
5238 // We need to create a new LocalTemporary each time since
5239 // you can't share LocalBuilders among ILGeneators.
5240 LocalTemporary temp = new LocalTemporary (type);
5242 Label label_activator = ig.DefineLabel ();
5243 Label label_end = ig.DefineLabel ();
5245 temp.AddressOf (ec, AddressOp.Store);
5246 ig.Emit (OpCodes.Initobj, type);
5249 ig.Emit (OpCodes.Box, type);
5250 ig.Emit (OpCodes.Brfalse, label_activator);
5252 temp.AddressOf (ec, AddressOp.Store);
5253 ig.Emit (OpCodes.Initobj, type);
5255 ig.Emit (OpCodes.Br, label_end);
5257 ig.MarkLabel (label_activator);
5259 ig.Emit (OpCodes.Call, ci);
5260 ig.MarkLabel (label_end);
5263 throw new InternalErrorException ();
5268 // This DoEmit can be invoked in two contexts:
5269 // * As a mechanism that will leave a value on the stack (new object)
5270 // * As one that wont (init struct)
5272 // You can control whether a value is required on the stack by passing
5273 // need_value_on_stack. The code *might* leave a value on the stack
5274 // so it must be popped manually
5276 // If we are dealing with a ValueType, we have a few
5277 // situations to deal with:
5279 // * The target is a ValueType, and we have been provided
5280 // the instance (this is easy, we are being assigned).
5282 // * The target of New is being passed as an argument,
5283 // to a boxing operation or a function that takes a
5286 // In this case, we need to create a temporary variable
5287 // that is the argument of New.
5289 // Returns whether a value is left on the stack
5291 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5293 bool is_value_type = TypeManager.IsValueType (type);
5294 ILGenerator ig = ec.ig;
5299 // Allow DoEmit() to be called multiple times.
5300 // We need to create a new LocalTemporary each time since
5301 // you can't share LocalBuilders among ILGeneators.
5302 if (!value_target_set)
5303 value_target = new LocalTemporary (type);
5305 ml = (IMemoryLocation) value_target;
5306 ml.AddressOf (ec, AddressOp.Store);
5310 method.EmitArguments (ec, Arguments);
5314 ig.Emit (OpCodes.Initobj, type);
5316 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5317 if (need_value_on_stack){
5318 value_target.Emit (ec);
5323 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5328 public override void Emit (EmitContext ec)
5330 if (is_type_parameter)
5331 DoEmitTypeParameter (ec);
5336 public override void EmitStatement (EmitContext ec)
5338 bool value_on_stack;
5340 if (is_type_parameter)
5341 value_on_stack = DoEmitTypeParameter (ec);
5343 value_on_stack = DoEmit (ec, false);
5346 ec.ig.Emit (OpCodes.Pop);
5350 public void AddressOf (EmitContext ec, AddressOp Mode)
5352 if (is_type_parameter) {
5353 LocalTemporary temp = new LocalTemporary (type);
5354 DoEmitTypeParameter (ec);
5356 temp.AddressOf (ec, Mode);
5360 if (!type.IsValueType){
5362 // We throw an exception. So far, I believe we only need to support
5364 // foreach (int j in new StructType ())
5367 throw new Exception ("AddressOf should not be used for classes");
5370 if (!value_target_set)
5371 value_target = new LocalTemporary (type);
5372 IMemoryLocation ml = (IMemoryLocation) value_target;
5374 ml.AddressOf (ec, AddressOp.Store);
5375 if (method == null) {
5376 ec.ig.Emit (OpCodes.Initobj, type);
5378 method.EmitArguments (ec, Arguments);
5379 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5382 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5385 protected override void CloneTo (CloneContext clonectx, Expression t)
5387 New target = (New) t;
5389 target.RequestedType = RequestedType.Clone (clonectx);
5390 if (Arguments != null){
5391 target.Arguments = new ArrayList ();
5392 foreach (Argument a in Arguments){
5393 target.Arguments.Add (a.Clone (clonectx));
5400 /// 14.5.10.2: Represents an array creation expression.
5404 /// There are two possible scenarios here: one is an array creation
5405 /// expression that specifies the dimensions and optionally the
5406 /// initialization data and the other which does not need dimensions
5407 /// specified but where initialization data is mandatory.
5409 public class ArrayCreation : Expression {
5410 Expression requested_base_type;
5411 ArrayList initializers;
5414 // The list of Argument types.
5415 // This is used to construct the `newarray' or constructor signature
5417 protected ArrayList arguments;
5419 protected Type array_element_type;
5420 bool expect_initializers = false;
5421 int num_arguments = 0;
5422 protected int dimensions;
5423 protected readonly string rank;
5425 protected ArrayList array_data;
5429 // The number of constants in array initializers
5430 int const_initializers_count;
5431 bool only_constant_initializers;
5433 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5435 this.requested_base_type = requested_base_type;
5436 this.initializers = initializers;
5440 arguments = new ArrayList ();
5442 foreach (Expression e in exprs) {
5443 arguments.Add (new Argument (e, Argument.AType.Expression));
5448 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5450 this.requested_base_type = requested_base_type;
5451 this.initializers = initializers;
5455 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5457 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5459 //dimensions = tmp.Length - 1;
5460 expect_initializers = true;
5463 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5465 StringBuilder sb = new StringBuilder (rank);
5468 for (int i = 1; i < idx_count; i++)
5473 return new ComposedCast (base_type, sb.ToString (), loc);
5476 void Error_IncorrectArrayInitializer ()
5478 Error (178, "Invalid rank specifier: expected `,' or `]'");
5481 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5483 if (specified_dims) {
5484 Argument a = (Argument) arguments [idx];
5486 if (!a.Resolve (ec, loc))
5489 Constant c = a.Expr as Constant;
5491 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5495 Report.Error (150, a.Expr.Location, "A constant value is expected");
5499 int value = (int) c.GetValue ();
5501 if (value != probe.Count) {
5502 Error_IncorrectArrayInitializer ();
5506 bounds [idx] = value;
5509 int child_bounds = -1;
5510 only_constant_initializers = true;
5511 for (int i = 0; i < probe.Count; ++i) {
5512 object o = probe [i];
5513 if (o is ArrayList) {
5514 ArrayList sub_probe = o as ArrayList;
5515 int current_bounds = sub_probe.Count;
5517 if (child_bounds == -1)
5518 child_bounds = current_bounds;
5520 else if (child_bounds != current_bounds){
5521 Error_IncorrectArrayInitializer ();
5524 if (idx + 1 >= dimensions){
5525 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5529 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5533 if (child_bounds != -1){
5534 Error_IncorrectArrayInitializer ();
5538 Expression element = ResolveArrayElement (ec, (Expression) o);
5539 if (element == null)
5542 // Initializers with the default values can be ignored
5543 Constant c = element as Constant;
5545 if (c.IsDefaultInitializer (array_element_type)) {
5549 ++const_initializers_count;
5552 only_constant_initializers = false;
5555 array_data.Add (element);
5562 public void UpdateIndices ()
5565 for (ArrayList probe = initializers; probe != null;) {
5566 if (probe.Count > 0 && probe [0] is ArrayList) {
5567 Expression e = new IntConstant (probe.Count, Location.Null);
5568 arguments.Add (new Argument (e, Argument.AType.Expression));
5570 bounds [i++] = probe.Count;
5572 probe = (ArrayList) probe [0];
5575 Expression e = new IntConstant (probe.Count, Location.Null);
5576 arguments.Add (new Argument (e, Argument.AType.Expression));
5578 bounds [i++] = probe.Count;
5585 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5587 element = element.Resolve (ec);
5588 if (element == null)
5591 return Convert.ImplicitConversionRequired (
5592 ec, element, array_element_type, loc);
5595 protected bool ResolveInitializers (EmitContext ec)
5597 if (initializers == null) {
5598 return !expect_initializers;
5602 // We use this to store all the date values in the order in which we
5603 // will need to store them in the byte blob later
5605 array_data = new ArrayList ();
5606 bounds = new System.Collections.Specialized.HybridDictionary ();
5608 if (arguments != null)
5609 return CheckIndices (ec, initializers, 0, true);
5611 arguments = new ArrayList ();
5613 if (!CheckIndices (ec, initializers, 0, false))
5622 // Resolved the type of the array
5624 bool ResolveArrayType (EmitContext ec)
5626 if (requested_base_type == null) {
5627 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5631 StringBuilder array_qualifier = new StringBuilder (rank);
5634 // `In the first form allocates an array instace of the type that results
5635 // from deleting each of the individual expression from the expression list'
5637 if (num_arguments > 0) {
5638 array_qualifier.Append ("[");
5639 for (int i = num_arguments-1; i > 0; i--)
5640 array_qualifier.Append (",");
5641 array_qualifier.Append ("]");
5647 TypeExpr array_type_expr;
5648 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5649 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5650 if (array_type_expr == null)
5653 type = array_type_expr.Type;
5654 array_element_type = TypeManager.GetElementType (type);
5655 dimensions = type.GetArrayRank ();
5660 public override Expression DoResolve (EmitContext ec)
5665 if (!ResolveArrayType (ec))
5668 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5669 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5670 TypeManager.CSharpName (array_element_type));
5674 // First step is to validate the initializers and fill
5675 // in any missing bits
5677 if (!ResolveInitializers (ec))
5680 if (arguments.Count != dimensions) {
5681 Error_IncorrectArrayInitializer ();
5684 foreach (Argument a in arguments){
5685 if (!a.Resolve (ec, loc))
5688 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5689 if (real_arg == null)
5695 eclass = ExprClass.Value;
5699 MethodInfo GetArrayMethod (int arguments)
5701 ModuleBuilder mb = CodeGen.Module.Builder;
5703 Type[] arg_types = new Type[arguments];
5704 for (int i = 0; i < arguments; i++)
5705 arg_types[i] = TypeManager.int32_type;
5707 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5711 Report.Error (-6, "New invocation: Can not find a constructor for " +
5712 "this argument list");
5719 byte [] MakeByteBlob ()
5724 int count = array_data.Count;
5726 if (array_element_type.IsEnum)
5727 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5729 factor = GetTypeSize (array_element_type);
5731 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5733 data = new byte [(count * factor + 4) & ~3];
5736 for (int i = 0; i < count; ++i) {
5737 object v = array_data [i];
5739 if (v is EnumConstant)
5740 v = ((EnumConstant) v).Child;
5742 if (v is Constant && !(v is StringConstant))
5743 v = ((Constant) v).GetValue ();
5749 if (array_element_type == TypeManager.int64_type){
5750 if (!(v is Expression)){
5751 long val = (long) v;
5753 for (int j = 0; j < factor; ++j) {
5754 data [idx + j] = (byte) (val & 0xFF);
5758 } else if (array_element_type == TypeManager.uint64_type){
5759 if (!(v is Expression)){
5760 ulong val = (ulong) v;
5762 for (int j = 0; j < factor; ++j) {
5763 data [idx + j] = (byte) (val & 0xFF);
5767 } else if (array_element_type == TypeManager.float_type) {
5768 if (!(v is Expression)){
5769 element = BitConverter.GetBytes ((float) v);
5771 for (int j = 0; j < factor; ++j)
5772 data [idx + j] = element [j];
5773 if (!BitConverter.IsLittleEndian)
5774 System.Array.Reverse (data, idx, 4);
5776 } else if (array_element_type == TypeManager.double_type) {
5777 if (!(v is Expression)){
5778 element = BitConverter.GetBytes ((double) v);
5780 for (int j = 0; j < factor; ++j)
5781 data [idx + j] = element [j];
5783 // FIXME: Handle the ARM float format.
5784 if (!BitConverter.IsLittleEndian)
5785 System.Array.Reverse (data, idx, 8);
5787 } else if (array_element_type == TypeManager.char_type){
5788 if (!(v is Expression)){
5789 int val = (int) ((char) v);
5791 data [idx] = (byte) (val & 0xff);
5792 data [idx+1] = (byte) (val >> 8);
5794 } else if (array_element_type == TypeManager.short_type){
5795 if (!(v is Expression)){
5796 int val = (int) ((short) v);
5798 data [idx] = (byte) (val & 0xff);
5799 data [idx+1] = (byte) (val >> 8);
5801 } else if (array_element_type == TypeManager.ushort_type){
5802 if (!(v is Expression)){
5803 int val = (int) ((ushort) v);
5805 data [idx] = (byte) (val & 0xff);
5806 data [idx+1] = (byte) (val >> 8);
5808 } else if (array_element_type == TypeManager.int32_type) {
5809 if (!(v is Expression)){
5812 data [idx] = (byte) (val & 0xff);
5813 data [idx+1] = (byte) ((val >> 8) & 0xff);
5814 data [idx+2] = (byte) ((val >> 16) & 0xff);
5815 data [idx+3] = (byte) (val >> 24);
5817 } else if (array_element_type == TypeManager.uint32_type) {
5818 if (!(v is Expression)){
5819 uint val = (uint) v;
5821 data [idx] = (byte) (val & 0xff);
5822 data [idx+1] = (byte) ((val >> 8) & 0xff);
5823 data [idx+2] = (byte) ((val >> 16) & 0xff);
5824 data [idx+3] = (byte) (val >> 24);
5826 } else if (array_element_type == TypeManager.sbyte_type) {
5827 if (!(v is Expression)){
5828 sbyte val = (sbyte) v;
5829 data [idx] = (byte) val;
5831 } else if (array_element_type == TypeManager.byte_type) {
5832 if (!(v is Expression)){
5833 byte val = (byte) v;
5834 data [idx] = (byte) val;
5836 } else if (array_element_type == TypeManager.bool_type) {
5837 if (!(v is Expression)){
5838 bool val = (bool) v;
5839 data [idx] = (byte) (val ? 1 : 0);
5841 } else if (array_element_type == TypeManager.decimal_type){
5842 if (!(v is Expression)){
5843 int [] bits = Decimal.GetBits ((decimal) v);
5846 // FIXME: For some reason, this doesn't work on the MS runtime.
5847 int [] nbits = new int [4];
5848 nbits [0] = bits [3];
5849 nbits [1] = bits [2];
5850 nbits [2] = bits [0];
5851 nbits [3] = bits [1];
5853 for (int j = 0; j < 4; j++){
5854 data [p++] = (byte) (nbits [j] & 0xff);
5855 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5856 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5857 data [p++] = (byte) (nbits [j] >> 24);
5861 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5870 // Emits the initializers for the array
5872 void EmitStaticInitializers (EmitContext ec)
5875 // First, the static data
5878 ILGenerator ig = ec.ig;
5880 byte [] data = MakeByteBlob ();
5882 fb = RootContext.MakeStaticData (data);
5884 ig.Emit (OpCodes.Dup);
5885 ig.Emit (OpCodes.Ldtoken, fb);
5886 ig.Emit (OpCodes.Call,
5887 TypeManager.void_initializearray_array_fieldhandle);
5891 // Emits pieces of the array that can not be computed at compile
5892 // time (variables and string locations).
5894 // This always expect the top value on the stack to be the array
5896 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5898 ILGenerator ig = ec.ig;
5899 int dims = bounds.Count;
5900 int [] current_pos = new int [dims];
5902 MethodInfo set = null;
5905 Type [] args = new Type [dims + 1];
5907 for (int j = 0; j < dims; j++)
5908 args [j] = TypeManager.int32_type;
5909 args [dims] = array_element_type;
5911 set = CodeGen.Module.Builder.GetArrayMethod (
5913 CallingConventions.HasThis | CallingConventions.Standard,
5914 TypeManager.void_type, args);
5917 for (int i = 0; i < array_data.Count; i++){
5919 Expression e = (Expression)array_data [i];
5921 // Constant can be initialized via StaticInitializer
5922 if (e != null && !(!emitConstants && e is Constant)) {
5923 Type etype = e.Type;
5925 ig.Emit (OpCodes.Dup);
5927 for (int idx = 0; idx < dims; idx++)
5928 IntConstant.EmitInt (ig, current_pos [idx]);
5931 // If we are dealing with a struct, get the
5932 // address of it, so we can store it.
5934 if ((dims == 1) && etype.IsValueType &&
5935 (!TypeManager.IsBuiltinOrEnum (etype) ||
5936 etype == TypeManager.decimal_type)) {
5941 // Let new know that we are providing
5942 // the address where to store the results
5944 n.DisableTemporaryValueType ();
5947 ig.Emit (OpCodes.Ldelema, etype);
5953 bool is_stobj, has_type_arg;
5954 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5956 ig.Emit (OpCodes.Stobj, etype);
5957 else if (has_type_arg)
5958 ig.Emit (op, etype);
5962 ig.Emit (OpCodes.Call, set);
5969 for (int j = dims - 1; j >= 0; j--){
5971 if (current_pos [j] < (int) bounds [j])
5973 current_pos [j] = 0;
5978 void EmitArrayArguments (EmitContext ec)
5980 ILGenerator ig = ec.ig;
5982 foreach (Argument a in arguments) {
5983 Type atype = a.Type;
5986 if (atype == TypeManager.uint64_type)
5987 ig.Emit (OpCodes.Conv_Ovf_U4);
5988 else if (atype == TypeManager.int64_type)
5989 ig.Emit (OpCodes.Conv_Ovf_I4);
5993 public override void Emit (EmitContext ec)
5995 ILGenerator ig = ec.ig;
5997 EmitArrayArguments (ec);
5998 if (arguments.Count == 1)
5999 ig.Emit (OpCodes.Newarr, array_element_type);
6001 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6004 if (initializers == null)
6007 // Emit static initializer for arrays which have contain more than 4 items and
6008 // the static initializer will initialize at least 25% of array values.
6009 // NOTE: const_initializers_count does not contain default constant values.
6010 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6011 TypeManager.IsPrimitiveType (array_element_type)) {
6012 EmitStaticInitializers (ec);
6014 if (!only_constant_initializers)
6015 EmitDynamicInitializers (ec, false);
6017 EmitDynamicInitializers (ec, true);
6021 public override bool GetAttributableValue (Type valueType, out object value)
6023 if (arguments.Count != 1) {
6024 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6025 return base.GetAttributableValue (null, out value);
6028 if (array_data == null) {
6029 Constant c = (Constant)((Argument)arguments [0]).Expr;
6030 if (c.IsDefaultValue) {
6031 value = Array.CreateInstance (array_element_type, 0);
6034 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6035 return base.GetAttributableValue (null, out value);
6038 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6039 object element_value;
6040 for (int i = 0; i < ret.Length; ++i)
6042 Expression e = (Expression)array_data [i];
6044 // Is null when an initializer is optimized (value == predefined value)
6048 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6052 ret.SetValue (element_value, i);
6058 protected override void CloneTo (CloneContext clonectx, Expression t)
6060 ArrayCreation target = (ArrayCreation) t;
6062 target.requested_base_type = requested_base_type.Clone (clonectx);
6064 if (arguments != null){
6065 target.arguments = new ArrayList (arguments.Count);
6066 foreach (Argument a in arguments)
6067 target.arguments.Add (a.Clone (clonectx));
6070 if (initializers != null){
6071 target.initializers = new ArrayList (initializers.Count);
6072 foreach (Expression initializer in initializers)
6073 target.initializers.Add (initializer.Clone (clonectx));
6079 // Represents an implicitly typed array epxression
6081 public class ImplicitlyTypedArrayCreation : ArrayCreation
6083 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6084 : base (null, rank, initializers, loc)
6086 if (rank.Length > 2) {
6087 while (rank [++dimensions] == ',');
6093 public override Expression DoResolve (EmitContext ec)
6098 if (!ResolveInitializers (ec))
6101 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6102 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6103 arguments.Count != dimensions) {
6104 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6109 // At this point we found common base type for all initializer elements
6110 // but we have to be sure that all static initializer elements are of
6113 UnifyInitializerElement (ec);
6115 type = TypeManager.GetConstructedType (array_element_type, rank);
6116 eclass = ExprClass.Value;
6121 // Converts static initializer only
6123 void UnifyInitializerElement (EmitContext ec)
6125 for (int i = 0; i < array_data.Count; ++i) {
6126 Expression e = (Expression)array_data[i];
6128 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6132 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6134 element = element.Resolve (ec);
6135 if (element == null)
6138 if (array_element_type == null) {
6139 array_element_type = element.Type;
6143 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6147 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6148 array_element_type = element.Type;
6152 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6157 public sealed class CompilerGeneratedThis : This
6159 public static This Instance = new CompilerGeneratedThis ();
6161 private CompilerGeneratedThis ()
6162 : base (Location.Null)
6166 public override Expression DoResolve (EmitContext ec)
6168 eclass = ExprClass.Variable;
6169 type = ec.ContainerType;
6170 variable = new SimpleThis (type);
6176 /// Represents the `this' construct
6179 public class This : VariableReference, IVariable
6182 VariableInfo variable_info;
6183 protected Variable variable;
6186 public This (Block block, Location loc)
6192 public This (Location loc)
6197 public VariableInfo VariableInfo {
6198 get { return variable_info; }
6201 public bool VerifyFixed ()
6203 return !TypeManager.IsValueType (Type);
6206 public override bool IsRef {
6207 get { return is_struct; }
6210 public override Variable Variable {
6211 get { return variable; }
6214 public bool ResolveBase (EmitContext ec)
6216 eclass = ExprClass.Variable;
6218 if (ec.TypeContainer.CurrentType != null)
6219 type = ec.TypeContainer.CurrentType;
6221 type = ec.ContainerType;
6223 is_struct = ec.TypeContainer is Struct;
6226 Error (26, "Keyword `this' is not valid in a static property, " +
6227 "static method, or static field initializer");
6231 if (block != null) {
6232 if (block.Toplevel.ThisVariable != null)
6233 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6235 AnonymousContainer am = ec.CurrentAnonymousMethod;
6236 if (is_struct && (am != null) && !am.IsIterator) {
6237 Report.Error (1673, loc, "Anonymous methods inside structs " +
6238 "cannot access instance members of `this'. " +
6239 "Consider copying `this' to a local variable " +
6240 "outside the anonymous method and using the " +
6245 RootScopeInfo host = block.Toplevel.RootScope;
6246 if ((host != null) && !ec.IsConstructor &&
6247 (!is_struct || host.IsIterator)) {
6248 variable = host.CaptureThis ();
6249 type = variable.Type;
6254 if (variable == null)
6255 variable = new SimpleThis (type);
6261 // Called from Invocation to check if the invocation is correct
6263 public bool CheckThisUsage (EmitContext ec)
6265 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6266 !variable_info.IsAssigned (ec)) {
6267 Error (188, "The `this' object cannot be used before all of its " +
6268 "fields are assigned to");
6269 variable_info.SetAssigned (ec);
6276 public override Expression DoResolve (EmitContext ec)
6278 if (!ResolveBase (ec))
6282 if (ec.IsFieldInitializer) {
6283 Error (27, "Keyword `this' is not available in the current context");
6290 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6292 if (!ResolveBase (ec))
6295 if (variable_info != null)
6296 variable_info.SetAssigned (ec);
6298 if (ec.TypeContainer is Class){
6299 Error (1604, "Cannot assign to 'this' because it is read-only");
6305 public override int GetHashCode()
6307 return block.GetHashCode ();
6310 public override bool Equals (object obj)
6312 This t = obj as This;
6316 return block == t.block;
6319 protected class SimpleThis : Variable
6323 public SimpleThis (Type type)
6328 public override Type Type {
6329 get { return type; }
6332 public override bool HasInstance {
6333 get { return false; }
6336 public override bool NeedsTemporary {
6337 get { return false; }
6340 public override void EmitInstance (EmitContext ec)
6345 public override void Emit (EmitContext ec)
6347 ec.ig.Emit (OpCodes.Ldarg_0);
6350 public override void EmitAssign (EmitContext ec)
6352 throw new InvalidOperationException ();
6355 public override void EmitAddressOf (EmitContext ec)
6357 ec.ig.Emit (OpCodes.Ldarg_0);
6361 protected override void CloneTo (CloneContext clonectx, Expression t)
6363 This target = (This) t;
6365 target.block = clonectx.LookupBlock (block);
6370 /// Represents the `__arglist' construct
6372 public class ArglistAccess : Expression
6374 public ArglistAccess (Location loc)
6379 public override Expression DoResolve (EmitContext ec)
6381 eclass = ExprClass.Variable;
6382 type = TypeManager.runtime_argument_handle_type;
6384 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6386 Error (190, "The __arglist construct is valid only within " +
6387 "a variable argument method");
6394 public override void Emit (EmitContext ec)
6396 ec.ig.Emit (OpCodes.Arglist);
6399 protected override void CloneTo (CloneContext clonectx, Expression target)
6406 /// Represents the `__arglist (....)' construct
6408 public class Arglist : Expression
6410 Argument[] Arguments;
6412 public Arglist (Location loc)
6413 : this (Argument.Empty, loc)
6417 public Arglist (Argument[] args, Location l)
6423 public Type[] ArgumentTypes {
6425 Type[] retval = new Type [Arguments.Length];
6426 for (int i = 0; i < Arguments.Length; i++)
6427 retval [i] = Arguments [i].Type;
6432 public override Expression DoResolve (EmitContext ec)
6434 eclass = ExprClass.Variable;
6435 type = TypeManager.runtime_argument_handle_type;
6437 foreach (Argument arg in Arguments) {
6438 if (!arg.Resolve (ec, loc))
6445 public override void Emit (EmitContext ec)
6447 foreach (Argument arg in Arguments)
6451 protected override void CloneTo (CloneContext clonectx, Expression t)
6453 Arglist target = (Arglist) t;
6455 target.Arguments = new Argument [Arguments.Length];
6456 for (int i = 0; i < Arguments.Length; i++)
6457 target.Arguments [i] = Arguments [i].Clone (clonectx);
6462 // This produces the value that renders an instance, used by the iterators code
6464 public class ProxyInstance : Expression, IMemoryLocation {
6465 public override Expression DoResolve (EmitContext ec)
6467 eclass = ExprClass.Variable;
6468 type = ec.ContainerType;
6472 public override void Emit (EmitContext ec)
6474 ec.ig.Emit (OpCodes.Ldarg_0);
6478 public void AddressOf (EmitContext ec, AddressOp mode)
6480 ec.ig.Emit (OpCodes.Ldarg_0);
6485 /// Implements the typeof operator
6487 public class TypeOf : Expression {
6488 Expression QueriedType;
6489 protected Type typearg;
6491 public TypeOf (Expression queried_type, Location l)
6493 QueriedType = queried_type;
6497 public override Expression DoResolve (EmitContext ec)
6499 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6503 typearg = texpr.Type;
6505 if (typearg == TypeManager.void_type) {
6506 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6510 if (typearg.IsPointer && !ec.InUnsafe){
6515 type = TypeManager.type_type;
6516 // Even though what is returned is a type object, it's treated as a value by the compiler.
6517 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6518 eclass = ExprClass.Value;
6522 public override void Emit (EmitContext ec)
6524 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6525 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6528 public override bool GetAttributableValue (Type valueType, out object value)
6530 if (TypeManager.ContainsGenericParameters (typearg) &&
6531 !TypeManager.IsGenericTypeDefinition (typearg)) {
6532 Report.SymbolRelatedToPreviousError (typearg);
6533 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6534 TypeManager.CSharpName (typearg));
6539 if (valueType == TypeManager.object_type) {
6540 value = (object)typearg;
6547 public Type TypeArgument
6555 protected override void CloneTo (CloneContext clonectx, Expression t)
6557 TypeOf target = (TypeOf) t;
6559 target.QueriedType = QueriedType.Clone (clonectx);
6564 /// Implements the `typeof (void)' operator
6566 public class TypeOfVoid : TypeOf {
6567 public TypeOfVoid (Location l) : base (null, l)
6572 public override Expression DoResolve (EmitContext ec)
6574 type = TypeManager.type_type;
6575 typearg = TypeManager.void_type;
6576 // See description in TypeOf.
6577 eclass = ExprClass.Value;
6583 /// Implements the sizeof expression
6585 public class SizeOf : Expression {
6586 readonly Expression QueriedType;
6589 public SizeOf (Expression queried_type, Location l)
6591 this.QueriedType = queried_type;
6595 public override Expression DoResolve (EmitContext ec)
6597 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6602 if (texpr is TypeParameterExpr){
6603 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6608 type_queried = texpr.Type;
6609 if (type_queried.IsEnum)
6610 type_queried = TypeManager.EnumToUnderlying (type_queried);
6612 if (type_queried == TypeManager.void_type) {
6613 Expression.Error_VoidInvalidInTheContext (loc);
6617 int size_of = GetTypeSize (type_queried);
6619 return new IntConstant (size_of, loc);
6623 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)",
6624 TypeManager.CSharpName (type_queried));
6628 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6632 type = TypeManager.int32_type;
6633 eclass = ExprClass.Value;
6637 public override void Emit (EmitContext ec)
6639 int size = GetTypeSize (type_queried);
6642 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6644 IntConstant.EmitInt (ec.ig, size);
6647 protected override void CloneTo (CloneContext clonectx, Expression t)
6653 /// Implements the qualified-alias-member (::) expression.
6655 public class QualifiedAliasMember : Expression
6657 string alias, identifier;
6659 public QualifiedAliasMember (string alias, string identifier, Location l)
6661 if (RootContext.Version == LanguageVersion.ISO_1)
6662 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6665 this.identifier = identifier;
6669 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6671 if (alias == "global")
6672 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6674 int errors = Report.Errors;
6675 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6677 if (errors == Report.Errors)
6678 Report.Error (432, loc, "Alias `{0}' not found", alias);
6681 if (fne.eclass != ExprClass.Namespace) {
6683 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6686 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6689 public override Expression DoResolve (EmitContext ec)
6691 FullNamedExpression fne;
6692 if (alias == "global") {
6693 fne = RootNamespace.Global;
6695 int errors = Report.Errors;
6696 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6698 if (errors == Report.Errors)
6699 Report.Error (432, loc, "Alias `{0}' not found", alias);
6704 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6708 if (!(retval is FullNamedExpression)) {
6709 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6713 // We defer this check till the end to match the behaviour of CSC
6714 if (fne.eclass != ExprClass.Namespace) {
6715 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6721 public override void Emit (EmitContext ec)
6723 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6727 public override string ToString ()
6729 return alias + "::" + identifier;
6732 public override string GetSignatureForError ()
6737 protected override void CloneTo (CloneContext clonectx, Expression t)
6744 /// Implements the member access expression
6746 public class MemberAccess : Expression {
6747 public readonly string Identifier;
6749 readonly TypeArguments args;
6751 public MemberAccess (Expression expr, string id)
6752 : this (expr, id, expr.Location)
6756 public MemberAccess (Expression expr, string identifier, Location loc)
6759 Identifier = identifier;
6763 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6764 : this (expr, identifier, loc)
6769 protected string LookupIdentifier {
6770 get { return MemberName.MakeName (Identifier, args); }
6773 // TODO: this method has very poor performace for Enum fields and
6774 // probably for other constants as well
6775 Expression DoResolve (EmitContext ec, Expression right_side)
6778 throw new Exception ();
6781 // Resolve the expression with flow analysis turned off, we'll do the definite
6782 // assignment checks later. This is because we don't know yet what the expression
6783 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6784 // definite assignment check on the actual field and not on the whole struct.
6787 SimpleName original = expr as SimpleName;
6788 Expression expr_resolved = expr.Resolve (ec,
6789 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6790 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6792 if (expr_resolved == null)
6795 if (expr_resolved is Namespace) {
6796 Namespace ns = (Namespace) expr_resolved;
6797 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6799 if ((retval != null) && (args != null))
6800 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6804 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6808 Type expr_type = expr_resolved.Type;
6809 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6810 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6813 if (expr_type == TypeManager.anonymous_method_type){
6814 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6818 Constant c = expr_resolved as Constant;
6819 if (c != null && c.GetValue () == null) {
6820 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6821 "System.NullReferenceException");
6824 Expression member_lookup;
6825 member_lookup = MemberLookup (
6826 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6828 if ((member_lookup == null) && (args != null)) {
6829 member_lookup = MemberLookup (
6830 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6833 if (member_lookup == null) {
6834 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6835 if (ex_method_lookup != null) {
6836 ex_method_lookup.ExtensionExpression = expr_resolved;
6837 return ex_method_lookup.DoResolve (ec);
6840 if (!ec.IsInProbingMode)
6841 MemberLookupFailed (
6842 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6846 TypeExpr texpr = member_lookup as TypeExpr;
6847 if (texpr != null) {
6848 if (!(expr_resolved is TypeExpr) &&
6849 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6850 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6851 Identifier, member_lookup.GetSignatureForError ());
6855 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6856 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6857 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6862 ConstructedType ct = expr_resolved as ConstructedType;
6865 // When looking up a nested type in a generic instance
6866 // via reflection, we always get a generic type definition
6867 // and not a generic instance - so we have to do this here.
6869 // See gtest-172-lib.cs and gtest-172.cs for an example.
6871 ct = new ConstructedType (
6872 member_lookup.Type, ct.TypeArguments, loc);
6874 return ct.ResolveAsTypeStep (ec, false);
6877 return member_lookup;
6880 MemberExpr me = (MemberExpr) member_lookup;
6881 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6882 if (member_lookup == null)
6886 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6888 throw new InternalErrorException ();
6890 return mg.ResolveGeneric (ec, args);
6893 if (original != null && !TypeManager.IsValueType (expr_type)) {
6894 me = member_lookup as MemberExpr;
6895 if (me != null && me.IsInstance) {
6896 LocalVariableReference var = expr_resolved as LocalVariableReference;
6897 if (var != null && !var.VerifyAssigned (ec))
6902 // The following DoResolve/DoResolveLValue will do the definite assignment
6905 if (right_side != null)
6906 return member_lookup.DoResolveLValue (ec, right_side);
6908 return member_lookup.DoResolve (ec);
6911 public override Expression DoResolve (EmitContext ec)
6913 return DoResolve (ec, null);
6916 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6918 return DoResolve (ec, right_side);
6921 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6923 return ResolveNamespaceOrType (ec, silent);
6926 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6928 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6930 if (new_expr == null)
6933 if (new_expr is Namespace) {
6934 Namespace ns = (Namespace) new_expr;
6935 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6937 if ((retval != null) && (args != null))
6938 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6940 if (!silent && retval == null)
6941 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6945 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6946 if (tnew_expr == null)
6949 Type expr_type = tnew_expr.Type;
6951 if (expr_type.IsPointer){
6952 Error (23, "The `.' operator can not be applied to pointer operands (" +
6953 TypeManager.CSharpName (expr_type) + ")");
6957 Expression member_lookup = MemberLookup (
6958 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6959 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6960 if (member_lookup == null) {
6964 member_lookup = MemberLookup(
6965 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6966 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6968 if (member_lookup == null) {
6969 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6970 Identifier, new_expr.GetSignatureForError ());
6972 // TODO: Report.SymbolRelatedToPreviousError
6973 member_lookup.Error_UnexpectedKind (null, "type", loc);
6978 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6983 TypeArguments the_args = args;
6984 if (TypeManager.HasGenericArguments (expr_type)) {
6985 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6987 TypeArguments new_args = new TypeArguments (loc);
6988 foreach (Type decl in decl_args)
6989 new_args.Add (new TypeExpression (decl, loc));
6992 new_args.Add (args);
6994 the_args = new_args;
6997 if (the_args != null) {
6998 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6999 return ctype.ResolveAsTypeStep (rc, false);
7006 public override void Emit (EmitContext ec)
7008 throw new Exception ("Should not happen");
7011 public override string ToString ()
7013 return expr + "." + MemberName.MakeName (Identifier, args);
7016 public override string GetSignatureForError ()
7018 return expr.GetSignatureForError () + "." + Identifier;
7021 protected override void CloneTo (CloneContext clonectx, Expression t)
7023 MemberAccess target = (MemberAccess) t;
7025 target.expr = expr.Clone (clonectx);
7030 /// Implements checked expressions
7032 public class CheckedExpr : Expression {
7034 public Expression Expr;
7036 public CheckedExpr (Expression e, Location l)
7042 public override Expression DoResolve (EmitContext ec)
7044 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7045 Expr = Expr.Resolve (ec);
7050 if (Expr is Constant)
7053 eclass = Expr.eclass;
7058 public override void Emit (EmitContext ec)
7060 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7064 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7066 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7067 Expr.EmitBranchable (ec, target, onTrue);
7070 protected override void CloneTo (CloneContext clonectx, Expression t)
7072 CheckedExpr target = (CheckedExpr) t;
7074 target.Expr = Expr.Clone (clonectx);
7079 /// Implements the unchecked expression
7081 public class UnCheckedExpr : Expression {
7083 public Expression Expr;
7085 public UnCheckedExpr (Expression e, Location l)
7091 public override Expression DoResolve (EmitContext ec)
7093 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7094 Expr = Expr.Resolve (ec);
7099 if (Expr is Constant)
7102 eclass = Expr.eclass;
7107 public override void Emit (EmitContext ec)
7109 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7113 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7115 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7116 Expr.EmitBranchable (ec, target, onTrue);
7119 protected override void CloneTo (CloneContext clonectx, Expression t)
7121 UnCheckedExpr target = (UnCheckedExpr) t;
7123 target.Expr = Expr.Clone (clonectx);
7128 /// An Element Access expression.
7130 /// During semantic analysis these are transformed into
7131 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7133 public class ElementAccess : Expression {
7134 public ArrayList Arguments;
7135 public Expression Expr;
7137 public ElementAccess (Expression e, ArrayList e_list)
7146 Arguments = new ArrayList ();
7147 foreach (Expression tmp in e_list)
7148 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7152 bool CommonResolve (EmitContext ec)
7154 Expr = Expr.Resolve (ec);
7156 if (Arguments == null)
7159 foreach (Argument a in Arguments){
7160 if (!a.Resolve (ec, loc))
7164 return Expr != null;
7167 Expression MakePointerAccess (EmitContext ec, Type t)
7169 if (t == TypeManager.void_ptr_type){
7170 Error (242, "The array index operation is not valid on void pointers");
7173 if (Arguments.Count != 1){
7174 Error (196, "A pointer must be indexed by only one value");
7179 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7182 return new Indirection (p, loc).Resolve (ec);
7185 public override Expression DoResolve (EmitContext ec)
7187 if (!CommonResolve (ec))
7191 // We perform some simple tests, and then to "split" the emit and store
7192 // code we create an instance of a different class, and return that.
7194 // I am experimenting with this pattern.
7198 if (t == TypeManager.array_type){
7199 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7204 return (new ArrayAccess (this, loc)).Resolve (ec);
7206 return MakePointerAccess (ec, t);
7208 FieldExpr fe = Expr as FieldExpr;
7210 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7212 return MakePointerAccess (ec, ff.ElementType);
7215 return (new IndexerAccess (this, loc)).Resolve (ec);
7218 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7220 if (!CommonResolve (ec))
7225 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7228 return MakePointerAccess (ec, t);
7230 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7233 public override void Emit (EmitContext ec)
7235 throw new Exception ("Should never be reached");
7238 protected override void CloneTo (CloneContext clonectx, Expression t)
7240 ElementAccess target = (ElementAccess) t;
7242 target.Expr = Expr.Clone (clonectx);
7243 target.Arguments = new ArrayList (Arguments.Count);
7244 foreach (Argument a in Arguments)
7245 target.Arguments.Add (a.Clone (clonectx));
7250 /// Implements array access
7252 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7254 // Points to our "data" repository
7258 LocalTemporary temp;
7261 public ArrayAccess (ElementAccess ea_data, Location l)
7264 eclass = ExprClass.Variable;
7268 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7270 return DoResolve (ec);
7273 public override Expression DoResolve (EmitContext ec)
7276 ExprClass eclass = ea.Expr.eclass;
7278 // As long as the type is valid
7279 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7280 eclass == ExprClass.Value)) {
7281 ea.Expr.Error_UnexpectedKind ("variable or value");
7286 Type t = ea.Expr.Type;
7287 if (t.GetArrayRank () != ea.Arguments.Count){
7288 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7289 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7293 type = TypeManager.GetElementType (t);
7294 if (type.IsPointer && !ec.InUnsafe){
7295 UnsafeError (ea.Location);
7299 foreach (Argument a in ea.Arguments){
7300 Type argtype = a.Type;
7302 if (argtype == TypeManager.int32_type ||
7303 argtype == TypeManager.uint32_type ||
7304 argtype == TypeManager.int64_type ||
7305 argtype == TypeManager.uint64_type) {
7306 Constant c = a.Expr as Constant;
7307 if (c != null && c.IsNegative) {
7308 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7314 // Mhm. This is strage, because the Argument.Type is not the same as
7315 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7317 // Wonder if I will run into trouble for this.
7319 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7324 eclass = ExprClass.Variable;
7330 /// Emits the right opcode to load an object of Type `t'
7331 /// from an array of T
7333 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7335 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7336 ig.Emit (OpCodes.Ldelem_U1);
7337 else if (type == TypeManager.sbyte_type)
7338 ig.Emit (OpCodes.Ldelem_I1);
7339 else if (type == TypeManager.short_type)
7340 ig.Emit (OpCodes.Ldelem_I2);
7341 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7342 ig.Emit (OpCodes.Ldelem_U2);
7343 else if (type == TypeManager.int32_type)
7344 ig.Emit (OpCodes.Ldelem_I4);
7345 else if (type == TypeManager.uint32_type)
7346 ig.Emit (OpCodes.Ldelem_U4);
7347 else if (type == TypeManager.uint64_type)
7348 ig.Emit (OpCodes.Ldelem_I8);
7349 else if (type == TypeManager.int64_type)
7350 ig.Emit (OpCodes.Ldelem_I8);
7351 else if (type == TypeManager.float_type)
7352 ig.Emit (OpCodes.Ldelem_R4);
7353 else if (type == TypeManager.double_type)
7354 ig.Emit (OpCodes.Ldelem_R8);
7355 else if (type == TypeManager.intptr_type)
7356 ig.Emit (OpCodes.Ldelem_I);
7357 else if (TypeManager.IsEnumType (type)){
7358 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7359 } else if (type.IsValueType){
7360 ig.Emit (OpCodes.Ldelema, type);
7361 ig.Emit (OpCodes.Ldobj, type);
7363 } else if (type.IsGenericParameter) {
7364 ig.Emit (OpCodes.Ldelem, type);
7366 } else if (type.IsPointer)
7367 ig.Emit (OpCodes.Ldelem_I);
7369 ig.Emit (OpCodes.Ldelem_Ref);
7373 /// Returns the right opcode to store an object of Type `t'
7374 /// from an array of T.
7376 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7378 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7379 has_type_arg = false; is_stobj = false;
7380 t = TypeManager.TypeToCoreType (t);
7381 if (TypeManager.IsEnumType (t))
7382 t = TypeManager.EnumToUnderlying (t);
7383 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7384 t == TypeManager.bool_type)
7385 return OpCodes.Stelem_I1;
7386 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7387 t == TypeManager.char_type)
7388 return OpCodes.Stelem_I2;
7389 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7390 return OpCodes.Stelem_I4;
7391 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7392 return OpCodes.Stelem_I8;
7393 else if (t == TypeManager.float_type)
7394 return OpCodes.Stelem_R4;
7395 else if (t == TypeManager.double_type)
7396 return OpCodes.Stelem_R8;
7397 else if (t == TypeManager.intptr_type) {
7398 has_type_arg = true;
7400 return OpCodes.Stobj;
7401 } else if (t.IsValueType) {
7402 has_type_arg = true;
7404 return OpCodes.Stobj;
7406 } else if (t.IsGenericParameter) {
7407 has_type_arg = true;
7408 return OpCodes.Stelem;
7411 } else if (t.IsPointer)
7412 return OpCodes.Stelem_I;
7414 return OpCodes.Stelem_Ref;
7417 MethodInfo FetchGetMethod ()
7419 ModuleBuilder mb = CodeGen.Module.Builder;
7420 int arg_count = ea.Arguments.Count;
7421 Type [] args = new Type [arg_count];
7424 for (int i = 0; i < arg_count; i++){
7425 //args [i++] = a.Type;
7426 args [i] = TypeManager.int32_type;
7429 get = mb.GetArrayMethod (
7430 ea.Expr.Type, "Get",
7431 CallingConventions.HasThis |
7432 CallingConventions.Standard,
7438 MethodInfo FetchAddressMethod ()
7440 ModuleBuilder mb = CodeGen.Module.Builder;
7441 int arg_count = ea.Arguments.Count;
7442 Type [] args = new Type [arg_count];
7446 ret_type = TypeManager.GetReferenceType (type);
7448 for (int i = 0; i < arg_count; i++){
7449 //args [i++] = a.Type;
7450 args [i] = TypeManager.int32_type;
7453 address = mb.GetArrayMethod (
7454 ea.Expr.Type, "Address",
7455 CallingConventions.HasThis |
7456 CallingConventions.Standard,
7463 // Load the array arguments into the stack.
7465 // If we have been requested to cache the values (cached_locations array
7466 // initialized), then load the arguments the first time and store them
7467 // in locals. otherwise load from local variables.
7469 void LoadArrayAndArguments (EmitContext ec)
7471 ILGenerator ig = ec.ig;
7474 foreach (Argument a in ea.Arguments){
7475 Type argtype = a.Expr.Type;
7479 if (argtype == TypeManager.int64_type)
7480 ig.Emit (OpCodes.Conv_Ovf_I);
7481 else if (argtype == TypeManager.uint64_type)
7482 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7486 public void Emit (EmitContext ec, bool leave_copy)
7488 int rank = ea.Expr.Type.GetArrayRank ();
7489 ILGenerator ig = ec.ig;
7492 LoadArrayAndArguments (ec);
7495 EmitLoadOpcode (ig, type);
7499 method = FetchGetMethod ();
7500 ig.Emit (OpCodes.Call, method);
7503 LoadFromPtr (ec.ig, this.type);
7506 ec.ig.Emit (OpCodes.Dup);
7507 temp = new LocalTemporary (this.type);
7512 public override void Emit (EmitContext ec)
7517 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7519 int rank = ea.Expr.Type.GetArrayRank ();
7520 ILGenerator ig = ec.ig;
7521 Type t = source.Type;
7522 prepared = prepare_for_load;
7524 if (prepare_for_load) {
7525 AddressOf (ec, AddressOp.LoadStore);
7526 ec.ig.Emit (OpCodes.Dup);
7529 ec.ig.Emit (OpCodes.Dup);
7530 temp = new LocalTemporary (this.type);
7533 StoreFromPtr (ec.ig, t);
7543 LoadArrayAndArguments (ec);
7546 bool is_stobj, has_type_arg;
7547 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7549 // The stobj opcode used by value types will need
7550 // an address on the stack, not really an array/array
7554 ig.Emit (OpCodes.Ldelema, t);
7558 ec.ig.Emit (OpCodes.Dup);
7559 temp = new LocalTemporary (this.type);
7564 ig.Emit (OpCodes.Stobj, t);
7565 else if (has_type_arg)
7570 ModuleBuilder mb = CodeGen.Module.Builder;
7571 int arg_count = ea.Arguments.Count;
7572 Type [] args = new Type [arg_count + 1];
7577 ec.ig.Emit (OpCodes.Dup);
7578 temp = new LocalTemporary (this.type);
7582 for (int i = 0; i < arg_count; i++){
7583 //args [i++] = a.Type;
7584 args [i] = TypeManager.int32_type;
7587 args [arg_count] = type;
7589 set = mb.GetArrayMethod (
7590 ea.Expr.Type, "Set",
7591 CallingConventions.HasThis |
7592 CallingConventions.Standard,
7593 TypeManager.void_type, args);
7595 ig.Emit (OpCodes.Call, set);
7604 public void AddressOf (EmitContext ec, AddressOp mode)
7606 int rank = ea.Expr.Type.GetArrayRank ();
7607 ILGenerator ig = ec.ig;
7609 LoadArrayAndArguments (ec);
7612 ig.Emit (OpCodes.Ldelema, type);
7614 MethodInfo address = FetchAddressMethod ();
7615 ig.Emit (OpCodes.Call, address);
7619 public void EmitGetLength (EmitContext ec, int dim)
7621 int rank = ea.Expr.Type.GetArrayRank ();
7622 ILGenerator ig = ec.ig;
7626 ig.Emit (OpCodes.Ldlen);
7627 ig.Emit (OpCodes.Conv_I4);
7629 IntLiteral.EmitInt (ig, dim);
7630 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7636 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7637 public readonly ArrayList Properties;
7638 static Indexers empty;
7640 public struct Indexer {
7641 public readonly PropertyInfo PropertyInfo;
7642 public readonly MethodInfo Getter, Setter;
7644 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7646 this.PropertyInfo = property_info;
7654 empty = new Indexers (null);
7657 Indexers (ArrayList array)
7662 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7667 foreach (PropertyInfo property in mi){
7668 MethodInfo get, set;
7670 get = property.GetGetMethod (true);
7671 set = property.GetSetMethod (true);
7672 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7674 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7676 if (get != null || set != null) {
7678 ix = new Indexers (new ArrayList ());
7679 ix.Properties.Add (new Indexer (property, get, set));
7684 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7686 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7688 return TypeManager.MemberLookup (
7689 caller_type, caller_type, lookup_type, MemberTypes.Property,
7690 BindingFlags.Public | BindingFlags.Instance |
7691 BindingFlags.DeclaredOnly, p_name, null);
7694 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7696 Indexers ix = empty;
7699 if (lookup_type.IsGenericParameter) {
7700 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7704 if (gc.HasClassConstraint)
7705 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7707 Type[] ifaces = gc.InterfaceConstraints;
7708 foreach (Type itype in ifaces)
7709 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7715 Type copy = lookup_type;
7716 while (copy != TypeManager.object_type && copy != null){
7717 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7718 copy = copy.BaseType;
7721 if (lookup_type.IsInterface) {
7722 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7723 if (ifaces != null) {
7724 foreach (Type itype in ifaces)
7725 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7734 /// Expressions that represent an indexer call.
7736 public class IndexerAccess : Expression, IAssignMethod {
7738 // Points to our "data" repository
7740 MethodInfo get, set;
7741 ArrayList set_arguments;
7742 bool is_base_indexer;
7744 protected Type indexer_type;
7745 protected Type current_type;
7746 protected Expression instance_expr;
7747 protected ArrayList arguments;
7749 public IndexerAccess (ElementAccess ea, Location loc)
7750 : this (ea.Expr, false, loc)
7752 this.arguments = ea.Arguments;
7755 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7758 this.instance_expr = instance_expr;
7759 this.is_base_indexer = is_base_indexer;
7760 this.eclass = ExprClass.Value;
7764 protected virtual bool CommonResolve (EmitContext ec)
7766 indexer_type = instance_expr.Type;
7767 current_type = ec.ContainerType;
7772 public override Expression DoResolve (EmitContext ec)
7774 if (!CommonResolve (ec))
7778 // Step 1: Query for all `Item' *properties*. Notice
7779 // that the actual methods are pointed from here.
7781 // This is a group of properties, piles of them.
7783 ArrayList AllGetters = null;
7785 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7786 if (ilist.Properties != null) {
7787 AllGetters = new ArrayList(ilist.Properties.Count);
7788 foreach (Indexers.Indexer ix in ilist.Properties) {
7789 if (ix.Getter != null)
7790 AllGetters.Add (ix.Getter);
7794 if (AllGetters == null) {
7795 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7796 TypeManager.CSharpName (indexer_type));
7800 if (AllGetters.Count == 0) {
7801 // FIXME: we cannot simply select first one as the error message is missleading when
7802 // multiple indexers exist
7803 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7804 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7805 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7809 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7810 arguments, false, loc);
7813 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7818 // Only base will allow this invocation to happen.
7820 if (get.IsAbstract && this is BaseIndexerAccess){
7821 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7825 type = get.ReturnType;
7826 if (type.IsPointer && !ec.InUnsafe){
7831 instance_expr.CheckMarshalByRefAccess ();
7833 eclass = ExprClass.IndexerAccess;
7837 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7839 if (right_side == EmptyExpression.OutAccess) {
7840 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7841 GetSignatureForError ());
7845 // if the indexer returns a value type, and we try to set a field in it
7846 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7847 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7848 GetSignatureForError ());
7852 ArrayList AllSetters = new ArrayList();
7853 if (!CommonResolve (ec))
7856 bool found_any = false, found_any_setters = false;
7858 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7859 if (ilist.Properties != null) {
7861 foreach (Indexers.Indexer ix in ilist.Properties) {
7862 if (ix.Setter != null)
7863 AllSetters.Add (ix.Setter);
7866 if (AllSetters.Count > 0) {
7867 found_any_setters = true;
7868 set_arguments = (ArrayList) arguments.Clone ();
7869 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7870 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7872 set_arguments, false, loc);
7876 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7877 TypeManager.CSharpName (indexer_type));
7881 if (!found_any_setters) {
7882 Error (154, "indexer can not be used in this context, because " +
7883 "it lacks a `set' accessor");
7888 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7893 // Only base will allow this invocation to happen.
7895 if (set.IsAbstract && this is BaseIndexerAccess){
7896 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7901 // Now look for the actual match in the list of indexers to set our "return" type
7903 type = TypeManager.void_type; // default value
7904 foreach (Indexers.Indexer ix in ilist.Properties){
7905 if (ix.Setter == set){
7906 type = ix.PropertyInfo.PropertyType;
7911 instance_expr.CheckMarshalByRefAccess ();
7913 eclass = ExprClass.IndexerAccess;
7917 bool prepared = false;
7918 LocalTemporary temp;
7920 public void Emit (EmitContext ec, bool leave_copy)
7922 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7924 ec.ig.Emit (OpCodes.Dup);
7925 temp = new LocalTemporary (Type);
7931 // source is ignored, because we already have a copy of it from the
7932 // LValue resolution and we have already constructed a pre-cached
7933 // version of the arguments (ea.set_arguments);
7935 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7937 prepared = prepare_for_load;
7938 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7943 ec.ig.Emit (OpCodes.Dup);
7944 temp = new LocalTemporary (Type);
7947 } else if (leave_copy) {
7948 temp = new LocalTemporary (Type);
7954 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7963 public override void Emit (EmitContext ec)
7968 public override string GetSignatureForError ()
7970 // FIXME: print the argument list of the indexer
7971 return instance_expr.GetSignatureForError () + ".this[...]";
7974 protected override void CloneTo (CloneContext clonectx, Expression t)
7976 IndexerAccess target = (IndexerAccess) t;
7978 if (arguments != null){
7979 target.arguments = new ArrayList ();
7980 foreach (Argument a in arguments)
7981 target.arguments.Add (a.Clone (clonectx));
7983 if (instance_expr != null)
7984 target.instance_expr = instance_expr.Clone (clonectx);
7989 /// The base operator for method names
7991 public class BaseAccess : Expression {
7992 public readonly string Identifier;
7995 public BaseAccess (string member, Location l)
7997 this.Identifier = member;
8001 public BaseAccess (string member, TypeArguments args, Location l)
8007 public override Expression DoResolve (EmitContext ec)
8009 Expression c = CommonResolve (ec);
8015 // MethodGroups use this opportunity to flag an error on lacking ()
8017 if (!(c is MethodGroupExpr))
8018 return c.Resolve (ec);
8022 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8024 Expression c = CommonResolve (ec);
8030 // MethodGroups use this opportunity to flag an error on lacking ()
8032 if (! (c is MethodGroupExpr))
8033 return c.DoResolveLValue (ec, right_side);
8038 Expression CommonResolve (EmitContext ec)
8040 Expression member_lookup;
8041 Type current_type = ec.ContainerType;
8042 Type base_type = current_type.BaseType;
8045 Error (1511, "Keyword `base' is not available in a static method");
8049 if (ec.IsFieldInitializer){
8050 Error (1512, "Keyword `base' is not available in the current context");
8054 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8055 AllMemberTypes, AllBindingFlags, loc);
8056 if (member_lookup == null) {
8057 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8064 left = new TypeExpression (base_type, loc);
8066 left = ec.GetThis (loc);
8068 MemberExpr me = (MemberExpr) member_lookup;
8070 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8072 if (e is PropertyExpr) {
8073 PropertyExpr pe = (PropertyExpr) e;
8075 } else if (e is EventExpr) {
8076 EventExpr ee = (EventExpr) e;
8080 MethodGroupExpr mg = e as MethodGroupExpr;
8086 return mg.ResolveGeneric (ec, args);
8088 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8096 public override void Emit (EmitContext ec)
8098 throw new Exception ("Should never be called");
8101 protected override void CloneTo (CloneContext clonectx, Expression t)
8103 BaseAccess target = (BaseAccess) t;
8105 target.args = args.Clone ();
8110 /// The base indexer operator
8112 public class BaseIndexerAccess : IndexerAccess {
8113 public BaseIndexerAccess (ArrayList args, Location loc)
8114 : base (null, true, loc)
8116 arguments = new ArrayList ();
8117 foreach (Expression tmp in args)
8118 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8121 protected override bool CommonResolve (EmitContext ec)
8123 instance_expr = ec.GetThis (loc);
8125 current_type = ec.ContainerType.BaseType;
8126 indexer_type = current_type;
8128 foreach (Argument a in arguments){
8129 if (!a.Resolve (ec, loc))
8138 /// This class exists solely to pass the Type around and to be a dummy
8139 /// that can be passed to the conversion functions (this is used by
8140 /// foreach implementation to typecast the object return value from
8141 /// get_Current into the proper type. All code has been generated and
8142 /// we only care about the side effect conversions to be performed
8144 /// This is also now used as a placeholder where a no-action expression
8145 /// is needed (the `New' class).
8147 public class EmptyExpression : Expression {
8148 public static readonly EmptyExpression Null = new EmptyExpression ();
8150 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8151 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8152 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8154 static EmptyExpression temp = new EmptyExpression ();
8155 public static EmptyExpression Grab ()
8157 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8162 public static void Release (EmptyExpression e)
8167 // TODO: should be protected
8168 public EmptyExpression ()
8170 type = TypeManager.object_type;
8171 eclass = ExprClass.Value;
8172 loc = Location.Null;
8175 public EmptyExpression (Type t)
8178 eclass = ExprClass.Value;
8179 loc = Location.Null;
8182 public override Expression DoResolve (EmitContext ec)
8187 public override void Emit (EmitContext ec)
8189 // nothing, as we only exist to not do anything.
8193 // This is just because we might want to reuse this bad boy
8194 // instead of creating gazillions of EmptyExpressions.
8195 // (CanImplicitConversion uses it)
8197 public void SetType (Type t)
8203 public class UserCast : Expression {
8207 public UserCast (MethodInfo method, Expression source, Location l)
8209 this.method = method;
8210 this.source = source;
8211 type = method.ReturnType;
8212 eclass = ExprClass.Value;
8216 public Expression Source {
8222 public override Expression DoResolve (EmitContext ec)
8225 // We are born fully resolved
8230 public override void Emit (EmitContext ec)
8232 ILGenerator ig = ec.ig;
8236 if (method is MethodInfo)
8237 ig.Emit (OpCodes.Call, (MethodInfo) method);
8239 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8245 // This class is used to "construct" the type during a typecast
8246 // operation. Since the Type.GetType class in .NET can parse
8247 // the type specification, we just use this to construct the type
8248 // one bit at a time.
8250 public class ComposedCast : TypeExpr {
8254 public ComposedCast (Expression left, string dim)
8255 : this (left, dim, left.Location)
8259 public ComposedCast (Expression left, string dim, Location l)
8267 public Expression RemoveNullable ()
8269 if (dim.EndsWith ("?")) {
8270 dim = dim.Substring (0, dim.Length - 1);
8279 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8281 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8285 Type ltype = lexpr.Type;
8286 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8287 Error_VoidInvalidInTheContext (loc);
8292 if ((dim.Length > 0) && (dim [0] == '?')) {
8293 TypeExpr nullable = new NullableType (left, loc);
8295 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8296 return nullable.ResolveAsTypeTerminal (ec, false);
8300 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8303 if (dim != "" && dim [0] == '[' &&
8304 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8305 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8310 type = TypeManager.GetConstructedType (ltype, dim);
8315 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8317 if (type.IsPointer && !ec.IsInUnsafeScope){
8322 eclass = ExprClass.Type;
8326 public override string Name {
8327 get { return left + dim; }
8330 public override string FullName {
8331 get { return type.FullName; }
8334 public override string GetSignatureForError ()
8336 return left.GetSignatureForError () + dim;
8339 protected override void CloneTo (CloneContext clonectx, Expression t)
8341 ComposedCast target = (ComposedCast) t;
8343 target.left = left.Clone (clonectx);
8347 public class FixedBufferPtr : Expression {
8350 public FixedBufferPtr (Expression array, Type array_type, Location l)
8355 type = TypeManager.GetPointerType (array_type);
8356 eclass = ExprClass.Value;
8359 public override void Emit(EmitContext ec)
8364 public override Expression DoResolve (EmitContext ec)
8367 // We are born fully resolved
8375 // This class is used to represent the address of an array, used
8376 // only by the Fixed statement, this generates "&a [0]" construct
8377 // for fixed (char *pa = a)
8379 public class ArrayPtr : FixedBufferPtr {
8382 public ArrayPtr (Expression array, Type array_type, Location l):
8383 base (array, array_type, l)
8385 this.array_type = array_type;
8388 public override void Emit (EmitContext ec)
8392 ILGenerator ig = ec.ig;
8393 IntLiteral.EmitInt (ig, 0);
8394 ig.Emit (OpCodes.Ldelema, array_type);
8399 // Used by the fixed statement
8401 public class StringPtr : Expression {
8404 public StringPtr (LocalBuilder b, Location l)
8407 eclass = ExprClass.Value;
8408 type = TypeManager.char_ptr_type;
8412 public override Expression DoResolve (EmitContext ec)
8414 // This should never be invoked, we are born in fully
8415 // initialized state.
8420 public override void Emit (EmitContext ec)
8422 ILGenerator ig = ec.ig;
8424 ig.Emit (OpCodes.Ldloc, b);
8425 ig.Emit (OpCodes.Conv_I);
8426 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8427 ig.Emit (OpCodes.Add);
8432 // Implements the `stackalloc' keyword
8434 public class StackAlloc : Expression {
8439 public StackAlloc (Expression type, Expression count, Location l)
8446 public override Expression DoResolve (EmitContext ec)
8448 count = count.Resolve (ec);
8452 if (count.Type != TypeManager.int32_type){
8453 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8458 Constant c = count as Constant;
8459 if (c != null && c.IsNegative) {
8460 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8464 if (ec.InCatch || ec.InFinally) {
8465 Error (255, "Cannot use stackalloc in finally or catch");
8469 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8475 if (!TypeManager.VerifyUnManaged (otype, loc))
8478 type = TypeManager.GetPointerType (otype);
8479 eclass = ExprClass.Value;
8484 public override void Emit (EmitContext ec)
8486 int size = GetTypeSize (otype);
8487 ILGenerator ig = ec.ig;
8490 ig.Emit (OpCodes.Sizeof, otype);
8492 IntConstant.EmitInt (ig, size);
8494 ig.Emit (OpCodes.Mul);
8495 ig.Emit (OpCodes.Localloc);
8498 protected override void CloneTo (CloneContext clonectx, Expression t)
8500 StackAlloc target = (StackAlloc) t;
8501 target.count = count.Clone (clonectx);
8502 target.t = t.Clone (clonectx);
8506 public interface IInitializable
8508 bool Initialize (EmitContext ec, Expression target);
8511 public class Initializer
8513 public readonly string Name;
8514 public readonly object Value;
8516 public Initializer (string name, Expression value)
8522 public Initializer (string name, IInitializable value)
8529 public class ObjectInitializer : IInitializable
8531 readonly ArrayList initializers;
8532 public ObjectInitializer (ArrayList initializers)
8534 this.initializers = initializers;
8537 public bool Initialize (EmitContext ec, Expression target)
8539 ArrayList initialized = new ArrayList (initializers.Count);
8540 for (int i = initializers.Count - 1; i >= 0; i--) {
8541 Initializer initializer = initializers[i] as Initializer;
8542 if (initialized.Contains (initializer.Name)) {
8543 //FIXME proper error
8544 Console.WriteLine ("Object member can only be initialized once");
8548 MemberAccess ma = new MemberAccess (target, initializer.Name);
8549 Expression expr = initializer.Value as Expression;
8550 // If it's an expresison, append the assign.
8552 Assign a = new Assign (ma, expr);
8553 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8555 // If it's another initializer (object or collection), initialize it.
8556 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8559 initialized.Add (initializer.Name);
8565 public class CollectionInitializer : IInitializable
8567 readonly ArrayList items;
8568 public CollectionInitializer (ArrayList items)
8573 bool CheckCollection (EmitContext ec, Expression e)
8575 if (e == null || e.Type == null)
8577 bool is_ienumerable = false;
8578 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8579 if (t == typeof (IEnumerable)) {
8580 is_ienumerable = true;
8584 if (!is_ienumerable)
8587 MethodGroupExpr mg = Expression.MemberLookup (
8588 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8589 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8594 foreach (MethodInfo mi in mg.Methods) {
8595 if (TypeManager.GetParameterData (mi).Count != 1)
8597 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8604 public bool Initialize (EmitContext ec, Expression target)
8606 if (!CheckCollection (ec, target.Resolve (ec))) {
8607 // FIXME throw proper error
8608 Console.WriteLine ("Error: This is not a collection");
8612 for (int i = items.Count - 1; i >= 0; i--) {
8613 MemberAccess ma = new MemberAccess (target, "Add");
8614 ArrayList array = new ArrayList ();
8615 array.Add (new Argument ((Expression)items[i]));
8616 Invocation invoke = new Invocation (ma, array);
8617 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8623 public class NewInitialize : New, IInitializable
8625 IInitializable initializer;
8627 public bool Initialize (EmitContext ec, Expression target)
8629 return initializer.Initialize (ec, target);
8632 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8633 : base (requested_type, arguments, l)
8635 this.initializer = initializer;
8639 public class AnonymousTypeDeclaration : Expression
8641 readonly ArrayList parameters;
8642 readonly TypeContainer parent;
8644 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8646 this.parameters = parameters;
8647 this.parent = parent;
8651 AnonymousTypeClass CreateAnonymousType ()
8653 AnonymousTypeClass type = AnonymousTypeClass.Create (parent, parameters, loc);
8658 type.DefineMembers ();
8662 RootContext.ToplevelTypes.AddAnonymousType (type);
8666 public override Expression DoResolve (EmitContext ec)
8669 ArrayList arguments = new ArrayList (parameters.Count);
8670 TypeExpression [] t_args = new TypeExpression [parameters.Count];
8671 for (int i = 0; i < parameters.Count; ++i) {
8672 Expression e = ((AnonymousTypeParameter)parameters [i]).Resolve (ec);
8678 arguments.Add (new Argument (e));
8679 t_args [i] = new TypeExpression (e.Type, e.Location);
8685 AnonymousTypeClass anonymous_type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8686 if (anonymous_type == null) {
8687 anonymous_type = CreateAnonymousType ();
8688 if (anonymous_type == null)
8692 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8693 new TypeArguments (loc, t_args), loc);
8695 return new New (te, arguments, loc).Resolve (ec);
8698 public override void Emit (EmitContext ec)
8700 throw new InternalErrorException ("Should not be reached");
8704 public class AnonymousTypeParameter : Expression
8706 public readonly string Name;
8707 readonly Expression initializer;
8709 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8713 this.initializer = initializer;
8716 public override bool Equals (object o)
8718 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8719 return other != null && Name == other.Name;
8722 public override int GetHashCode ()
8724 return Name.GetHashCode ();
8727 public override Expression DoResolve (EmitContext ec)
8729 Expression e = initializer.Resolve (ec);
8734 if (type == TypeManager.void_type || type == TypeManager.null_type ||
8735 type == TypeManager.anonymous_method_type || type.IsPointer) {
8736 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8737 Name, e.GetSignatureForError ());
8744 public override void Emit (EmitContext ec)
8746 throw new InternalErrorException ("Should not be reached");