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) {
3529 if (Variable.HasInstance)
3530 ig.Emit (OpCodes.Dup);
3539 ig.Emit (OpCodes.Dup);
3540 if (IsRef || Variable.NeedsTemporary) {
3541 temp = new LocalTemporary (Type);
3547 StoreFromPtr (ig, type);
3549 Variable.EmitAssign (ec);
3557 public void AddressOf (EmitContext ec, AddressOp mode)
3559 Variable.EmitInstance (ec);
3560 Variable.EmitAddressOf (ec);
3567 public class LocalVariableReference : VariableReference, IVariable {
3568 public readonly string Name;
3570 public LocalInfo local_info;
3574 public LocalVariableReference (Block block, string name, Location l)
3579 eclass = ExprClass.Variable;
3583 // Setting `is_readonly' to false will allow you to create a writable
3584 // reference to a read-only variable. This is used by foreach and using.
3586 public LocalVariableReference (Block block, string name, Location l,
3587 LocalInfo local_info, bool is_readonly)
3588 : this (block, name, l)
3590 this.local_info = local_info;
3591 this.is_readonly = is_readonly;
3594 public VariableInfo VariableInfo {
3595 get { return local_info.VariableInfo; }
3598 public override bool IsRef {
3599 get { return false; }
3602 public bool IsReadOnly {
3603 get { return is_readonly; }
3606 public bool VerifyAssigned (EmitContext ec)
3608 VariableInfo variable_info = local_info.VariableInfo;
3609 return variable_info == null || variable_info.IsAssigned (ec, loc);
3612 void ResolveLocalInfo ()
3614 if (local_info == null) {
3615 local_info = Block.GetLocalInfo (Name);
3616 type = local_info.VariableType;
3617 is_readonly = local_info.ReadOnly;
3621 protected Expression DoResolveBase (EmitContext ec)
3623 type = local_info.VariableType;
3625 Expression e = Block.GetConstantExpression (Name);
3627 return e.Resolve (ec);
3629 if (!VerifyAssigned (ec))
3633 // If we are referencing a variable from the external block
3634 // flag it for capturing
3636 if (ec.MustCaptureVariable (local_info)) {
3637 if (local_info.AddressTaken){
3638 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3642 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3643 variable = scope.AddLocal (local_info);
3644 type = variable.Type;
3650 public override Expression DoResolve (EmitContext ec)
3652 ResolveLocalInfo ();
3653 local_info.Used = true;
3655 if (type == null && local_info.Type is VarExpr) {
3656 local_info.VariableType = TypeManager.object_type;
3657 Error_VariableIsUsedBeforeItIsDeclared (Name);
3661 return DoResolveBase (ec);
3664 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3666 ResolveLocalInfo ();
3669 if (right_side == EmptyExpression.OutAccess)
3670 local_info.Used = true;
3672 // Infer implicitly typed local variable
3674 VarExpr ve = local_info.Type as VarExpr;
3676 ve.DoResolveLValue (ec, right_side);
3677 type = local_info.VariableType = ve.Type;
3684 if (right_side == EmptyExpression.OutAccess) {
3685 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3686 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3687 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3688 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3689 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3691 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3693 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3697 if (VariableInfo != null)
3698 VariableInfo.SetAssigned (ec);
3700 return DoResolveBase (ec);
3703 public bool VerifyFixed ()
3705 // A local Variable is always fixed.
3709 public override int GetHashCode ()
3711 return Name.GetHashCode ();
3714 public override bool Equals (object obj)
3716 LocalVariableReference lvr = obj as LocalVariableReference;
3720 return Name == lvr.Name && Block == lvr.Block;
3723 public override Variable Variable {
3724 get { return variable != null ? variable : local_info.Variable; }
3727 public override string ToString ()
3729 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3732 protected override void CloneTo (CloneContext clonectx, Expression t)
3734 LocalVariableReference target = (LocalVariableReference) t;
3736 target.Block = clonectx.LookupBlock (Block);
3737 if (local_info != null)
3738 target.local_info = clonectx.LookupVariable (local_info);
3743 /// This represents a reference to a parameter in the intermediate
3746 public class ParameterReference : VariableReference, IVariable {
3747 readonly ToplevelParameterInfo pi;
3748 readonly ToplevelBlock referenced;
3751 public bool is_ref, is_out;
3754 get { return is_out; }
3757 public override bool IsRef {
3758 get { return is_ref; }
3761 public string Name {
3762 get { return Parameter.Name; }
3765 public Parameter Parameter {
3766 get { return pi.Parameter; }
3769 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3772 this.referenced = referenced;
3774 eclass = ExprClass.Variable;
3777 public VariableInfo VariableInfo {
3778 get { return pi.VariableInfo; }
3781 public override Variable Variable {
3782 get { return variable != null ? variable : Parameter.Variable; }
3785 public bool VerifyFixed ()
3787 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3788 return Parameter.ModFlags == Parameter.Modifier.NONE;
3791 public bool IsAssigned (EmitContext ec, Location loc)
3793 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3796 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3800 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3802 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3805 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3809 public void SetAssigned (EmitContext ec)
3811 if (is_out && ec.DoFlowAnalysis)
3812 ec.CurrentBranching.SetAssigned (VariableInfo);
3815 public void SetFieldAssigned (EmitContext ec, string field_name)
3817 if (is_out && ec.DoFlowAnalysis)
3818 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3821 protected bool DoResolveBase (EmitContext ec)
3823 Parameter par = Parameter;
3824 if (!par.Resolve (ec)) {
3828 type = par.ParameterType;
3829 Parameter.Modifier mod = par.ModFlags;
3830 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3831 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3832 eclass = ExprClass.Variable;
3834 AnonymousContainer am = ec.CurrentAnonymousMethod;
3838 ToplevelBlock declared = pi.Block;
3839 if (is_ref && declared != referenced) {
3840 Report.Error (1628, Location,
3841 "Cannot use ref or out parameter `{0}' inside an " +
3842 "anonymous method block", par.Name);
3846 if (!am.IsIterator && declared == referenced)
3849 // Don't capture aruments when the probing is on
3850 if (!ec.IsInProbingMode) {
3851 ScopeInfo scope = declared.CreateScopeInfo ();
3852 variable = scope.AddParameter (par, pi.Index);
3853 type = variable.Type;
3858 public override int GetHashCode ()
3860 return Name.GetHashCode ();
3863 public override bool Equals (object obj)
3865 ParameterReference pr = obj as ParameterReference;
3869 return Name == pr.Name && referenced == pr.referenced;
3873 // Notice that for ref/out parameters, the type exposed is not the
3874 // same type exposed externally.
3877 // externally we expose "int&"
3878 // here we expose "int".
3880 // We record this in "is_ref". This means that the type system can treat
3881 // the type as it is expected, but when we generate the code, we generate
3882 // the alternate kind of code.
3884 public override Expression DoResolve (EmitContext ec)
3886 if (!DoResolveBase (ec))
3889 if (is_out && ec.DoFlowAnalysis &&
3890 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3896 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3898 if (!DoResolveBase (ec))
3901 // HACK: parameters are not captured when probing is on
3902 if (!ec.IsInProbingMode)
3908 static public void EmitLdArg (ILGenerator ig, int x)
3912 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3913 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3914 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3915 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3916 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3919 ig.Emit (OpCodes.Ldarg, x);
3922 public override string ToString ()
3924 return "ParameterReference[" + Name + "]";
3929 /// Used for arguments to New(), Invocation()
3931 public class Argument {
3932 public enum AType : byte {
3939 public static readonly Argument[] Empty = new Argument [0];
3941 public readonly AType ArgType;
3942 public Expression Expr;
3944 public Argument (Expression expr, AType type)
3947 this.ArgType = type;
3950 public Argument (Expression expr)
3953 this.ArgType = AType.Expression;
3958 if (ArgType == AType.Ref || ArgType == AType.Out)
3959 return TypeManager.GetReferenceType (Expr.Type);
3965 public Parameter.Modifier Modifier
3970 return Parameter.Modifier.OUT;
3973 return Parameter.Modifier.REF;
3976 return Parameter.Modifier.NONE;
3981 public static string FullDesc (Argument a)
3983 if (a.ArgType == AType.ArgList)
3986 return (a.ArgType == AType.Ref ? "ref " :
3987 (a.ArgType == AType.Out ? "out " : "")) +
3988 TypeManager.CSharpName (a.Expr.Type);
3991 public bool ResolveMethodGroup (EmitContext ec)
3993 SimpleName sn = Expr as SimpleName;
3995 Expr = sn.GetMethodGroup ();
3997 // FIXME: csc doesn't report any error if you try to use `ref' or
3998 // `out' in a delegate creation expression.
3999 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4006 public bool Resolve (EmitContext ec, Location loc)
4008 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4009 // Verify that the argument is readable
4010 if (ArgType != AType.Out)
4011 Expr = Expr.Resolve (ec);
4013 // Verify that the argument is writeable
4014 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4015 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4017 return Expr != null;
4021 public void Emit (EmitContext ec)
4023 if (ArgType != AType.Ref && ArgType != AType.Out) {
4028 AddressOp mode = AddressOp.Store;
4029 if (ArgType == AType.Ref)
4030 mode |= AddressOp.Load;
4032 IMemoryLocation ml = (IMemoryLocation) Expr;
4033 ParameterReference pr = ml as ParameterReference;
4036 // ParameterReferences might already be references, so we want
4037 // to pass just the value
4039 if (pr != null && pr.IsRef)
4042 ml.AddressOf (ec, mode);
4045 public Argument Clone (CloneContext clonectx)
4047 return new Argument (Expr.Clone (clonectx), ArgType);
4052 /// Invocation of methods or delegates.
4054 public class Invocation : ExpressionStatement {
4055 ArrayList Arguments;
4060 // arguments is an ArrayList, but we do not want to typecast,
4061 // as it might be null.
4063 public Invocation (Expression expr, ArrayList arguments)
4065 SimpleName sn = expr as SimpleName;
4067 this.expr = sn.GetMethodGroup ();
4071 Arguments = arguments;
4072 loc = expr.Location;
4075 public static string FullMethodDesc (MethodBase mb)
4081 if (mb is MethodInfo) {
4082 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4086 sb = new StringBuilder ();
4088 sb.Append (TypeManager.CSharpSignature (mb));
4089 return sb.ToString ();
4092 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4093 ArrayList arguments, int arg_count,
4094 ref MethodBase candidate)
4096 return IsParamsMethodApplicable (
4097 ec, me, arguments, arg_count, false, ref candidate) ||
4098 IsParamsMethodApplicable (
4099 ec, me, arguments, arg_count, true, ref candidate);
4104 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4105 ArrayList arguments, int arg_count,
4106 bool do_varargs, ref MethodBase candidate)
4109 if (!me.HasTypeArguments &&
4110 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4113 if (TypeManager.IsGenericMethodDefinition (candidate))
4114 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4117 return IsParamsMethodApplicable (
4118 ec, arguments, arg_count, candidate, do_varargs);
4122 /// Determines if the candidate method, if a params method, is applicable
4123 /// in its expanded form to the given set of arguments
4125 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4126 int arg_count, MethodBase candidate,
4129 ParameterData pd = TypeManager.GetParameterData (candidate);
4131 int pd_count = pd.Count;
4135 int count = pd_count - 1;
4137 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4139 if (pd_count != arg_count)
4142 if (!(((Argument) arguments [count]).Expr is Arglist))
4150 if (count > arg_count)
4153 if (pd_count == 1 && arg_count == 0)
4157 // If we have come this far, the case which
4158 // remains is when the number of parameters is
4159 // less than or equal to the argument count.
4161 int argument_index = 0;
4163 for (int i = 0; i < pd_count; ++i) {
4165 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4166 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4167 int params_args_count = arg_count - pd_count;
4168 if (params_args_count < 0)
4172 a = (Argument) arguments [argument_index++];
4174 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4176 } while (params_args_count-- > 0);
4180 a = (Argument) arguments [argument_index++];
4182 Parameter.Modifier a_mod = a.Modifier &
4183 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4184 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4185 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4187 if (a_mod == p_mod) {
4189 if (a_mod == Parameter.Modifier.NONE)
4190 if (!Convert.ImplicitConversionExists (ec,
4192 pd.ParameterType (i)))
4195 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4196 Type pt = pd.ParameterType (i);
4199 pt = TypeManager.GetReferenceType (pt);
4212 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4213 ArrayList arguments, int arg_count,
4214 ref MethodBase method)
4216 MethodBase candidate = method;
4219 if (!me.HasTypeArguments &&
4220 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4223 if (TypeManager.IsGenericMethodDefinition (candidate))
4224 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4227 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4236 /// Determines if the candidate method is applicable (section 14.4.2.1)
4237 /// to the given set of arguments
4239 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4240 MethodBase candidate)
4242 ParameterData pd = TypeManager.GetParameterData (candidate);
4244 if (arg_count != pd.Count)
4247 for (int i = arg_count; i > 0; ) {
4250 Argument a = (Argument) arguments [i];
4252 Parameter.Modifier a_mod = a.Modifier &
4253 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4255 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4256 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4261 Type pt = pd.ParameterType (i);
4263 if (TypeManager.IsEqual (pt, a.Type))
4266 if (a_mod != Parameter.Modifier.NONE)
4269 // FIXME: Kill this abomination (EmitContext.TempEc)
4270 EmitContext prevec = EmitContext.TempEc;
4271 EmitContext.TempEc = ec;
4273 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4276 EmitContext.TempEc = prevec;
4283 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4285 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4286 name, arg_count.ToString ());
4289 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4290 Type delegate_type, Argument a, ParameterData expected_par)
4292 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4293 Report.SymbolRelatedToPreviousError (method);
4294 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
4295 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4296 TypeManager.CSharpSignature (method));
4299 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4300 TypeManager.CSharpSignature (method));
4301 } else if (delegate_type == null) {
4302 Report.SymbolRelatedToPreviousError (method);
4303 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4304 TypeManager.CSharpSignature (method));
4306 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4307 TypeManager.CSharpName (delegate_type));
4309 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4311 string index = (idx + 1).ToString ();
4312 if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4313 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4314 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4315 index, Parameter.GetModifierSignature (a.Modifier));
4317 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4318 index, Parameter.GetModifierSignature (mod));
4320 string p1 = Argument.FullDesc (a);
4321 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4324 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4325 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4326 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4328 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4332 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4333 int arg_count, MethodBase method,
4334 bool chose_params_expanded,
4335 Type delegate_type, bool may_fail,
4338 ParameterData pd = TypeManager.GetParameterData (method);
4342 for (j = 0; j < pd.Count; j++) {
4343 Type parameter_type = pd.ParameterType (j);
4344 Parameter.Modifier pm = pd.ParameterModifier (j);
4346 if (pm == Parameter.Modifier.ARGLIST) {
4347 a = (Argument) Arguments [a_idx];
4348 if (!(a.Expr is Arglist))
4354 int params_arg_count = 1;
4355 if (pm == Parameter.Modifier.PARAMS) {
4356 pm = Parameter.Modifier.NONE;
4357 params_arg_count = arg_count - pd.Count + 1;
4358 if (chose_params_expanded)
4359 parameter_type = TypeManager.GetElementType (parameter_type);
4362 while (params_arg_count > 0) {
4363 a = (Argument) Arguments [a_idx];
4364 if (pm != a.Modifier)
4367 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4368 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4371 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4375 // Update the argument with the implicit conversion
4383 if (params_arg_count > 0)
4386 if (parameter_type.IsPointer && !ec.InUnsafe) {
4393 if (a_idx == arg_count)
4397 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4401 public override Expression DoResolve (EmitContext ec)
4403 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4404 if (expr_resolved == null)
4407 mg = expr_resolved as MethodGroupExpr;
4409 Type expr_type = expr_resolved.Type;
4411 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4412 return (new DelegateInvocation (
4413 expr_resolved, Arguments, loc)).Resolve (ec);
4415 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4420 // Next, evaluate all the expressions in the argument list
4422 if (Arguments != null){
4423 foreach (Argument a in Arguments){
4424 if (!a.Resolve (ec, loc))
4429 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4433 MethodInfo method = (MethodInfo)mg;
4434 if (method != null) {
4435 type = TypeManager.TypeToCoreType (method.ReturnType);
4436 Expression iexpr = mg.InstanceExpression;
4437 if (method.IsStatic) {
4438 if (iexpr == null ||
4439 iexpr is This || iexpr is EmptyExpression ||
4440 mg.IdenticalTypeName) {
4441 mg.InstanceExpression = null;
4443 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4447 if (iexpr == null || iexpr is EmptyExpression) {
4448 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4454 if (type.IsPointer){
4462 // Only base will allow this invocation to happen.
4464 if (mg.IsBase && method.IsAbstract){
4465 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4469 if (Arguments == null && method.Name == "Finalize") {
4471 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4473 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4477 if (IsSpecialMethodInvocation (method)) {
4481 if (mg.InstanceExpression != null){
4482 mg.InstanceExpression.CheckMarshalByRefAccess ();
4485 // This is used to check that no methods are called in struct
4486 // constructors before all the fields on the struct have been
4489 if (!method.IsStatic){
4490 This mgthis = mg.InstanceExpression as This;
4491 if (mgthis != null){
4492 if (!mgthis.CheckThisUsage (ec))
4498 eclass = ExprClass.Value;
4502 bool IsSpecialMethodInvocation (MethodBase method)
4504 if (!TypeManager.IsSpecialMethod (method))
4507 Report.SymbolRelatedToPreviousError (method);
4508 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4509 TypeManager.CSharpSignature (method, true));
4515 // Emits the list of arguments as an array
4517 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4519 ILGenerator ig = ec.ig;
4521 for (int j = 0; j < count; j++){
4522 Argument a = (Argument) arguments [j + idx];
4525 IntConstant.EmitInt (ig, count);
4526 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4529 ig.Emit (OpCodes.Dup);
4530 IntConstant.EmitInt (ig, j);
4532 bool is_stobj, has_type_arg;
4533 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4535 ig.Emit (OpCodes.Ldelema, t);
4547 /// Emits a list of resolved Arguments that are in the arguments
4550 /// The MethodBase argument might be null if the
4551 /// emission of the arguments is known not to contain
4552 /// a `params' field (for example in constructors or other routines
4553 /// that keep their arguments in this structure)
4555 /// if `dup_args' is true, a copy of the arguments will be left
4556 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4557 /// which will be duplicated before any other args. Only EmitCall
4558 /// should be using this interface.
4560 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4562 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4564 LocalTemporary [] temps = null;
4566 if (dup_args && top != 0)
4567 temps = new LocalTemporary [top];
4569 int argument_index = 0;
4571 for (int i = 0; i < top; i++){
4573 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4574 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4575 int params_args_count = arguments == null ?
4576 0 : arguments.Count - top + 1;
4578 // Fill not provided argument
4579 if (params_args_count <= 0) {
4580 ILGenerator ig = ec.ig;
4581 IntConstant.EmitInt (ig, 0);
4582 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4587 // Special case if we are passing the same data as the
4588 // params argument, we do not need to recreate an array.
4590 a = (Argument) arguments [argument_index];
4591 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4597 EmitParams (ec, arguments, i, params_args_count);
4598 argument_index += params_args_count;
4603 a = (Argument) arguments [argument_index++];
4606 ec.ig.Emit (OpCodes.Dup);
4607 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4612 if (this_arg != null)
4615 for (int i = 0; i < top; i ++) {
4616 temps [i].Emit (ec);
4617 temps [i].Release (ec);
4622 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4624 ParameterData pd = TypeManager.GetParameterData (mb);
4626 if (arguments == null)
4627 return new Type [0];
4629 Argument a = (Argument) arguments [pd.Count - 1];
4630 Arglist list = (Arglist) a.Expr;
4632 return list.ArgumentTypes;
4636 /// This checks the ConditionalAttribute on the method
4638 static bool IsMethodExcluded (MethodBase method)
4640 if (method.IsConstructor)
4643 IMethodData md = TypeManager.GetMethod (method);
4645 return md.IsExcluded ();
4647 // For some methods (generated by delegate class) GetMethod returns null
4648 // because they are not included in builder_to_method table
4649 if (method.DeclaringType is TypeBuilder)
4652 return AttributeTester.IsConditionalMethodExcluded (method);
4656 /// is_base tells whether we want to force the use of the `call'
4657 /// opcode instead of using callvirt. Call is required to call
4658 /// a specific method, while callvirt will always use the most
4659 /// recent method in the vtable.
4661 /// is_static tells whether this is an invocation on a static method
4663 /// instance_expr is an expression that represents the instance
4664 /// it must be non-null if is_static is false.
4666 /// method is the method to invoke.
4668 /// Arguments is the list of arguments to pass to the method or constructor.
4670 public static void EmitCall (EmitContext ec, bool is_base,
4671 Expression instance_expr,
4672 MethodBase method, ArrayList Arguments, Location loc)
4674 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4677 // `dup_args' leaves an extra copy of the arguments on the stack
4678 // `omit_args' does not leave any arguments at all.
4679 // So, basically, you could make one call with `dup_args' set to true,
4680 // and then another with `omit_args' set to true, and the two calls
4681 // would have the same set of arguments. However, each argument would
4682 // only have been evaluated once.
4683 public static void EmitCall (EmitContext ec, bool is_base,
4684 Expression instance_expr,
4685 MethodBase method, ArrayList Arguments, Location loc,
4686 bool dup_args, bool omit_args)
4688 ILGenerator ig = ec.ig;
4689 bool struct_call = false;
4690 bool this_call = false;
4691 LocalTemporary this_arg = null;
4693 Type decl_type = method.DeclaringType;
4695 if (!RootContext.StdLib) {
4696 // Replace any calls to the system's System.Array type with calls to
4697 // the newly created one.
4698 if (method == TypeManager.system_int_array_get_length)
4699 method = TypeManager.int_array_get_length;
4700 else if (method == TypeManager.system_int_array_get_rank)
4701 method = TypeManager.int_array_get_rank;
4702 else if (method == TypeManager.system_object_array_clone)
4703 method = TypeManager.object_array_clone;
4704 else if (method == TypeManager.system_int_array_get_length_int)
4705 method = TypeManager.int_array_get_length_int;
4706 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4707 method = TypeManager.int_array_get_lower_bound_int;
4708 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4709 method = TypeManager.int_array_get_upper_bound_int;
4710 else if (method == TypeManager.system_void_array_copyto_array_int)
4711 method = TypeManager.void_array_copyto_array_int;
4714 if (!ec.IsInObsoleteScope) {
4716 // This checks ObsoleteAttribute on the method and on the declaring type
4718 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4720 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4722 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4724 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4728 if (IsMethodExcluded (method))
4731 bool is_static = method.IsStatic;
4733 if (instance_expr == EmptyExpression.Null) {
4734 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4738 this_call = instance_expr is This;
4739 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4743 // If this is ourselves, push "this"
4747 Type iexpr_type = instance_expr.Type;
4750 // Push the instance expression
4752 if (TypeManager.IsValueType (iexpr_type)) {
4754 // Special case: calls to a function declared in a
4755 // reference-type with a value-type argument need
4756 // to have their value boxed.
4757 if (decl_type.IsValueType ||
4758 TypeManager.IsGenericParameter (iexpr_type)) {
4760 // If the expression implements IMemoryLocation, then
4761 // we can optimize and use AddressOf on the
4764 // If not we have to use some temporary storage for
4766 if (instance_expr is IMemoryLocation) {
4767 ((IMemoryLocation)instance_expr).
4768 AddressOf (ec, AddressOp.LoadStore);
4770 LocalTemporary temp = new LocalTemporary (iexpr_type);
4771 instance_expr.Emit (ec);
4773 temp.AddressOf (ec, AddressOp.Load);
4776 // avoid the overhead of doing this all the time.
4778 t = TypeManager.GetReferenceType (iexpr_type);
4780 instance_expr.Emit (ec);
4781 ig.Emit (OpCodes.Box, instance_expr.Type);
4782 t = TypeManager.object_type;
4785 instance_expr.Emit (ec);
4786 t = instance_expr.Type;
4790 ig.Emit (OpCodes.Dup);
4791 if (Arguments != null && Arguments.Count != 0) {
4792 this_arg = new LocalTemporary (t);
4793 this_arg.Store (ec);
4800 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4803 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4804 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4808 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4809 call_op = OpCodes.Call;
4811 call_op = OpCodes.Callvirt;
4813 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4814 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4815 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4822 // and DoFoo is not virtual, you can omit the callvirt,
4823 // because you don't need the null checking behavior.
4825 if (method is MethodInfo)
4826 ig.Emit (call_op, (MethodInfo) method);
4828 ig.Emit (call_op, (ConstructorInfo) method);
4831 public override void Emit (EmitContext ec)
4833 mg.EmitCall (ec, Arguments);
4836 public override void EmitStatement (EmitContext ec)
4841 // Pop the return value if there is one
4843 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4844 ec.ig.Emit (OpCodes.Pop);
4847 protected override void CloneTo (CloneContext clonectx, Expression t)
4849 Invocation target = (Invocation) t;
4851 if (Arguments != null) {
4852 target.Arguments = new ArrayList (Arguments.Count);
4853 foreach (Argument a in Arguments)
4854 target.Arguments.Add (a.Clone (clonectx));
4857 target.expr = expr.Clone (clonectx);
4861 public class InvocationOrCast : ExpressionStatement
4864 Expression argument;
4866 public InvocationOrCast (Expression expr, Expression argument)
4869 this.argument = argument;
4870 this.loc = expr.Location;
4873 public override Expression DoResolve (EmitContext ec)
4876 // First try to resolve it as a cast.
4878 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4879 if ((te != null) && (te.eclass == ExprClass.Type)) {
4880 Cast cast = new Cast (te, argument, loc);
4881 return cast.Resolve (ec);
4885 // This can either be a type or a delegate invocation.
4886 // Let's just resolve it and see what we'll get.
4888 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4893 // Ok, so it's a Cast.
4895 if (expr.eclass == ExprClass.Type) {
4896 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4897 return cast.Resolve (ec);
4901 // It's a delegate invocation.
4903 if (!TypeManager.IsDelegateType (expr.Type)) {
4904 Error (149, "Method name expected");
4908 ArrayList args = new ArrayList ();
4909 args.Add (new Argument (argument, Argument.AType.Expression));
4910 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4911 return invocation.Resolve (ec);
4914 public override ExpressionStatement ResolveStatement (EmitContext ec)
4917 // First try to resolve it as a cast.
4919 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4920 if ((te != null) && (te.eclass == ExprClass.Type)) {
4921 Error_InvalidExpressionStatement ();
4926 // This can either be a type or a delegate invocation.
4927 // Let's just resolve it and see what we'll get.
4929 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4930 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4931 Error_InvalidExpressionStatement ();
4936 // It's a delegate invocation.
4938 if (!TypeManager.IsDelegateType (expr.Type)) {
4939 Error (149, "Method name expected");
4943 ArrayList args = new ArrayList ();
4944 args.Add (new Argument (argument, Argument.AType.Expression));
4945 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4946 return invocation.ResolveStatement (ec);
4949 public override void Emit (EmitContext ec)
4951 throw new Exception ("Cannot happen");
4954 public override void EmitStatement (EmitContext ec)
4956 throw new Exception ("Cannot happen");
4959 protected override void CloneTo (CloneContext clonectx, Expression t)
4961 InvocationOrCast target = (InvocationOrCast) t;
4963 target.expr = expr.Clone (clonectx);
4964 target.argument = argument.Clone (clonectx);
4969 // This class is used to "disable" the code generation for the
4970 // temporary variable when initializing value types.
4972 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4973 public void AddressOf (EmitContext ec, AddressOp Mode)
4980 /// Implements the new expression
4982 public class New : ExpressionStatement, IMemoryLocation {
4983 ArrayList Arguments;
4986 // During bootstrap, it contains the RequestedType,
4987 // but if `type' is not null, it *might* contain a NewDelegate
4988 // (because of field multi-initialization)
4990 public Expression RequestedType;
4992 MethodGroupExpr method;
4995 // If set, the new expression is for a value_target, and
4996 // we will not leave anything on the stack.
4998 Expression value_target;
4999 bool value_target_set = false;
5000 bool is_type_parameter = false;
5002 public New (Expression requested_type, ArrayList arguments, Location l)
5004 RequestedType = requested_type;
5005 Arguments = arguments;
5009 public bool SetValueTypeVariable (Expression value)
5011 value_target = value;
5012 value_target_set = true;
5013 if (!(value_target is IMemoryLocation)){
5014 Error_UnexpectedKind (null, "variable", loc);
5021 // This function is used to disable the following code sequence for
5022 // value type initialization:
5024 // AddressOf (temporary)
5028 // Instead the provide will have provided us with the address on the
5029 // stack to store the results.
5031 static Expression MyEmptyExpression;
5033 public void DisableTemporaryValueType ()
5035 if (MyEmptyExpression == null)
5036 MyEmptyExpression = new EmptyAddressOf ();
5039 // To enable this, look into:
5040 // test-34 and test-89 and self bootstrapping.
5042 // For instance, we can avoid a copy by using `newobj'
5043 // instead of Call + Push-temp on value types.
5044 // value_target = MyEmptyExpression;
5049 /// Converts complex core type syntax like 'new int ()' to simple constant
5051 public static Constant Constantify (Type t)
5053 if (t == TypeManager.int32_type)
5054 return new IntConstant (0, Location.Null);
5055 if (t == TypeManager.uint32_type)
5056 return new UIntConstant (0, Location.Null);
5057 if (t == TypeManager.int64_type)
5058 return new LongConstant (0, Location.Null);
5059 if (t == TypeManager.uint64_type)
5060 return new ULongConstant (0, Location.Null);
5061 if (t == TypeManager.float_type)
5062 return new FloatConstant (0, Location.Null);
5063 if (t == TypeManager.double_type)
5064 return new DoubleConstant (0, Location.Null);
5065 if (t == TypeManager.short_type)
5066 return new ShortConstant (0, Location.Null);
5067 if (t == TypeManager.ushort_type)
5068 return new UShortConstant (0, Location.Null);
5069 if (t == TypeManager.sbyte_type)
5070 return new SByteConstant (0, Location.Null);
5071 if (t == TypeManager.byte_type)
5072 return new ByteConstant (0, Location.Null);
5073 if (t == TypeManager.char_type)
5074 return new CharConstant ('\0', Location.Null);
5075 if (t == TypeManager.bool_type)
5076 return new BoolConstant (false, Location.Null);
5077 if (t == TypeManager.decimal_type)
5078 return new DecimalConstant (0, Location.Null);
5079 if (TypeManager.IsEnumType (t))
5080 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5086 // Checks whether the type is an interface that has the
5087 // [ComImport, CoClass] attributes and must be treated
5090 public Expression CheckComImport (EmitContext ec)
5092 if (!type.IsInterface)
5096 // Turn the call into:
5097 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5099 Type real_class = AttributeTester.GetCoClassAttribute (type);
5100 if (real_class == null)
5103 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5104 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5105 return cast.Resolve (ec);
5108 public override Expression DoResolve (EmitContext ec)
5111 // The New DoResolve might be called twice when initializing field
5112 // expressions (see EmitFieldInitializers, the call to
5113 // GetInitializerExpression will perform a resolve on the expression,
5114 // and later the assign will trigger another resolution
5116 // This leads to bugs (#37014)
5119 if (RequestedType is NewDelegate)
5120 return RequestedType;
5124 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5130 if (type == TypeManager.void_type) {
5131 Error_VoidInvalidInTheContext (loc);
5135 if (type.IsPointer) {
5136 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5137 TypeManager.CSharpName (type));
5141 if (Arguments == null) {
5142 Expression c = Constantify (type);
5147 if (TypeManager.IsDelegateType (type)) {
5148 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5149 if (RequestedType != null)
5150 if (!(RequestedType is DelegateCreation))
5151 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5152 return RequestedType;
5156 if (type.IsGenericParameter) {
5157 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5159 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5160 Error (304, String.Format (
5161 "Cannot create an instance of the " +
5162 "variable type '{0}' because it " +
5163 "doesn't have the new() constraint",
5168 if ((Arguments != null) && (Arguments.Count != 0)) {
5169 Error (417, String.Format (
5170 "`{0}': cannot provide arguments " +
5171 "when creating an instance of a " +
5172 "variable type.", type));
5176 is_type_parameter = true;
5177 eclass = ExprClass.Value;
5182 if (type.IsAbstract && type.IsSealed) {
5183 Report.SymbolRelatedToPreviousError (type);
5184 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5188 if (type.IsInterface || type.IsAbstract){
5189 if (!TypeManager.IsGenericType (type)) {
5190 RequestedType = CheckComImport (ec);
5191 if (RequestedType != null)
5192 return RequestedType;
5195 Report.SymbolRelatedToPreviousError (type);
5196 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5200 bool is_struct = type.IsValueType;
5201 eclass = ExprClass.Value;
5204 // SRE returns a match for .ctor () on structs (the object constructor),
5205 // so we have to manually ignore it.
5207 if (is_struct && Arguments == null)
5210 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5211 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5212 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5214 if (Arguments != null){
5215 foreach (Argument a in Arguments){
5216 if (!a.Resolve (ec, loc))
5224 method = ml as MethodGroupExpr;
5225 if (method == null) {
5226 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5230 method = method.OverloadResolve (ec, Arguments, false, loc);
5237 bool DoEmitTypeParameter (EmitContext ec)
5240 ILGenerator ig = ec.ig;
5241 // IMemoryLocation ml;
5243 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5244 new Type [] { type });
5246 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5247 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5248 ig.Emit (OpCodes.Call, ci);
5252 // Allow DoEmit() to be called multiple times.
5253 // We need to create a new LocalTemporary each time since
5254 // you can't share LocalBuilders among ILGeneators.
5255 LocalTemporary temp = new LocalTemporary (type);
5257 Label label_activator = ig.DefineLabel ();
5258 Label label_end = ig.DefineLabel ();
5260 temp.AddressOf (ec, AddressOp.Store);
5261 ig.Emit (OpCodes.Initobj, type);
5264 ig.Emit (OpCodes.Box, type);
5265 ig.Emit (OpCodes.Brfalse, label_activator);
5267 temp.AddressOf (ec, AddressOp.Store);
5268 ig.Emit (OpCodes.Initobj, type);
5270 ig.Emit (OpCodes.Br, label_end);
5272 ig.MarkLabel (label_activator);
5274 ig.Emit (OpCodes.Call, ci);
5275 ig.MarkLabel (label_end);
5278 throw new InternalErrorException ();
5283 // This DoEmit can be invoked in two contexts:
5284 // * As a mechanism that will leave a value on the stack (new object)
5285 // * As one that wont (init struct)
5287 // You can control whether a value is required on the stack by passing
5288 // need_value_on_stack. The code *might* leave a value on the stack
5289 // so it must be popped manually
5291 // If we are dealing with a ValueType, we have a few
5292 // situations to deal with:
5294 // * The target is a ValueType, and we have been provided
5295 // the instance (this is easy, we are being assigned).
5297 // * The target of New is being passed as an argument,
5298 // to a boxing operation or a function that takes a
5301 // In this case, we need to create a temporary variable
5302 // that is the argument of New.
5304 // Returns whether a value is left on the stack
5306 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5308 bool is_value_type = TypeManager.IsValueType (type);
5309 ILGenerator ig = ec.ig;
5314 // Allow DoEmit() to be called multiple times.
5315 // We need to create a new LocalTemporary each time since
5316 // you can't share LocalBuilders among ILGeneators.
5317 if (!value_target_set)
5318 value_target = new LocalTemporary (type);
5320 ml = (IMemoryLocation) value_target;
5321 ml.AddressOf (ec, AddressOp.Store);
5325 method.EmitArguments (ec, Arguments);
5329 ig.Emit (OpCodes.Initobj, type);
5331 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5332 if (need_value_on_stack){
5333 value_target.Emit (ec);
5338 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5343 public override void Emit (EmitContext ec)
5345 if (is_type_parameter)
5346 DoEmitTypeParameter (ec);
5351 public override void EmitStatement (EmitContext ec)
5353 bool value_on_stack;
5355 if (is_type_parameter)
5356 value_on_stack = DoEmitTypeParameter (ec);
5358 value_on_stack = DoEmit (ec, false);
5361 ec.ig.Emit (OpCodes.Pop);
5365 public void AddressOf (EmitContext ec, AddressOp Mode)
5367 if (is_type_parameter) {
5368 LocalTemporary temp = new LocalTemporary (type);
5369 DoEmitTypeParameter (ec);
5371 temp.AddressOf (ec, Mode);
5375 if (!type.IsValueType){
5377 // We throw an exception. So far, I believe we only need to support
5379 // foreach (int j in new StructType ())
5382 throw new Exception ("AddressOf should not be used for classes");
5385 if (!value_target_set)
5386 value_target = new LocalTemporary (type);
5387 IMemoryLocation ml = (IMemoryLocation) value_target;
5389 ml.AddressOf (ec, AddressOp.Store);
5390 if (method == null) {
5391 ec.ig.Emit (OpCodes.Initobj, type);
5393 method.EmitArguments (ec, Arguments);
5394 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5397 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5400 protected override void CloneTo (CloneContext clonectx, Expression t)
5402 New target = (New) t;
5404 target.RequestedType = RequestedType.Clone (clonectx);
5405 if (Arguments != null){
5406 target.Arguments = new ArrayList ();
5407 foreach (Argument a in Arguments){
5408 target.Arguments.Add (a.Clone (clonectx));
5415 /// 14.5.10.2: Represents an array creation expression.
5419 /// There are two possible scenarios here: one is an array creation
5420 /// expression that specifies the dimensions and optionally the
5421 /// initialization data and the other which does not need dimensions
5422 /// specified but where initialization data is mandatory.
5424 public class ArrayCreation : Expression {
5425 Expression requested_base_type;
5426 ArrayList initializers;
5429 // The list of Argument types.
5430 // This is used to construct the `newarray' or constructor signature
5432 protected ArrayList arguments;
5434 protected Type array_element_type;
5435 bool expect_initializers = false;
5436 int num_arguments = 0;
5437 protected int dimensions;
5438 protected readonly string rank;
5440 protected ArrayList array_data;
5444 // The number of constants in array initializers
5445 int const_initializers_count;
5446 bool only_constant_initializers;
5448 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5450 this.requested_base_type = requested_base_type;
5451 this.initializers = initializers;
5455 arguments = new ArrayList ();
5457 foreach (Expression e in exprs) {
5458 arguments.Add (new Argument (e, Argument.AType.Expression));
5463 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5465 this.requested_base_type = requested_base_type;
5466 this.initializers = initializers;
5470 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5472 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5474 //dimensions = tmp.Length - 1;
5475 expect_initializers = true;
5478 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5480 StringBuilder sb = new StringBuilder (rank);
5483 for (int i = 1; i < idx_count; i++)
5488 return new ComposedCast (base_type, sb.ToString (), loc);
5491 void Error_IncorrectArrayInitializer ()
5493 Error (178, "Invalid rank specifier: expected `,' or `]'");
5496 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5498 if (specified_dims) {
5499 Argument a = (Argument) arguments [idx];
5501 if (!a.Resolve (ec, loc))
5504 Constant c = a.Expr as Constant;
5506 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5510 Report.Error (150, a.Expr.Location, "A constant value is expected");
5514 int value = (int) c.GetValue ();
5516 if (value != probe.Count) {
5517 Error_IncorrectArrayInitializer ();
5521 bounds [idx] = value;
5524 int child_bounds = -1;
5525 only_constant_initializers = true;
5526 for (int i = 0; i < probe.Count; ++i) {
5527 object o = probe [i];
5528 if (o is ArrayList) {
5529 ArrayList sub_probe = o as ArrayList;
5530 int current_bounds = sub_probe.Count;
5532 if (child_bounds == -1)
5533 child_bounds = current_bounds;
5535 else if (child_bounds != current_bounds){
5536 Error_IncorrectArrayInitializer ();
5539 if (idx + 1 >= dimensions){
5540 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5544 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5548 if (child_bounds != -1){
5549 Error_IncorrectArrayInitializer ();
5553 Expression element = ResolveArrayElement (ec, (Expression) o);
5554 if (element == null)
5557 // Initializers with the default values can be ignored
5558 Constant c = element as Constant;
5560 if (c.IsDefaultInitializer (array_element_type)) {
5564 ++const_initializers_count;
5567 only_constant_initializers = false;
5570 array_data.Add (element);
5577 public void UpdateIndices ()
5580 for (ArrayList probe = initializers; probe != null;) {
5581 if (probe.Count > 0 && probe [0] is ArrayList) {
5582 Expression e = new IntConstant (probe.Count, Location.Null);
5583 arguments.Add (new Argument (e, Argument.AType.Expression));
5585 bounds [i++] = probe.Count;
5587 probe = (ArrayList) probe [0];
5590 Expression e = new IntConstant (probe.Count, Location.Null);
5591 arguments.Add (new Argument (e, Argument.AType.Expression));
5593 bounds [i++] = probe.Count;
5600 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5602 element = element.Resolve (ec);
5603 if (element == null)
5606 return Convert.ImplicitConversionRequired (
5607 ec, element, array_element_type, loc);
5610 protected bool ResolveInitializers (EmitContext ec)
5612 if (initializers == null) {
5613 return !expect_initializers;
5617 // We use this to store all the date values in the order in which we
5618 // will need to store them in the byte blob later
5620 array_data = new ArrayList ();
5621 bounds = new System.Collections.Specialized.HybridDictionary ();
5623 if (arguments != null)
5624 return CheckIndices (ec, initializers, 0, true);
5626 arguments = new ArrayList ();
5628 if (!CheckIndices (ec, initializers, 0, false))
5637 // Resolved the type of the array
5639 bool ResolveArrayType (EmitContext ec)
5641 if (requested_base_type == null) {
5642 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5646 StringBuilder array_qualifier = new StringBuilder (rank);
5649 // `In the first form allocates an array instace of the type that results
5650 // from deleting each of the individual expression from the expression list'
5652 if (num_arguments > 0) {
5653 array_qualifier.Append ("[");
5654 for (int i = num_arguments-1; i > 0; i--)
5655 array_qualifier.Append (",");
5656 array_qualifier.Append ("]");
5662 TypeExpr array_type_expr;
5663 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5664 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5665 if (array_type_expr == null)
5668 type = array_type_expr.Type;
5669 array_element_type = TypeManager.GetElementType (type);
5670 dimensions = type.GetArrayRank ();
5675 public override Expression DoResolve (EmitContext ec)
5680 if (!ResolveArrayType (ec))
5683 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5684 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5685 TypeManager.CSharpName (array_element_type));
5689 // First step is to validate the initializers and fill
5690 // in any missing bits
5692 if (!ResolveInitializers (ec))
5695 if (arguments.Count != dimensions) {
5696 Error_IncorrectArrayInitializer ();
5699 foreach (Argument a in arguments){
5700 if (!a.Resolve (ec, loc))
5703 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5704 if (real_arg == null)
5710 eclass = ExprClass.Value;
5714 MethodInfo GetArrayMethod (int arguments)
5716 ModuleBuilder mb = CodeGen.Module.Builder;
5718 Type[] arg_types = new Type[arguments];
5719 for (int i = 0; i < arguments; i++)
5720 arg_types[i] = TypeManager.int32_type;
5722 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5726 Report.Error (-6, "New invocation: Can not find a constructor for " +
5727 "this argument list");
5734 byte [] MakeByteBlob ()
5739 int count = array_data.Count;
5741 if (array_element_type.IsEnum)
5742 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5744 factor = GetTypeSize (array_element_type);
5746 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5748 data = new byte [(count * factor + 4) & ~3];
5751 for (int i = 0; i < count; ++i) {
5752 object v = array_data [i];
5754 if (v is EnumConstant)
5755 v = ((EnumConstant) v).Child;
5757 if (v is Constant && !(v is StringConstant))
5758 v = ((Constant) v).GetValue ();
5764 if (array_element_type == TypeManager.int64_type){
5765 if (!(v is Expression)){
5766 long val = (long) v;
5768 for (int j = 0; j < factor; ++j) {
5769 data [idx + j] = (byte) (val & 0xFF);
5773 } else if (array_element_type == TypeManager.uint64_type){
5774 if (!(v is Expression)){
5775 ulong val = (ulong) v;
5777 for (int j = 0; j < factor; ++j) {
5778 data [idx + j] = (byte) (val & 0xFF);
5782 } else if (array_element_type == TypeManager.float_type) {
5783 if (!(v is Expression)){
5784 element = BitConverter.GetBytes ((float) v);
5786 for (int j = 0; j < factor; ++j)
5787 data [idx + j] = element [j];
5788 if (!BitConverter.IsLittleEndian)
5789 System.Array.Reverse (data, idx, 4);
5791 } else if (array_element_type == TypeManager.double_type) {
5792 if (!(v is Expression)){
5793 element = BitConverter.GetBytes ((double) v);
5795 for (int j = 0; j < factor; ++j)
5796 data [idx + j] = element [j];
5798 // FIXME: Handle the ARM float format.
5799 if (!BitConverter.IsLittleEndian)
5800 System.Array.Reverse (data, idx, 8);
5802 } else if (array_element_type == TypeManager.char_type){
5803 if (!(v is Expression)){
5804 int val = (int) ((char) v);
5806 data [idx] = (byte) (val & 0xff);
5807 data [idx+1] = (byte) (val >> 8);
5809 } else if (array_element_type == TypeManager.short_type){
5810 if (!(v is Expression)){
5811 int val = (int) ((short) v);
5813 data [idx] = (byte) (val & 0xff);
5814 data [idx+1] = (byte) (val >> 8);
5816 } else if (array_element_type == TypeManager.ushort_type){
5817 if (!(v is Expression)){
5818 int val = (int) ((ushort) v);
5820 data [idx] = (byte) (val & 0xff);
5821 data [idx+1] = (byte) (val >> 8);
5823 } else if (array_element_type == TypeManager.int32_type) {
5824 if (!(v is Expression)){
5827 data [idx] = (byte) (val & 0xff);
5828 data [idx+1] = (byte) ((val >> 8) & 0xff);
5829 data [idx+2] = (byte) ((val >> 16) & 0xff);
5830 data [idx+3] = (byte) (val >> 24);
5832 } else if (array_element_type == TypeManager.uint32_type) {
5833 if (!(v is Expression)){
5834 uint val = (uint) v;
5836 data [idx] = (byte) (val & 0xff);
5837 data [idx+1] = (byte) ((val >> 8) & 0xff);
5838 data [idx+2] = (byte) ((val >> 16) & 0xff);
5839 data [idx+3] = (byte) (val >> 24);
5841 } else if (array_element_type == TypeManager.sbyte_type) {
5842 if (!(v is Expression)){
5843 sbyte val = (sbyte) v;
5844 data [idx] = (byte) val;
5846 } else if (array_element_type == TypeManager.byte_type) {
5847 if (!(v is Expression)){
5848 byte val = (byte) v;
5849 data [idx] = (byte) val;
5851 } else if (array_element_type == TypeManager.bool_type) {
5852 if (!(v is Expression)){
5853 bool val = (bool) v;
5854 data [idx] = (byte) (val ? 1 : 0);
5856 } else if (array_element_type == TypeManager.decimal_type){
5857 if (!(v is Expression)){
5858 int [] bits = Decimal.GetBits ((decimal) v);
5861 // FIXME: For some reason, this doesn't work on the MS runtime.
5862 int [] nbits = new int [4];
5863 nbits [0] = bits [3];
5864 nbits [1] = bits [2];
5865 nbits [2] = bits [0];
5866 nbits [3] = bits [1];
5868 for (int j = 0; j < 4; j++){
5869 data [p++] = (byte) (nbits [j] & 0xff);
5870 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5871 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5872 data [p++] = (byte) (nbits [j] >> 24);
5876 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5885 // Emits the initializers for the array
5887 void EmitStaticInitializers (EmitContext ec)
5890 // First, the static data
5893 ILGenerator ig = ec.ig;
5895 byte [] data = MakeByteBlob ();
5897 fb = RootContext.MakeStaticData (data);
5899 ig.Emit (OpCodes.Dup);
5900 ig.Emit (OpCodes.Ldtoken, fb);
5901 ig.Emit (OpCodes.Call,
5902 TypeManager.void_initializearray_array_fieldhandle);
5906 // Emits pieces of the array that can not be computed at compile
5907 // time (variables and string locations).
5909 // This always expect the top value on the stack to be the array
5911 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5913 ILGenerator ig = ec.ig;
5914 int dims = bounds.Count;
5915 int [] current_pos = new int [dims];
5917 MethodInfo set = null;
5920 Type [] args = new Type [dims + 1];
5922 for (int j = 0; j < dims; j++)
5923 args [j] = TypeManager.int32_type;
5924 args [dims] = array_element_type;
5926 set = CodeGen.Module.Builder.GetArrayMethod (
5928 CallingConventions.HasThis | CallingConventions.Standard,
5929 TypeManager.void_type, args);
5932 for (int i = 0; i < array_data.Count; i++){
5934 Expression e = (Expression)array_data [i];
5936 // Constant can be initialized via StaticInitializer
5937 if (e != null && !(!emitConstants && e is Constant)) {
5938 Type etype = e.Type;
5940 ig.Emit (OpCodes.Dup);
5942 for (int idx = 0; idx < dims; idx++)
5943 IntConstant.EmitInt (ig, current_pos [idx]);
5946 // If we are dealing with a struct, get the
5947 // address of it, so we can store it.
5949 if ((dims == 1) && etype.IsValueType &&
5950 (!TypeManager.IsBuiltinOrEnum (etype) ||
5951 etype == TypeManager.decimal_type)) {
5956 // Let new know that we are providing
5957 // the address where to store the results
5959 n.DisableTemporaryValueType ();
5962 ig.Emit (OpCodes.Ldelema, etype);
5968 bool is_stobj, has_type_arg;
5969 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5971 ig.Emit (OpCodes.Stobj, etype);
5972 else if (has_type_arg)
5973 ig.Emit (op, etype);
5977 ig.Emit (OpCodes.Call, set);
5984 for (int j = dims - 1; j >= 0; j--){
5986 if (current_pos [j] < (int) bounds [j])
5988 current_pos [j] = 0;
5993 void EmitArrayArguments (EmitContext ec)
5995 ILGenerator ig = ec.ig;
5997 foreach (Argument a in arguments) {
5998 Type atype = a.Type;
6001 if (atype == TypeManager.uint64_type)
6002 ig.Emit (OpCodes.Conv_Ovf_U4);
6003 else if (atype == TypeManager.int64_type)
6004 ig.Emit (OpCodes.Conv_Ovf_I4);
6008 public override void Emit (EmitContext ec)
6010 ILGenerator ig = ec.ig;
6012 EmitArrayArguments (ec);
6013 if (arguments.Count == 1)
6014 ig.Emit (OpCodes.Newarr, array_element_type);
6016 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6019 if (initializers == null)
6022 // Emit static initializer for arrays which have contain more than 4 items and
6023 // the static initializer will initialize at least 25% of array values.
6024 // NOTE: const_initializers_count does not contain default constant values.
6025 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6026 TypeManager.IsPrimitiveType (array_element_type)) {
6027 EmitStaticInitializers (ec);
6029 if (!only_constant_initializers)
6030 EmitDynamicInitializers (ec, false);
6032 EmitDynamicInitializers (ec, true);
6036 public override bool GetAttributableValue (Type valueType, out object value)
6038 if (arguments.Count != 1) {
6039 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6040 return base.GetAttributableValue (null, out value);
6043 if (array_data == null) {
6044 Constant c = (Constant)((Argument)arguments [0]).Expr;
6045 if (c.IsDefaultValue) {
6046 value = Array.CreateInstance (array_element_type, 0);
6049 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6050 return base.GetAttributableValue (null, out value);
6053 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6054 object element_value;
6055 for (int i = 0; i < ret.Length; ++i)
6057 Expression e = (Expression)array_data [i];
6059 // Is null when an initializer is optimized (value == predefined value)
6063 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6067 ret.SetValue (element_value, i);
6073 protected override void CloneTo (CloneContext clonectx, Expression t)
6075 ArrayCreation target = (ArrayCreation) t;
6077 target.requested_base_type = requested_base_type.Clone (clonectx);
6079 if (arguments != null){
6080 target.arguments = new ArrayList (arguments.Count);
6081 foreach (Argument a in arguments)
6082 target.arguments.Add (a.Clone (clonectx));
6085 if (initializers != null){
6086 target.initializers = new ArrayList (initializers.Count);
6087 foreach (Expression initializer in initializers)
6088 target.initializers.Add (initializer.Clone (clonectx));
6094 // Represents an implicitly typed array epxression
6096 public class ImplicitlyTypedArrayCreation : ArrayCreation
6098 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6099 : base (null, rank, initializers, loc)
6101 if (rank.Length > 2) {
6102 while (rank [++dimensions] == ',');
6108 public override Expression DoResolve (EmitContext ec)
6113 if (!ResolveInitializers (ec))
6116 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6117 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6118 arguments.Count != dimensions) {
6119 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6124 // At this point we found common base type for all initializer elements
6125 // but we have to be sure that all static initializer elements are of
6128 UnifyInitializerElement (ec);
6130 type = TypeManager.GetConstructedType (array_element_type, rank);
6131 eclass = ExprClass.Value;
6136 // Converts static initializer only
6138 void UnifyInitializerElement (EmitContext ec)
6140 for (int i = 0; i < array_data.Count; ++i) {
6141 Expression e = (Expression)array_data[i];
6143 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6147 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6149 element = element.Resolve (ec);
6150 if (element == null)
6153 if (array_element_type == null) {
6154 array_element_type = element.Type;
6158 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6162 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6163 array_element_type = element.Type;
6167 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6172 public sealed class CompilerGeneratedThis : This
6174 public static This Instance = new CompilerGeneratedThis ();
6176 private CompilerGeneratedThis ()
6177 : base (Location.Null)
6181 public override Expression DoResolve (EmitContext ec)
6183 eclass = ExprClass.Variable;
6184 type = ec.ContainerType;
6185 variable = new SimpleThis (type);
6191 /// Represents the `this' construct
6194 public class This : VariableReference, IVariable
6197 VariableInfo variable_info;
6198 protected Variable variable;
6201 public This (Block block, Location loc)
6207 public This (Location loc)
6212 public VariableInfo VariableInfo {
6213 get { return variable_info; }
6216 public bool VerifyFixed ()
6218 return !TypeManager.IsValueType (Type);
6221 public override bool IsRef {
6222 get { return is_struct; }
6225 public override Variable Variable {
6226 get { return variable; }
6229 public bool ResolveBase (EmitContext ec)
6231 eclass = ExprClass.Variable;
6233 if (ec.TypeContainer.CurrentType != null)
6234 type = ec.TypeContainer.CurrentType;
6236 type = ec.ContainerType;
6238 is_struct = ec.TypeContainer is Struct;
6241 Error (26, "Keyword `this' is not valid in a static property, " +
6242 "static method, or static field initializer");
6246 if (block != null) {
6247 if (block.Toplevel.ThisVariable != null)
6248 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6250 AnonymousContainer am = ec.CurrentAnonymousMethod;
6251 if (is_struct && (am != null) && !am.IsIterator) {
6252 Report.Error (1673, loc, "Anonymous methods inside structs " +
6253 "cannot access instance members of `this'. " +
6254 "Consider copying `this' to a local variable " +
6255 "outside the anonymous method and using the " +
6260 RootScopeInfo host = block.Toplevel.RootScope;
6261 if ((host != null) && !ec.IsConstructor &&
6262 (!is_struct || host.IsIterator)) {
6263 variable = host.CaptureThis ();
6264 type = variable.Type;
6269 if (variable == null)
6270 variable = new SimpleThis (type);
6276 // Called from Invocation to check if the invocation is correct
6278 public bool CheckThisUsage (EmitContext ec)
6280 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6281 !variable_info.IsAssigned (ec)) {
6282 Error (188, "The `this' object cannot be used before all of its " +
6283 "fields are assigned to");
6284 variable_info.SetAssigned (ec);
6291 public override Expression DoResolve (EmitContext ec)
6293 if (!ResolveBase (ec))
6297 if (ec.IsFieldInitializer) {
6298 Error (27, "Keyword `this' is not available in the current context");
6305 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6307 if (!ResolveBase (ec))
6310 if (variable_info != null)
6311 variable_info.SetAssigned (ec);
6313 if (ec.TypeContainer is Class){
6314 Error (1604, "Cannot assign to 'this' because it is read-only");
6320 public override int GetHashCode()
6322 return block.GetHashCode ();
6325 public override bool Equals (object obj)
6327 This t = obj as This;
6331 return block == t.block;
6334 protected class SimpleThis : Variable
6338 public SimpleThis (Type type)
6343 public override Type Type {
6344 get { return type; }
6347 public override bool HasInstance {
6348 get { return false; }
6351 public override bool NeedsTemporary {
6352 get { return false; }
6355 public override void EmitInstance (EmitContext ec)
6360 public override void Emit (EmitContext ec)
6362 ec.ig.Emit (OpCodes.Ldarg_0);
6365 public override void EmitAssign (EmitContext ec)
6367 throw new InvalidOperationException ();
6370 public override void EmitAddressOf (EmitContext ec)
6372 ec.ig.Emit (OpCodes.Ldarg_0);
6376 protected override void CloneTo (CloneContext clonectx, Expression t)
6378 This target = (This) t;
6380 target.block = clonectx.LookupBlock (block);
6385 /// Represents the `__arglist' construct
6387 public class ArglistAccess : Expression
6389 public ArglistAccess (Location loc)
6394 public override Expression DoResolve (EmitContext ec)
6396 eclass = ExprClass.Variable;
6397 type = TypeManager.runtime_argument_handle_type;
6399 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6401 Error (190, "The __arglist construct is valid only within " +
6402 "a variable argument method");
6409 public override void Emit (EmitContext ec)
6411 ec.ig.Emit (OpCodes.Arglist);
6414 protected override void CloneTo (CloneContext clonectx, Expression target)
6421 /// Represents the `__arglist (....)' construct
6423 public class Arglist : Expression
6425 Argument[] Arguments;
6427 public Arglist (Location loc)
6428 : this (Argument.Empty, loc)
6432 public Arglist (Argument[] args, Location l)
6438 public Type[] ArgumentTypes {
6440 Type[] retval = new Type [Arguments.Length];
6441 for (int i = 0; i < Arguments.Length; i++)
6442 retval [i] = Arguments [i].Type;
6447 public override Expression DoResolve (EmitContext ec)
6449 eclass = ExprClass.Variable;
6450 type = TypeManager.runtime_argument_handle_type;
6452 foreach (Argument arg in Arguments) {
6453 if (!arg.Resolve (ec, loc))
6460 public override void Emit (EmitContext ec)
6462 foreach (Argument arg in Arguments)
6466 protected override void CloneTo (CloneContext clonectx, Expression t)
6468 Arglist target = (Arglist) t;
6470 target.Arguments = new Argument [Arguments.Length];
6471 for (int i = 0; i < Arguments.Length; i++)
6472 target.Arguments [i] = Arguments [i].Clone (clonectx);
6477 // This produces the value that renders an instance, used by the iterators code
6479 public class ProxyInstance : Expression, IMemoryLocation {
6480 public override Expression DoResolve (EmitContext ec)
6482 eclass = ExprClass.Variable;
6483 type = ec.ContainerType;
6487 public override void Emit (EmitContext ec)
6489 ec.ig.Emit (OpCodes.Ldarg_0);
6493 public void AddressOf (EmitContext ec, AddressOp mode)
6495 ec.ig.Emit (OpCodes.Ldarg_0);
6500 /// Implements the typeof operator
6502 public class TypeOf : Expression {
6503 Expression QueriedType;
6504 protected Type typearg;
6506 public TypeOf (Expression queried_type, Location l)
6508 QueriedType = queried_type;
6512 public override Expression DoResolve (EmitContext ec)
6514 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6518 typearg = texpr.Type;
6520 if (typearg == TypeManager.void_type) {
6521 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6525 if (typearg.IsPointer && !ec.InUnsafe){
6530 type = TypeManager.type_type;
6531 // Even though what is returned is a type object, it's treated as a value by the compiler.
6532 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6533 eclass = ExprClass.Value;
6537 public override void Emit (EmitContext ec)
6539 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6540 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6543 public override bool GetAttributableValue (Type valueType, out object value)
6545 if (TypeManager.ContainsGenericParameters (typearg) &&
6546 !TypeManager.IsGenericTypeDefinition (typearg)) {
6547 Report.SymbolRelatedToPreviousError (typearg);
6548 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6549 TypeManager.CSharpName (typearg));
6554 if (valueType == TypeManager.object_type) {
6555 value = (object)typearg;
6562 public Type TypeArgument
6570 protected override void CloneTo (CloneContext clonectx, Expression t)
6572 TypeOf target = (TypeOf) t;
6574 target.QueriedType = QueriedType.Clone (clonectx);
6579 /// Implements the `typeof (void)' operator
6581 public class TypeOfVoid : TypeOf {
6582 public TypeOfVoid (Location l) : base (null, l)
6587 public override Expression DoResolve (EmitContext ec)
6589 type = TypeManager.type_type;
6590 typearg = TypeManager.void_type;
6591 // See description in TypeOf.
6592 eclass = ExprClass.Value;
6598 /// Implements the sizeof expression
6600 public class SizeOf : Expression {
6601 readonly Expression QueriedType;
6604 public SizeOf (Expression queried_type, Location l)
6606 this.QueriedType = queried_type;
6610 public override Expression DoResolve (EmitContext ec)
6612 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6617 if (texpr is TypeParameterExpr){
6618 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6623 type_queried = texpr.Type;
6624 if (type_queried.IsEnum)
6625 type_queried = TypeManager.EnumToUnderlying (type_queried);
6627 if (type_queried == TypeManager.void_type) {
6628 Expression.Error_VoidInvalidInTheContext (loc);
6632 int size_of = GetTypeSize (type_queried);
6634 return new IntConstant (size_of, loc);
6638 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)",
6639 TypeManager.CSharpName (type_queried));
6643 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6647 type = TypeManager.int32_type;
6648 eclass = ExprClass.Value;
6652 public override void Emit (EmitContext ec)
6654 int size = GetTypeSize (type_queried);
6657 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6659 IntConstant.EmitInt (ec.ig, size);
6662 protected override void CloneTo (CloneContext clonectx, Expression t)
6668 /// Implements the qualified-alias-member (::) expression.
6670 public class QualifiedAliasMember : Expression
6672 string alias, identifier;
6674 public QualifiedAliasMember (string alias, string identifier, Location l)
6676 if (RootContext.Version == LanguageVersion.ISO_1)
6677 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6680 this.identifier = identifier;
6684 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6686 if (alias == "global")
6687 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6689 int errors = Report.Errors;
6690 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6692 if (errors == Report.Errors)
6693 Report.Error (432, loc, "Alias `{0}' not found", alias);
6696 if (fne.eclass != ExprClass.Namespace) {
6698 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6701 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6704 public override Expression DoResolve (EmitContext ec)
6706 FullNamedExpression fne;
6707 if (alias == "global") {
6708 fne = RootNamespace.Global;
6710 int errors = Report.Errors;
6711 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6713 if (errors == Report.Errors)
6714 Report.Error (432, loc, "Alias `{0}' not found", alias);
6719 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6723 if (!(retval is FullNamedExpression)) {
6724 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6728 // We defer this check till the end to match the behaviour of CSC
6729 if (fne.eclass != ExprClass.Namespace) {
6730 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6736 public override void Emit (EmitContext ec)
6738 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6742 public override string ToString ()
6744 return alias + "::" + identifier;
6747 public override string GetSignatureForError ()
6752 protected override void CloneTo (CloneContext clonectx, Expression t)
6759 /// Implements the member access expression
6761 public class MemberAccess : Expression {
6762 public readonly string Identifier;
6764 readonly TypeArguments args;
6766 public MemberAccess (Expression expr, string id)
6767 : this (expr, id, expr.Location)
6771 public MemberAccess (Expression expr, string identifier, Location loc)
6774 Identifier = identifier;
6778 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6779 : this (expr, identifier, loc)
6784 protected string LookupIdentifier {
6785 get { return MemberName.MakeName (Identifier, args); }
6788 // TODO: this method has very poor performace for Enum fields and
6789 // probably for other constants as well
6790 Expression DoResolve (EmitContext ec, Expression right_side)
6793 throw new Exception ();
6796 // Resolve the expression with flow analysis turned off, we'll do the definite
6797 // assignment checks later. This is because we don't know yet what the expression
6798 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6799 // definite assignment check on the actual field and not on the whole struct.
6802 SimpleName original = expr as SimpleName;
6803 Expression expr_resolved = expr.Resolve (ec,
6804 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6805 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6807 if (expr_resolved == null)
6810 if (expr_resolved is Namespace) {
6811 Namespace ns = (Namespace) expr_resolved;
6812 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6814 if ((retval != null) && (args != null))
6815 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6819 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6823 Type expr_type = expr_resolved.Type;
6824 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6825 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6828 if (expr_type == TypeManager.anonymous_method_type){
6829 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6833 Constant c = expr_resolved as Constant;
6834 if (c != null && c.GetValue () == null) {
6835 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6836 "System.NullReferenceException");
6839 Expression member_lookup;
6840 member_lookup = MemberLookup (
6841 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6843 if ((member_lookup == null) && (args != null)) {
6844 member_lookup = MemberLookup (
6845 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6848 if (member_lookup == null) {
6849 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6850 if (ex_method_lookup != null) {
6851 ex_method_lookup.ExtensionExpression = expr_resolved;
6852 return ex_method_lookup.DoResolve (ec);
6855 if (!ec.IsInProbingMode)
6856 Error_MemberLookupFailed (
6857 ec.ContainerType, expr_type, expr_type, Identifier, null,
6858 AllMemberTypes, AllBindingFlags, loc);
6862 TypeExpr texpr = member_lookup as TypeExpr;
6863 if (texpr != null) {
6864 if (!(expr_resolved is TypeExpr) &&
6865 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6866 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6867 Identifier, member_lookup.GetSignatureForError ());
6871 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6872 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6873 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6878 ConstructedType ct = expr_resolved as ConstructedType;
6881 // When looking up a nested type in a generic instance
6882 // via reflection, we always get a generic type definition
6883 // and not a generic instance - so we have to do this here.
6885 // See gtest-172-lib.cs and gtest-172.cs for an example.
6887 ct = new ConstructedType (
6888 member_lookup.Type, ct.TypeArguments, loc);
6890 return ct.ResolveAsTypeStep (ec, false);
6893 return member_lookup;
6896 MemberExpr me = (MemberExpr) member_lookup;
6897 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6898 if (member_lookup == null)
6902 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6904 throw new InternalErrorException ();
6906 return mg.ResolveGeneric (ec, args);
6909 if (original != null && !TypeManager.IsValueType (expr_type)) {
6910 me = member_lookup as MemberExpr;
6911 if (me != null && me.IsInstance) {
6912 LocalVariableReference var = expr_resolved as LocalVariableReference;
6913 if (var != null && !var.VerifyAssigned (ec))
6918 // The following DoResolve/DoResolveLValue will do the definite assignment
6921 if (right_side != null)
6922 return member_lookup.DoResolveLValue (ec, right_side);
6924 return member_lookup.DoResolve (ec);
6927 public override Expression DoResolve (EmitContext ec)
6929 return DoResolve (ec, null);
6932 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6934 return DoResolve (ec, right_side);
6937 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6939 return ResolveNamespaceOrType (ec, silent);
6942 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6944 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6946 if (new_expr == null)
6949 if (new_expr is Namespace) {
6950 Namespace ns = (Namespace) new_expr;
6951 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6953 if ((retval != null) && (args != null))
6954 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6956 if (!silent && retval == null)
6957 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6961 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6962 if (tnew_expr == null)
6965 Type expr_type = tnew_expr.Type;
6967 if (expr_type.IsPointer){
6968 Error (23, "The `.' operator can not be applied to pointer operands (" +
6969 TypeManager.CSharpName (expr_type) + ")");
6973 Expression member_lookup = MemberLookup (
6974 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6975 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6976 if (member_lookup == null) {
6980 member_lookup = MemberLookup(
6981 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6982 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6984 if (member_lookup == null) {
6985 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6986 Identifier, new_expr.GetSignatureForError ());
6988 // TODO: Report.SymbolRelatedToPreviousError
6989 member_lookup.Error_UnexpectedKind (null, "type", loc);
6994 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6999 TypeArguments the_args = args;
7000 if (TypeManager.HasGenericArguments (expr_type)) {
7001 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7003 TypeArguments new_args = new TypeArguments (loc);
7004 foreach (Type decl in decl_args)
7005 new_args.Add (new TypeExpression (decl, loc));
7008 new_args.Add (args);
7010 the_args = new_args;
7013 if (the_args != null) {
7014 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7015 return ctype.ResolveAsTypeStep (rc, false);
7022 public override void Emit (EmitContext ec)
7024 throw new Exception ("Should not happen");
7027 public override string ToString ()
7029 return expr + "." + MemberName.MakeName (Identifier, args);
7032 public override string GetSignatureForError ()
7034 return expr.GetSignatureForError () + "." + Identifier;
7037 protected override void CloneTo (CloneContext clonectx, Expression t)
7039 MemberAccess target = (MemberAccess) t;
7041 target.expr = expr.Clone (clonectx);
7046 /// Implements checked expressions
7048 public class CheckedExpr : Expression {
7050 public Expression Expr;
7052 public CheckedExpr (Expression e, Location l)
7058 public override Expression DoResolve (EmitContext ec)
7060 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7061 Expr = Expr.Resolve (ec);
7066 if (Expr is Constant)
7069 eclass = Expr.eclass;
7074 public override void Emit (EmitContext ec)
7076 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7080 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7082 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7083 Expr.EmitBranchable (ec, target, onTrue);
7086 protected override void CloneTo (CloneContext clonectx, Expression t)
7088 CheckedExpr target = (CheckedExpr) t;
7090 target.Expr = Expr.Clone (clonectx);
7095 /// Implements the unchecked expression
7097 public class UnCheckedExpr : Expression {
7099 public Expression Expr;
7101 public UnCheckedExpr (Expression e, Location l)
7107 public override Expression DoResolve (EmitContext ec)
7109 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7110 Expr = Expr.Resolve (ec);
7115 if (Expr is Constant)
7118 eclass = Expr.eclass;
7123 public override void Emit (EmitContext ec)
7125 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7129 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7131 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7132 Expr.EmitBranchable (ec, target, onTrue);
7135 protected override void CloneTo (CloneContext clonectx, Expression t)
7137 UnCheckedExpr target = (UnCheckedExpr) t;
7139 target.Expr = Expr.Clone (clonectx);
7144 /// An Element Access expression.
7146 /// During semantic analysis these are transformed into
7147 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7149 public class ElementAccess : Expression {
7150 public ArrayList Arguments;
7151 public Expression Expr;
7153 public ElementAccess (Expression e, ArrayList e_list)
7162 Arguments = new ArrayList ();
7163 foreach (Expression tmp in e_list)
7164 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7168 bool CommonResolve (EmitContext ec)
7170 Expr = Expr.Resolve (ec);
7172 if (Arguments == null)
7175 foreach (Argument a in Arguments){
7176 if (!a.Resolve (ec, loc))
7180 return Expr != null;
7183 Expression MakePointerAccess (EmitContext ec, Type t)
7185 if (t == TypeManager.void_ptr_type){
7186 Error (242, "The array index operation is not valid on void pointers");
7189 if (Arguments.Count != 1){
7190 Error (196, "A pointer must be indexed by only one value");
7195 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7198 return new Indirection (p, loc).Resolve (ec);
7201 public override Expression DoResolve (EmitContext ec)
7203 if (!CommonResolve (ec))
7207 // We perform some simple tests, and then to "split" the emit and store
7208 // code we create an instance of a different class, and return that.
7210 // I am experimenting with this pattern.
7214 if (t == TypeManager.array_type){
7215 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7220 return (new ArrayAccess (this, loc)).Resolve (ec);
7222 return MakePointerAccess (ec, t);
7224 FieldExpr fe = Expr as FieldExpr;
7226 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7228 return MakePointerAccess (ec, ff.ElementType);
7231 return (new IndexerAccess (this, loc)).Resolve (ec);
7234 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7236 if (!CommonResolve (ec))
7241 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7244 return MakePointerAccess (ec, t);
7246 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7249 public override void Emit (EmitContext ec)
7251 throw new Exception ("Should never be reached");
7254 protected override void CloneTo (CloneContext clonectx, Expression t)
7256 ElementAccess target = (ElementAccess) t;
7258 target.Expr = Expr.Clone (clonectx);
7259 target.Arguments = new ArrayList (Arguments.Count);
7260 foreach (Argument a in Arguments)
7261 target.Arguments.Add (a.Clone (clonectx));
7266 /// Implements array access
7268 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7270 // Points to our "data" repository
7274 LocalTemporary temp;
7277 public ArrayAccess (ElementAccess ea_data, Location l)
7280 eclass = ExprClass.Variable;
7284 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7286 return DoResolve (ec);
7289 public override Expression DoResolve (EmitContext ec)
7292 ExprClass eclass = ea.Expr.eclass;
7294 // As long as the type is valid
7295 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7296 eclass == ExprClass.Value)) {
7297 ea.Expr.Error_UnexpectedKind ("variable or value");
7302 Type t = ea.Expr.Type;
7303 if (t.GetArrayRank () != ea.Arguments.Count){
7304 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7305 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7309 type = TypeManager.GetElementType (t);
7310 if (type.IsPointer && !ec.InUnsafe){
7311 UnsafeError (ea.Location);
7315 foreach (Argument a in ea.Arguments){
7316 Type argtype = a.Type;
7318 if (argtype == TypeManager.int32_type ||
7319 argtype == TypeManager.uint32_type ||
7320 argtype == TypeManager.int64_type ||
7321 argtype == TypeManager.uint64_type) {
7322 Constant c = a.Expr as Constant;
7323 if (c != null && c.IsNegative) {
7324 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7330 // Mhm. This is strage, because the Argument.Type is not the same as
7331 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7333 // Wonder if I will run into trouble for this.
7335 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7340 eclass = ExprClass.Variable;
7346 /// Emits the right opcode to load an object of Type `t'
7347 /// from an array of T
7349 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7351 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7352 ig.Emit (OpCodes.Ldelem_U1);
7353 else if (type == TypeManager.sbyte_type)
7354 ig.Emit (OpCodes.Ldelem_I1);
7355 else if (type == TypeManager.short_type)
7356 ig.Emit (OpCodes.Ldelem_I2);
7357 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7358 ig.Emit (OpCodes.Ldelem_U2);
7359 else if (type == TypeManager.int32_type)
7360 ig.Emit (OpCodes.Ldelem_I4);
7361 else if (type == TypeManager.uint32_type)
7362 ig.Emit (OpCodes.Ldelem_U4);
7363 else if (type == TypeManager.uint64_type)
7364 ig.Emit (OpCodes.Ldelem_I8);
7365 else if (type == TypeManager.int64_type)
7366 ig.Emit (OpCodes.Ldelem_I8);
7367 else if (type == TypeManager.float_type)
7368 ig.Emit (OpCodes.Ldelem_R4);
7369 else if (type == TypeManager.double_type)
7370 ig.Emit (OpCodes.Ldelem_R8);
7371 else if (type == TypeManager.intptr_type)
7372 ig.Emit (OpCodes.Ldelem_I);
7373 else if (TypeManager.IsEnumType (type)){
7374 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7375 } else if (type.IsValueType){
7376 ig.Emit (OpCodes.Ldelema, type);
7377 ig.Emit (OpCodes.Ldobj, type);
7379 } else if (type.IsGenericParameter) {
7380 ig.Emit (OpCodes.Ldelem, type);
7382 } else if (type.IsPointer)
7383 ig.Emit (OpCodes.Ldelem_I);
7385 ig.Emit (OpCodes.Ldelem_Ref);
7389 /// Returns the right opcode to store an object of Type `t'
7390 /// from an array of T.
7392 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7394 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7395 has_type_arg = false; is_stobj = false;
7396 t = TypeManager.TypeToCoreType (t);
7397 if (TypeManager.IsEnumType (t))
7398 t = TypeManager.EnumToUnderlying (t);
7399 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7400 t == TypeManager.bool_type)
7401 return OpCodes.Stelem_I1;
7402 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7403 t == TypeManager.char_type)
7404 return OpCodes.Stelem_I2;
7405 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7406 return OpCodes.Stelem_I4;
7407 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7408 return OpCodes.Stelem_I8;
7409 else if (t == TypeManager.float_type)
7410 return OpCodes.Stelem_R4;
7411 else if (t == TypeManager.double_type)
7412 return OpCodes.Stelem_R8;
7413 else if (t == TypeManager.intptr_type) {
7414 has_type_arg = true;
7416 return OpCodes.Stobj;
7417 } else if (t.IsValueType) {
7418 has_type_arg = true;
7420 return OpCodes.Stobj;
7422 } else if (t.IsGenericParameter) {
7423 has_type_arg = true;
7424 return OpCodes.Stelem;
7427 } else if (t.IsPointer)
7428 return OpCodes.Stelem_I;
7430 return OpCodes.Stelem_Ref;
7433 MethodInfo FetchGetMethod ()
7435 ModuleBuilder mb = CodeGen.Module.Builder;
7436 int arg_count = ea.Arguments.Count;
7437 Type [] args = new Type [arg_count];
7440 for (int i = 0; i < arg_count; i++){
7441 //args [i++] = a.Type;
7442 args [i] = TypeManager.int32_type;
7445 get = mb.GetArrayMethod (
7446 ea.Expr.Type, "Get",
7447 CallingConventions.HasThis |
7448 CallingConventions.Standard,
7454 MethodInfo FetchAddressMethod ()
7456 ModuleBuilder mb = CodeGen.Module.Builder;
7457 int arg_count = ea.Arguments.Count;
7458 Type [] args = new Type [arg_count];
7462 ret_type = TypeManager.GetReferenceType (type);
7464 for (int i = 0; i < arg_count; i++){
7465 //args [i++] = a.Type;
7466 args [i] = TypeManager.int32_type;
7469 address = mb.GetArrayMethod (
7470 ea.Expr.Type, "Address",
7471 CallingConventions.HasThis |
7472 CallingConventions.Standard,
7479 // Load the array arguments into the stack.
7481 // If we have been requested to cache the values (cached_locations array
7482 // initialized), then load the arguments the first time and store them
7483 // in locals. otherwise load from local variables.
7485 void LoadArrayAndArguments (EmitContext ec)
7487 ILGenerator ig = ec.ig;
7490 foreach (Argument a in ea.Arguments){
7491 Type argtype = a.Expr.Type;
7495 if (argtype == TypeManager.int64_type)
7496 ig.Emit (OpCodes.Conv_Ovf_I);
7497 else if (argtype == TypeManager.uint64_type)
7498 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7502 public void Emit (EmitContext ec, bool leave_copy)
7504 int rank = ea.Expr.Type.GetArrayRank ();
7505 ILGenerator ig = ec.ig;
7508 LoadArrayAndArguments (ec);
7511 EmitLoadOpcode (ig, type);
7515 method = FetchGetMethod ();
7516 ig.Emit (OpCodes.Call, method);
7519 LoadFromPtr (ec.ig, this.type);
7522 ec.ig.Emit (OpCodes.Dup);
7523 temp = new LocalTemporary (this.type);
7528 public override void Emit (EmitContext ec)
7533 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7535 int rank = ea.Expr.Type.GetArrayRank ();
7536 ILGenerator ig = ec.ig;
7537 Type t = source.Type;
7538 prepared = prepare_for_load;
7540 if (prepare_for_load) {
7541 AddressOf (ec, AddressOp.LoadStore);
7542 ec.ig.Emit (OpCodes.Dup);
7545 ec.ig.Emit (OpCodes.Dup);
7546 temp = new LocalTemporary (this.type);
7549 StoreFromPtr (ec.ig, t);
7559 LoadArrayAndArguments (ec);
7562 bool is_stobj, has_type_arg;
7563 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7565 // The stobj opcode used by value types will need
7566 // an address on the stack, not really an array/array
7570 ig.Emit (OpCodes.Ldelema, t);
7574 ec.ig.Emit (OpCodes.Dup);
7575 temp = new LocalTemporary (this.type);
7580 ig.Emit (OpCodes.Stobj, t);
7581 else if (has_type_arg)
7586 ModuleBuilder mb = CodeGen.Module.Builder;
7587 int arg_count = ea.Arguments.Count;
7588 Type [] args = new Type [arg_count + 1];
7593 ec.ig.Emit (OpCodes.Dup);
7594 temp = new LocalTemporary (this.type);
7598 for (int i = 0; i < arg_count; i++){
7599 //args [i++] = a.Type;
7600 args [i] = TypeManager.int32_type;
7603 args [arg_count] = type;
7605 set = mb.GetArrayMethod (
7606 ea.Expr.Type, "Set",
7607 CallingConventions.HasThis |
7608 CallingConventions.Standard,
7609 TypeManager.void_type, args);
7611 ig.Emit (OpCodes.Call, set);
7620 public void AddressOf (EmitContext ec, AddressOp mode)
7622 int rank = ea.Expr.Type.GetArrayRank ();
7623 ILGenerator ig = ec.ig;
7625 LoadArrayAndArguments (ec);
7628 ig.Emit (OpCodes.Ldelema, type);
7630 MethodInfo address = FetchAddressMethod ();
7631 ig.Emit (OpCodes.Call, address);
7635 public void EmitGetLength (EmitContext ec, int dim)
7637 int rank = ea.Expr.Type.GetArrayRank ();
7638 ILGenerator ig = ec.ig;
7642 ig.Emit (OpCodes.Ldlen);
7643 ig.Emit (OpCodes.Conv_I4);
7645 IntLiteral.EmitInt (ig, dim);
7646 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7652 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7653 public readonly ArrayList Properties;
7654 static Indexers empty;
7656 public struct Indexer {
7657 public readonly PropertyInfo PropertyInfo;
7658 public readonly MethodInfo Getter, Setter;
7660 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7662 this.PropertyInfo = property_info;
7670 empty = new Indexers (null);
7673 Indexers (ArrayList array)
7678 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7683 foreach (PropertyInfo property in mi){
7684 MethodInfo get, set;
7686 get = property.GetGetMethod (true);
7687 set = property.GetSetMethod (true);
7688 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7690 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7692 if (get != null || set != null) {
7694 ix = new Indexers (new ArrayList ());
7695 ix.Properties.Add (new Indexer (property, get, set));
7700 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7702 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7704 return TypeManager.MemberLookup (
7705 caller_type, caller_type, lookup_type, MemberTypes.Property,
7706 BindingFlags.Public | BindingFlags.Instance |
7707 BindingFlags.DeclaredOnly, p_name, null);
7710 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7712 Indexers ix = empty;
7715 if (lookup_type.IsGenericParameter) {
7716 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7720 if (gc.HasClassConstraint)
7721 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7723 Type[] ifaces = gc.InterfaceConstraints;
7724 foreach (Type itype in ifaces)
7725 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7731 Type copy = lookup_type;
7732 while (copy != TypeManager.object_type && copy != null){
7733 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7734 copy = copy.BaseType;
7737 if (lookup_type.IsInterface) {
7738 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7739 if (ifaces != null) {
7740 foreach (Type itype in ifaces)
7741 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7750 /// Expressions that represent an indexer call.
7752 public class IndexerAccess : Expression, IAssignMethod {
7754 // Points to our "data" repository
7756 MethodInfo get, set;
7757 ArrayList set_arguments;
7758 bool is_base_indexer;
7760 protected Type indexer_type;
7761 protected Type current_type;
7762 protected Expression instance_expr;
7763 protected ArrayList arguments;
7765 public IndexerAccess (ElementAccess ea, Location loc)
7766 : this (ea.Expr, false, loc)
7768 this.arguments = ea.Arguments;
7771 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7774 this.instance_expr = instance_expr;
7775 this.is_base_indexer = is_base_indexer;
7776 this.eclass = ExprClass.Value;
7780 protected virtual bool CommonResolve (EmitContext ec)
7782 indexer_type = instance_expr.Type;
7783 current_type = ec.ContainerType;
7788 public override Expression DoResolve (EmitContext ec)
7790 if (!CommonResolve (ec))
7794 // Step 1: Query for all `Item' *properties*. Notice
7795 // that the actual methods are pointed from here.
7797 // This is a group of properties, piles of them.
7799 ArrayList AllGetters = null;
7801 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7802 if (ilist.Properties != null) {
7803 AllGetters = new ArrayList(ilist.Properties.Count);
7804 foreach (Indexers.Indexer ix in ilist.Properties) {
7805 if (ix.Getter != null)
7806 AllGetters.Add (ix.Getter);
7810 if (AllGetters == null) {
7811 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7812 TypeManager.CSharpName (indexer_type));
7816 if (AllGetters.Count == 0) {
7817 // FIXME: we cannot simply select first one as the error message is missleading when
7818 // multiple indexers exist
7819 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7820 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7821 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7825 get = (MethodInfo)new MethodGroupExpr (AllGetters, type, loc).OverloadResolve (ec,
7826 arguments, false, loc);
7829 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7834 // Only base will allow this invocation to happen.
7836 if (get.IsAbstract && this is BaseIndexerAccess){
7837 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7841 type = get.ReturnType;
7842 if (type.IsPointer && !ec.InUnsafe){
7847 instance_expr.CheckMarshalByRefAccess ();
7849 eclass = ExprClass.IndexerAccess;
7853 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7855 if (right_side == EmptyExpression.OutAccess) {
7856 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7857 GetSignatureForError ());
7861 // if the indexer returns a value type, and we try to set a field in it
7862 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7863 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7864 GetSignatureForError ());
7868 ArrayList AllSetters = new ArrayList();
7869 if (!CommonResolve (ec))
7872 bool found_any = false, found_any_setters = false;
7874 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7875 if (ilist.Properties != null) {
7877 foreach (Indexers.Indexer ix in ilist.Properties) {
7878 if (ix.Setter != null)
7879 AllSetters.Add (ix.Setter);
7882 if (AllSetters.Count > 0) {
7883 found_any_setters = true;
7884 set_arguments = (ArrayList) arguments.Clone ();
7885 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7886 set = (MethodInfo)(new MethodGroupExpr (AllSetters, type, loc)).OverloadResolve (
7888 set_arguments, false, loc);
7892 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7893 TypeManager.CSharpName (indexer_type));
7897 if (!found_any_setters) {
7898 Error (154, "indexer can not be used in this context, because " +
7899 "it lacks a `set' accessor");
7904 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7909 // Only base will allow this invocation to happen.
7911 if (set.IsAbstract && this is BaseIndexerAccess){
7912 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7917 // Now look for the actual match in the list of indexers to set our "return" type
7919 type = TypeManager.void_type; // default value
7920 foreach (Indexers.Indexer ix in ilist.Properties){
7921 if (ix.Setter == set){
7922 type = ix.PropertyInfo.PropertyType;
7927 instance_expr.CheckMarshalByRefAccess ();
7929 eclass = ExprClass.IndexerAccess;
7933 bool prepared = false;
7934 LocalTemporary temp;
7936 public void Emit (EmitContext ec, bool leave_copy)
7938 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7940 ec.ig.Emit (OpCodes.Dup);
7941 temp = new LocalTemporary (Type);
7947 // source is ignored, because we already have a copy of it from the
7948 // LValue resolution and we have already constructed a pre-cached
7949 // version of the arguments (ea.set_arguments);
7951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7953 prepared = prepare_for_load;
7954 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7959 ec.ig.Emit (OpCodes.Dup);
7960 temp = new LocalTemporary (Type);
7963 } else if (leave_copy) {
7964 temp = new LocalTemporary (Type);
7970 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7979 public override void Emit (EmitContext ec)
7984 public override string GetSignatureForError ()
7986 // FIXME: print the argument list of the indexer
7987 return instance_expr.GetSignatureForError () + ".this[...]";
7990 protected override void CloneTo (CloneContext clonectx, Expression t)
7992 IndexerAccess target = (IndexerAccess) t;
7994 if (arguments != null){
7995 target.arguments = new ArrayList ();
7996 foreach (Argument a in arguments)
7997 target.arguments.Add (a.Clone (clonectx));
7999 if (instance_expr != null)
8000 target.instance_expr = instance_expr.Clone (clonectx);
8005 /// The base operator for method names
8007 public class BaseAccess : Expression {
8008 public readonly string Identifier;
8011 public BaseAccess (string member, Location l)
8013 this.Identifier = member;
8017 public BaseAccess (string member, TypeArguments args, Location l)
8023 public override Expression DoResolve (EmitContext ec)
8025 Expression c = CommonResolve (ec);
8031 // MethodGroups use this opportunity to flag an error on lacking ()
8033 if (!(c is MethodGroupExpr))
8034 return c.Resolve (ec);
8038 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8040 Expression c = CommonResolve (ec);
8046 // MethodGroups use this opportunity to flag an error on lacking ()
8048 if (! (c is MethodGroupExpr))
8049 return c.DoResolveLValue (ec, right_side);
8054 Expression CommonResolve (EmitContext ec)
8056 Expression member_lookup;
8057 Type current_type = ec.ContainerType;
8058 Type base_type = current_type.BaseType;
8061 Error (1511, "Keyword `base' is not available in a static method");
8065 if (ec.IsFieldInitializer){
8066 Error (1512, "Keyword `base' is not available in the current context");
8070 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8071 AllMemberTypes, AllBindingFlags, loc);
8072 if (member_lookup == null) {
8073 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8074 null, AllMemberTypes, AllBindingFlags, loc);
8081 left = new TypeExpression (base_type, loc);
8083 left = ec.GetThis (loc);
8085 MemberExpr me = (MemberExpr) member_lookup;
8087 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8089 if (e is PropertyExpr) {
8090 PropertyExpr pe = (PropertyExpr) e;
8092 } else if (e is EventExpr) {
8093 EventExpr ee = (EventExpr) e;
8097 MethodGroupExpr mg = e as MethodGroupExpr;
8103 return mg.ResolveGeneric (ec, args);
8105 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8113 public override void Emit (EmitContext ec)
8115 throw new Exception ("Should never be called");
8118 protected override void CloneTo (CloneContext clonectx, Expression t)
8120 BaseAccess target = (BaseAccess) t;
8122 target.args = args.Clone ();
8127 /// The base indexer operator
8129 public class BaseIndexerAccess : IndexerAccess {
8130 public BaseIndexerAccess (ArrayList args, Location loc)
8131 : base (null, true, loc)
8133 arguments = new ArrayList ();
8134 foreach (Expression tmp in args)
8135 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8138 protected override bool CommonResolve (EmitContext ec)
8140 instance_expr = ec.GetThis (loc);
8142 current_type = ec.ContainerType.BaseType;
8143 indexer_type = current_type;
8145 foreach (Argument a in arguments){
8146 if (!a.Resolve (ec, loc))
8155 /// This class exists solely to pass the Type around and to be a dummy
8156 /// that can be passed to the conversion functions (this is used by
8157 /// foreach implementation to typecast the object return value from
8158 /// get_Current into the proper type. All code has been generated and
8159 /// we only care about the side effect conversions to be performed
8161 /// This is also now used as a placeholder where a no-action expression
8162 /// is needed (the `New' class).
8164 public class EmptyExpression : Expression {
8165 public static readonly EmptyExpression Null = new EmptyExpression ();
8167 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8168 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8169 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8171 static EmptyExpression temp = new EmptyExpression ();
8172 public static EmptyExpression Grab ()
8174 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8179 public static void Release (EmptyExpression e)
8184 // TODO: should be protected
8185 public EmptyExpression ()
8187 type = TypeManager.object_type;
8188 eclass = ExprClass.Value;
8189 loc = Location.Null;
8192 public EmptyExpression (Type t)
8195 eclass = ExprClass.Value;
8196 loc = Location.Null;
8199 public override Expression DoResolve (EmitContext ec)
8204 public override void Emit (EmitContext ec)
8206 // nothing, as we only exist to not do anything.
8210 // This is just because we might want to reuse this bad boy
8211 // instead of creating gazillions of EmptyExpressions.
8212 // (CanImplicitConversion uses it)
8214 public void SetType (Type t)
8221 // Empty statement expression
8223 public sealed class EmptyExpressionStatement : ExpressionStatement
8225 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8227 private EmptyExpressionStatement ()
8229 type = TypeManager.object_type;
8230 eclass = ExprClass.Value;
8231 loc = Location.Null;
8234 public override void EmitStatement (EmitContext ec)
8239 public override Expression DoResolve (EmitContext ec)
8244 public override void Emit (EmitContext ec)
8250 public class UserCast : Expression {
8254 public UserCast (MethodInfo method, Expression source, Location l)
8256 this.method = method;
8257 this.source = source;
8258 type = method.ReturnType;
8259 eclass = ExprClass.Value;
8263 public Expression Source {
8269 public override Expression DoResolve (EmitContext ec)
8272 // We are born fully resolved
8277 public override void Emit (EmitContext ec)
8279 ILGenerator ig = ec.ig;
8283 if (method is MethodInfo)
8284 ig.Emit (OpCodes.Call, (MethodInfo) method);
8286 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8292 // This class is used to "construct" the type during a typecast
8293 // operation. Since the Type.GetType class in .NET can parse
8294 // the type specification, we just use this to construct the type
8295 // one bit at a time.
8297 public class ComposedCast : TypeExpr {
8301 public ComposedCast (Expression left, string dim)
8302 : this (left, dim, left.Location)
8306 public ComposedCast (Expression left, string dim, Location l)
8314 public Expression RemoveNullable ()
8316 if (dim.EndsWith ("?")) {
8317 dim = dim.Substring (0, dim.Length - 1);
8326 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8328 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8332 Type ltype = lexpr.Type;
8333 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8334 Error_VoidInvalidInTheContext (loc);
8339 if ((dim.Length > 0) && (dim [0] == '?')) {
8340 TypeExpr nullable = new NullableType (left, loc);
8342 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8343 return nullable.ResolveAsTypeTerminal (ec, false);
8347 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8350 if (dim != "" && dim [0] == '[' &&
8351 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8352 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8357 type = TypeManager.GetConstructedType (ltype, dim);
8362 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8364 if (type.IsPointer && !ec.IsInUnsafeScope){
8369 eclass = ExprClass.Type;
8373 public override string Name {
8374 get { return left + dim; }
8377 public override string FullName {
8378 get { return type.FullName; }
8381 public override string GetSignatureForError ()
8383 return left.GetSignatureForError () + dim;
8386 protected override void CloneTo (CloneContext clonectx, Expression t)
8388 ComposedCast target = (ComposedCast) t;
8390 target.left = left.Clone (clonectx);
8394 public class FixedBufferPtr : Expression {
8397 public FixedBufferPtr (Expression array, Type array_type, Location l)
8402 type = TypeManager.GetPointerType (array_type);
8403 eclass = ExprClass.Value;
8406 public override void Emit(EmitContext ec)
8411 public override Expression DoResolve (EmitContext ec)
8414 // We are born fully resolved
8422 // This class is used to represent the address of an array, used
8423 // only by the Fixed statement, this generates "&a [0]" construct
8424 // for fixed (char *pa = a)
8426 public class ArrayPtr : FixedBufferPtr {
8429 public ArrayPtr (Expression array, Type array_type, Location l):
8430 base (array, array_type, l)
8432 this.array_type = array_type;
8435 public override void Emit (EmitContext ec)
8439 ILGenerator ig = ec.ig;
8440 IntLiteral.EmitInt (ig, 0);
8441 ig.Emit (OpCodes.Ldelema, array_type);
8446 // Used by the fixed statement
8448 public class StringPtr : Expression {
8451 public StringPtr (LocalBuilder b, Location l)
8454 eclass = ExprClass.Value;
8455 type = TypeManager.char_ptr_type;
8459 public override Expression DoResolve (EmitContext ec)
8461 // This should never be invoked, we are born in fully
8462 // initialized state.
8467 public override void Emit (EmitContext ec)
8469 ILGenerator ig = ec.ig;
8471 ig.Emit (OpCodes.Ldloc, b);
8472 ig.Emit (OpCodes.Conv_I);
8473 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8474 ig.Emit (OpCodes.Add);
8479 // Implements the `stackalloc' keyword
8481 public class StackAlloc : Expression {
8486 public StackAlloc (Expression type, Expression count, Location l)
8493 public override Expression DoResolve (EmitContext ec)
8495 count = count.Resolve (ec);
8499 if (count.Type != TypeManager.int32_type){
8500 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8505 Constant c = count as Constant;
8506 if (c != null && c.IsNegative) {
8507 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8511 if (ec.InCatch || ec.InFinally) {
8512 Error (255, "Cannot use stackalloc in finally or catch");
8516 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8522 if (!TypeManager.VerifyUnManaged (otype, loc))
8525 type = TypeManager.GetPointerType (otype);
8526 eclass = ExprClass.Value;
8531 public override void Emit (EmitContext ec)
8533 int size = GetTypeSize (otype);
8534 ILGenerator ig = ec.ig;
8537 ig.Emit (OpCodes.Sizeof, otype);
8539 IntConstant.EmitInt (ig, size);
8541 ig.Emit (OpCodes.Mul);
8542 ig.Emit (OpCodes.Localloc);
8545 protected override void CloneTo (CloneContext clonectx, Expression t)
8547 StackAlloc target = (StackAlloc) t;
8548 target.count = count.Clone (clonectx);
8549 target.t = t.Clone (clonectx);
8554 // An object initializer expression
8556 public class ElementInitializer : Expression
8558 Expression initializer;
8559 public readonly string Name;
8561 public ElementInitializer (string name, Expression initializer, Location loc)
8564 this.initializer = initializer;
8568 protected override void CloneTo (CloneContext clonectx, Expression t)
8570 if (initializer == null)
8573 ElementInitializer target = (ElementInitializer) t;
8574 target.initializer = initializer.Clone (clonectx);
8577 public override Expression DoResolve (EmitContext ec)
8579 if (initializer == null)
8580 return EmptyExpressionStatement.Instance;
8582 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8583 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8585 if (element_member == null)
8588 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8590 if (initializer is CollectionOrObjectInitializers) {
8591 Expression previous = ec.CurrentInitializerVariable;
8592 ec.CurrentInitializerVariable = element_member;
8593 initializer = initializer.Resolve (ec);
8594 ec.CurrentInitializerVariable = previous;
8598 return new Assign (element_member, initializer, loc).Resolve (ec);
8601 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8603 MemberInfo member = members [0];
8604 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8605 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8606 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8608 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8609 TypeManager.GetFullNameSignature (member));
8614 public override void Emit (EmitContext ec)
8616 throw new NotSupportedException ("Should not be reached");
8621 // A collection initializer expression
8623 public class CollectionElementInitializer : Expression
8625 public class ElementInitializerArgument : Argument
8627 public ElementInitializerArgument (Expression e)
8633 ArrayList arguments;
8635 public CollectionElementInitializer (Expression argument)
8637 arguments = new ArrayList (1);
8638 arguments.Add (argument);
8639 this.loc = argument.Location;
8642 public CollectionElementInitializer (ArrayList arguments, Location loc)
8644 this.arguments = arguments;
8648 protected override void CloneTo (CloneContext clonectx, Expression t)
8650 CollectionElementInitializer target = (CollectionElementInitializer) t;
8651 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8652 foreach (Expression e in arguments)
8653 t_arguments.Add (e.Clone (clonectx));
8656 public override Expression DoResolve (EmitContext ec)
8658 // TODO: We should call a constructor which takes element counts argument,
8659 // for know types like List<T>, Dictionary<T, U>
8661 for (int i = 0; i < arguments.Count; ++i)
8662 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8664 Expression add_method = new Invocation (
8665 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8668 add_method = add_method.Resolve (ec);
8673 public override void Emit (EmitContext ec)
8675 throw new NotSupportedException ("Should not be reached");
8680 // A block of object or collection initializers
8682 public class CollectionOrObjectInitializers : ExpressionStatement
8684 ArrayList initializers;
8686 public static readonly CollectionOrObjectInitializers Empty =
8687 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8689 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8691 this.initializers = initializers;
8695 public bool IsEmpty {
8697 return initializers.Count == 0;
8701 protected override void CloneTo (CloneContext clonectx, Expression target)
8703 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8705 t.initializers = new ArrayList (initializers.Count);
8706 foreach (Expression e in initializers)
8707 t.initializers.Add (e.Clone (clonectx));
8710 public override Expression DoResolve (EmitContext ec)
8712 bool is_elements_initialization = false;
8713 ArrayList element_names = null;
8714 for (int i = 0; i < initializers.Count; ++i) {
8715 Expression initializer = (Expression) initializers [i];
8716 ElementInitializer element_initializer = initializer as ElementInitializer;
8719 if (element_initializer != null) {
8720 is_elements_initialization = true;
8721 element_names = new ArrayList (initializers.Count);
8722 element_names.Add (element_initializer.Name);
8724 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8725 TypeManager.ienumerable_type)) {
8726 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8727 "object initializer because type `{1}' does not implement `{2}' interface",
8728 ec.CurrentInitializerVariable.GetSignatureForError (),
8729 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8730 TypeManager.CSharpName (TypeManager.ienumerable_type));
8735 if (is_elements_initialization == (element_initializer == null)) {
8736 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8737 is_elements_initialization ? "object initializer" : "collection initializer");
8741 if (is_elements_initialization) {
8742 if (element_names.Contains (element_initializer.Name)) {
8743 Report.Error (1912, element_initializer.Location,
8744 "An object initializer includes more than one member `{0}' initialization",
8745 element_initializer.Name);
8747 element_names.Add (element_initializer.Name);
8752 initializers [i] = initializer.Resolve (ec);
8755 type = typeof (CollectionOrObjectInitializers);
8756 eclass = ExprClass.Variable;
8760 public override void Emit (EmitContext ec)
8765 public override void EmitStatement (EmitContext ec)
8767 foreach (ExpressionStatement e in initializers)
8768 e.EmitStatement (ec);
8773 // New expression with element/object initializers
8775 public class NewInitialize : New
8777 CollectionOrObjectInitializers initializers;
8778 TemporaryVariable type_instance;
8780 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8781 : base (requested_type, arguments, l)
8783 this.initializers = initializers;
8786 protected override void CloneTo (CloneContext clonectx, Expression t)
8788 base.CloneTo (clonectx, t);
8790 NewInitialize target = (NewInitialize) t;
8791 target.initializers = (CollectionOrObjectInitializers)initializers.Clone (clonectx);
8794 public override Expression DoResolve (EmitContext ec)
8796 Expression e = base.DoResolve (ec);
8800 // Empty initializer can be optimized to simple new
8801 if (initializers.IsEmpty)
8804 type_instance = new TemporaryVariable (type, loc);
8805 type_instance = (TemporaryVariable)type_instance.Resolve (ec);
8807 Expression previous = ec.CurrentInitializerVariable;
8808 ec.CurrentInitializerVariable = type_instance;
8809 initializers.Resolve (ec);
8810 ec.CurrentInitializerVariable = previous;
8814 public override void Emit (EmitContext ec)
8818 type_instance.EmitStore (ec);
8819 initializers.Emit (ec);
8820 type_instance.Emit (ec);
8824 public class AnonymousTypeDeclaration : Expression
8826 readonly ArrayList parameters;
8827 readonly TypeContainer parent;
8829 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8831 this.parameters = parameters;
8832 this.parent = parent;
8836 AnonymousTypeClass CreateAnonymousType ()
8838 AnonymousTypeClass type = AnonymousTypeClass.Create (parent, parameters, loc);
8843 type.DefineMembers ();
8847 RootContext.ToplevelTypes.AddAnonymousType (type);
8851 public override Expression DoResolve (EmitContext ec)
8854 ArrayList arguments = new ArrayList (parameters.Count);
8855 TypeExpression [] t_args = new TypeExpression [parameters.Count];
8856 for (int i = 0; i < parameters.Count; ++i) {
8857 Expression e = ((AnonymousTypeParameter)parameters [i]).Resolve (ec);
8863 arguments.Add (new Argument (e));
8864 t_args [i] = new TypeExpression (e.Type, e.Location);
8870 AnonymousTypeClass anonymous_type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8871 if (anonymous_type == null) {
8872 anonymous_type = CreateAnonymousType ();
8873 if (anonymous_type == null)
8877 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8878 new TypeArguments (loc, t_args), loc);
8880 return new New (te, arguments, loc).Resolve (ec);
8883 public override void Emit (EmitContext ec)
8885 throw new InternalErrorException ("Should not be reached");
8889 public class AnonymousTypeParameter : Expression
8891 public readonly string Name;
8892 readonly Expression initializer;
8894 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8898 this.initializer = initializer;
8901 public override bool Equals (object o)
8903 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8904 return other != null && Name == other.Name;
8907 public override int GetHashCode ()
8909 return Name.GetHashCode ();
8912 public override Expression DoResolve (EmitContext ec)
8914 Expression e = initializer.Resolve (ec);
8919 if (type == TypeManager.void_type || type == TypeManager.null_type ||
8920 type == TypeManager.anonymous_method_type || type.IsPointer) {
8921 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8922 Name, e.GetSignatureForError ());
8929 public override void Emit (EmitContext ec)
8931 throw new InternalErrorException ("Should not be reached");