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 EmptyCast.Create (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 EmptyCast.Create (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 EmptyCast.Create (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)
1639 return is_unsigned (t.GetElementType ());
1641 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1642 t == TypeManager.short_type || t == TypeManager.byte_type);
1645 Expression Make32or64 (EmitContext ec, Expression e)
1649 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1650 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1652 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1655 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1658 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1661 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1667 Expression CheckShiftArguments (EmitContext ec)
1669 Expression new_left = Make32or64 (ec, left);
1670 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1671 if (new_left == null || new_right == null) {
1672 Error_OperatorCannotBeApplied ();
1675 type = new_left.Type;
1676 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1678 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1683 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1684 // i.e., not invoke op_Equality.
1686 static bool EqualsNullIsReferenceEquals (Type t)
1688 return t == TypeManager.object_type || t == TypeManager.string_type ||
1689 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1692 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1694 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1695 "Possible unintended reference comparison; to get a value comparison, " +
1696 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1699 static void Warning_Constant_Result (Location loc, bool result, Type type)
1701 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1702 "This operation is undocumented and it is temporary supported for compatibility reasons only",
1703 TypeManager.CSharpName (type), result ? "true" : "false");
1706 Expression ResolveOperator (EmitContext ec)
1709 Type r = right.Type;
1711 if (oper == Operator.Equality || oper == Operator.Inequality){
1712 if (right.Type == TypeManager.null_type){
1713 if (TypeManager.IsGenericParameter (l)){
1714 if (l.BaseType == TypeManager.value_type) {
1715 Error_OperatorCannotBeApplied ();
1719 left = new BoxedCast (left, TypeManager.object_type);
1720 Type = TypeManager.bool_type;
1725 // CSC 2 has this behavior, it allows structs to be compared
1726 // with the null literal *outside* of a generics context and
1727 // inlines that as true or false.
1729 // This is, in my opinion, completely wrong.
1731 if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType){
1732 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1733 return new BoolLiteral (oper == Operator.Inequality, loc);
1737 if (left is NullLiteral){
1738 if (TypeManager.IsGenericParameter (r)){
1739 if (r.BaseType == TypeManager.value_type) {
1740 Error_OperatorCannotBeApplied ();
1744 right = new BoxedCast (right, TypeManager.object_type);
1745 Type = TypeManager.bool_type;
1750 // CSC 2 has this behavior, it allows structs to be compared
1751 // with the null literal *outside* of a generics context and
1752 // inlines that as true or false.
1754 // This is, in my opinion, completely wrong.
1756 if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1757 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1758 return new BoolLiteral (oper == Operator.Inequality, loc);
1763 // Optimize out call to op_Equality in a few cases.
1765 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1766 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1767 Type = TypeManager.bool_type;
1772 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1773 Type = TypeManager.bool_type;
1779 // Delegate equality
1781 MethodGroupExpr mg = null;
1782 Type delegate_type = null;
1783 if (left.eclass == ExprClass.MethodGroup) {
1784 if (!TypeManager.IsDelegateType(r)) {
1785 Error_OperatorCannotBeApplied(Location, OperName(oper),
1786 left.ExprClassName, right.ExprClassName);
1789 mg = (MethodGroupExpr)left;
1791 } else if (right.eclass == ExprClass.MethodGroup) {
1792 if (!TypeManager.IsDelegateType(l)) {
1793 Error_OperatorCannotBeApplied(Location, OperName(oper),
1794 left.ExprClassName, right.ExprClassName);
1797 mg = (MethodGroupExpr)right;
1802 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1806 // Find operator method
1807 string op = oper_names[(int)oper];
1808 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1809 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1811 ArrayList args = new ArrayList(2);
1812 args.Add(new Argument(e, Argument.AType.Expression));
1813 if (delegate_type == l)
1814 args.Insert(0, new Argument(left, Argument.AType.Expression));
1816 args.Add(new Argument(right, Argument.AType.Expression));
1818 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1821 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1822 Error_OperatorCannotBeApplied(Location, OperName(oper),
1823 left.ExprClassName, right.ExprClassName);
1830 // Do not perform operator overload resolution when both sides are
1833 MethodGroupExpr left_operators = null, right_operators = null;
1834 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1836 // Step 1: Perform Operator Overload location
1838 string op = oper_names [(int) oper];
1840 MethodGroupExpr union;
1841 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1843 right_operators = MemberLookup (
1844 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1845 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
1847 union = left_operators;
1849 if (union != null) {
1850 ArrayList args = new ArrayList (2);
1851 args.Add (new Argument (left, Argument.AType.Expression));
1852 args.Add (new Argument (right, Argument.AType.Expression));
1854 union = union.OverloadResolve (ec, args, true, Location.Null);
1856 if (union != null) {
1857 MethodInfo mi = (MethodInfo) union;
1858 return new BinaryMethod (mi.ReturnType, mi, args);
1864 // Step 0: String concatenation (because overloading will get this wrong)
1866 if (oper == Operator.Addition){
1868 // If any of the arguments is a string, cast to string
1871 // Simple constant folding
1872 if (left is StringConstant && right is StringConstant)
1873 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1875 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1877 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1878 Error_OperatorCannotBeApplied ();
1882 // try to fold it in on the left
1883 if (left is StringConcat) {
1886 // We have to test here for not-null, since we can be doubly-resolved
1887 // take care of not appending twice
1890 type = TypeManager.string_type;
1891 ((StringConcat) left).Append (ec, right);
1892 return left.Resolve (ec);
1898 // Otherwise, start a new concat expression
1899 return new StringConcat (ec, loc, left, right).Resolve (ec);
1903 // Transform a + ( - b) into a - b
1905 if (right is Unary){
1906 Unary right_unary = (Unary) right;
1908 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1909 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
1914 if (oper == Operator.Equality || oper == Operator.Inequality){
1915 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1916 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1917 Error_OperatorCannotBeApplied ();
1921 type = TypeManager.bool_type;
1925 if (l.IsPointer || r.IsPointer) {
1926 if (l.IsPointer && r.IsPointer) {
1927 type = TypeManager.bool_type;
1931 if (l.IsPointer && r == TypeManager.null_type) {
1932 right = new EmptyConstantCast (NullPointer.Null, l);
1933 type = TypeManager.bool_type;
1937 if (r.IsPointer && l == TypeManager.null_type) {
1938 left = new EmptyConstantCast (NullPointer.Null, r);
1939 type = TypeManager.bool_type;
1945 if (l.IsGenericParameter && r.IsGenericParameter) {
1946 GenericConstraints l_gc, r_gc;
1948 l_gc = TypeManager.GetTypeParameterConstraints (l);
1949 r_gc = TypeManager.GetTypeParameterConstraints (r);
1951 if ((l_gc == null) || (r_gc == null) ||
1952 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1953 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1954 Error_OperatorCannotBeApplied ();
1962 // operator != (object a, object b)
1963 // operator == (object a, object b)
1965 // For this to be used, both arguments have to be reference-types.
1966 // Read the rationale on the spec (14.9.6)
1968 if (!(l.IsValueType || r.IsValueType)){
1969 type = TypeManager.bool_type;
1975 // Also, a standard conversion must exist from either one
1977 bool left_to_right =
1978 Convert.ImplicitStandardConversionExists (left, r);
1979 bool right_to_left = !left_to_right &&
1980 Convert.ImplicitStandardConversionExists (right, l);
1982 if (!left_to_right && !right_to_left) {
1983 Error_OperatorCannotBeApplied ();
1987 if (left_to_right && left_operators != null &&
1988 Report.WarningLevel >= 2) {
1989 ArrayList args = new ArrayList (2);
1990 args.Add (new Argument (left, Argument.AType.Expression));
1991 args.Add (new Argument (left, Argument.AType.Expression));
1992 if (left_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1993 Warning_UnintendedReferenceComparison (loc, "right", l);
1996 if (right_to_left && right_operators != null &&
1997 Report.WarningLevel >= 2) {
1998 ArrayList args = new ArrayList (2);
1999 args.Add (new Argument (right, Argument.AType.Expression));
2000 args.Add (new Argument (right, Argument.AType.Expression));
2001 if (right_operators.OverloadResolve (ec, args, true, Location.Null) != null)
2002 Warning_UnintendedReferenceComparison (loc, "left", r);
2006 // We are going to have to convert to an object to compare
2008 if (l != TypeManager.object_type)
2009 left = EmptyCast.Create (left, TypeManager.object_type);
2010 if (r != TypeManager.object_type)
2011 right = EmptyCast.Create (right, TypeManager.object_type);
2017 // Only perform numeric promotions on:
2018 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2020 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2021 if (TypeManager.IsDelegateType (l)){
2022 if (((right.eclass == ExprClass.MethodGroup) ||
2023 (r == TypeManager.anonymous_method_type))){
2024 if ((RootContext.Version != LanguageVersion.ISO_1)){
2025 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2033 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2035 ArrayList args = new ArrayList (2);
2037 args = new ArrayList (2);
2038 args.Add (new Argument (left, Argument.AType.Expression));
2039 args.Add (new Argument (right, Argument.AType.Expression));
2041 if (oper == Operator.Addition)
2042 method = TypeManager.delegate_combine_delegate_delegate;
2044 method = TypeManager.delegate_remove_delegate_delegate;
2046 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2047 Error_OperatorCannotBeApplied ();
2051 return new BinaryDelegate (l, method, args);
2056 // Pointer arithmetic:
2058 // T* operator + (T* x, int y);
2059 // T* operator + (T* x, uint y);
2060 // T* operator + (T* x, long y);
2061 // T* operator + (T* x, ulong y);
2063 // T* operator + (int y, T* x);
2064 // T* operator + (uint y, T *x);
2065 // T* operator + (long y, T *x);
2066 // T* operator + (ulong y, T *x);
2068 // T* operator - (T* x, int y);
2069 // T* operator - (T* x, uint y);
2070 // T* operator - (T* x, long y);
2071 // T* operator - (T* x, ulong y);
2073 // long operator - (T* x, T *y)
2076 if (r.IsPointer && oper == Operator.Subtraction){
2078 return new PointerArithmetic (
2079 false, left, right, TypeManager.int64_type,
2082 Expression t = Make32or64 (ec, right);
2084 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2086 } else if (r.IsPointer && oper == Operator.Addition){
2087 Expression t = Make32or64 (ec, left);
2089 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2094 // Enumeration operators
2096 bool lie = TypeManager.IsEnumType (l);
2097 bool rie = TypeManager.IsEnumType (r);
2101 // U operator - (E e, E f)
2103 if (oper == Operator.Subtraction){
2105 type = TypeManager.EnumToUnderlying (l);
2108 Error_OperatorCannotBeApplied ();
2114 // operator + (E e, U x)
2115 // operator - (E e, U x)
2117 if (oper == Operator.Addition || oper == Operator.Subtraction){
2118 Type enum_type = lie ? l : r;
2119 Type other_type = lie ? r : l;
2120 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2122 if (underlying_type != other_type){
2123 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2133 Error_OperatorCannotBeApplied ();
2142 temp = Convert.ImplicitConversion (ec, right, l, loc);
2146 Error_OperatorCannotBeApplied ();
2150 temp = Convert.ImplicitConversion (ec, left, r, loc);
2155 Error_OperatorCannotBeApplied ();
2160 if (oper == Operator.Equality || oper == Operator.Inequality ||
2161 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2162 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2163 if (left.Type != right.Type){
2164 Error_OperatorCannotBeApplied ();
2167 type = TypeManager.bool_type;
2171 if (oper == Operator.BitwiseAnd ||
2172 oper == Operator.BitwiseOr ||
2173 oper == Operator.ExclusiveOr){
2174 if (left.Type != right.Type){
2175 Error_OperatorCannotBeApplied ();
2181 Error_OperatorCannotBeApplied ();
2185 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2186 return CheckShiftArguments (ec);
2188 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2189 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2190 type = TypeManager.bool_type;
2194 Expression left_operators_e = l == TypeManager.bool_type ?
2195 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2196 Expression right_operators_e = r == TypeManager.bool_type ?
2197 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2199 if (left_operators_e != null && right_operators_e != null) {
2200 left = left_operators_e;
2201 right = right_operators_e;
2202 type = TypeManager.bool_type;
2206 Expression e = new ConditionalLogicalOperator (
2207 oper == Operator.LogicalAnd, left, right, l, loc);
2208 return e.Resolve (ec);
2211 Expression orig_left = left;
2212 Expression orig_right = right;
2215 // operator & (bool x, bool y)
2216 // operator | (bool x, bool y)
2217 // operator ^ (bool x, bool y)
2219 if (oper == Operator.BitwiseAnd ||
2220 oper == Operator.BitwiseOr ||
2221 oper == Operator.ExclusiveOr) {
2222 if (OverloadResolve_PredefinedIntegral (ec)) {
2223 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2224 Error_OperatorAmbiguous (loc, oper, l, r);
2228 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2229 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2230 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2231 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2232 TypeManager.CSharpName (r));
2235 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2236 Error_OperatorCannotBeApplied ();
2243 // Pointer comparison
2245 if (l.IsPointer && r.IsPointer){
2246 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2247 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2248 type = TypeManager.bool_type;
2253 if (OverloadResolve_PredefinedIntegral (ec)) {
2254 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2255 Error_OperatorAmbiguous (loc, oper, l, r);
2258 } else if (OverloadResolve_PredefinedFloating (ec)) {
2259 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2260 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2261 Error_OperatorAmbiguous (loc, oper, l, r);
2264 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2265 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2266 Error_OperatorAmbiguous (loc, oper, l, r);
2269 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2270 Error_OperatorCannotBeApplied ();
2274 if (oper == Operator.Equality ||
2275 oper == Operator.Inequality ||
2276 oper == Operator.LessThanOrEqual ||
2277 oper == Operator.LessThan ||
2278 oper == Operator.GreaterThanOrEqual ||
2279 oper == Operator.GreaterThan)
2280 type = TypeManager.bool_type;
2285 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2287 if (r == TypeManager.string_type)
2289 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2290 ec.ContainerType, lookup, oper_names [(int) oper],
2291 MemberTypes.Method, AllBindingFlags, loc);
2292 ArrayList args = new ArrayList (2);
2293 args.Add (new Argument (left, Argument.AType.Expression));
2294 args.Add (new Argument (right, Argument.AType.Expression));
2295 ops = ops.OverloadResolve (ec, args, true, Location.Null);
2296 return new BinaryMethod (type, (MethodInfo)ops, args);
2302 Constant EnumLiftUp (Constant left, Constant right)
2305 case Operator.BitwiseOr:
2306 case Operator.BitwiseAnd:
2307 case Operator.ExclusiveOr:
2308 case Operator.Equality:
2309 case Operator.Inequality:
2310 case Operator.LessThan:
2311 case Operator.LessThanOrEqual:
2312 case Operator.GreaterThan:
2313 case Operator.GreaterThanOrEqual:
2314 if (left is EnumConstant)
2317 if (left.IsZeroInteger)
2318 return new EnumConstant (left, right.Type);
2322 case Operator.Addition:
2323 case Operator.Subtraction:
2326 case Operator.Multiply:
2327 case Operator.Division:
2328 case Operator.Modulus:
2329 case Operator.LeftShift:
2330 case Operator.RightShift:
2331 if (right is EnumConstant || left is EnumConstant)
2335 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2339 public override Expression DoResolve (EmitContext ec)
2344 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2345 left = ((ParenthesizedExpression) left).Expr;
2346 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2350 if (left.eclass == ExprClass.Type) {
2351 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2355 left = left.Resolve (ec);
2360 Constant lc = left as Constant;
2361 if (lc != null && lc.Type == TypeManager.bool_type &&
2362 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2363 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2365 // TODO: make a sense to resolve unreachable expression as we do for statement
2366 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2370 right = right.Resolve (ec);
2374 eclass = ExprClass.Value;
2375 Constant rc = right as Constant;
2377 // The conversion rules are ignored in enum context but why
2378 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2379 left = lc = EnumLiftUp (lc, rc);
2383 right = rc = EnumLiftUp (rc, lc);
2388 if (oper == Operator.BitwiseAnd) {
2389 if (rc != null && rc.IsZeroInteger) {
2390 return lc is EnumConstant ?
2391 new EnumConstant (rc, lc.Type):
2395 if (lc != null && lc.IsZeroInteger) {
2396 return rc is EnumConstant ?
2397 new EnumConstant (lc, rc.Type):
2401 else if (oper == Operator.BitwiseOr) {
2402 if (lc is EnumConstant &&
2403 rc != null && rc.IsZeroInteger)
2405 if (rc is EnumConstant &&
2406 lc != null && lc.IsZeroInteger)
2408 } else if (oper == Operator.LogicalAnd) {
2409 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2411 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2415 if (rc != null && lc != null){
2416 int prev_e = Report.Errors;
2417 Expression e = ConstantFold.BinaryFold (
2418 ec, oper, lc, rc, loc);
2419 if (e != null || Report.Errors != prev_e)
2424 if ((left is NullLiteral || left.Type.IsValueType) &&
2425 (right is NullLiteral || right.Type.IsValueType) &&
2426 !(left is NullLiteral && right is NullLiteral) &&
2427 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2428 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2431 // Comparison warnings
2432 if (oper == Operator.Equality || oper == Operator.Inequality ||
2433 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2434 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2435 if (left.Equals (right)) {
2436 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2438 CheckUselessComparison (lc, right.Type);
2439 CheckUselessComparison (rc, left.Type);
2442 return ResolveOperator (ec);
2445 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2450 private void CheckUselessComparison (Constant c, Type type)
2452 if (c == null || !IsTypeIntegral (type)
2453 || c is StringConstant
2454 || c is BoolConstant
2455 || c is FloatConstant
2456 || c is DoubleConstant
2457 || c is DecimalConstant
2463 if (c is ULongConstant) {
2464 ulong uvalue = ((ULongConstant) c).Value;
2465 if (uvalue > long.MaxValue) {
2466 if (type == TypeManager.byte_type ||
2467 type == TypeManager.sbyte_type ||
2468 type == TypeManager.short_type ||
2469 type == TypeManager.ushort_type ||
2470 type == TypeManager.int32_type ||
2471 type == TypeManager.uint32_type ||
2472 type == TypeManager.int64_type ||
2473 type == TypeManager.char_type)
2474 WarnUselessComparison (type);
2477 value = (long) uvalue;
2479 else if (c is ByteConstant)
2480 value = ((ByteConstant) c).Value;
2481 else if (c is SByteConstant)
2482 value = ((SByteConstant) c).Value;
2483 else if (c is ShortConstant)
2484 value = ((ShortConstant) c).Value;
2485 else if (c is UShortConstant)
2486 value = ((UShortConstant) c).Value;
2487 else if (c is IntConstant)
2488 value = ((IntConstant) c).Value;
2489 else if (c is UIntConstant)
2490 value = ((UIntConstant) c).Value;
2491 else if (c is LongConstant)
2492 value = ((LongConstant) c).Value;
2493 else if (c is CharConstant)
2494 value = ((CharConstant)c).Value;
2499 if (IsValueOutOfRange (value, type))
2500 WarnUselessComparison (type);
2503 private bool IsValueOutOfRange (long value, Type type)
2505 if (IsTypeUnsigned (type) && value < 0)
2507 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2508 type == TypeManager.byte_type && value >= 0x100 ||
2509 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2510 type == TypeManager.ushort_type && value >= 0x10000 ||
2511 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2512 type == TypeManager.uint32_type && value >= 0x100000000;
2515 private static bool IsTypeIntegral (Type type)
2517 return type == TypeManager.uint64_type ||
2518 type == TypeManager.int64_type ||
2519 type == TypeManager.uint32_type ||
2520 type == TypeManager.int32_type ||
2521 type == TypeManager.ushort_type ||
2522 type == TypeManager.short_type ||
2523 type == TypeManager.sbyte_type ||
2524 type == TypeManager.byte_type ||
2525 type == TypeManager.char_type;
2528 private static bool IsTypeUnsigned (Type type)
2530 return type == TypeManager.uint64_type ||
2531 type == TypeManager.uint32_type ||
2532 type == TypeManager.ushort_type ||
2533 type == TypeManager.byte_type ||
2534 type == TypeManager.char_type;
2537 private void WarnUselessComparison (Type type)
2539 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}'",
2540 TypeManager.CSharpName (type));
2544 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2545 /// context of a conditional bool expression. This function will return
2546 /// false if it is was possible to use EmitBranchable, or true if it was.
2548 /// The expression's code is generated, and we will generate a branch to `target'
2549 /// if the resulting expression value is equal to isTrue
2551 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2553 ILGenerator ig = ec.ig;
2556 // This is more complicated than it looks, but its just to avoid
2557 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2558 // but on top of that we want for == and != to use a special path
2559 // if we are comparing against null
2561 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2562 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2565 // put the constant on the rhs, for simplicity
2567 if (left is Constant) {
2568 Expression swap = right;
2573 if (((Constant) right).IsZeroInteger) {
2576 ig.Emit (OpCodes.Brtrue, target);
2578 ig.Emit (OpCodes.Brfalse, target);
2581 } else if (right is BoolConstant) {
2583 if (my_on_true != ((BoolConstant) right).Value)
2584 ig.Emit (OpCodes.Brtrue, target);
2586 ig.Emit (OpCodes.Brfalse, target);
2591 } else if (oper == Operator.LogicalAnd) {
2594 Label tests_end = ig.DefineLabel ();
2596 left.EmitBranchable (ec, tests_end, false);
2597 right.EmitBranchable (ec, target, true);
2598 ig.MarkLabel (tests_end);
2601 // This optimizes code like this
2602 // if (true && i > 4)
2604 if (!(left is Constant))
2605 left.EmitBranchable (ec, target, false);
2607 if (!(right is Constant))
2608 right.EmitBranchable (ec, target, false);
2613 } else if (oper == Operator.LogicalOr){
2615 left.EmitBranchable (ec, target, true);
2616 right.EmitBranchable (ec, target, true);
2619 Label tests_end = ig.DefineLabel ();
2620 left.EmitBranchable (ec, tests_end, true);
2621 right.EmitBranchable (ec, target, false);
2622 ig.MarkLabel (tests_end);
2627 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2628 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2629 oper == Operator.Equality || oper == Operator.Inequality)) {
2630 base.EmitBranchable (ec, target, onTrue);
2638 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2641 case Operator.Equality:
2643 ig.Emit (OpCodes.Beq, target);
2645 ig.Emit (OpCodes.Bne_Un, target);
2648 case Operator.Inequality:
2650 ig.Emit (OpCodes.Bne_Un, target);
2652 ig.Emit (OpCodes.Beq, target);
2655 case Operator.LessThan:
2658 ig.Emit (OpCodes.Blt_Un, target);
2660 ig.Emit (OpCodes.Blt, target);
2663 ig.Emit (OpCodes.Bge_Un, target);
2665 ig.Emit (OpCodes.Bge, target);
2668 case Operator.GreaterThan:
2671 ig.Emit (OpCodes.Bgt_Un, target);
2673 ig.Emit (OpCodes.Bgt, target);
2676 ig.Emit (OpCodes.Ble_Un, target);
2678 ig.Emit (OpCodes.Ble, target);
2681 case Operator.LessThanOrEqual:
2684 ig.Emit (OpCodes.Ble_Un, target);
2686 ig.Emit (OpCodes.Ble, target);
2689 ig.Emit (OpCodes.Bgt_Un, target);
2691 ig.Emit (OpCodes.Bgt, target);
2695 case Operator.GreaterThanOrEqual:
2698 ig.Emit (OpCodes.Bge_Un, target);
2700 ig.Emit (OpCodes.Bge, target);
2703 ig.Emit (OpCodes.Blt_Un, target);
2705 ig.Emit (OpCodes.Blt, target);
2708 Console.WriteLine (oper);
2709 throw new Exception ("what is THAT");
2713 public override void Emit (EmitContext ec)
2715 ILGenerator ig = ec.ig;
2720 // Handle short-circuit operators differently
2723 if (oper == Operator.LogicalAnd) {
2724 Label load_zero = ig.DefineLabel ();
2725 Label end = ig.DefineLabel ();
2727 left.EmitBranchable (ec, load_zero, false);
2729 ig.Emit (OpCodes.Br, end);
2731 ig.MarkLabel (load_zero);
2732 ig.Emit (OpCodes.Ldc_I4_0);
2735 } else if (oper == Operator.LogicalOr) {
2736 Label load_one = ig.DefineLabel ();
2737 Label end = ig.DefineLabel ();
2739 left.EmitBranchable (ec, load_one, true);
2741 ig.Emit (OpCodes.Br, end);
2743 ig.MarkLabel (load_one);
2744 ig.Emit (OpCodes.Ldc_I4_1);
2752 bool isUnsigned = is_unsigned (left.Type);
2755 case Operator.Multiply:
2757 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2758 opcode = OpCodes.Mul_Ovf;
2759 else if (isUnsigned)
2760 opcode = OpCodes.Mul_Ovf_Un;
2762 opcode = OpCodes.Mul;
2764 opcode = OpCodes.Mul;
2768 case Operator.Division:
2770 opcode = OpCodes.Div_Un;
2772 opcode = OpCodes.Div;
2775 case Operator.Modulus:
2777 opcode = OpCodes.Rem_Un;
2779 opcode = OpCodes.Rem;
2782 case Operator.Addition:
2784 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2785 opcode = OpCodes.Add_Ovf;
2786 else if (isUnsigned)
2787 opcode = OpCodes.Add_Ovf_Un;
2789 opcode = OpCodes.Add;
2791 opcode = OpCodes.Add;
2794 case Operator.Subtraction:
2796 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2797 opcode = OpCodes.Sub_Ovf;
2798 else if (isUnsigned)
2799 opcode = OpCodes.Sub_Ovf_Un;
2801 opcode = OpCodes.Sub;
2803 opcode = OpCodes.Sub;
2806 case Operator.RightShift:
2808 opcode = OpCodes.Shr_Un;
2810 opcode = OpCodes.Shr;
2813 case Operator.LeftShift:
2814 opcode = OpCodes.Shl;
2817 case Operator.Equality:
2818 opcode = OpCodes.Ceq;
2821 case Operator.Inequality:
2822 ig.Emit (OpCodes.Ceq);
2823 ig.Emit (OpCodes.Ldc_I4_0);
2825 opcode = OpCodes.Ceq;
2828 case Operator.LessThan:
2830 opcode = OpCodes.Clt_Un;
2832 opcode = OpCodes.Clt;
2835 case Operator.GreaterThan:
2837 opcode = OpCodes.Cgt_Un;
2839 opcode = OpCodes.Cgt;
2842 case Operator.LessThanOrEqual:
2843 Type lt = left.Type;
2845 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2846 ig.Emit (OpCodes.Cgt_Un);
2848 ig.Emit (OpCodes.Cgt);
2849 ig.Emit (OpCodes.Ldc_I4_0);
2851 opcode = OpCodes.Ceq;
2854 case Operator.GreaterThanOrEqual:
2855 Type le = left.Type;
2857 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2858 ig.Emit (OpCodes.Clt_Un);
2860 ig.Emit (OpCodes.Clt);
2862 ig.Emit (OpCodes.Ldc_I4_0);
2864 opcode = OpCodes.Ceq;
2867 case Operator.BitwiseOr:
2868 opcode = OpCodes.Or;
2871 case Operator.BitwiseAnd:
2872 opcode = OpCodes.And;
2875 case Operator.ExclusiveOr:
2876 opcode = OpCodes.Xor;
2880 throw new Exception ("This should not happen: Operator = "
2881 + oper.ToString ());
2887 protected override void CloneTo (CloneContext clonectx, Expression t)
2889 Binary target = (Binary) t;
2891 target.left = left.Clone (clonectx);
2892 target.right = right.Clone (clonectx);
2897 // Object created by Binary when the binary operator uses an method instead of being
2898 // a binary operation that maps to a CIL binary operation.
2900 public class BinaryMethod : Expression {
2901 public MethodBase method;
2902 public ArrayList Arguments;
2904 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2909 eclass = ExprClass.Value;
2912 public override Expression DoResolve (EmitContext ec)
2917 public override void Emit (EmitContext ec)
2919 ILGenerator ig = ec.ig;
2921 if (Arguments != null)
2922 Invocation.EmitArguments (ec, method, Arguments, false, null);
2924 if (method is MethodInfo)
2925 ig.Emit (OpCodes.Call, (MethodInfo) method);
2927 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2932 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2933 // b, c, d... may be strings or objects.
2935 public class StringConcat : Expression {
2937 bool invalid = false;
2938 bool emit_conv_done = false;
2940 // Are we also concating objects?
2942 bool is_strings_only = true;
2944 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2947 type = TypeManager.string_type;
2948 eclass = ExprClass.Value;
2950 operands = new ArrayList (2);
2955 public override Expression DoResolve (EmitContext ec)
2963 public void Append (EmitContext ec, Expression operand)
2968 StringConstant sc = operand as StringConstant;
2970 // TODO: it will be better to do this silently as an optimalization
2972 // string s = "" + i;
2973 // because this code has poor performace
2974 // if (sc.Value.Length == 0)
2975 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2977 if (operands.Count != 0) {
2978 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2979 if (last_operand != null) {
2980 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2988 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
2990 StringConcat concat_oper = operand as StringConcat;
2991 if (concat_oper != null) {
2992 operands.AddRange (concat_oper.operands);
2997 // Conversion to object
2999 if (operand.Type != TypeManager.string_type) {
3000 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3003 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3009 operands.Add (operand);
3012 public override void Emit (EmitContext ec)
3014 MethodInfo concat_method = null;
3017 // Do conversion to arguments; check for strings only
3020 // This can get called multiple times, so we have to deal with that.
3021 if (!emit_conv_done) {
3022 emit_conv_done = true;
3023 for (int i = 0; i < operands.Count; i ++) {
3024 Expression e = (Expression) operands [i];
3025 is_strings_only &= e.Type == TypeManager.string_type;
3028 for (int i = 0; i < operands.Count; i ++) {
3029 Expression e = (Expression) operands [i];
3031 if (! is_strings_only && e.Type == TypeManager.string_type) {
3032 // need to make sure this is an object, because the EmitParams
3033 // method might look at the type of this expression, see it is a
3034 // string and emit a string [] when we want an object [];
3036 e = EmptyCast.Create (e, TypeManager.object_type);
3038 operands [i] = new Argument (e, Argument.AType.Expression);
3043 // Find the right method
3045 switch (operands.Count) {
3048 // This should not be possible, because simple constant folding
3049 // is taken care of in the Binary code.
3051 throw new Exception ("how did you get here?");
3054 concat_method = is_strings_only ?
3055 TypeManager.string_concat_string_string :
3056 TypeManager.string_concat_object_object ;
3059 concat_method = is_strings_only ?
3060 TypeManager.string_concat_string_string_string :
3061 TypeManager.string_concat_object_object_object ;
3065 // There is not a 4 param overlaod for object (the one that there is
3066 // is actually a varargs methods, and is only in corlib because it was
3067 // introduced there before.).
3069 if (!is_strings_only)
3072 concat_method = TypeManager.string_concat_string_string_string_string;
3075 concat_method = is_strings_only ?
3076 TypeManager.string_concat_string_dot_dot_dot :
3077 TypeManager.string_concat_object_dot_dot_dot ;
3081 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3082 ec.ig.Emit (OpCodes.Call, concat_method);
3087 // Object created with +/= on delegates
3089 public class BinaryDelegate : Expression {
3093 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3098 eclass = ExprClass.Value;
3101 public override Expression DoResolve (EmitContext ec)
3106 public override void Emit (EmitContext ec)
3108 ILGenerator ig = ec.ig;
3110 Invocation.EmitArguments (ec, method, args, false, null);
3112 ig.Emit (OpCodes.Call, (MethodInfo) method);
3113 ig.Emit (OpCodes.Castclass, type);
3116 public Expression Right {
3118 Argument arg = (Argument) args [1];
3123 public bool IsAddition {
3125 return method == TypeManager.delegate_combine_delegate_delegate;
3131 // User-defined conditional logical operator
3132 public class ConditionalLogicalOperator : Expression {
3133 Expression left, right;
3136 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3139 eclass = ExprClass.Value;
3143 this.is_and = is_and;
3146 protected void Error19 ()
3148 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3151 protected void Error218 ()
3153 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3154 "declarations of operator true and operator false");
3157 Expression op_true, op_false, op;
3158 LocalTemporary left_temp;
3160 public override Expression DoResolve (EmitContext ec)
3162 MethodGroupExpr operator_group;
3164 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3165 if (operator_group == null) {
3170 left_temp = new LocalTemporary (type);
3172 ArrayList arguments = new ArrayList (2);
3173 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3174 arguments.Add (new Argument (right, Argument.AType.Expression));
3175 operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3176 if (operator_group == null) {
3181 MethodInfo method = (MethodInfo)operator_group;
3182 if (method.ReturnType != type) {
3183 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3184 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3188 op = new StaticCallExpr (method, arguments, loc);
3190 op_true = GetOperatorTrue (ec, left_temp, loc);
3191 op_false = GetOperatorFalse (ec, left_temp, loc);
3192 if ((op_true == null) || (op_false == null)) {
3200 public override void Emit (EmitContext ec)
3202 ILGenerator ig = ec.ig;
3203 Label false_target = ig.DefineLabel ();
3204 Label end_target = ig.DefineLabel ();
3207 left_temp.Store (ec);
3209 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3210 left_temp.Emit (ec);
3211 ig.Emit (OpCodes.Br, end_target);
3212 ig.MarkLabel (false_target);
3214 ig.MarkLabel (end_target);
3216 // We release 'left_temp' here since 'op' may refer to it too
3217 left_temp.Release (ec);
3221 public class PointerArithmetic : Expression {
3222 Expression left, right;
3226 // We assume that `l' is always a pointer
3228 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3234 is_add = is_addition;
3237 public override Expression DoResolve (EmitContext ec)
3239 eclass = ExprClass.Variable;
3241 if (left.Type == TypeManager.void_ptr_type) {
3242 Error (242, "The operation in question is undefined on void pointers");
3249 public override void Emit (EmitContext ec)
3251 Type op_type = left.Type;
3252 ILGenerator ig = ec.ig;
3254 // It must be either array or fixed buffer
3255 Type element = TypeManager.HasElementType (op_type) ?
3256 element = TypeManager.GetElementType (op_type) :
3257 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3259 int size = GetTypeSize (element);
3260 Type rtype = right.Type;
3262 if (rtype.IsPointer){
3264 // handle (pointer - pointer)
3268 ig.Emit (OpCodes.Sub);
3272 ig.Emit (OpCodes.Sizeof, element);
3274 IntLiteral.EmitInt (ig, size);
3275 ig.Emit (OpCodes.Div);
3277 ig.Emit (OpCodes.Conv_I8);
3280 // handle + and - on (pointer op int)
3283 ig.Emit (OpCodes.Conv_I);
3285 Constant right_const = right as Constant;
3286 if (right_const != null && size != 0) {
3287 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3295 ig.Emit (OpCodes.Sizeof, element);
3297 IntLiteral.EmitInt (ig, size);
3298 if (rtype == TypeManager.int64_type)
3299 ig.Emit (OpCodes.Conv_I8);
3300 else if (rtype == TypeManager.uint64_type)
3301 ig.Emit (OpCodes.Conv_U8);
3302 ig.Emit (OpCodes.Mul);
3306 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3307 ig.Emit (OpCodes.Conv_I);
3310 ig.Emit (OpCodes.Add);
3312 ig.Emit (OpCodes.Sub);
3318 /// Implements the ternary conditional operator (?:)
3320 public class Conditional : Expression {
3321 Expression expr, trueExpr, falseExpr;
3323 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3326 this.trueExpr = trueExpr;
3327 this.falseExpr = falseExpr;
3328 this.loc = expr.Location;
3331 public Expression Expr {
3337 public Expression TrueExpr {
3343 public Expression FalseExpr {
3349 public override Expression DoResolve (EmitContext ec)
3351 expr = expr.Resolve (ec);
3357 if (TypeManager.IsNullableValueType (expr.Type))
3358 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3361 if (expr.Type != TypeManager.bool_type){
3362 expr = Expression.ResolveBoolean (
3369 Assign ass = expr as Assign;
3370 if (ass != null && ass.Source is Constant) {
3371 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3374 trueExpr = trueExpr.Resolve (ec);
3375 falseExpr = falseExpr.Resolve (ec);
3377 if (trueExpr == null || falseExpr == null)
3380 eclass = ExprClass.Value;
3381 if (trueExpr.Type == falseExpr.Type) {
3382 type = trueExpr.Type;
3383 if (type == TypeManager.null_type) {
3384 // TODO: probably will have to implement ConditionalConstant
3385 // to call method without return constant as well
3386 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3391 Type true_type = trueExpr.Type;
3392 Type false_type = falseExpr.Type;
3395 // First, if an implicit conversion exists from trueExpr
3396 // to falseExpr, then the result type is of type falseExpr.Type
3398 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3401 // Check if both can convert implicitl to each other's type
3403 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3405 "Can not compute type of conditional expression " +
3406 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3407 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3408 "' convert implicitly to each other");
3413 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3417 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3418 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3423 // Dead code optimalization
3424 if (expr is BoolConstant){
3425 BoolConstant bc = (BoolConstant) expr;
3427 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3428 return bc.Value ? trueExpr : falseExpr;
3434 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3439 public override void Emit (EmitContext ec)
3441 ILGenerator ig = ec.ig;
3442 Label false_target = ig.DefineLabel ();
3443 Label end_target = ig.DefineLabel ();
3445 expr.EmitBranchable (ec, false_target, false);
3447 ig.Emit (OpCodes.Br, end_target);
3448 ig.MarkLabel (false_target);
3449 falseExpr.Emit (ec);
3450 ig.MarkLabel (end_target);
3453 protected override void CloneTo (CloneContext clonectx, Expression t)
3455 Conditional target = (Conditional) t;
3457 target.expr = expr.Clone (clonectx);
3458 target.trueExpr = trueExpr.Clone (clonectx);
3459 target.falseExpr = falseExpr.Clone (clonectx);
3463 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3465 LocalTemporary temp;
3467 public abstract Variable Variable {
3471 public abstract bool IsRef {
3475 public override void Emit (EmitContext ec)
3481 // This method is used by parameters that are references, that are
3482 // being passed as references: we only want to pass the pointer (that
3483 // is already stored in the parameter, not the address of the pointer,
3484 // and not the value of the variable).
3486 public void EmitLoad (EmitContext ec)
3488 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3490 Variable.EmitInstance (ec);
3494 public void Emit (EmitContext ec, bool leave_copy)
3496 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3502 ec.ig.Emit (OpCodes.Dup);
3505 // If we are a reference, we loaded on the stack a pointer
3506 // Now lets load the real value
3508 LoadFromPtr (ec.ig, type);
3512 ec.ig.Emit (OpCodes.Dup);
3514 if (IsRef || Variable.NeedsTemporary) {
3515 temp = new LocalTemporary (Type);
3521 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3522 bool prepare_for_load)
3524 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3527 ILGenerator ig = ec.ig;
3528 prepared = prepare_for_load;
3530 Variable.EmitInstance (ec);
3531 if (prepare_for_load) {
3532 if (Variable.HasInstance)
3533 ig.Emit (OpCodes.Dup);
3542 ig.Emit (OpCodes.Dup);
3543 if (IsRef || Variable.NeedsTemporary) {
3544 temp = new LocalTemporary (Type);
3550 StoreFromPtr (ig, type);
3552 Variable.EmitAssign (ec);
3560 public void AddressOf (EmitContext ec, AddressOp mode)
3562 Variable.EmitInstance (ec);
3563 Variable.EmitAddressOf (ec);
3570 public class LocalVariableReference : VariableReference, IVariable {
3571 public readonly string Name;
3573 public LocalInfo local_info;
3577 public LocalVariableReference (Block block, string name, Location l)
3582 eclass = ExprClass.Variable;
3586 // Setting `is_readonly' to false will allow you to create a writable
3587 // reference to a read-only variable. This is used by foreach and using.
3589 public LocalVariableReference (Block block, string name, Location l,
3590 LocalInfo local_info, bool is_readonly)
3591 : this (block, name, l)
3593 this.local_info = local_info;
3594 this.is_readonly = is_readonly;
3597 public VariableInfo VariableInfo {
3598 get { return local_info.VariableInfo; }
3601 public override bool IsRef {
3602 get { return false; }
3605 public bool IsReadOnly {
3606 get { return is_readonly; }
3609 public bool VerifyAssigned (EmitContext ec)
3611 VariableInfo variable_info = local_info.VariableInfo;
3612 return variable_info == null || variable_info.IsAssigned (ec, loc);
3615 void ResolveLocalInfo ()
3617 if (local_info == null) {
3618 local_info = Block.GetLocalInfo (Name);
3619 type = local_info.VariableType;
3620 is_readonly = local_info.ReadOnly;
3624 protected Expression DoResolveBase (EmitContext ec)
3626 type = local_info.VariableType;
3628 Expression e = Block.GetConstantExpression (Name);
3630 return e.Resolve (ec);
3632 if (!VerifyAssigned (ec))
3636 // If we are referencing a variable from the external block
3637 // flag it for capturing
3639 if (ec.MustCaptureVariable (local_info)) {
3640 if (local_info.AddressTaken){
3641 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3645 if (!ec.IsInProbingMode)
3647 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3648 variable = scope.AddLocal (local_info);
3649 type = variable.Type;
3656 public override Expression DoResolve (EmitContext ec)
3658 ResolveLocalInfo ();
3659 local_info.Used = true;
3661 if (type == null && local_info.Type is VarExpr) {
3662 local_info.VariableType = TypeManager.object_type;
3663 Error_VariableIsUsedBeforeItIsDeclared (Name);
3667 return DoResolveBase (ec);
3670 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3672 ResolveLocalInfo ();
3675 if (right_side == EmptyExpression.OutAccess)
3676 local_info.Used = true;
3678 // Infer implicitly typed local variable
3680 VarExpr ve = local_info.Type as VarExpr;
3682 ve.DoResolveLValue (ec, right_side);
3683 type = local_info.VariableType = ve.Type;
3690 if (right_side == EmptyExpression.OutAccess) {
3691 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3692 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3693 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3694 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3695 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3697 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3699 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3703 if (VariableInfo != null)
3704 VariableInfo.SetAssigned (ec);
3706 return DoResolveBase (ec);
3709 public bool VerifyFixed ()
3711 // A local Variable is always fixed.
3715 public override int GetHashCode ()
3717 return Name.GetHashCode ();
3720 public override bool Equals (object obj)
3722 LocalVariableReference lvr = obj as LocalVariableReference;
3726 return Name == lvr.Name && Block == lvr.Block;
3729 public override Variable Variable {
3730 get { return variable != null ? variable : local_info.Variable; }
3733 public override string ToString ()
3735 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3738 protected override void CloneTo (CloneContext clonectx, Expression t)
3740 LocalVariableReference target = (LocalVariableReference) t;
3742 target.Block = clonectx.LookupBlock (Block);
3743 if (local_info != null)
3744 target.local_info = clonectx.LookupVariable (local_info);
3749 /// This represents a reference to a parameter in the intermediate
3752 public class ParameterReference : VariableReference, IVariable {
3753 readonly ToplevelParameterInfo pi;
3754 readonly ToplevelBlock referenced;
3757 public bool is_ref, is_out;
3760 get { return is_out; }
3763 public override bool IsRef {
3764 get { return is_ref; }
3767 public string Name {
3768 get { return Parameter.Name; }
3771 public Parameter Parameter {
3772 get { return pi.Parameter; }
3775 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3778 this.referenced = referenced;
3780 eclass = ExprClass.Variable;
3783 public VariableInfo VariableInfo {
3784 get { return pi.VariableInfo; }
3787 public override Variable Variable {
3788 get { return variable != null ? variable : Parameter.Variable; }
3791 public bool VerifyFixed ()
3793 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3794 return Parameter.ModFlags == Parameter.Modifier.NONE;
3797 public bool IsAssigned (EmitContext ec, Location loc)
3799 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3802 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3806 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3808 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3811 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3815 public void SetAssigned (EmitContext ec)
3817 if (is_out && ec.DoFlowAnalysis)
3818 ec.CurrentBranching.SetAssigned (VariableInfo);
3821 public void SetFieldAssigned (EmitContext ec, string field_name)
3823 if (is_out && ec.DoFlowAnalysis)
3824 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3827 protected bool DoResolveBase (EmitContext ec)
3829 Parameter par = Parameter;
3830 if (!par.Resolve (ec)) {
3834 type = par.ParameterType;
3835 Parameter.Modifier mod = par.ModFlags;
3836 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3837 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3838 eclass = ExprClass.Variable;
3840 AnonymousContainer am = ec.CurrentAnonymousMethod;
3844 ToplevelBlock declared = pi.Block;
3845 if (is_ref && declared != referenced) {
3846 Report.Error (1628, Location,
3847 "Cannot use ref or out parameter `{0}' inside an " +
3848 "anonymous method block", par.Name);
3852 if (!am.IsIterator && declared == referenced)
3855 // Don't capture aruments when the probing is on
3856 if (!ec.IsInProbingMode) {
3857 ScopeInfo scope = declared.CreateScopeInfo ();
3858 variable = scope.AddParameter (par, pi.Index);
3859 type = variable.Type;
3864 public override int GetHashCode ()
3866 return Name.GetHashCode ();
3869 public override bool Equals (object obj)
3871 ParameterReference pr = obj as ParameterReference;
3875 return Name == pr.Name && referenced == pr.referenced;
3879 // Notice that for ref/out parameters, the type exposed is not the
3880 // same type exposed externally.
3883 // externally we expose "int&"
3884 // here we expose "int".
3886 // We record this in "is_ref". This means that the type system can treat
3887 // the type as it is expected, but when we generate the code, we generate
3888 // the alternate kind of code.
3890 public override Expression DoResolve (EmitContext ec)
3892 if (!DoResolveBase (ec))
3895 if (is_out && ec.DoFlowAnalysis &&
3896 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3902 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3904 if (!DoResolveBase (ec))
3907 // HACK: parameters are not captured when probing is on
3908 if (!ec.IsInProbingMode)
3914 static public void EmitLdArg (ILGenerator ig, int x)
3918 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3919 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3920 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3921 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3922 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3925 ig.Emit (OpCodes.Ldarg, x);
3928 public override string ToString ()
3930 return "ParameterReference[" + Name + "]";
3935 /// Used for arguments to New(), Invocation()
3937 public class Argument {
3938 public enum AType : byte {
3945 public static readonly Argument[] Empty = new Argument [0];
3947 public readonly AType ArgType;
3948 public Expression Expr;
3950 public Argument (Expression expr, AType type)
3953 this.ArgType = type;
3956 public Argument (Expression expr)
3959 this.ArgType = AType.Expression;
3964 if (ArgType == AType.Ref || ArgType == AType.Out)
3965 return TypeManager.GetReferenceType (Expr.Type);
3971 public Parameter.Modifier Modifier
3976 return Parameter.Modifier.OUT;
3979 return Parameter.Modifier.REF;
3982 return Parameter.Modifier.NONE;
3987 public static string FullDesc (Argument a)
3989 if (a.ArgType == AType.ArgList)
3992 return (a.ArgType == AType.Ref ? "ref " :
3993 (a.ArgType == AType.Out ? "out " : "")) +
3994 TypeManager.CSharpName (a.Expr.Type);
3997 public bool ResolveMethodGroup (EmitContext ec)
3999 SimpleName sn = Expr as SimpleName;
4001 Expr = sn.GetMethodGroup ();
4003 // FIXME: csc doesn't report any error if you try to use `ref' or
4004 // `out' in a delegate creation expression.
4005 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4012 public bool Resolve (EmitContext ec, Location loc)
4014 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4015 // Verify that the argument is readable
4016 if (ArgType != AType.Out)
4017 Expr = Expr.Resolve (ec);
4019 // Verify that the argument is writeable
4020 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4021 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4023 return Expr != null;
4027 public void Emit (EmitContext ec)
4029 if (ArgType != AType.Ref && ArgType != AType.Out) {
4034 AddressOp mode = AddressOp.Store;
4035 if (ArgType == AType.Ref)
4036 mode |= AddressOp.Load;
4038 IMemoryLocation ml = (IMemoryLocation) Expr;
4039 ParameterReference pr = ml as ParameterReference;
4042 // ParameterReferences might already be references, so we want
4043 // to pass just the value
4045 if (pr != null && pr.IsRef)
4048 ml.AddressOf (ec, mode);
4051 public void EmitArrayArgument (EmitContext ec)
4053 Type argtype = Expr.Type;
4056 if (argtype == TypeManager.uint32_type)
4057 ec.ig.Emit (OpCodes.Conv_U);
4058 else if (argtype == TypeManager.int64_type)
4059 ec.ig.Emit (OpCodes.Conv_Ovf_I);
4060 else if (argtype == TypeManager.uint64_type)
4061 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
4064 public Argument Clone (CloneContext clonectx)
4066 return new Argument (Expr.Clone (clonectx), ArgType);
4071 /// Invocation of methods or delegates.
4073 public class Invocation : ExpressionStatement {
4074 ArrayList Arguments;
4079 // arguments is an ArrayList, but we do not want to typecast,
4080 // as it might be null.
4082 public Invocation (Expression expr, ArrayList arguments)
4084 SimpleName sn = expr as SimpleName;
4086 this.expr = sn.GetMethodGroup ();
4090 Arguments = arguments;
4091 loc = expr.Location;
4094 public static string FullMethodDesc (MethodBase mb)
4100 if (mb is MethodInfo) {
4101 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4105 sb = new StringBuilder ();
4107 sb.Append (TypeManager.CSharpSignature (mb));
4108 return sb.ToString ();
4111 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4112 ArrayList arguments, int arg_count,
4113 ref MethodBase candidate)
4115 return IsParamsMethodApplicable (
4116 ec, me, arguments, arg_count, false, ref candidate) ||
4117 IsParamsMethodApplicable (
4118 ec, me, arguments, arg_count, true, ref candidate);
4123 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4124 ArrayList arguments, int arg_count,
4125 bool do_varargs, ref MethodBase candidate)
4128 if (!me.HasTypeArguments &&
4129 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4132 if (TypeManager.IsGenericMethodDefinition (candidate))
4133 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4136 return IsParamsMethodApplicable (
4137 ec, arguments, arg_count, candidate, do_varargs);
4141 /// Determines if the candidate method, if a params method, is applicable
4142 /// in its expanded form to the given set of arguments
4144 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4145 int arg_count, MethodBase candidate,
4148 ParameterData pd = TypeManager.GetParameterData (candidate);
4150 int pd_count = pd.Count;
4154 int count = pd_count - 1;
4156 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4158 if (pd_count != arg_count)
4161 if (!(((Argument) arguments [count]).Expr is Arglist))
4169 if (count > arg_count)
4172 if (pd_count == 1 && arg_count == 0)
4176 // If we have come this far, the case which
4177 // remains is when the number of parameters is
4178 // less than or equal to the argument count.
4180 int argument_index = 0;
4182 for (int i = 0; i < pd_count; ++i) {
4184 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4185 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4186 int params_args_count = arg_count - pd_count;
4187 if (params_args_count < 0)
4191 a = (Argument) arguments [argument_index++];
4193 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4195 } while (params_args_count-- > 0);
4199 a = (Argument) arguments [argument_index++];
4201 Parameter.Modifier a_mod = a.Modifier &
4202 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4203 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4204 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4206 if (a_mod == p_mod) {
4208 if (a_mod == Parameter.Modifier.NONE)
4209 if (!Convert.ImplicitConversionExists (ec,
4211 pd.ParameterType (i)))
4214 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4215 Type pt = pd.ParameterType (i);
4218 pt = TypeManager.GetReferenceType (pt);
4231 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4232 ArrayList arguments, int arg_count,
4233 ref MethodBase method)
4235 MethodBase candidate = method;
4238 if (!me.HasTypeArguments &&
4239 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4242 if (TypeManager.IsGenericMethodDefinition (candidate))
4243 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4246 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4255 /// Determines if the candidate method is applicable (section 14.4.2.1)
4256 /// to the given set of arguments
4258 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4259 MethodBase candidate)
4261 ParameterData pd = TypeManager.GetParameterData (candidate);
4263 if (arg_count != pd.Count)
4266 for (int i = arg_count; i > 0; ) {
4269 Argument a = (Argument) arguments [i];
4271 Parameter.Modifier a_mod = a.Modifier &
4272 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4274 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4275 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4280 Type pt = pd.ParameterType (i);
4282 if (TypeManager.IsEqual (pt, a.Type))
4285 if (a_mod != Parameter.Modifier.NONE)
4288 // FIXME: Kill this abomination (EmitContext.TempEc)
4289 EmitContext prevec = EmitContext.TempEc;
4290 EmitContext.TempEc = ec;
4292 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4295 EmitContext.TempEc = prevec;
4302 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4304 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4305 name, arg_count.ToString ());
4308 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4309 Type delegate_type, Argument a, ParameterData expected_par)
4311 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4312 Report.SymbolRelatedToPreviousError (method);
4313 if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) {
4314 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4315 TypeManager.CSharpSignature (method));
4318 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4319 TypeManager.CSharpSignature (method));
4320 } else if (delegate_type == null) {
4321 Report.SymbolRelatedToPreviousError (method);
4322 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4323 TypeManager.CSharpSignature (method));
4325 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4326 TypeManager.CSharpName (delegate_type));
4328 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4330 string index = (idx + 1).ToString ();
4331 if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4332 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4333 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4334 index, Parameter.GetModifierSignature (a.Modifier));
4336 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4337 index, Parameter.GetModifierSignature (mod));
4339 string p1 = Argument.FullDesc (a);
4340 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4343 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4344 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4345 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4347 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4351 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4352 int arg_count, MethodBase method,
4353 bool chose_params_expanded,
4354 Type delegate_type, bool may_fail,
4357 ParameterData pd = TypeManager.GetParameterData (method);
4361 for (j = 0; j < pd.Count; j++) {
4362 Type parameter_type = pd.ParameterType (j);
4363 Parameter.Modifier pm = pd.ParameterModifier (j);
4365 if (pm == Parameter.Modifier.ARGLIST) {
4366 a = (Argument) Arguments [a_idx];
4367 if (!(a.Expr is Arglist))
4373 int params_arg_count = 1;
4374 if (pm == Parameter.Modifier.PARAMS) {
4375 pm = Parameter.Modifier.NONE;
4376 params_arg_count = arg_count - pd.Count + 1;
4377 if (chose_params_expanded)
4378 parameter_type = TypeManager.GetElementType (parameter_type);
4381 while (params_arg_count > 0) {
4382 a = (Argument) Arguments [a_idx];
4383 if (pm != a.Modifier)
4386 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4387 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4390 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4394 // Update the argument with the implicit conversion
4402 if (params_arg_count > 0)
4405 if (parameter_type.IsPointer && !ec.InUnsafe) {
4412 if (a_idx == arg_count)
4416 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4420 public override Expression DoResolve (EmitContext ec)
4422 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4423 if (expr_resolved == null)
4426 mg = expr_resolved as MethodGroupExpr;
4428 Type expr_type = expr_resolved.Type;
4430 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4431 return (new DelegateInvocation (
4432 expr_resolved, Arguments, loc)).Resolve (ec);
4434 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4439 // Next, evaluate all the expressions in the argument list
4441 if (Arguments != null){
4442 foreach (Argument a in Arguments){
4443 if (!a.Resolve (ec, loc))
4448 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4452 MethodInfo method = (MethodInfo)mg;
4453 if (method != null) {
4454 type = TypeManager.TypeToCoreType (method.ReturnType);
4455 Expression iexpr = mg.InstanceExpression;
4456 if (method.IsStatic) {
4457 if (iexpr == null ||
4458 iexpr is This || iexpr is EmptyExpression ||
4459 mg.IdenticalTypeName) {
4460 mg.InstanceExpression = null;
4462 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4466 if (iexpr == null || iexpr is EmptyExpression) {
4467 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4473 if (type.IsPointer){
4481 // Only base will allow this invocation to happen.
4483 if (mg.IsBase && method.IsAbstract){
4484 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4488 if (Arguments == null && method.Name == "Finalize") {
4490 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4492 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4496 if (IsSpecialMethodInvocation (method)) {
4500 if (mg.InstanceExpression != null){
4501 mg.InstanceExpression.CheckMarshalByRefAccess ();
4504 // This is used to check that no methods are called in struct
4505 // constructors before all the fields on the struct have been
4508 if (!method.IsStatic){
4509 This mgthis = mg.InstanceExpression as This;
4510 if (mgthis != null){
4511 if (!mgthis.CheckThisUsage (ec))
4517 eclass = ExprClass.Value;
4521 bool IsSpecialMethodInvocation (MethodBase method)
4523 if (!TypeManager.IsSpecialMethod (method))
4526 Report.SymbolRelatedToPreviousError (method);
4527 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4528 TypeManager.CSharpSignature (method, true));
4534 // Emits the list of arguments as an array
4536 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4538 ILGenerator ig = ec.ig;
4540 for (int j = 0; j < count; j++){
4541 Argument a = (Argument) arguments [j + idx];
4544 IntConstant.EmitInt (ig, count);
4545 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4548 ig.Emit (OpCodes.Dup);
4549 IntConstant.EmitInt (ig, j);
4551 bool is_stobj, has_type_arg;
4552 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4554 ig.Emit (OpCodes.Ldelema, t);
4566 /// Emits a list of resolved Arguments that are in the arguments
4569 /// The MethodBase argument might be null if the
4570 /// emission of the arguments is known not to contain
4571 /// a `params' field (for example in constructors or other routines
4572 /// that keep their arguments in this structure)
4574 /// if `dup_args' is true, a copy of the arguments will be left
4575 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4576 /// which will be duplicated before any other args. Only EmitCall
4577 /// should be using this interface.
4579 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4581 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4583 LocalTemporary [] temps = null;
4585 if (dup_args && top != 0)
4586 temps = new LocalTemporary [top];
4588 int argument_index = 0;
4590 for (int i = 0; i < top; i++){
4592 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4593 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4594 int params_args_count = arguments == null ?
4595 0 : arguments.Count - top + 1;
4597 // Fill not provided argument
4598 if (params_args_count <= 0) {
4599 ILGenerator ig = ec.ig;
4600 IntConstant.EmitInt (ig, 0);
4601 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4606 // Special case if we are passing the same data as the
4607 // params argument, we do not need to recreate an array.
4609 a = (Argument) arguments [argument_index];
4610 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4616 EmitParams (ec, arguments, i, params_args_count);
4617 argument_index += params_args_count;
4622 a = (Argument) arguments [argument_index++];
4625 ec.ig.Emit (OpCodes.Dup);
4626 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4631 if (this_arg != null)
4634 for (int i = 0; i < top; i ++) {
4635 temps [i].Emit (ec);
4636 temps [i].Release (ec);
4641 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4643 ParameterData pd = TypeManager.GetParameterData (mb);
4645 if (arguments == null)
4646 return new Type [0];
4648 Argument a = (Argument) arguments [pd.Count - 1];
4649 Arglist list = (Arglist) a.Expr;
4651 return list.ArgumentTypes;
4655 /// This checks the ConditionalAttribute on the method
4657 static bool IsMethodExcluded (MethodBase method)
4659 if (method.IsConstructor)
4662 IMethodData md = TypeManager.GetMethod (method);
4664 return md.IsExcluded ();
4666 // For some methods (generated by delegate class) GetMethod returns null
4667 // because they are not included in builder_to_method table
4668 if (method.DeclaringType is TypeBuilder)
4671 return AttributeTester.IsConditionalMethodExcluded (method);
4675 /// is_base tells whether we want to force the use of the `call'
4676 /// opcode instead of using callvirt. Call is required to call
4677 /// a specific method, while callvirt will always use the most
4678 /// recent method in the vtable.
4680 /// is_static tells whether this is an invocation on a static method
4682 /// instance_expr is an expression that represents the instance
4683 /// it must be non-null if is_static is false.
4685 /// method is the method to invoke.
4687 /// Arguments is the list of arguments to pass to the method or constructor.
4689 public static void EmitCall (EmitContext ec, bool is_base,
4690 Expression instance_expr,
4691 MethodBase method, ArrayList Arguments, Location loc)
4693 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4696 // `dup_args' leaves an extra copy of the arguments on the stack
4697 // `omit_args' does not leave any arguments at all.
4698 // So, basically, you could make one call with `dup_args' set to true,
4699 // and then another with `omit_args' set to true, and the two calls
4700 // would have the same set of arguments. However, each argument would
4701 // only have been evaluated once.
4702 public static void EmitCall (EmitContext ec, bool is_base,
4703 Expression instance_expr,
4704 MethodBase method, ArrayList Arguments, Location loc,
4705 bool dup_args, bool omit_args)
4707 ILGenerator ig = ec.ig;
4708 bool struct_call = false;
4709 bool this_call = false;
4710 LocalTemporary this_arg = null;
4712 Type decl_type = method.DeclaringType;
4714 if (!RootContext.StdLib) {
4715 // Replace any calls to the system's System.Array type with calls to
4716 // the newly created one.
4717 if (method == TypeManager.system_int_array_get_length)
4718 method = TypeManager.int_array_get_length;
4719 else if (method == TypeManager.system_int_array_get_rank)
4720 method = TypeManager.int_array_get_rank;
4721 else if (method == TypeManager.system_object_array_clone)
4722 method = TypeManager.object_array_clone;
4723 else if (method == TypeManager.system_int_array_get_length_int)
4724 method = TypeManager.int_array_get_length_int;
4725 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4726 method = TypeManager.int_array_get_lower_bound_int;
4727 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4728 method = TypeManager.int_array_get_upper_bound_int;
4729 else if (method == TypeManager.system_void_array_copyto_array_int)
4730 method = TypeManager.void_array_copyto_array_int;
4733 if (!ec.IsInObsoleteScope) {
4735 // This checks ObsoleteAttribute on the method and on the declaring type
4737 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4739 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4741 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4743 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4747 if (IsMethodExcluded (method))
4750 bool is_static = method.IsStatic;
4752 if (instance_expr == EmptyExpression.Null) {
4753 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4757 this_call = instance_expr is This;
4758 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4762 // If this is ourselves, push "this"
4766 Type iexpr_type = instance_expr.Type;
4769 // Push the instance expression
4771 if (TypeManager.IsValueType (iexpr_type)) {
4773 // Special case: calls to a function declared in a
4774 // reference-type with a value-type argument need
4775 // to have their value boxed.
4776 if (decl_type.IsValueType ||
4777 TypeManager.IsGenericParameter (iexpr_type)) {
4779 // If the expression implements IMemoryLocation, then
4780 // we can optimize and use AddressOf on the
4783 // If not we have to use some temporary storage for
4785 if (instance_expr is IMemoryLocation) {
4786 ((IMemoryLocation)instance_expr).
4787 AddressOf (ec, AddressOp.LoadStore);
4789 LocalTemporary temp = new LocalTemporary (iexpr_type);
4790 instance_expr.Emit (ec);
4792 temp.AddressOf (ec, AddressOp.Load);
4795 // avoid the overhead of doing this all the time.
4797 t = TypeManager.GetReferenceType (iexpr_type);
4799 instance_expr.Emit (ec);
4800 ig.Emit (OpCodes.Box, instance_expr.Type);
4801 t = TypeManager.object_type;
4804 instance_expr.Emit (ec);
4805 t = instance_expr.Type;
4809 ig.Emit (OpCodes.Dup);
4810 if (Arguments != null && Arguments.Count != 0) {
4811 this_arg = new LocalTemporary (t);
4812 this_arg.Store (ec);
4819 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4822 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4823 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4827 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4828 call_op = OpCodes.Call;
4830 call_op = OpCodes.Callvirt;
4832 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4833 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4834 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4841 // and DoFoo is not virtual, you can omit the callvirt,
4842 // because you don't need the null checking behavior.
4844 if (method is MethodInfo)
4845 ig.Emit (call_op, (MethodInfo) method);
4847 ig.Emit (call_op, (ConstructorInfo) method);
4850 public override void Emit (EmitContext ec)
4852 mg.EmitCall (ec, Arguments);
4855 public override void EmitStatement (EmitContext ec)
4860 // Pop the return value if there is one
4862 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4863 ec.ig.Emit (OpCodes.Pop);
4866 protected override void CloneTo (CloneContext clonectx, Expression t)
4868 Invocation target = (Invocation) t;
4870 if (Arguments != null) {
4871 target.Arguments = new ArrayList (Arguments.Count);
4872 foreach (Argument a in Arguments)
4873 target.Arguments.Add (a.Clone (clonectx));
4876 target.expr = expr.Clone (clonectx);
4880 public class InvocationOrCast : ExpressionStatement
4883 Expression argument;
4885 public InvocationOrCast (Expression expr, Expression argument)
4888 this.argument = argument;
4889 this.loc = expr.Location;
4892 public override Expression DoResolve (EmitContext ec)
4895 // First try to resolve it as a cast.
4897 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4898 if ((te != null) && (te.eclass == ExprClass.Type)) {
4899 Cast cast = new Cast (te, argument, loc);
4900 return cast.Resolve (ec);
4904 // This can either be a type or a delegate invocation.
4905 // Let's just resolve it and see what we'll get.
4907 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4912 // Ok, so it's a Cast.
4914 if (expr.eclass == ExprClass.Type) {
4915 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4916 return cast.Resolve (ec);
4920 // It's a delegate invocation.
4922 if (!TypeManager.IsDelegateType (expr.Type)) {
4923 Error (149, "Method name expected");
4927 ArrayList args = new ArrayList ();
4928 args.Add (new Argument (argument, Argument.AType.Expression));
4929 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4930 return invocation.Resolve (ec);
4933 public override ExpressionStatement ResolveStatement (EmitContext ec)
4936 // First try to resolve it as a cast.
4938 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4939 if ((te != null) && (te.eclass == ExprClass.Type)) {
4940 Error_InvalidExpressionStatement ();
4945 // This can either be a type or a delegate invocation.
4946 // Let's just resolve it and see what we'll get.
4948 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4949 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4950 Error_InvalidExpressionStatement ();
4955 // It's a delegate invocation.
4957 if (!TypeManager.IsDelegateType (expr.Type)) {
4958 Error (149, "Method name expected");
4962 ArrayList args = new ArrayList ();
4963 args.Add (new Argument (argument, Argument.AType.Expression));
4964 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4965 return invocation.ResolveStatement (ec);
4968 public override void Emit (EmitContext ec)
4970 throw new Exception ("Cannot happen");
4973 public override void EmitStatement (EmitContext ec)
4975 throw new Exception ("Cannot happen");
4978 protected override void CloneTo (CloneContext clonectx, Expression t)
4980 InvocationOrCast target = (InvocationOrCast) t;
4982 target.expr = expr.Clone (clonectx);
4983 target.argument = argument.Clone (clonectx);
4988 // This class is used to "disable" the code generation for the
4989 // temporary variable when initializing value types.
4991 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4992 public void AddressOf (EmitContext ec, AddressOp Mode)
4999 /// Implements the new expression
5001 public class New : ExpressionStatement, IMemoryLocation {
5002 ArrayList Arguments;
5005 // During bootstrap, it contains the RequestedType,
5006 // but if `type' is not null, it *might* contain a NewDelegate
5007 // (because of field multi-initialization)
5009 public Expression RequestedType;
5011 MethodGroupExpr method;
5014 // If set, the new expression is for a value_target, and
5015 // we will not leave anything on the stack.
5017 Expression value_target;
5018 bool value_target_set = false;
5019 bool is_type_parameter = false;
5021 public New (Expression requested_type, ArrayList arguments, Location l)
5023 RequestedType = requested_type;
5024 Arguments = arguments;
5028 public bool SetValueTypeVariable (Expression value)
5030 value_target = value;
5031 value_target_set = true;
5032 if (!(value_target is IMemoryLocation)){
5033 Error_UnexpectedKind (null, "variable", loc);
5040 // This function is used to disable the following code sequence for
5041 // value type initialization:
5043 // AddressOf (temporary)
5047 // Instead the provide will have provided us with the address on the
5048 // stack to store the results.
5050 static Expression MyEmptyExpression;
5052 public void DisableTemporaryValueType ()
5054 if (MyEmptyExpression == null)
5055 MyEmptyExpression = new EmptyAddressOf ();
5058 // To enable this, look into:
5059 // test-34 and test-89 and self bootstrapping.
5061 // For instance, we can avoid a copy by using `newobj'
5062 // instead of Call + Push-temp on value types.
5063 // value_target = MyEmptyExpression;
5068 /// Converts complex core type syntax like 'new int ()' to simple constant
5070 public static Constant Constantify (Type t)
5072 if (t == TypeManager.int32_type)
5073 return new IntConstant (0, Location.Null);
5074 if (t == TypeManager.uint32_type)
5075 return new UIntConstant (0, Location.Null);
5076 if (t == TypeManager.int64_type)
5077 return new LongConstant (0, Location.Null);
5078 if (t == TypeManager.uint64_type)
5079 return new ULongConstant (0, Location.Null);
5080 if (t == TypeManager.float_type)
5081 return new FloatConstant (0, Location.Null);
5082 if (t == TypeManager.double_type)
5083 return new DoubleConstant (0, Location.Null);
5084 if (t == TypeManager.short_type)
5085 return new ShortConstant (0, Location.Null);
5086 if (t == TypeManager.ushort_type)
5087 return new UShortConstant (0, Location.Null);
5088 if (t == TypeManager.sbyte_type)
5089 return new SByteConstant (0, Location.Null);
5090 if (t == TypeManager.byte_type)
5091 return new ByteConstant (0, Location.Null);
5092 if (t == TypeManager.char_type)
5093 return new CharConstant ('\0', Location.Null);
5094 if (t == TypeManager.bool_type)
5095 return new BoolConstant (false, Location.Null);
5096 if (t == TypeManager.decimal_type)
5097 return new DecimalConstant (0, Location.Null);
5098 if (TypeManager.IsEnumType (t))
5099 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5105 // Checks whether the type is an interface that has the
5106 // [ComImport, CoClass] attributes and must be treated
5109 public Expression CheckComImport (EmitContext ec)
5111 if (!type.IsInterface)
5115 // Turn the call into:
5116 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5118 Type real_class = AttributeTester.GetCoClassAttribute (type);
5119 if (real_class == null)
5122 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5123 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5124 return cast.Resolve (ec);
5127 public override Expression DoResolve (EmitContext ec)
5130 // The New DoResolve might be called twice when initializing field
5131 // expressions (see EmitFieldInitializers, the call to
5132 // GetInitializerExpression will perform a resolve on the expression,
5133 // and later the assign will trigger another resolution
5135 // This leads to bugs (#37014)
5138 if (RequestedType is NewDelegate)
5139 return RequestedType;
5143 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5149 if (type == TypeManager.void_type) {
5150 Error_VoidInvalidInTheContext (loc);
5154 if (type.IsPointer) {
5155 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5156 TypeManager.CSharpName (type));
5160 if (Arguments == null) {
5161 Expression c = Constantify (type);
5166 if (TypeManager.IsDelegateType (type)) {
5167 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5168 if (RequestedType != null)
5169 if (!(RequestedType is DelegateCreation))
5170 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5171 return RequestedType;
5175 if (type.IsGenericParameter) {
5176 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5178 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5179 Error (304, String.Format (
5180 "Cannot create an instance of the " +
5181 "variable type '{0}' because it " +
5182 "doesn't have the new() constraint",
5187 if ((Arguments != null) && (Arguments.Count != 0)) {
5188 Error (417, String.Format (
5189 "`{0}': cannot provide arguments " +
5190 "when creating an instance of a " +
5191 "variable type.", type));
5195 is_type_parameter = true;
5196 eclass = ExprClass.Value;
5201 if (type.IsAbstract && type.IsSealed) {
5202 Report.SymbolRelatedToPreviousError (type);
5203 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5207 if (type.IsInterface || type.IsAbstract){
5208 if (!TypeManager.IsGenericType (type)) {
5209 RequestedType = CheckComImport (ec);
5210 if (RequestedType != null)
5211 return RequestedType;
5214 Report.SymbolRelatedToPreviousError (type);
5215 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5219 bool is_struct = type.IsValueType;
5220 eclass = ExprClass.Value;
5223 // SRE returns a match for .ctor () on structs (the object constructor),
5224 // so we have to manually ignore it.
5226 if (is_struct && Arguments == null)
5229 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5230 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5231 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5233 if (Arguments != null){
5234 foreach (Argument a in Arguments){
5235 if (!a.Resolve (ec, loc))
5243 method = ml as MethodGroupExpr;
5244 if (method == null) {
5245 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5249 method = method.OverloadResolve (ec, Arguments, false, loc);
5256 bool DoEmitTypeParameter (EmitContext ec)
5259 ILGenerator ig = ec.ig;
5260 // IMemoryLocation ml;
5262 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5263 new Type [] { type });
5265 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5266 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5267 ig.Emit (OpCodes.Call, ci);
5271 // Allow DoEmit() to be called multiple times.
5272 // We need to create a new LocalTemporary each time since
5273 // you can't share LocalBuilders among ILGeneators.
5274 LocalTemporary temp = new LocalTemporary (type);
5276 Label label_activator = ig.DefineLabel ();
5277 Label label_end = ig.DefineLabel ();
5279 temp.AddressOf (ec, AddressOp.Store);
5280 ig.Emit (OpCodes.Initobj, type);
5283 ig.Emit (OpCodes.Box, type);
5284 ig.Emit (OpCodes.Brfalse, label_activator);
5286 temp.AddressOf (ec, AddressOp.Store);
5287 ig.Emit (OpCodes.Initobj, type);
5289 ig.Emit (OpCodes.Br, label_end);
5291 ig.MarkLabel (label_activator);
5293 ig.Emit (OpCodes.Call, ci);
5294 ig.MarkLabel (label_end);
5297 throw new InternalErrorException ();
5302 // This DoEmit can be invoked in two contexts:
5303 // * As a mechanism that will leave a value on the stack (new object)
5304 // * As one that wont (init struct)
5306 // You can control whether a value is required on the stack by passing
5307 // need_value_on_stack. The code *might* leave a value on the stack
5308 // so it must be popped manually
5310 // If we are dealing with a ValueType, we have a few
5311 // situations to deal with:
5313 // * The target is a ValueType, and we have been provided
5314 // the instance (this is easy, we are being assigned).
5316 // * The target of New is being passed as an argument,
5317 // to a boxing operation or a function that takes a
5320 // In this case, we need to create a temporary variable
5321 // that is the argument of New.
5323 // Returns whether a value is left on the stack
5325 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5327 bool is_value_type = TypeManager.IsValueType (type);
5328 ILGenerator ig = ec.ig;
5333 // Allow DoEmit() to be called multiple times.
5334 // We need to create a new LocalTemporary each time since
5335 // you can't share LocalBuilders among ILGeneators.
5336 if (!value_target_set)
5337 value_target = new LocalTemporary (type);
5339 ml = (IMemoryLocation) value_target;
5340 ml.AddressOf (ec, AddressOp.Store);
5344 method.EmitArguments (ec, Arguments);
5348 ig.Emit (OpCodes.Initobj, type);
5350 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5351 if (need_value_on_stack){
5352 value_target.Emit (ec);
5357 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5362 public override void Emit (EmitContext ec)
5364 if (is_type_parameter)
5365 DoEmitTypeParameter (ec);
5370 public override void EmitStatement (EmitContext ec)
5372 bool value_on_stack;
5374 if (is_type_parameter)
5375 value_on_stack = DoEmitTypeParameter (ec);
5377 value_on_stack = DoEmit (ec, false);
5380 ec.ig.Emit (OpCodes.Pop);
5384 public void AddressOf (EmitContext ec, AddressOp Mode)
5386 if (is_type_parameter) {
5387 LocalTemporary temp = new LocalTemporary (type);
5388 DoEmitTypeParameter (ec);
5390 temp.AddressOf (ec, Mode);
5394 if (!type.IsValueType){
5396 // We throw an exception. So far, I believe we only need to support
5398 // foreach (int j in new StructType ())
5401 throw new Exception ("AddressOf should not be used for classes");
5404 if (!value_target_set)
5405 value_target = new LocalTemporary (type);
5406 IMemoryLocation ml = (IMemoryLocation) value_target;
5408 ml.AddressOf (ec, AddressOp.Store);
5409 if (method == null) {
5410 ec.ig.Emit (OpCodes.Initobj, type);
5412 method.EmitArguments (ec, Arguments);
5413 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5416 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5419 protected override void CloneTo (CloneContext clonectx, Expression t)
5421 New target = (New) t;
5423 target.RequestedType = RequestedType.Clone (clonectx);
5424 if (Arguments != null){
5425 target.Arguments = new ArrayList ();
5426 foreach (Argument a in Arguments){
5427 target.Arguments.Add (a.Clone (clonectx));
5434 /// 14.5.10.2: Represents an array creation expression.
5438 /// There are two possible scenarios here: one is an array creation
5439 /// expression that specifies the dimensions and optionally the
5440 /// initialization data and the other which does not need dimensions
5441 /// specified but where initialization data is mandatory.
5443 public class ArrayCreation : Expression {
5444 Expression requested_base_type;
5445 ArrayList initializers;
5448 // The list of Argument types.
5449 // This is used to construct the `newarray' or constructor signature
5451 protected ArrayList arguments;
5453 protected Type array_element_type;
5454 bool expect_initializers = false;
5455 int num_arguments = 0;
5456 protected int dimensions;
5457 protected readonly string rank;
5459 protected ArrayList array_data;
5463 // The number of constants in array initializers
5464 int const_initializers_count;
5465 bool only_constant_initializers;
5467 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5469 this.requested_base_type = requested_base_type;
5470 this.initializers = initializers;
5474 arguments = new ArrayList ();
5476 foreach (Expression e in exprs) {
5477 arguments.Add (new Argument (e, Argument.AType.Expression));
5482 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5484 this.requested_base_type = requested_base_type;
5485 this.initializers = initializers;
5489 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5491 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5493 //dimensions = tmp.Length - 1;
5494 expect_initializers = true;
5497 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5499 StringBuilder sb = new StringBuilder (rank);
5502 for (int i = 1; i < idx_count; i++)
5507 return new ComposedCast (base_type, sb.ToString (), loc);
5510 void Error_IncorrectArrayInitializer ()
5512 Error (178, "Invalid rank specifier: expected `,' or `]'");
5515 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5517 if (specified_dims) {
5518 Argument a = (Argument) arguments [idx];
5520 if (!a.Resolve (ec, loc))
5523 Constant c = a.Expr as Constant;
5525 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5529 Report.Error (150, a.Expr.Location, "A constant value is expected");
5533 int value = (int) c.GetValue ();
5535 if (value != probe.Count) {
5536 Error_IncorrectArrayInitializer ();
5540 bounds [idx] = value;
5543 int child_bounds = -1;
5544 only_constant_initializers = true;
5545 for (int i = 0; i < probe.Count; ++i) {
5546 object o = probe [i];
5547 if (o is ArrayList) {
5548 ArrayList sub_probe = o as ArrayList;
5549 int current_bounds = sub_probe.Count;
5551 if (child_bounds == -1)
5552 child_bounds = current_bounds;
5554 else if (child_bounds != current_bounds){
5555 Error_IncorrectArrayInitializer ();
5558 if (idx + 1 >= dimensions){
5559 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5563 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5567 if (child_bounds != -1){
5568 Error_IncorrectArrayInitializer ();
5572 Expression element = ResolveArrayElement (ec, (Expression) o);
5573 if (element == null)
5576 // Initializers with the default values can be ignored
5577 Constant c = element as Constant;
5579 if (c.IsDefaultInitializer (array_element_type)) {
5583 ++const_initializers_count;
5586 only_constant_initializers = false;
5589 array_data.Add (element);
5596 public void UpdateIndices ()
5599 for (ArrayList probe = initializers; probe != null;) {
5600 if (probe.Count > 0 && probe [0] is ArrayList) {
5601 Expression e = new IntConstant (probe.Count, Location.Null);
5602 arguments.Add (new Argument (e, Argument.AType.Expression));
5604 bounds [i++] = probe.Count;
5606 probe = (ArrayList) probe [0];
5609 Expression e = new IntConstant (probe.Count, Location.Null);
5610 arguments.Add (new Argument (e, Argument.AType.Expression));
5612 bounds [i++] = probe.Count;
5619 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5621 element = element.Resolve (ec);
5622 if (element == null)
5625 return Convert.ImplicitConversionRequired (
5626 ec, element, array_element_type, loc);
5629 protected bool ResolveInitializers (EmitContext ec)
5631 if (initializers == null) {
5632 return !expect_initializers;
5636 // We use this to store all the date values in the order in which we
5637 // will need to store them in the byte blob later
5639 array_data = new ArrayList ();
5640 bounds = new System.Collections.Specialized.HybridDictionary ();
5642 if (arguments != null)
5643 return CheckIndices (ec, initializers, 0, true);
5645 arguments = new ArrayList ();
5647 if (!CheckIndices (ec, initializers, 0, false))
5656 // Resolved the type of the array
5658 bool ResolveArrayType (EmitContext ec)
5660 if (requested_base_type == null) {
5661 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5665 StringBuilder array_qualifier = new StringBuilder (rank);
5668 // `In the first form allocates an array instace of the type that results
5669 // from deleting each of the individual expression from the expression list'
5671 if (num_arguments > 0) {
5672 array_qualifier.Append ("[");
5673 for (int i = num_arguments-1; i > 0; i--)
5674 array_qualifier.Append (",");
5675 array_qualifier.Append ("]");
5681 TypeExpr array_type_expr;
5682 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5683 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5684 if (array_type_expr == null)
5687 type = array_type_expr.Type;
5688 array_element_type = TypeManager.GetElementType (type);
5689 dimensions = type.GetArrayRank ();
5694 public override Expression DoResolve (EmitContext ec)
5699 if (!ResolveArrayType (ec))
5702 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5703 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5704 TypeManager.CSharpName (array_element_type));
5708 // First step is to validate the initializers and fill
5709 // in any missing bits
5711 if (!ResolveInitializers (ec))
5714 if (arguments.Count != dimensions) {
5715 Error_IncorrectArrayInitializer ();
5718 foreach (Argument a in arguments){
5719 if (!a.Resolve (ec, loc))
5722 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5723 if (real_arg == null)
5729 eclass = ExprClass.Value;
5733 MethodInfo GetArrayMethod (int arguments)
5735 ModuleBuilder mb = CodeGen.Module.Builder;
5737 Type[] arg_types = new Type[arguments];
5738 for (int i = 0; i < arguments; i++)
5739 arg_types[i] = TypeManager.int32_type;
5741 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5745 Report.Error (-6, "New invocation: Can not find a constructor for " +
5746 "this argument list");
5753 byte [] MakeByteBlob ()
5758 int count = array_data.Count;
5760 if (array_element_type.IsEnum)
5761 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5763 factor = GetTypeSize (array_element_type);
5765 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5767 data = new byte [(count * factor + 3) & ~3];
5770 for (int i = 0; i < count; ++i) {
5771 object v = array_data [i];
5773 if (v is EnumConstant)
5774 v = ((EnumConstant) v).Child;
5776 if (v is Constant && !(v is StringConstant))
5777 v = ((Constant) v).GetValue ();
5783 if (array_element_type == TypeManager.int64_type){
5784 if (!(v is Expression)){
5785 long val = (long) v;
5787 for (int j = 0; j < factor; ++j) {
5788 data [idx + j] = (byte) (val & 0xFF);
5792 } else if (array_element_type == TypeManager.uint64_type){
5793 if (!(v is Expression)){
5794 ulong val = (ulong) v;
5796 for (int j = 0; j < factor; ++j) {
5797 data [idx + j] = (byte) (val & 0xFF);
5801 } else if (array_element_type == TypeManager.float_type) {
5802 if (!(v is Expression)){
5803 element = BitConverter.GetBytes ((float) v);
5805 for (int j = 0; j < factor; ++j)
5806 data [idx + j] = element [j];
5807 if (!BitConverter.IsLittleEndian)
5808 System.Array.Reverse (data, idx, 4);
5810 } else if (array_element_type == TypeManager.double_type) {
5811 if (!(v is Expression)){
5812 element = BitConverter.GetBytes ((double) v);
5814 for (int j = 0; j < factor; ++j)
5815 data [idx + j] = element [j];
5817 // FIXME: Handle the ARM float format.
5818 if (!BitConverter.IsLittleEndian)
5819 System.Array.Reverse (data, idx, 8);
5821 } else if (array_element_type == TypeManager.char_type){
5822 if (!(v is Expression)){
5823 int val = (int) ((char) v);
5825 data [idx] = (byte) (val & 0xff);
5826 data [idx+1] = (byte) (val >> 8);
5828 } else if (array_element_type == TypeManager.short_type){
5829 if (!(v is Expression)){
5830 int val = (int) ((short) v);
5832 data [idx] = (byte) (val & 0xff);
5833 data [idx+1] = (byte) (val >> 8);
5835 } else if (array_element_type == TypeManager.ushort_type){
5836 if (!(v is Expression)){
5837 int val = (int) ((ushort) v);
5839 data [idx] = (byte) (val & 0xff);
5840 data [idx+1] = (byte) (val >> 8);
5842 } else if (array_element_type == TypeManager.int32_type) {
5843 if (!(v is Expression)){
5846 data [idx] = (byte) (val & 0xff);
5847 data [idx+1] = (byte) ((val >> 8) & 0xff);
5848 data [idx+2] = (byte) ((val >> 16) & 0xff);
5849 data [idx+3] = (byte) (val >> 24);
5851 } else if (array_element_type == TypeManager.uint32_type) {
5852 if (!(v is Expression)){
5853 uint val = (uint) v;
5855 data [idx] = (byte) (val & 0xff);
5856 data [idx+1] = (byte) ((val >> 8) & 0xff);
5857 data [idx+2] = (byte) ((val >> 16) & 0xff);
5858 data [idx+3] = (byte) (val >> 24);
5860 } else if (array_element_type == TypeManager.sbyte_type) {
5861 if (!(v is Expression)){
5862 sbyte val = (sbyte) v;
5863 data [idx] = (byte) val;
5865 } else if (array_element_type == TypeManager.byte_type) {
5866 if (!(v is Expression)){
5867 byte val = (byte) v;
5868 data [idx] = (byte) val;
5870 } else if (array_element_type == TypeManager.bool_type) {
5871 if (!(v is Expression)){
5872 bool val = (bool) v;
5873 data [idx] = (byte) (val ? 1 : 0);
5875 } else if (array_element_type == TypeManager.decimal_type){
5876 if (!(v is Expression)){
5877 int [] bits = Decimal.GetBits ((decimal) v);
5880 // FIXME: For some reason, this doesn't work on the MS runtime.
5881 int [] nbits = new int [4];
5882 nbits [0] = bits [3];
5883 nbits [1] = bits [2];
5884 nbits [2] = bits [0];
5885 nbits [3] = bits [1];
5887 for (int j = 0; j < 4; j++){
5888 data [p++] = (byte) (nbits [j] & 0xff);
5889 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5890 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5891 data [p++] = (byte) (nbits [j] >> 24);
5895 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5904 // Emits the initializers for the array
5906 void EmitStaticInitializers (EmitContext ec)
5909 // First, the static data
5912 ILGenerator ig = ec.ig;
5914 byte [] data = MakeByteBlob ();
5916 fb = RootContext.MakeStaticData (data);
5918 ig.Emit (OpCodes.Dup);
5919 ig.Emit (OpCodes.Ldtoken, fb);
5920 ig.Emit (OpCodes.Call,
5921 TypeManager.void_initializearray_array_fieldhandle);
5925 // Emits pieces of the array that can not be computed at compile
5926 // time (variables and string locations).
5928 // This always expect the top value on the stack to be the array
5930 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5932 ILGenerator ig = ec.ig;
5933 int dims = bounds.Count;
5934 int [] current_pos = new int [dims];
5936 MethodInfo set = null;
5939 Type [] args = new Type [dims + 1];
5941 for (int j = 0; j < dims; j++)
5942 args [j] = TypeManager.int32_type;
5943 args [dims] = array_element_type;
5945 set = CodeGen.Module.Builder.GetArrayMethod (
5947 CallingConventions.HasThis | CallingConventions.Standard,
5948 TypeManager.void_type, args);
5951 for (int i = 0; i < array_data.Count; i++){
5953 Expression e = (Expression)array_data [i];
5955 // Constant can be initialized via StaticInitializer
5956 if (e != null && !(!emitConstants && e is Constant)) {
5957 Type etype = e.Type;
5959 ig.Emit (OpCodes.Dup);
5961 for (int idx = 0; idx < dims; idx++)
5962 IntConstant.EmitInt (ig, current_pos [idx]);
5965 // If we are dealing with a struct, get the
5966 // address of it, so we can store it.
5968 if ((dims == 1) && etype.IsValueType &&
5969 (!TypeManager.IsBuiltinOrEnum (etype) ||
5970 etype == TypeManager.decimal_type)) {
5975 // Let new know that we are providing
5976 // the address where to store the results
5978 n.DisableTemporaryValueType ();
5981 ig.Emit (OpCodes.Ldelema, etype);
5987 bool is_stobj, has_type_arg;
5988 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5990 ig.Emit (OpCodes.Stobj, etype);
5991 else if (has_type_arg)
5992 ig.Emit (op, etype);
5996 ig.Emit (OpCodes.Call, set);
6003 for (int j = dims - 1; j >= 0; j--){
6005 if (current_pos [j] < (int) bounds [j])
6007 current_pos [j] = 0;
6012 void EmitArrayArguments (EmitContext ec)
6014 foreach (Argument a in arguments)
6015 a.EmitArrayArgument (ec);
6018 public override void Emit (EmitContext ec)
6020 ILGenerator ig = ec.ig;
6022 EmitArrayArguments (ec);
6023 if (arguments.Count == 1)
6024 ig.Emit (OpCodes.Newarr, array_element_type);
6026 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6029 if (initializers == null)
6032 // Emit static initializer for arrays which have contain more than 4 items and
6033 // the static initializer will initialize at least 25% of array values.
6034 // NOTE: const_initializers_count does not contain default constant values.
6035 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6036 TypeManager.IsPrimitiveType (array_element_type)) {
6037 EmitStaticInitializers (ec);
6039 if (!only_constant_initializers)
6040 EmitDynamicInitializers (ec, false);
6042 EmitDynamicInitializers (ec, true);
6046 public override bool GetAttributableValue (Type valueType, out object value)
6048 if (arguments.Count != 1) {
6049 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6050 return base.GetAttributableValue (null, out value);
6053 if (array_data == null) {
6054 Constant c = (Constant)((Argument)arguments [0]).Expr;
6055 if (c.IsDefaultValue) {
6056 value = Array.CreateInstance (array_element_type, 0);
6059 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6060 return base.GetAttributableValue (null, out value);
6063 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6064 object element_value;
6065 for (int i = 0; i < ret.Length; ++i)
6067 Expression e = (Expression)array_data [i];
6069 // Is null when an initializer is optimized (value == predefined value)
6073 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6077 ret.SetValue (element_value, i);
6083 protected override void CloneTo (CloneContext clonectx, Expression t)
6085 ArrayCreation target = (ArrayCreation) t;
6087 target.requested_base_type = requested_base_type.Clone (clonectx);
6089 if (arguments != null){
6090 target.arguments = new ArrayList (arguments.Count);
6091 foreach (Argument a in arguments)
6092 target.arguments.Add (a.Clone (clonectx));
6095 if (initializers != null){
6096 target.initializers = new ArrayList (initializers.Count);
6097 foreach (Expression initializer in initializers)
6098 target.initializers.Add (initializer.Clone (clonectx));
6104 // Represents an implicitly typed array epxression
6106 public class ImplicitlyTypedArrayCreation : ArrayCreation
6108 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6109 : base (null, rank, initializers, loc)
6111 if (rank.Length > 2) {
6112 while (rank [++dimensions] == ',');
6118 public override Expression DoResolve (EmitContext ec)
6123 if (!ResolveInitializers (ec))
6126 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6127 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6128 arguments.Count != dimensions) {
6129 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6134 // At this point we found common base type for all initializer elements
6135 // but we have to be sure that all static initializer elements are of
6138 UnifyInitializerElement (ec);
6140 type = TypeManager.GetConstructedType (array_element_type, rank);
6141 eclass = ExprClass.Value;
6146 // Converts static initializer only
6148 void UnifyInitializerElement (EmitContext ec)
6150 for (int i = 0; i < array_data.Count; ++i) {
6151 Expression e = (Expression)array_data[i];
6153 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6157 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6159 element = element.Resolve (ec);
6160 if (element == null)
6163 if (array_element_type == null) {
6164 array_element_type = element.Type;
6168 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6172 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6173 array_element_type = element.Type;
6177 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6182 public sealed class CompilerGeneratedThis : This
6184 public static This Instance = new CompilerGeneratedThis ();
6186 private CompilerGeneratedThis ()
6187 : base (Location.Null)
6191 public override Expression DoResolve (EmitContext ec)
6193 eclass = ExprClass.Variable;
6194 type = ec.ContainerType;
6195 variable = new SimpleThis (type);
6201 /// Represents the `this' construct
6204 public class This : VariableReference, IVariable
6207 VariableInfo variable_info;
6208 protected Variable variable;
6211 public This (Block block, Location loc)
6217 public This (Location loc)
6222 public VariableInfo VariableInfo {
6223 get { return variable_info; }
6226 public bool VerifyFixed ()
6228 return !TypeManager.IsValueType (Type);
6231 public override bool IsRef {
6232 get { return is_struct; }
6235 public override Variable Variable {
6236 get { return variable; }
6239 public bool ResolveBase (EmitContext ec)
6241 eclass = ExprClass.Variable;
6243 if (ec.TypeContainer.CurrentType != null)
6244 type = ec.TypeContainer.CurrentType;
6246 type = ec.ContainerType;
6248 is_struct = ec.TypeContainer is Struct;
6251 Error (26, "Keyword `this' is not valid in a static property, " +
6252 "static method, or static field initializer");
6256 if (block != null) {
6257 if (block.Toplevel.ThisVariable != null)
6258 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6260 AnonymousContainer am = ec.CurrentAnonymousMethod;
6261 if (is_struct && (am != null) && !am.IsIterator) {
6262 Report.Error (1673, loc, "Anonymous methods inside structs " +
6263 "cannot access instance members of `this'. " +
6264 "Consider copying `this' to a local variable " +
6265 "outside the anonymous method and using the " +
6270 RootScopeInfo host = block.Toplevel.RootScope;
6271 if ((host != null) && !ec.IsConstructor &&
6272 (!is_struct || host.IsIterator)) {
6273 variable = host.CaptureThis ();
6274 type = variable.Type;
6279 if (variable == null)
6280 variable = new SimpleThis (type);
6286 // Called from Invocation to check if the invocation is correct
6288 public bool CheckThisUsage (EmitContext ec)
6290 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6291 !variable_info.IsAssigned (ec)) {
6292 Error (188, "The `this' object cannot be used before all of its " +
6293 "fields are assigned to");
6294 variable_info.SetAssigned (ec);
6301 public override Expression DoResolve (EmitContext ec)
6303 if (!ResolveBase (ec))
6307 if (ec.IsFieldInitializer) {
6308 Error (27, "Keyword `this' is not available in the current context");
6315 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6317 if (!ResolveBase (ec))
6320 if (variable_info != null)
6321 variable_info.SetAssigned (ec);
6323 if (ec.TypeContainer is Class){
6324 Error (1604, "Cannot assign to 'this' because it is read-only");
6330 public override int GetHashCode()
6332 return block.GetHashCode ();
6335 public override bool Equals (object obj)
6337 This t = obj as This;
6341 return block == t.block;
6344 protected class SimpleThis : Variable
6348 public SimpleThis (Type type)
6353 public override Type Type {
6354 get { return type; }
6357 public override bool HasInstance {
6358 get { return false; }
6361 public override bool NeedsTemporary {
6362 get { return false; }
6365 public override void EmitInstance (EmitContext ec)
6370 public override void Emit (EmitContext ec)
6372 ec.ig.Emit (OpCodes.Ldarg_0);
6375 public override void EmitAssign (EmitContext ec)
6377 throw new InvalidOperationException ();
6380 public override void EmitAddressOf (EmitContext ec)
6382 ec.ig.Emit (OpCodes.Ldarg_0);
6386 protected override void CloneTo (CloneContext clonectx, Expression t)
6388 This target = (This) t;
6390 target.block = clonectx.LookupBlock (block);
6395 /// Represents the `__arglist' construct
6397 public class ArglistAccess : Expression
6399 public ArglistAccess (Location loc)
6404 public override Expression DoResolve (EmitContext ec)
6406 eclass = ExprClass.Variable;
6407 type = TypeManager.runtime_argument_handle_type;
6409 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6411 Error (190, "The __arglist construct is valid only within " +
6412 "a variable argument method");
6419 public override void Emit (EmitContext ec)
6421 ec.ig.Emit (OpCodes.Arglist);
6424 protected override void CloneTo (CloneContext clonectx, Expression target)
6431 /// Represents the `__arglist (....)' construct
6433 public class Arglist : Expression
6435 Argument[] Arguments;
6437 public Arglist (Location loc)
6438 : this (Argument.Empty, loc)
6442 public Arglist (Argument[] args, Location l)
6448 public Type[] ArgumentTypes {
6450 Type[] retval = new Type [Arguments.Length];
6451 for (int i = 0; i < Arguments.Length; i++)
6452 retval [i] = Arguments [i].Type;
6457 public override Expression DoResolve (EmitContext ec)
6459 eclass = ExprClass.Variable;
6460 type = TypeManager.runtime_argument_handle_type;
6462 foreach (Argument arg in Arguments) {
6463 if (!arg.Resolve (ec, loc))
6470 public override void Emit (EmitContext ec)
6472 foreach (Argument arg in Arguments)
6476 protected override void CloneTo (CloneContext clonectx, Expression t)
6478 Arglist target = (Arglist) t;
6480 target.Arguments = new Argument [Arguments.Length];
6481 for (int i = 0; i < Arguments.Length; i++)
6482 target.Arguments [i] = Arguments [i].Clone (clonectx);
6487 // This produces the value that renders an instance, used by the iterators code
6489 public class ProxyInstance : Expression, IMemoryLocation {
6490 public override Expression DoResolve (EmitContext ec)
6492 eclass = ExprClass.Variable;
6493 type = ec.ContainerType;
6497 public override void Emit (EmitContext ec)
6499 ec.ig.Emit (OpCodes.Ldarg_0);
6503 public void AddressOf (EmitContext ec, AddressOp mode)
6505 ec.ig.Emit (OpCodes.Ldarg_0);
6510 /// Implements the typeof operator
6512 public class TypeOf : Expression {
6513 Expression QueriedType;
6514 protected Type typearg;
6516 public TypeOf (Expression queried_type, Location l)
6518 QueriedType = queried_type;
6522 public override Expression DoResolve (EmitContext ec)
6524 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6528 typearg = texpr.Type;
6530 if (typearg == TypeManager.void_type) {
6531 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6535 if (typearg.IsPointer && !ec.InUnsafe){
6540 type = TypeManager.type_type;
6541 // Even though what is returned is a type object, it's treated as a value by the compiler.
6542 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6543 eclass = ExprClass.Value;
6547 public override void Emit (EmitContext ec)
6549 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6550 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6553 public override bool GetAttributableValue (Type valueType, out object value)
6555 if (TypeManager.ContainsGenericParameters (typearg) &&
6556 !TypeManager.IsGenericTypeDefinition (typearg)) {
6557 Report.SymbolRelatedToPreviousError (typearg);
6558 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6559 TypeManager.CSharpName (typearg));
6564 if (valueType == TypeManager.object_type) {
6565 value = (object)typearg;
6572 public Type TypeArgument
6580 protected override void CloneTo (CloneContext clonectx, Expression t)
6582 TypeOf target = (TypeOf) t;
6584 target.QueriedType = QueriedType.Clone (clonectx);
6589 /// Implements the `typeof (void)' operator
6591 public class TypeOfVoid : TypeOf {
6592 public TypeOfVoid (Location l) : base (null, l)
6597 public override Expression DoResolve (EmitContext ec)
6599 type = TypeManager.type_type;
6600 typearg = TypeManager.void_type;
6601 // See description in TypeOf.
6602 eclass = ExprClass.Value;
6608 /// Implements the sizeof expression
6610 public class SizeOf : Expression {
6611 readonly Expression QueriedType;
6614 public SizeOf (Expression queried_type, Location l)
6616 this.QueriedType = queried_type;
6620 public override Expression DoResolve (EmitContext ec)
6622 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6627 if (texpr is TypeParameterExpr){
6628 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6633 type_queried = texpr.Type;
6634 if (type_queried.IsEnum)
6635 type_queried = TypeManager.EnumToUnderlying (type_queried);
6637 if (type_queried == TypeManager.void_type) {
6638 Expression.Error_VoidInvalidInTheContext (loc);
6642 int size_of = GetTypeSize (type_queried);
6644 return new IntConstant (size_of, loc);
6648 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)",
6649 TypeManager.CSharpName (type_queried));
6653 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6657 type = TypeManager.int32_type;
6658 eclass = ExprClass.Value;
6662 public override void Emit (EmitContext ec)
6664 int size = GetTypeSize (type_queried);
6667 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6669 IntConstant.EmitInt (ec.ig, size);
6672 protected override void CloneTo (CloneContext clonectx, Expression t)
6678 /// Implements the qualified-alias-member (::) expression.
6680 public class QualifiedAliasMember : Expression
6682 string alias, identifier;
6684 public QualifiedAliasMember (string alias, string identifier, Location l)
6686 if (RootContext.Version == LanguageVersion.ISO_1)
6687 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6690 this.identifier = identifier;
6694 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6696 if (alias == "global")
6697 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6699 int errors = Report.Errors;
6700 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6702 if (errors == Report.Errors)
6703 Report.Error (432, loc, "Alias `{0}' not found", alias);
6706 if (fne.eclass != ExprClass.Namespace) {
6708 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6711 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6714 public override Expression DoResolve (EmitContext ec)
6716 FullNamedExpression fne;
6717 if (alias == "global") {
6718 fne = RootNamespace.Global;
6720 int errors = Report.Errors;
6721 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6723 if (errors == Report.Errors)
6724 Report.Error (432, loc, "Alias `{0}' not found", alias);
6729 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6733 if (!(retval is FullNamedExpression)) {
6734 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6738 // We defer this check till the end to match the behaviour of CSC
6739 if (fne.eclass != ExprClass.Namespace) {
6740 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6746 public override void Emit (EmitContext ec)
6748 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6752 public override string ToString ()
6754 return alias + "::" + identifier;
6757 public override string GetSignatureForError ()
6762 protected override void CloneTo (CloneContext clonectx, Expression t)
6769 /// Implements the member access expression
6771 public class MemberAccess : Expression {
6772 public readonly string Identifier;
6774 readonly TypeArguments args;
6776 public MemberAccess (Expression expr, string id)
6777 : this (expr, id, expr.Location)
6781 public MemberAccess (Expression expr, string identifier, Location loc)
6784 Identifier = identifier;
6788 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6789 : this (expr, identifier, loc)
6794 protected string LookupIdentifier {
6795 get { return MemberName.MakeName (Identifier, args); }
6798 // TODO: this method has very poor performace for Enum fields and
6799 // probably for other constants as well
6800 Expression DoResolve (EmitContext ec, Expression right_side)
6803 throw new Exception ();
6806 // Resolve the expression with flow analysis turned off, we'll do the definite
6807 // assignment checks later. This is because we don't know yet what the expression
6808 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6809 // definite assignment check on the actual field and not on the whole struct.
6812 SimpleName original = expr as SimpleName;
6813 Expression expr_resolved = expr.Resolve (ec,
6814 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6815 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6817 if (expr_resolved == null)
6820 if (expr_resolved is Namespace) {
6821 Namespace ns = (Namespace) expr_resolved;
6822 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6824 if ((retval != null) && (args != null))
6825 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6829 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6833 Type expr_type = expr_resolved.Type;
6834 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6835 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6838 if (expr_type == TypeManager.anonymous_method_type){
6839 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6843 Constant c = expr_resolved as Constant;
6844 if (c != null && c.GetValue () == null) {
6845 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6846 "System.NullReferenceException");
6849 Expression member_lookup;
6850 member_lookup = MemberLookup (
6851 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6853 if ((member_lookup == null) && (args != null)) {
6854 member_lookup = MemberLookup (
6855 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6858 if (member_lookup == null) {
6859 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6860 if (ex_method_lookup != null) {
6861 ex_method_lookup.ExtensionExpression = expr_resolved;
6862 return ex_method_lookup.DoResolve (ec);
6865 if (!ec.IsInProbingMode)
6866 Error_MemberLookupFailed (
6867 ec.ContainerType, expr_type, expr_type, Identifier, null,
6868 AllMemberTypes, AllBindingFlags, loc);
6872 TypeExpr texpr = member_lookup as TypeExpr;
6873 if (texpr != null) {
6874 if (!(expr_resolved is TypeExpr) &&
6875 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6876 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6877 Identifier, member_lookup.GetSignatureForError ());
6881 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6882 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6883 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6888 ConstructedType ct = expr_resolved as ConstructedType;
6891 // When looking up a nested type in a generic instance
6892 // via reflection, we always get a generic type definition
6893 // and not a generic instance - so we have to do this here.
6895 // See gtest-172-lib.cs and gtest-172.cs for an example.
6897 ct = new ConstructedType (
6898 member_lookup.Type, ct.TypeArguments, loc);
6900 return ct.ResolveAsTypeStep (ec, false);
6903 return member_lookup;
6906 MemberExpr me = (MemberExpr) member_lookup;
6907 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6908 if (member_lookup == null)
6912 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6914 throw new InternalErrorException ();
6916 return mg.ResolveGeneric (ec, args);
6919 if (original != null && !TypeManager.IsValueType (expr_type)) {
6920 me = member_lookup as MemberExpr;
6921 if (me != null && me.IsInstance) {
6922 LocalVariableReference var = expr_resolved as LocalVariableReference;
6923 if (var != null && !var.VerifyAssigned (ec))
6928 // The following DoResolve/DoResolveLValue will do the definite assignment
6931 if (right_side != null)
6932 return member_lookup.DoResolveLValue (ec, right_side);
6934 return member_lookup.DoResolve (ec);
6937 public override Expression DoResolve (EmitContext ec)
6939 return DoResolve (ec, null);
6942 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6944 return DoResolve (ec, right_side);
6947 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6949 return ResolveNamespaceOrType (ec, silent);
6952 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6954 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6956 if (new_expr == null)
6959 if (new_expr is Namespace) {
6960 Namespace ns = (Namespace) new_expr;
6961 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6963 if ((retval != null) && (args != null))
6964 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6966 if (!silent && retval == null)
6967 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6971 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6972 if (tnew_expr == null)
6975 Type expr_type = tnew_expr.Type;
6977 if (expr_type.IsPointer){
6978 Error (23, "The `.' operator can not be applied to pointer operands (" +
6979 TypeManager.CSharpName (expr_type) + ")");
6983 Expression member_lookup = MemberLookup (
6984 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6985 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6986 if (member_lookup == null) {
6990 member_lookup = MemberLookup(
6991 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6992 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6994 if (member_lookup == null) {
6995 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6996 Identifier, new_expr.GetSignatureForError ());
6998 // TODO: Report.SymbolRelatedToPreviousError
6999 member_lookup.Error_UnexpectedKind (null, "type", loc);
7004 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7009 TypeArguments the_args = args;
7010 if (TypeManager.HasGenericArguments (expr_type)) {
7011 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7013 TypeArguments new_args = new TypeArguments (loc);
7014 foreach (Type decl in decl_args)
7015 new_args.Add (new TypeExpression (decl, loc));
7018 new_args.Add (args);
7020 the_args = new_args;
7023 if (the_args != null) {
7024 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7025 return ctype.ResolveAsTypeStep (rc, false);
7032 public override void Emit (EmitContext ec)
7034 throw new Exception ("Should not happen");
7037 public override string ToString ()
7039 return expr + "." + MemberName.MakeName (Identifier, args);
7042 public override string GetSignatureForError ()
7044 return expr.GetSignatureForError () + "." + Identifier;
7047 protected override void CloneTo (CloneContext clonectx, Expression t)
7049 MemberAccess target = (MemberAccess) t;
7051 target.expr = expr.Clone (clonectx);
7056 /// Implements checked expressions
7058 public class CheckedExpr : Expression {
7060 public Expression Expr;
7062 public CheckedExpr (Expression e, Location l)
7068 public override Expression DoResolve (EmitContext ec)
7070 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7071 Expr = Expr.Resolve (ec);
7076 if (Expr is Constant)
7079 eclass = Expr.eclass;
7084 public override void Emit (EmitContext ec)
7086 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7090 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7092 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7093 Expr.EmitBranchable (ec, target, onTrue);
7096 protected override void CloneTo (CloneContext clonectx, Expression t)
7098 CheckedExpr target = (CheckedExpr) t;
7100 target.Expr = Expr.Clone (clonectx);
7105 /// Implements the unchecked expression
7107 public class UnCheckedExpr : Expression {
7109 public Expression Expr;
7111 public UnCheckedExpr (Expression e, Location l)
7117 public override Expression DoResolve (EmitContext ec)
7119 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7120 Expr = Expr.Resolve (ec);
7125 if (Expr is Constant)
7128 eclass = Expr.eclass;
7133 public override void Emit (EmitContext ec)
7135 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7139 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7141 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7142 Expr.EmitBranchable (ec, target, onTrue);
7145 protected override void CloneTo (CloneContext clonectx, Expression t)
7147 UnCheckedExpr target = (UnCheckedExpr) t;
7149 target.Expr = Expr.Clone (clonectx);
7154 /// An Element Access expression.
7156 /// During semantic analysis these are transformed into
7157 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7159 public class ElementAccess : Expression {
7160 public ArrayList Arguments;
7161 public Expression Expr;
7163 public ElementAccess (Expression e, ArrayList e_list)
7172 Arguments = new ArrayList ();
7173 foreach (Expression tmp in e_list)
7174 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7178 bool CommonResolve (EmitContext ec)
7180 Expr = Expr.Resolve (ec);
7182 if (Arguments == null)
7185 foreach (Argument a in Arguments){
7186 if (!a.Resolve (ec, loc))
7190 return Expr != null;
7193 Expression MakePointerAccess (EmitContext ec, Type t)
7195 if (t == TypeManager.void_ptr_type){
7196 Error (242, "The array index operation is not valid on void pointers");
7199 if (Arguments.Count != 1){
7200 Error (196, "A pointer must be indexed by only one value");
7205 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7208 return new Indirection (p, loc).Resolve (ec);
7211 public override Expression DoResolve (EmitContext ec)
7213 if (!CommonResolve (ec))
7217 // We perform some simple tests, and then to "split" the emit and store
7218 // code we create an instance of a different class, and return that.
7220 // I am experimenting with this pattern.
7224 if (t == TypeManager.array_type){
7225 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7230 return (new ArrayAccess (this, loc)).Resolve (ec);
7232 return MakePointerAccess (ec, t);
7234 FieldExpr fe = Expr as FieldExpr;
7236 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7238 return MakePointerAccess (ec, ff.ElementType);
7241 return (new IndexerAccess (this, loc)).Resolve (ec);
7244 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7246 if (!CommonResolve (ec))
7251 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7254 return MakePointerAccess (ec, t);
7256 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7259 public override void Emit (EmitContext ec)
7261 throw new Exception ("Should never be reached");
7264 protected override void CloneTo (CloneContext clonectx, Expression t)
7266 ElementAccess target = (ElementAccess) t;
7268 target.Expr = Expr.Clone (clonectx);
7269 target.Arguments = new ArrayList (Arguments.Count);
7270 foreach (Argument a in Arguments)
7271 target.Arguments.Add (a.Clone (clonectx));
7276 /// Implements array access
7278 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7280 // Points to our "data" repository
7284 LocalTemporary temp;
7287 public ArrayAccess (ElementAccess ea_data, Location l)
7290 eclass = ExprClass.Variable;
7294 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7296 return DoResolve (ec);
7299 public override Expression DoResolve (EmitContext ec)
7302 ExprClass eclass = ea.Expr.eclass;
7304 // As long as the type is valid
7305 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7306 eclass == ExprClass.Value)) {
7307 ea.Expr.Error_UnexpectedKind ("variable or value");
7312 Type t = ea.Expr.Type;
7313 if (t.GetArrayRank () != ea.Arguments.Count){
7314 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7315 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7319 type = TypeManager.GetElementType (t);
7320 if (type.IsPointer && !ec.InUnsafe){
7321 UnsafeError (ea.Location);
7325 foreach (Argument a in ea.Arguments){
7326 Type argtype = a.Type;
7328 if (argtype == TypeManager.int32_type ||
7329 argtype == TypeManager.uint32_type ||
7330 argtype == TypeManager.int64_type ||
7331 argtype == TypeManager.uint64_type) {
7332 Constant c = a.Expr as Constant;
7333 if (c != null && c.IsNegative) {
7334 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7340 // Mhm. This is strage, because the Argument.Type is not the same as
7341 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7343 // Wonder if I will run into trouble for this.
7345 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7350 eclass = ExprClass.Variable;
7356 /// Emits the right opcode to load an object of Type `t'
7357 /// from an array of T
7359 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7361 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7362 ig.Emit (OpCodes.Ldelem_U1);
7363 else if (type == TypeManager.sbyte_type)
7364 ig.Emit (OpCodes.Ldelem_I1);
7365 else if (type == TypeManager.short_type)
7366 ig.Emit (OpCodes.Ldelem_I2);
7367 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7368 ig.Emit (OpCodes.Ldelem_U2);
7369 else if (type == TypeManager.int32_type)
7370 ig.Emit (OpCodes.Ldelem_I4);
7371 else if (type == TypeManager.uint32_type)
7372 ig.Emit (OpCodes.Ldelem_U4);
7373 else if (type == TypeManager.uint64_type)
7374 ig.Emit (OpCodes.Ldelem_I8);
7375 else if (type == TypeManager.int64_type)
7376 ig.Emit (OpCodes.Ldelem_I8);
7377 else if (type == TypeManager.float_type)
7378 ig.Emit (OpCodes.Ldelem_R4);
7379 else if (type == TypeManager.double_type)
7380 ig.Emit (OpCodes.Ldelem_R8);
7381 else if (type == TypeManager.intptr_type)
7382 ig.Emit (OpCodes.Ldelem_I);
7383 else if (TypeManager.IsEnumType (type)){
7384 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7385 } else if (type.IsValueType){
7386 ig.Emit (OpCodes.Ldelema, type);
7387 ig.Emit (OpCodes.Ldobj, type);
7389 } else if (type.IsGenericParameter) {
7390 ig.Emit (OpCodes.Ldelem, type);
7392 } else if (type.IsPointer)
7393 ig.Emit (OpCodes.Ldelem_I);
7395 ig.Emit (OpCodes.Ldelem_Ref);
7399 /// Returns the right opcode to store an object of Type `t'
7400 /// from an array of T.
7402 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7404 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7405 has_type_arg = false; is_stobj = false;
7406 t = TypeManager.TypeToCoreType (t);
7407 if (TypeManager.IsEnumType (t))
7408 t = TypeManager.EnumToUnderlying (t);
7409 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7410 t == TypeManager.bool_type)
7411 return OpCodes.Stelem_I1;
7412 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7413 t == TypeManager.char_type)
7414 return OpCodes.Stelem_I2;
7415 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7416 return OpCodes.Stelem_I4;
7417 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7418 return OpCodes.Stelem_I8;
7419 else if (t == TypeManager.float_type)
7420 return OpCodes.Stelem_R4;
7421 else if (t == TypeManager.double_type)
7422 return OpCodes.Stelem_R8;
7423 else if (t == TypeManager.intptr_type) {
7424 has_type_arg = true;
7426 return OpCodes.Stobj;
7427 } else if (t.IsValueType) {
7428 has_type_arg = true;
7430 return OpCodes.Stobj;
7432 } else if (t.IsGenericParameter) {
7433 has_type_arg = true;
7434 return OpCodes.Stelem;
7437 } else if (t.IsPointer)
7438 return OpCodes.Stelem_I;
7440 return OpCodes.Stelem_Ref;
7443 MethodInfo FetchGetMethod ()
7445 ModuleBuilder mb = CodeGen.Module.Builder;
7446 int arg_count = ea.Arguments.Count;
7447 Type [] args = new Type [arg_count];
7450 for (int i = 0; i < arg_count; i++){
7451 //args [i++] = a.Type;
7452 args [i] = TypeManager.int32_type;
7455 get = mb.GetArrayMethod (
7456 ea.Expr.Type, "Get",
7457 CallingConventions.HasThis |
7458 CallingConventions.Standard,
7464 MethodInfo FetchAddressMethod ()
7466 ModuleBuilder mb = CodeGen.Module.Builder;
7467 int arg_count = ea.Arguments.Count;
7468 Type [] args = new Type [arg_count];
7472 ret_type = TypeManager.GetReferenceType (type);
7474 for (int i = 0; i < arg_count; i++){
7475 //args [i++] = a.Type;
7476 args [i] = TypeManager.int32_type;
7479 address = mb.GetArrayMethod (
7480 ea.Expr.Type, "Address",
7481 CallingConventions.HasThis |
7482 CallingConventions.Standard,
7489 // Load the array arguments into the stack.
7491 // If we have been requested to cache the values (cached_locations array
7492 // initialized), then load the arguments the first time and store them
7493 // in locals. otherwise load from local variables.
7495 void LoadArrayAndArguments (EmitContext ec)
7498 foreach (Argument a in ea.Arguments){
7499 a.EmitArrayArgument (ec);
7503 public void Emit (EmitContext ec, bool leave_copy)
7505 int rank = ea.Expr.Type.GetArrayRank ();
7506 ILGenerator ig = ec.ig;
7509 LoadArrayAndArguments (ec);
7512 EmitLoadOpcode (ig, type);
7516 method = FetchGetMethod ();
7517 ig.Emit (OpCodes.Call, method);
7520 LoadFromPtr (ec.ig, this.type);
7523 ec.ig.Emit (OpCodes.Dup);
7524 temp = new LocalTemporary (this.type);
7529 public override void Emit (EmitContext ec)
7534 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7536 int rank = ea.Expr.Type.GetArrayRank ();
7537 ILGenerator ig = ec.ig;
7538 Type t = source.Type;
7539 prepared = prepare_for_load;
7541 if (prepare_for_load) {
7542 AddressOf (ec, AddressOp.LoadStore);
7543 ec.ig.Emit (OpCodes.Dup);
7546 ec.ig.Emit (OpCodes.Dup);
7547 temp = new LocalTemporary (this.type);
7550 StoreFromPtr (ec.ig, t);
7560 LoadArrayAndArguments (ec);
7563 bool is_stobj, has_type_arg;
7564 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7566 // The stobj opcode used by value types will need
7567 // an address on the stack, not really an array/array
7571 ig.Emit (OpCodes.Ldelema, t);
7575 ec.ig.Emit (OpCodes.Dup);
7576 temp = new LocalTemporary (this.type);
7581 ig.Emit (OpCodes.Stobj, t);
7582 else if (has_type_arg)
7587 ModuleBuilder mb = CodeGen.Module.Builder;
7588 int arg_count = ea.Arguments.Count;
7589 Type [] args = new Type [arg_count + 1];
7594 ec.ig.Emit (OpCodes.Dup);
7595 temp = new LocalTemporary (this.type);
7599 for (int i = 0; i < arg_count; i++){
7600 //args [i++] = a.Type;
7601 args [i] = TypeManager.int32_type;
7604 args [arg_count] = type;
7606 set = mb.GetArrayMethod (
7607 ea.Expr.Type, "Set",
7608 CallingConventions.HasThis |
7609 CallingConventions.Standard,
7610 TypeManager.void_type, args);
7612 ig.Emit (OpCodes.Call, set);
7621 public void AddressOf (EmitContext ec, AddressOp mode)
7623 int rank = ea.Expr.Type.GetArrayRank ();
7624 ILGenerator ig = ec.ig;
7626 LoadArrayAndArguments (ec);
7629 ig.Emit (OpCodes.Ldelema, type);
7631 MethodInfo address = FetchAddressMethod ();
7632 ig.Emit (OpCodes.Call, address);
7636 public void EmitGetLength (EmitContext ec, int dim)
7638 int rank = ea.Expr.Type.GetArrayRank ();
7639 ILGenerator ig = ec.ig;
7643 ig.Emit (OpCodes.Ldlen);
7644 ig.Emit (OpCodes.Conv_I4);
7646 IntLiteral.EmitInt (ig, dim);
7647 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7653 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7654 public readonly ArrayList Properties;
7655 static Indexers empty;
7657 public struct Indexer {
7658 public readonly PropertyInfo PropertyInfo;
7659 public readonly MethodInfo Getter, Setter;
7661 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7663 this.PropertyInfo = property_info;
7671 empty = new Indexers (null);
7674 Indexers (ArrayList array)
7679 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7684 foreach (PropertyInfo property in mi){
7685 MethodInfo get, set;
7687 get = property.GetGetMethod (true);
7688 set = property.GetSetMethod (true);
7689 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7691 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7693 if (get != null || set != null) {
7695 ix = new Indexers (new ArrayList ());
7696 ix.Properties.Add (new Indexer (property, get, set));
7701 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7703 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7705 return TypeManager.MemberLookup (
7706 caller_type, caller_type, lookup_type, MemberTypes.Property,
7707 BindingFlags.Public | BindingFlags.Instance |
7708 BindingFlags.DeclaredOnly, p_name, null);
7711 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7713 Indexers ix = empty;
7716 if (lookup_type.IsGenericParameter) {
7717 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7721 if (gc.HasClassConstraint)
7722 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7724 Type[] ifaces = gc.InterfaceConstraints;
7725 foreach (Type itype in ifaces)
7726 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7732 Type copy = lookup_type;
7733 while (copy != TypeManager.object_type && copy != null){
7734 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7735 copy = copy.BaseType;
7738 if (lookup_type.IsInterface) {
7739 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7740 if (ifaces != null) {
7741 foreach (Type itype in ifaces)
7742 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7751 /// Expressions that represent an indexer call.
7753 public class IndexerAccess : Expression, IAssignMethod {
7755 // Points to our "data" repository
7757 MethodInfo get, set;
7758 ArrayList set_arguments;
7759 bool is_base_indexer;
7761 protected Type indexer_type;
7762 protected Type current_type;
7763 protected Expression instance_expr;
7764 protected ArrayList arguments;
7766 public IndexerAccess (ElementAccess ea, Location loc)
7767 : this (ea.Expr, false, loc)
7769 this.arguments = ea.Arguments;
7772 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7775 this.instance_expr = instance_expr;
7776 this.is_base_indexer = is_base_indexer;
7777 this.eclass = ExprClass.Value;
7781 protected virtual bool CommonResolve (EmitContext ec)
7783 indexer_type = instance_expr.Type;
7784 current_type = ec.ContainerType;
7789 public override Expression DoResolve (EmitContext ec)
7791 if (!CommonResolve (ec))
7795 // Step 1: Query for all `Item' *properties*. Notice
7796 // that the actual methods are pointed from here.
7798 // This is a group of properties, piles of them.
7800 ArrayList AllGetters = null;
7802 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7803 if (ilist.Properties != null) {
7804 AllGetters = new ArrayList(ilist.Properties.Count);
7805 foreach (Indexers.Indexer ix in ilist.Properties) {
7806 if (ix.Getter != null)
7807 AllGetters.Add (ix.Getter);
7811 if (AllGetters == null) {
7812 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7813 TypeManager.CSharpName (indexer_type));
7817 if (AllGetters.Count == 0) {
7818 // FIXME: we cannot simply select first one as the error message is missleading when
7819 // multiple indexers exist
7820 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7821 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7822 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7826 get = (MethodInfo)new MethodGroupExpr (AllGetters, type, loc).OverloadResolve (ec,
7827 arguments, false, loc);
7830 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7835 // Only base will allow this invocation to happen.
7837 if (get.IsAbstract && this is BaseIndexerAccess){
7838 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7842 type = get.ReturnType;
7843 if (type.IsPointer && !ec.InUnsafe){
7848 instance_expr.CheckMarshalByRefAccess ();
7850 eclass = ExprClass.IndexerAccess;
7854 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7856 if (right_side == EmptyExpression.OutAccess) {
7857 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7858 GetSignatureForError ());
7862 // if the indexer returns a value type, and we try to set a field in it
7863 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7864 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7865 GetSignatureForError ());
7869 ArrayList AllSetters = new ArrayList();
7870 if (!CommonResolve (ec))
7873 bool found_any = false, found_any_setters = false;
7875 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7876 if (ilist.Properties != null) {
7878 foreach (Indexers.Indexer ix in ilist.Properties) {
7879 if (ix.Setter != null)
7880 AllSetters.Add (ix.Setter);
7883 if (AllSetters.Count > 0) {
7884 found_any_setters = true;
7885 set_arguments = (ArrayList) arguments.Clone ();
7886 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7887 set = (MethodInfo)(new MethodGroupExpr (AllSetters, type, loc)).OverloadResolve (
7889 set_arguments, false, loc);
7893 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7894 TypeManager.CSharpName (indexer_type));
7898 if (!found_any_setters) {
7899 Error (154, "indexer can not be used in this context, because " +
7900 "it lacks a `set' accessor");
7905 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7910 // Only base will allow this invocation to happen.
7912 if (set.IsAbstract && this is BaseIndexerAccess){
7913 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7918 // Now look for the actual match in the list of indexers to set our "return" type
7920 type = TypeManager.void_type; // default value
7921 foreach (Indexers.Indexer ix in ilist.Properties){
7922 if (ix.Setter == set){
7923 type = ix.PropertyInfo.PropertyType;
7928 instance_expr.CheckMarshalByRefAccess ();
7930 eclass = ExprClass.IndexerAccess;
7934 bool prepared = false;
7935 LocalTemporary temp;
7937 public void Emit (EmitContext ec, bool leave_copy)
7939 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7941 ec.ig.Emit (OpCodes.Dup);
7942 temp = new LocalTemporary (Type);
7948 // source is ignored, because we already have a copy of it from the
7949 // LValue resolution and we have already constructed a pre-cached
7950 // version of the arguments (ea.set_arguments);
7952 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7954 prepared = prepare_for_load;
7955 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7960 ec.ig.Emit (OpCodes.Dup);
7961 temp = new LocalTemporary (Type);
7964 } else if (leave_copy) {
7965 temp = new LocalTemporary (Type);
7971 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7980 public override void Emit (EmitContext ec)
7985 public override string GetSignatureForError ()
7987 // FIXME: print the argument list of the indexer
7988 return instance_expr.GetSignatureForError () + ".this[...]";
7991 protected override void CloneTo (CloneContext clonectx, Expression t)
7993 IndexerAccess target = (IndexerAccess) t;
7995 if (arguments != null){
7996 target.arguments = new ArrayList ();
7997 foreach (Argument a in arguments)
7998 target.arguments.Add (a.Clone (clonectx));
8000 if (instance_expr != null)
8001 target.instance_expr = instance_expr.Clone (clonectx);
8006 /// The base operator for method names
8008 public class BaseAccess : Expression {
8009 public readonly string Identifier;
8012 public BaseAccess (string member, Location l)
8014 this.Identifier = member;
8018 public BaseAccess (string member, TypeArguments args, Location l)
8024 public override Expression DoResolve (EmitContext ec)
8026 Expression c = CommonResolve (ec);
8032 // MethodGroups use this opportunity to flag an error on lacking ()
8034 if (!(c is MethodGroupExpr))
8035 return c.Resolve (ec);
8039 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8041 Expression c = CommonResolve (ec);
8047 // MethodGroups use this opportunity to flag an error on lacking ()
8049 if (! (c is MethodGroupExpr))
8050 return c.DoResolveLValue (ec, right_side);
8055 Expression CommonResolve (EmitContext ec)
8057 Expression member_lookup;
8058 Type current_type = ec.ContainerType;
8059 Type base_type = current_type.BaseType;
8062 Error (1511, "Keyword `base' is not available in a static method");
8066 if (ec.IsFieldInitializer){
8067 Error (1512, "Keyword `base' is not available in the current context");
8071 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8072 AllMemberTypes, AllBindingFlags, loc);
8073 if (member_lookup == null) {
8074 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8075 null, AllMemberTypes, AllBindingFlags, loc);
8082 left = new TypeExpression (base_type, loc);
8084 left = ec.GetThis (loc);
8086 MemberExpr me = (MemberExpr) member_lookup;
8088 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8090 if (e is PropertyExpr) {
8091 PropertyExpr pe = (PropertyExpr) e;
8093 } else if (e is EventExpr) {
8094 EventExpr ee = (EventExpr) e;
8098 MethodGroupExpr mg = e as MethodGroupExpr;
8104 return mg.ResolveGeneric (ec, args);
8106 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8114 public override void Emit (EmitContext ec)
8116 throw new Exception ("Should never be called");
8119 protected override void CloneTo (CloneContext clonectx, Expression t)
8121 BaseAccess target = (BaseAccess) t;
8123 target.args = args.Clone ();
8128 /// The base indexer operator
8130 public class BaseIndexerAccess : IndexerAccess {
8131 public BaseIndexerAccess (ArrayList args, Location loc)
8132 : base (null, true, loc)
8134 arguments = new ArrayList ();
8135 foreach (Expression tmp in args)
8136 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8139 protected override bool CommonResolve (EmitContext ec)
8141 instance_expr = ec.GetThis (loc);
8143 current_type = ec.ContainerType.BaseType;
8144 indexer_type = current_type;
8146 foreach (Argument a in arguments){
8147 if (!a.Resolve (ec, loc))
8156 /// This class exists solely to pass the Type around and to be a dummy
8157 /// that can be passed to the conversion functions (this is used by
8158 /// foreach implementation to typecast the object return value from
8159 /// get_Current into the proper type. All code has been generated and
8160 /// we only care about the side effect conversions to be performed
8162 /// This is also now used as a placeholder where a no-action expression
8163 /// is needed (the `New' class).
8165 public class EmptyExpression : Expression {
8166 public static readonly EmptyExpression Null = new EmptyExpression ();
8168 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8169 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8170 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8172 static EmptyExpression temp = new EmptyExpression ();
8173 public static EmptyExpression Grab ()
8175 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8180 public static void Release (EmptyExpression e)
8185 // TODO: should be protected
8186 public EmptyExpression ()
8188 type = TypeManager.object_type;
8189 eclass = ExprClass.Value;
8190 loc = Location.Null;
8193 public EmptyExpression (Type t)
8196 eclass = ExprClass.Value;
8197 loc = Location.Null;
8200 public override Expression DoResolve (EmitContext ec)
8205 public override void Emit (EmitContext ec)
8207 // nothing, as we only exist to not do anything.
8211 // This is just because we might want to reuse this bad boy
8212 // instead of creating gazillions of EmptyExpressions.
8213 // (CanImplicitConversion uses it)
8215 public void SetType (Type t)
8222 // Empty statement expression
8224 public sealed class EmptyExpressionStatement : ExpressionStatement
8226 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8228 private EmptyExpressionStatement ()
8230 type = TypeManager.object_type;
8231 eclass = ExprClass.Value;
8232 loc = Location.Null;
8235 public override void EmitStatement (EmitContext ec)
8240 public override Expression DoResolve (EmitContext ec)
8245 public override void Emit (EmitContext ec)
8251 public class UserCast : Expression {
8255 public UserCast (MethodInfo method, Expression source, Location l)
8257 this.method = method;
8258 this.source = source;
8259 type = method.ReturnType;
8260 eclass = ExprClass.Value;
8264 public Expression Source {
8270 public override Expression DoResolve (EmitContext ec)
8273 // We are born fully resolved
8278 public override void Emit (EmitContext ec)
8280 ILGenerator ig = ec.ig;
8284 if (method is MethodInfo)
8285 ig.Emit (OpCodes.Call, (MethodInfo) method);
8287 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8293 // This class is used to "construct" the type during a typecast
8294 // operation. Since the Type.GetType class in .NET can parse
8295 // the type specification, we just use this to construct the type
8296 // one bit at a time.
8298 public class ComposedCast : TypeExpr {
8302 public ComposedCast (Expression left, string dim)
8303 : this (left, dim, left.Location)
8307 public ComposedCast (Expression left, string dim, Location l)
8315 public Expression RemoveNullable ()
8317 if (dim.EndsWith ("?")) {
8318 dim = dim.Substring (0, dim.Length - 1);
8327 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8329 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8333 Type ltype = lexpr.Type;
8334 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8335 Error_VoidInvalidInTheContext (loc);
8340 if ((dim.Length > 0) && (dim [0] == '?')) {
8341 TypeExpr nullable = new NullableType (left, loc);
8343 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8344 return nullable.ResolveAsTypeTerminal (ec, false);
8348 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8351 if (dim != "" && dim [0] == '[' &&
8352 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8353 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8358 type = TypeManager.GetConstructedType (ltype, dim);
8363 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8365 if (type.IsPointer && !ec.IsInUnsafeScope){
8370 eclass = ExprClass.Type;
8374 public override string Name {
8375 get { return left + dim; }
8378 public override string FullName {
8379 get { return type.FullName; }
8382 public override string GetSignatureForError ()
8384 return left.GetSignatureForError () + dim;
8387 protected override void CloneTo (CloneContext clonectx, Expression t)
8389 ComposedCast target = (ComposedCast) t;
8391 target.left = left.Clone (clonectx);
8395 public class FixedBufferPtr : Expression {
8398 public FixedBufferPtr (Expression array, Type array_type, Location l)
8403 type = TypeManager.GetPointerType (array_type);
8404 eclass = ExprClass.Value;
8407 public override void Emit(EmitContext ec)
8412 public override Expression DoResolve (EmitContext ec)
8415 // We are born fully resolved
8423 // This class is used to represent the address of an array, used
8424 // only by the Fixed statement, this generates "&a [0]" construct
8425 // for fixed (char *pa = a)
8427 public class ArrayPtr : FixedBufferPtr {
8430 public ArrayPtr (Expression array, Type array_type, Location l):
8431 base (array, array_type, l)
8433 this.array_type = array_type;
8436 public override void Emit (EmitContext ec)
8440 ILGenerator ig = ec.ig;
8441 IntLiteral.EmitInt (ig, 0);
8442 ig.Emit (OpCodes.Ldelema, array_type);
8447 // Used by the fixed statement
8449 public class StringPtr : Expression {
8452 public StringPtr (LocalBuilder b, Location l)
8455 eclass = ExprClass.Value;
8456 type = TypeManager.char_ptr_type;
8460 public override Expression DoResolve (EmitContext ec)
8462 // This should never be invoked, we are born in fully
8463 // initialized state.
8468 public override void Emit (EmitContext ec)
8470 ILGenerator ig = ec.ig;
8472 ig.Emit (OpCodes.Ldloc, b);
8473 ig.Emit (OpCodes.Conv_I);
8474 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8475 ig.Emit (OpCodes.Add);
8480 // Implements the `stackalloc' keyword
8482 public class StackAlloc : Expression {
8487 public StackAlloc (Expression type, Expression count, Location l)
8494 public override Expression DoResolve (EmitContext ec)
8496 count = count.Resolve (ec);
8500 if (count.Type != TypeManager.int32_type){
8501 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8506 Constant c = count as Constant;
8507 if (c != null && c.IsNegative) {
8508 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8512 if (ec.InCatch || ec.InFinally) {
8513 Error (255, "Cannot use stackalloc in finally or catch");
8517 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8523 if (!TypeManager.VerifyUnManaged (otype, loc))
8526 type = TypeManager.GetPointerType (otype);
8527 eclass = ExprClass.Value;
8532 public override void Emit (EmitContext ec)
8534 int size = GetTypeSize (otype);
8535 ILGenerator ig = ec.ig;
8538 ig.Emit (OpCodes.Sizeof, otype);
8540 IntConstant.EmitInt (ig, size);
8542 ig.Emit (OpCodes.Mul);
8543 ig.Emit (OpCodes.Localloc);
8546 protected override void CloneTo (CloneContext clonectx, Expression t)
8548 StackAlloc target = (StackAlloc) t;
8549 target.count = count.Clone (clonectx);
8550 target.t = t.Clone (clonectx);
8555 // An object initializer expression
8557 public class ElementInitializer : Expression
8559 Expression initializer;
8560 public readonly string Name;
8562 public ElementInitializer (string name, Expression initializer, Location loc)
8565 this.initializer = initializer;
8569 protected override void CloneTo (CloneContext clonectx, Expression t)
8571 if (initializer == null)
8574 ElementInitializer target = (ElementInitializer) t;
8575 target.initializer = initializer.Clone (clonectx);
8578 public override Expression DoResolve (EmitContext ec)
8580 if (initializer == null)
8581 return EmptyExpressionStatement.Instance;
8583 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8584 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8586 if (element_member == null)
8589 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8591 if (initializer is CollectionOrObjectInitializers) {
8592 Expression previous = ec.CurrentInitializerVariable;
8593 ec.CurrentInitializerVariable = element_member;
8594 initializer = initializer.Resolve (ec);
8595 ec.CurrentInitializerVariable = previous;
8599 return new Assign (element_member, initializer, loc).Resolve (ec);
8602 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8604 MemberInfo member = members [0];
8605 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8606 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8607 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8609 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8610 TypeManager.GetFullNameSignature (member));
8615 public override void Emit (EmitContext ec)
8617 throw new NotSupportedException ("Should not be reached");
8622 // A collection initializer expression
8624 public class CollectionElementInitializer : Expression
8626 public class ElementInitializerArgument : Argument
8628 public ElementInitializerArgument (Expression e)
8634 ArrayList arguments;
8636 public CollectionElementInitializer (Expression argument)
8638 arguments = new ArrayList (1);
8639 arguments.Add (argument);
8640 this.loc = argument.Location;
8643 public CollectionElementInitializer (ArrayList arguments, Location loc)
8645 this.arguments = arguments;
8649 protected override void CloneTo (CloneContext clonectx, Expression t)
8651 CollectionElementInitializer target = (CollectionElementInitializer) t;
8652 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8653 foreach (Expression e in arguments)
8654 t_arguments.Add (e.Clone (clonectx));
8657 public override Expression DoResolve (EmitContext ec)
8659 // TODO: We should call a constructor which takes element counts argument,
8660 // for know types like List<T>, Dictionary<T, U>
8662 for (int i = 0; i < arguments.Count; ++i)
8663 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8665 Expression add_method = new Invocation (
8666 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8669 add_method = add_method.Resolve (ec);
8674 public override void Emit (EmitContext ec)
8676 throw new NotSupportedException ("Should not be reached");
8681 // A block of object or collection initializers
8683 public class CollectionOrObjectInitializers : ExpressionStatement
8685 ArrayList initializers;
8687 public static readonly CollectionOrObjectInitializers Empty =
8688 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8690 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8692 this.initializers = initializers;
8696 public bool IsEmpty {
8698 return initializers.Count == 0;
8702 protected override void CloneTo (CloneContext clonectx, Expression target)
8704 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8706 t.initializers = new ArrayList (initializers.Count);
8707 foreach (Expression e in initializers)
8708 t.initializers.Add (e.Clone (clonectx));
8711 public override Expression DoResolve (EmitContext ec)
8713 bool is_elements_initialization = false;
8714 ArrayList element_names = null;
8715 for (int i = 0; i < initializers.Count; ++i) {
8716 Expression initializer = (Expression) initializers [i];
8717 ElementInitializer element_initializer = initializer as ElementInitializer;
8720 if (element_initializer != null) {
8721 is_elements_initialization = true;
8722 element_names = new ArrayList (initializers.Count);
8723 element_names.Add (element_initializer.Name);
8725 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8726 TypeManager.ienumerable_type)) {
8727 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8728 "object initializer because type `{1}' does not implement `{2}' interface",
8729 ec.CurrentInitializerVariable.GetSignatureForError (),
8730 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8731 TypeManager.CSharpName (TypeManager.ienumerable_type));
8736 if (is_elements_initialization == (element_initializer == null)) {
8737 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8738 is_elements_initialization ? "object initializer" : "collection initializer");
8742 if (is_elements_initialization) {
8743 if (element_names.Contains (element_initializer.Name)) {
8744 Report.Error (1912, element_initializer.Location,
8745 "An object initializer includes more than one member `{0}' initialization",
8746 element_initializer.Name);
8748 element_names.Add (element_initializer.Name);
8753 initializers [i] = initializer.Resolve (ec);
8756 type = typeof (CollectionOrObjectInitializers);
8757 eclass = ExprClass.Variable;
8761 public override void Emit (EmitContext ec)
8766 public override void EmitStatement (EmitContext ec)
8768 foreach (ExpressionStatement e in initializers)
8769 e.EmitStatement (ec);
8774 // New expression with element/object initializers
8776 public class NewInitialize : New
8778 CollectionOrObjectInitializers initializers;
8779 TemporaryVariable type_instance;
8781 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8782 : base (requested_type, arguments, l)
8784 this.initializers = initializers;
8787 protected override void CloneTo (CloneContext clonectx, Expression t)
8789 base.CloneTo (clonectx, t);
8791 NewInitialize target = (NewInitialize) t;
8792 target.initializers = (CollectionOrObjectInitializers)initializers.Clone (clonectx);
8795 public override Expression DoResolve (EmitContext ec)
8797 Expression e = base.DoResolve (ec);
8801 // Empty initializer can be optimized to simple new
8802 if (initializers.IsEmpty)
8805 type_instance = new TemporaryVariable (type, loc);
8806 type_instance = (TemporaryVariable)type_instance.Resolve (ec);
8808 Expression previous = ec.CurrentInitializerVariable;
8809 ec.CurrentInitializerVariable = type_instance;
8810 initializers.Resolve (ec);
8811 ec.CurrentInitializerVariable = previous;
8815 public override void Emit (EmitContext ec)
8819 type_instance.EmitStore (ec);
8820 initializers.Emit (ec);
8821 type_instance.Emit (ec);
8825 public class AnonymousTypeDeclaration : Expression
8827 ArrayList parameters;
8828 readonly TypeContainer parent;
8829 static readonly ArrayList EmptyParameters = new ArrayList (0);
8831 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8833 this.parameters = parameters;
8834 this.parent = parent;
8838 protected override void CloneTo (CloneContext clonectx, Expression target)
8840 if (parameters == null)
8843 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
8844 t.parameters = new ArrayList (parameters.Count);
8845 foreach (AnonymousTypeParameter atp in parameters)
8846 t.parameters.Add (atp.Clone (clonectx));
8849 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
8851 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8855 type = AnonymousTypeClass.Create (parent, parameters, loc);
8860 type.DefineMembers ();
8864 RootContext.ToplevelTypes.AddAnonymousType (type);
8868 public override Expression DoResolve (EmitContext ec)
8870 AnonymousTypeClass anonymous_type;
8872 if (parameters == null) {
8873 anonymous_type = CreateAnonymousType (EmptyParameters);
8874 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
8875 null, loc).Resolve (ec);
8879 ArrayList arguments = new ArrayList (parameters.Count);
8880 TypeExpression [] t_args = new TypeExpression [parameters.Count];
8881 for (int i = 0; i < parameters.Count; ++i) {
8882 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
8888 arguments.Add (new Argument (e));
8889 t_args [i] = new TypeExpression (e.Type, e.Location);
8895 anonymous_type = CreateAnonymousType (parameters);
8896 if (anonymous_type == null)
8899 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8900 new TypeArguments (loc, t_args), loc);
8902 return new New (te, arguments, loc).Resolve (ec);
8905 public override void Emit (EmitContext ec)
8907 throw new InternalErrorException ("Should not be reached");
8911 public class AnonymousTypeParameter : Expression
8913 public readonly string Name;
8914 Expression initializer;
8916 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8920 this.initializer = initializer;
8923 public AnonymousTypeParameter (Parameter parameter)
8925 this.Name = parameter.Name;
8926 this.loc = parameter.Location;
8927 this.initializer = new SimpleName (Name, loc);
8930 protected override void CloneTo (CloneContext clonectx, Expression target)
8932 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
8933 t.initializer = initializer.Clone (clonectx);
8936 public override bool Equals (object o)
8938 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8939 return other != null && Name == other.Name;
8942 public override int GetHashCode ()
8944 return Name.GetHashCode ();
8947 public override Expression DoResolve (EmitContext ec)
8949 Expression e = initializer.Resolve (ec);
8954 if (type == TypeManager.void_type || type == TypeManager.null_type ||
8955 type == TypeManager.anonymous_method_type || type.IsPointer) {
8956 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8957 Name, e.GetSignatureForError ());
8964 public override void Emit (EmitContext ec)
8966 throw new InternalErrorException ("Should not be reached");