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 an user operator expression, automatically created during
24 public class UserOperatorCall : Expression {
25 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
27 readonly ArrayList arguments;
28 readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, ArrayList args, ExpressionTreeExpression expr_tree, Location loc)
34 this.arguments = args;
35 this.expr_tree = expr_tree;
37 type = ((MethodInfo)mg).ReturnType;
38 eclass = ExprClass.Value;
42 public override Expression CreateExpressionTree (EmitContext ec)
44 if (expr_tree != null)
45 return expr_tree (ec, mg);
47 ArrayList args = new ArrayList (arguments.Count + 1);
48 args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
49 args.Add (new Argument (mg.CreateExpressionTree (ec)));
50 foreach (Argument a in arguments) {
51 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
54 return CreateExpressionFactoryCall ("Call", args);
57 public override Expression DoResolve (EmitContext ec)
60 // We are born fully resolved
65 public override void Emit (EmitContext ec)
67 mg.EmitCall (ec, arguments);
70 [Obsolete ("It may not be compatible with expression trees")]
71 static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
72 Expression e, Location loc)
76 args = new ArrayList (1);
77 Argument a = new Argument (e, Argument.AType.Expression);
79 // We need to resolve the arguments before sending them in !
80 if (!a.Resolve (ec, loc))
84 mg = mg.OverloadResolve (ec, ref args, false, loc);
89 return new UserOperatorCall (mg, args, null, loc);
92 public MethodGroupExpr Method {
97 public class ParenthesizedExpression : Expression
99 public Expression Expr;
101 public ParenthesizedExpression (Expression expr)
106 public override Expression DoResolve (EmitContext ec)
108 Expr = Expr.Resolve (ec);
112 public override void Emit (EmitContext ec)
114 throw new Exception ("Should not happen");
117 public override Location Location
120 return Expr.Location;
124 protected override void CloneTo (CloneContext clonectx, Expression t)
126 ParenthesizedExpression target = (ParenthesizedExpression) t;
128 target.Expr = Expr.Clone (clonectx);
133 // Unary implements unary expressions.
135 public class Unary : Expression {
136 public enum Operator : byte {
137 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
138 Indirection, AddressOf, TOP
141 public readonly Operator Oper;
142 public Expression Expr;
144 public Unary (Operator op, Expression expr, Location loc)
152 /// Returns a stringified representation of the Operator
154 static public string OperName (Operator oper)
157 case Operator.UnaryPlus:
159 case Operator.UnaryNegation:
161 case Operator.LogicalNot:
163 case Operator.OnesComplement:
165 case Operator.AddressOf:
167 case Operator.Indirection:
171 return oper.ToString ();
174 public static readonly string [] oper_names;
178 oper_names = new string [(int)Operator.TOP];
180 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
181 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
182 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
183 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
184 oper_names [(int) Operator.Indirection] = "op_Indirection";
185 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
188 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
190 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
193 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
195 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
199 void Error23 (Type t)
201 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
205 // This routine will attempt to simplify the unary expression when the
206 // argument is a constant.
208 Constant TryReduceConstant (EmitContext ec, Constant e)
210 Type expr_type = e.Type;
213 case Operator.UnaryPlus:
214 // Unary numeric promotions
215 if (expr_type == TypeManager.byte_type)
216 return new IntConstant (((ByteConstant)e).Value, e.Location);
217 if (expr_type == TypeManager.sbyte_type)
218 return new IntConstant (((SByteConstant)e).Value, e.Location);
219 if (expr_type == TypeManager.short_type)
220 return new IntConstant (((ShortConstant)e).Value, e.Location);
221 if (expr_type == TypeManager.ushort_type)
222 return new IntConstant (((UShortConstant)e).Value, e.Location);
223 if (expr_type == TypeManager.char_type)
224 return new IntConstant (((CharConstant)e).Value, e.Location);
226 // Predefined operators
227 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
228 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
229 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
230 expr_type == TypeManager.decimal_type)
237 case Operator.UnaryNegation:
238 // Unary numeric promotions
239 if (expr_type == TypeManager.byte_type)
240 return new IntConstant (-((ByteConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.sbyte_type)
242 return new IntConstant (-((SByteConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.short_type)
244 return new IntConstant (-((ShortConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.ushort_type)
246 return new IntConstant (-((UShortConstant)e).Value, e.Location);
247 if (expr_type == TypeManager.char_type)
248 return new IntConstant (-((CharConstant)e).Value, e.Location);
250 // Predefined operators
251 if (expr_type == TypeManager.int32_type) {
252 int value = ((IntConstant)e).Value;
253 if (value == int.MinValue) {
254 if (ec.ConstantCheckState) {
255 ConstantFold.Error_CompileTimeOverflow (loc);
260 return new IntConstant (-value, e.Location);
262 if (expr_type == TypeManager.int64_type) {
263 long value = ((LongConstant)e).Value;
264 if (value == long.MinValue) {
265 if (ec.ConstantCheckState) {
266 ConstantFold.Error_CompileTimeOverflow (loc);
271 return new LongConstant (-value, e.Location);
274 if (expr_type == TypeManager.uint32_type) {
275 UIntLiteral uil = e as UIntLiteral;
277 if (uil.Value == 2147483648)
278 return new IntLiteral (int.MinValue, e.Location);
279 return new LongLiteral (-uil.Value, e.Location);
281 return new LongConstant (-((UIntConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.uint64_type) {
285 ULongLiteral ull = e as ULongLiteral;
286 if (ull != null && ull.Value == 9223372036854775808)
287 return new LongLiteral (long.MinValue, e.Location);
291 if (expr_type == TypeManager.float_type) {
292 FloatLiteral fl = e as FloatLiteral;
293 // For better error reporting
295 fl.Value = -fl.Value;
298 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
300 if (expr_type == TypeManager.double_type) {
301 DoubleLiteral dl = e as DoubleLiteral;
302 // For better error reporting
304 dl.Value = -dl.Value;
308 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
310 if (expr_type == TypeManager.decimal_type)
311 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
315 case Operator.LogicalNot:
316 if (expr_type != TypeManager.bool_type)
319 BoolConstant b = (BoolConstant) e;
320 return new BoolConstant (!(b.Value), b.Location);
322 case Operator.OnesComplement:
323 // Unary numeric promotions
324 if (expr_type == TypeManager.byte_type)
325 return new IntConstant (~((ByteConstant)e).Value, e.Location);
326 if (expr_type == TypeManager.sbyte_type)
327 return new IntConstant (~((SByteConstant)e).Value, e.Location);
328 if (expr_type == TypeManager.short_type)
329 return new IntConstant (~((ShortConstant)e).Value, e.Location);
330 if (expr_type == TypeManager.ushort_type)
331 return new IntConstant (~((UShortConstant)e).Value, e.Location);
332 if (expr_type == TypeManager.char_type)
333 return new IntConstant (~((CharConstant)e).Value, e.Location);
335 // Predefined operators
336 if (expr_type == TypeManager.int32_type)
337 return new IntConstant (~((IntConstant)e).Value, e.Location);
338 if (expr_type == TypeManager.uint32_type)
339 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
340 if (expr_type == TypeManager.int64_type)
341 return new LongConstant (~((LongConstant)e).Value, e.Location);
342 if (expr_type == TypeManager.uint64_type){
343 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
345 if (e is EnumConstant) {
346 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
348 e = new EnumConstant (e, expr_type);
353 case Operator.AddressOf:
356 case Operator.Indirection:
359 throw new Exception ("Can not constant fold: " + Oper.ToString());
362 Expression ResolveOperator (EmitContext ec)
365 // Step 1: Default operations on CLI native types.
368 // Attempt to use a constant folding operation.
369 Constant cexpr = Expr as Constant;
371 cexpr = TryReduceConstant (ec, cexpr);
378 // Step 2: Perform Operator Overload location
380 Type expr_type = Expr.Type;
381 string op_name = oper_names [(int) Oper];
383 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
384 if (user_op != null) {
385 ArrayList args = new ArrayList (1);
386 args.Add (new Argument (Expr));
387 user_op = user_op.OverloadResolve (ec, ref args, false, loc);
389 if (user_op == null) {
394 return new UserOperatorCall (user_op, args, CreateExpressionTree, loc);
398 case Operator.LogicalNot:
399 if (expr_type != TypeManager.bool_type) {
400 Expr = ResolveBoolean (ec, Expr, loc);
407 type = TypeManager.bool_type;
410 case Operator.OnesComplement:
411 // Unary numeric promotions
412 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
413 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
414 expr_type == TypeManager.char_type)
416 type = TypeManager.int32_type;
417 return EmptyCast.Create (this, type);
420 // Predefined operators
421 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
422 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
423 TypeManager.IsEnumType (expr_type))
429 type = TypeManager.int32_type;
430 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
437 case Operator.AddressOf:
443 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
447 IVariable variable = Expr as IVariable;
448 bool is_fixed = variable != null && variable.VerifyFixed ();
450 if (!ec.InFixedInitializer && !is_fixed) {
451 Error (212, "You can only take the address of unfixed expression inside " +
452 "of a fixed statement initializer");
456 if (ec.InFixedInitializer && is_fixed) {
457 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
461 LocalVariableReference lr = Expr as LocalVariableReference;
463 if (lr.local_info.IsCaptured){
464 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
467 lr.local_info.AddressTaken = true;
468 lr.local_info.Used = true;
471 ParameterReference pr = Expr as ParameterReference;
472 if ((pr != null) && pr.Parameter.IsCaptured) {
473 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
477 // According to the specs, a variable is considered definitely assigned if you take
479 if ((variable != null) && (variable.VariableInfo != null)){
480 variable.VariableInfo.SetAssigned (ec);
483 type = TypeManager.GetPointerType (Expr.Type);
486 case Operator.Indirection:
492 if (!expr_type.IsPointer){
493 Error (193, "The * or -> operator must be applied to a pointer");
498 // We create an Indirection expression, because
499 // it can implement the IMemoryLocation.
501 return new Indirection (Expr, loc);
503 case Operator.UnaryPlus:
504 // Unary numeric promotions
505 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
506 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
507 expr_type == TypeManager.char_type)
509 return EmptyCast.Create (Expr, TypeManager.int32_type);
512 // Predefined operators
513 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
514 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
515 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
516 expr_type == TypeManager.decimal_type)
521 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
523 // Because we can completely ignore unary +
530 case Operator.UnaryNegation:
532 // transform - - expr into expr
534 Unary u = Expr as Unary;
535 if (u != null && u.Oper == Operator.UnaryNegation) {
539 // Unary numeric promotions
540 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
541 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
542 expr_type == TypeManager.char_type)
544 type = TypeManager.int32_type;
545 return EmptyCast.Create (this, type);
549 // Predefined operators
551 if (expr_type == TypeManager.uint32_type) {
552 type = TypeManager.int64_type;
553 Expr = Convert.ImplicitNumericConversion (Expr, type);
557 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
558 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
559 expr_type == TypeManager.decimal_type)
568 type = TypeManager.int32_type;
569 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
577 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
578 TypeManager.CSharpName (expr_type) + "'");
582 public override Expression CreateExpressionTree (EmitContext ec)
584 return CreateExpressionTree (ec, null);
587 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
591 case Operator.UnaryNegation:
592 method_name = "Negate";
596 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
599 ArrayList args = new ArrayList (2);
600 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
602 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
603 return CreateExpressionFactoryCall (method_name, args);
606 public override Expression DoResolve (EmitContext ec)
608 if (Oper == Operator.AddressOf) {
609 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
611 if (Expr == null || Expr.eclass != ExprClass.Variable){
612 Error (211, "Cannot take the address of the given expression");
617 Expr = Expr.Resolve (ec);
623 if (TypeManager.IsNullableValueType (Expr.Type))
624 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
627 eclass = ExprClass.Value;
628 return ResolveOperator (ec);
631 public override Expression DoResolveLValue (EmitContext ec, Expression right)
633 if (Oper == Operator.Indirection)
634 return DoResolve (ec);
639 public override void Emit (EmitContext ec)
641 ILGenerator ig = ec.ig;
644 case Operator.UnaryPlus:
645 throw new Exception ("This should be caught by Resolve");
647 case Operator.UnaryNegation:
648 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
649 ig.Emit (OpCodes.Ldc_I4_0);
650 if (type == TypeManager.int64_type)
651 ig.Emit (OpCodes.Conv_U8);
653 ig.Emit (OpCodes.Sub_Ovf);
656 ig.Emit (OpCodes.Neg);
661 case Operator.LogicalNot:
663 ig.Emit (OpCodes.Ldc_I4_0);
664 ig.Emit (OpCodes.Ceq);
667 case Operator.OnesComplement:
669 ig.Emit (OpCodes.Not);
672 case Operator.AddressOf:
673 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
677 throw new Exception ("This should not happen: Operator = "
682 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
684 if (Oper == Operator.LogicalNot)
685 Expr.EmitBranchable (ec, target, !on_true);
687 base.EmitBranchable (ec, target, on_true);
690 public override string ToString ()
692 return "Unary (" + Oper + ", " + Expr + ")";
695 protected override void CloneTo (CloneContext clonectx, Expression t)
697 Unary target = (Unary) t;
699 target.Expr = Expr.Clone (clonectx);
704 // Unary operators are turned into Indirection expressions
705 // after semantic analysis (this is so we can take the address
706 // of an indirection).
708 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
710 LocalTemporary temporary;
713 public Indirection (Expression expr, Location l)
716 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
717 eclass = ExprClass.Variable;
721 public override void Emit (EmitContext ec)
726 LoadFromPtr (ec.ig, Type);
729 public void Emit (EmitContext ec, bool leave_copy)
733 ec.ig.Emit (OpCodes.Dup);
734 temporary = new LocalTemporary (expr.Type);
735 temporary.Store (ec);
739 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
741 prepared = prepare_for_load;
745 if (prepare_for_load)
746 ec.ig.Emit (OpCodes.Dup);
750 ec.ig.Emit (OpCodes.Dup);
751 temporary = new LocalTemporary (expr.Type);
752 temporary.Store (ec);
755 StoreFromPtr (ec.ig, type);
757 if (temporary != null) {
759 temporary.Release (ec);
763 public void AddressOf (EmitContext ec, AddressOp Mode)
768 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
770 return DoResolve (ec);
773 public override Expression DoResolve (EmitContext ec)
776 // Born fully resolved
781 public override string ToString ()
783 return "*(" + expr + ")";
786 #region IVariable Members
788 public VariableInfo VariableInfo {
792 public bool VerifyFixed ()
794 // A pointer-indirection is always fixed.
802 /// Unary Mutator expressions (pre and post ++ and --)
806 /// UnaryMutator implements ++ and -- expressions. It derives from
807 /// ExpressionStatement becuase the pre/post increment/decrement
808 /// operators can be used in a statement context.
810 /// FIXME: Idea, we could split this up in two classes, one simpler
811 /// for the common case, and one with the extra fields for more complex
812 /// classes (indexers require temporary access; overloaded require method)
815 public class UnaryMutator : ExpressionStatement {
817 public enum Mode : byte {
824 PreDecrement = IsDecrement,
825 PostIncrement = IsPost,
826 PostDecrement = IsPost | IsDecrement
830 bool is_expr = false;
831 bool recurse = false;
836 // This is expensive for the simplest case.
838 UserOperatorCall method;
840 public UnaryMutator (Mode m, Expression e, Location l)
847 static string OperName (Mode mode)
849 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
854 /// Returns whether an object of type `t' can be incremented
855 /// or decremented with add/sub (ie, basically whether we can
856 /// use pre-post incr-decr operations on it, but it is not a
857 /// System.Decimal, which we require operator overloading to catch)
859 static bool IsIncrementableNumber (Type t)
861 return (t == TypeManager.sbyte_type) ||
862 (t == TypeManager.byte_type) ||
863 (t == TypeManager.short_type) ||
864 (t == TypeManager.ushort_type) ||
865 (t == TypeManager.int32_type) ||
866 (t == TypeManager.uint32_type) ||
867 (t == TypeManager.int64_type) ||
868 (t == TypeManager.uint64_type) ||
869 (t == TypeManager.char_type) ||
870 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
871 (t == TypeManager.float_type) ||
872 (t == TypeManager.double_type) ||
873 (t.IsPointer && t != TypeManager.void_ptr_type);
876 Expression ResolveOperator (EmitContext ec)
878 Type expr_type = expr.Type;
881 // Step 1: Perform Operator Overload location
886 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
887 op_name = "op_Increment";
889 op_name = "op_Decrement";
891 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
894 method = UserOperatorCall.MakeSimpleCall (
895 ec, (MethodGroupExpr) mg, expr, loc);
898 } else if (!IsIncrementableNumber (expr_type)) {
899 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
900 TypeManager.CSharpName (expr_type) + "'");
905 // The operand of the prefix/postfix increment decrement operators
906 // should be an expression that is classified as a variable,
907 // a property access or an indexer access
910 if (expr.eclass == ExprClass.Variable){
911 LocalVariableReference var = expr as LocalVariableReference;
912 if ((var != null) && var.IsReadOnly) {
913 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
916 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
917 expr = expr.ResolveLValue (ec, this, Location);
921 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
928 public override Expression DoResolve (EmitContext ec)
930 expr = expr.Resolve (ec);
935 eclass = ExprClass.Value;
938 if (TypeManager.IsNullableValueType (expr.Type))
939 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
942 return ResolveOperator (ec);
946 // Loads the proper "1" into the stack based on the type, then it emits the
947 // opcode for the operation requested
949 void LoadOneAndEmitOp (EmitContext ec, Type t)
952 // Measure if getting the typecode and using that is more/less efficient
953 // that comparing types. t.GetTypeCode() is an internal call.
955 ILGenerator ig = ec.ig;
957 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
958 LongConstant.EmitLong (ig, 1);
959 else if (t == TypeManager.double_type)
960 ig.Emit (OpCodes.Ldc_R8, 1.0);
961 else if (t == TypeManager.float_type)
962 ig.Emit (OpCodes.Ldc_R4, 1.0F);
963 else if (t.IsPointer){
964 Type et = TypeManager.GetElementType (t);
965 int n = GetTypeSize (et);
968 ig.Emit (OpCodes.Sizeof, et);
970 IntConstant.EmitInt (ig, n);
972 ig.Emit (OpCodes.Ldc_I4_1);
975 // Now emit the operation
978 if (t == TypeManager.int32_type ||
979 t == TypeManager.int64_type){
980 if ((mode & Mode.IsDecrement) != 0)
981 ig.Emit (OpCodes.Sub_Ovf);
983 ig.Emit (OpCodes.Add_Ovf);
984 } else if (t == TypeManager.uint32_type ||
985 t == TypeManager.uint64_type){
986 if ((mode & Mode.IsDecrement) != 0)
987 ig.Emit (OpCodes.Sub_Ovf_Un);
989 ig.Emit (OpCodes.Add_Ovf_Un);
991 if ((mode & Mode.IsDecrement) != 0)
992 ig.Emit (OpCodes.Sub_Ovf);
994 ig.Emit (OpCodes.Add_Ovf);
997 if ((mode & Mode.IsDecrement) != 0)
998 ig.Emit (OpCodes.Sub);
1000 ig.Emit (OpCodes.Add);
1003 if (t == TypeManager.sbyte_type){
1005 ig.Emit (OpCodes.Conv_Ovf_I1);
1007 ig.Emit (OpCodes.Conv_I1);
1008 } else if (t == TypeManager.byte_type){
1010 ig.Emit (OpCodes.Conv_Ovf_U1);
1012 ig.Emit (OpCodes.Conv_U1);
1013 } else if (t == TypeManager.short_type){
1015 ig.Emit (OpCodes.Conv_Ovf_I2);
1017 ig.Emit (OpCodes.Conv_I2);
1018 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1020 ig.Emit (OpCodes.Conv_Ovf_U2);
1022 ig.Emit (OpCodes.Conv_U2);
1027 void EmitCode (EmitContext ec, bool is_expr)
1030 this.is_expr = is_expr;
1031 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1034 public override void Emit (EmitContext ec)
1037 // We use recurse to allow ourselfs to be the source
1038 // of an assignment. This little hack prevents us from
1039 // having to allocate another expression
1042 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1044 LoadOneAndEmitOp (ec, expr.Type);
1046 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1051 EmitCode (ec, true);
1054 public override void EmitStatement (EmitContext ec)
1056 EmitCode (ec, false);
1059 protected override void CloneTo (CloneContext clonectx, Expression t)
1061 UnaryMutator target = (UnaryMutator) t;
1063 target.expr = expr.Clone (clonectx);
1068 /// Base class for the `Is' and `As' classes.
1072 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1075 public abstract class Probe : Expression {
1076 public Expression ProbeType;
1077 protected Expression expr;
1078 protected TypeExpr probe_type_expr;
1080 public Probe (Expression expr, Expression probe_type, Location l)
1082 ProbeType = probe_type;
1087 public Expression Expr {
1093 public override Expression DoResolve (EmitContext ec)
1095 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1096 if (probe_type_expr == null)
1099 expr = expr.Resolve (ec);
1103 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1104 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1109 if (expr.Type == TypeManager.anonymous_method_type) {
1110 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1118 protected abstract string OperatorName { get; }
1120 protected override void CloneTo (CloneContext clonectx, Expression t)
1122 Probe target = (Probe) t;
1124 target.expr = expr.Clone (clonectx);
1125 target.ProbeType = ProbeType.Clone (clonectx);
1131 /// Implementation of the `is' operator.
1133 public class Is : Probe {
1134 public Is (Expression expr, Expression probe_type, Location l)
1135 : base (expr, probe_type, l)
1139 public override void Emit (EmitContext ec)
1141 ILGenerator ig = ec.ig;
1144 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1145 ig.Emit (OpCodes.Ldnull);
1146 ig.Emit (OpCodes.Cgt_Un);
1149 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1151 ILGenerator ig = ec.ig;
1154 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1155 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1158 Expression CreateConstantResult (bool result)
1161 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1162 TypeManager.CSharpName (probe_type_expr.Type));
1164 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1165 TypeManager.CSharpName (probe_type_expr.Type));
1167 return new BoolConstant (result, loc);
1170 public override Expression DoResolve (EmitContext ec)
1172 if (base.DoResolve (ec) == null)
1176 bool d_is_nullable = false;
1178 if (expr is Constant) {
1180 // If E is a method group or the null literal, of if the type of E is a reference
1181 // type or a nullable type and the value of E is null, the result is false
1184 return CreateConstantResult (false);
1185 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1186 d = TypeManager.GetTypeArguments (d) [0];
1187 d_is_nullable = true;
1190 type = TypeManager.bool_type;
1191 eclass = ExprClass.Value;
1192 Type t = probe_type_expr.Type;
1193 bool t_is_nullable = false;
1194 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1195 t = TypeManager.GetTypeArguments (t) [0];
1196 t_is_nullable = true;
1199 if (t.IsValueType) {
1202 // D and T are the same value types but D can be null
1204 if (d_is_nullable && !t_is_nullable)
1205 return Nullable.HasValue.Create (expr, ec);
1208 // The result is true if D and T are the same value types
1210 return CreateConstantResult (true);
1213 if (TypeManager.IsGenericParameter (d))
1214 return ResolveGenericParameter (t, d);
1217 // An unboxing conversion exists
1219 if (Convert.ExplicitReferenceConversionExists (d, t))
1222 if (TypeManager.IsGenericParameter (t))
1223 return ResolveGenericParameter (d, t);
1225 if (d.IsValueType) {
1227 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1228 return CreateConstantResult (true);
1230 if (TypeManager.IsGenericParameter (d))
1231 return ResolveGenericParameter (t, d);
1233 if (TypeManager.ContainsGenericParameters (d))
1236 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1237 Convert.ExplicitReferenceConversionExists (d, t)) {
1243 return CreateConstantResult (false);
1246 Expression ResolveGenericParameter (Type d, Type t)
1249 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1250 if (constraints != null) {
1251 if (constraints.IsReferenceType && d.IsValueType)
1252 return CreateConstantResult (false);
1254 if (constraints.IsValueType && !d.IsValueType)
1255 return CreateConstantResult (false);
1258 expr = new BoxedCast (expr, d);
1265 protected override string OperatorName {
1266 get { return "is"; }
1271 /// Implementation of the `as' operator.
1273 public class As : Probe {
1274 public As (Expression expr, Expression probe_type, Location l)
1275 : base (expr, probe_type, l)
1279 bool do_isinst = false;
1280 Expression resolved_type;
1282 public override void Emit (EmitContext ec)
1284 ILGenerator ig = ec.ig;
1289 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1292 if (TypeManager.IsNullableType (type))
1293 ig.Emit (OpCodes.Unbox_Any, type);
1297 static void Error_CannotConvertType (Type source, Type target, Location loc)
1299 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1300 TypeManager.CSharpName (source),
1301 TypeManager.CSharpName (target));
1304 public override Expression DoResolve (EmitContext ec)
1306 if (resolved_type == null) {
1307 resolved_type = base.DoResolve (ec);
1309 if (resolved_type == null)
1313 type = probe_type_expr.Type;
1314 eclass = ExprClass.Value;
1315 Type etype = expr.Type;
1317 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1318 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1319 TypeManager.CSharpName (type));
1326 // If the type is a type parameter, ensure
1327 // that it is constrained by a class
1329 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1331 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1334 if (constraints == null)
1337 if (!constraints.HasClassConstraint)
1338 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1342 Report.Error (413, loc,
1343 "The as operator requires that the `{0}' type parameter be constrained by a class",
1344 probe_type_expr.GetSignatureForError ());
1349 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1350 Report.Warning (458, 2, loc, "The result of the expression is always `null' of type `{0}'",
1351 TypeManager.CSharpName (type));
1354 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1361 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1362 if (TypeManager.IsGenericParameter (etype))
1363 expr = new BoxedCast (expr, etype);
1369 if (TypeManager.ContainsGenericParameters (etype) ||
1370 TypeManager.ContainsGenericParameters (type)) {
1371 expr = new BoxedCast (expr, etype);
1376 Error_CannotConvertType (etype, type, loc);
1380 protected override string OperatorName {
1381 get { return "as"; }
1384 public override bool GetAttributableValue (Type value_type, out object value)
1386 return expr.GetAttributableValue (value_type, out value);
1391 /// This represents a typecast in the source language.
1393 /// FIXME: Cast expressions have an unusual set of parsing
1394 /// rules, we need to figure those out.
1396 public class Cast : Expression {
1397 Expression target_type;
1400 public Cast (Expression cast_type, Expression expr)
1401 : this (cast_type, expr, cast_type.Location)
1405 public Cast (Expression cast_type, Expression expr, Location loc)
1407 this.target_type = cast_type;
1411 if (target_type == TypeManager.system_void_expr)
1412 Error_VoidInvalidInTheContext (loc);
1415 public Expression TargetType {
1416 get { return target_type; }
1419 public Expression Expr {
1420 get { return expr; }
1423 public override Expression DoResolve (EmitContext ec)
1425 expr = expr.Resolve (ec);
1429 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1435 if (type.IsAbstract && type.IsSealed) {
1436 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1440 eclass = ExprClass.Value;
1442 Constant c = expr as Constant;
1444 c = c.TryReduce (ec, type, loc);
1449 if (type.IsPointer && !ec.InUnsafe) {
1453 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1457 public override void Emit (EmitContext ec)
1459 throw new Exception ("Should not happen");
1462 protected override void CloneTo (CloneContext clonectx, Expression t)
1464 Cast target = (Cast) t;
1466 target.target_type = target_type.Clone (clonectx);
1467 target.expr = expr.Clone (clonectx);
1472 // C# 2.0 Default value expression
1474 public class DefaultValueExpression : Expression
1478 public DefaultValueExpression (Expression expr, Location loc)
1484 public override Expression DoResolve (EmitContext ec)
1486 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1492 if (type == TypeManager.void_type) {
1493 Error_VoidInvalidInTheContext (loc);
1497 if (TypeManager.IsGenericParameter (type))
1499 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1500 if (constraints != null && constraints.IsReferenceType)
1501 return new NullDefault (new NullLiteral (Location), type);
1505 Constant c = New.Constantify(type);
1507 return new NullDefault (c, type);
1509 if (!TypeManager.IsValueType (type))
1510 return new NullDefault (new NullLiteral (Location), type);
1512 eclass = ExprClass.Variable;
1516 public override void Emit (EmitContext ec)
1518 LocalTemporary temp_storage = new LocalTemporary(type);
1520 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1521 ec.ig.Emit(OpCodes.Initobj, type);
1522 temp_storage.Emit(ec);
1525 protected override void CloneTo (CloneContext clonectx, Expression t)
1527 DefaultValueExpression target = (DefaultValueExpression) t;
1529 target.expr = expr.Clone (clonectx);
1534 /// Binary operators
1536 public class Binary : Expression {
1537 public enum Operator : byte {
1538 Multiply, Division, Modulus,
1539 Addition, Subtraction,
1540 LeftShift, RightShift,
1541 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1542 Equality, Inequality,
1551 readonly Operator oper;
1552 protected Expression left, right;
1553 readonly bool is_compound;
1555 // This must be kept in sync with Operator!!!
1556 public static readonly string [] oper_names;
1560 oper_names = new string [(int) Operator.TOP];
1562 oper_names [(int) Operator.Multiply] = "op_Multiply";
1563 oper_names [(int) Operator.Division] = "op_Division";
1564 oper_names [(int) Operator.Modulus] = "op_Modulus";
1565 oper_names [(int) Operator.Addition] = "op_Addition";
1566 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1567 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1568 oper_names [(int) Operator.RightShift] = "op_RightShift";
1569 oper_names [(int) Operator.LessThan] = "op_LessThan";
1570 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1571 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1572 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1573 oper_names [(int) Operator.Equality] = "op_Equality";
1574 oper_names [(int) Operator.Inequality] = "op_Inequality";
1575 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1576 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1577 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1578 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1579 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1582 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1583 : this (oper, left, right)
1585 this.is_compound = isCompound;
1588 public Binary (Operator oper, Expression left, Expression right)
1593 this.loc = left.Location;
1596 public Operator Oper {
1603 /// Returns a stringified representation of the Operator
1605 string OperName (Operator oper)
1609 case Operator.Multiply:
1612 case Operator.Division:
1615 case Operator.Modulus:
1618 case Operator.Addition:
1621 case Operator.Subtraction:
1624 case Operator.LeftShift:
1627 case Operator.RightShift:
1630 case Operator.LessThan:
1633 case Operator.GreaterThan:
1636 case Operator.LessThanOrEqual:
1639 case Operator.GreaterThanOrEqual:
1642 case Operator.Equality:
1645 case Operator.Inequality:
1648 case Operator.BitwiseAnd:
1651 case Operator.BitwiseOr:
1654 case Operator.ExclusiveOr:
1657 case Operator.LogicalOr:
1660 case Operator.LogicalAnd:
1664 s = oper.ToString ();
1674 public override string ToString ()
1676 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1677 right.ToString () + ")";
1680 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1682 if (expr.Type == target_type)
1685 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1688 void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1691 34, loc, "Operator `" + OperName (oper)
1692 + "' is ambiguous on operands of type `"
1693 + TypeManager.CSharpName (l) + "' "
1694 + "and `" + TypeManager.CSharpName (r)
1698 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1700 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1703 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1705 if (!IsConvertible (ec, left, right, t))
1707 left = ForceConversion (ec, left, t);
1708 right = ForceConversion (ec, right, t);
1713 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1715 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1716 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1718 if (oper == Operator.Equality || oper == Operator.Inequality)
1720 if (oper == Operator.Addition)
1725 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1727 if (!IsApplicable_String (ec, left, right, oper))
1731 Type r = right.Type;
1732 if (OverloadResolve_PredefinedIntegral (ec) ||
1733 OverloadResolve_PredefinedFloating (ec)) {
1734 Error_OperatorAmbiguous (loc, oper, l, r);
1737 Type t = TypeManager.string_type;
1738 if (Convert.ImplicitConversionExists (ec, left, t))
1739 left = ForceConversion (ec, left, t);
1740 if (Convert.ImplicitConversionExists (ec, right, t))
1741 right = ForceConversion (ec, right, t);
1746 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1748 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1749 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1750 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1751 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1755 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1757 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1758 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1762 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1764 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1767 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1769 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1773 protected void Error_OperatorCannotBeApplied ()
1775 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1776 TypeManager.CSharpName(right.Type));
1779 static bool IsUnsigned (Type t)
1782 t = t.GetElementType ();
1784 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1785 t == TypeManager.ushort_type || t == TypeManager.byte_type);
1788 Expression Make32or64 (EmitContext ec, Expression e)
1792 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1793 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1795 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1798 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1801 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1804 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1810 Expression CheckShiftArguments (EmitContext ec)
1812 Expression new_left = Make32or64 (ec, left);
1813 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1814 if (new_left == null || new_right == null) {
1815 Error_OperatorCannotBeApplied ();
1818 type = new_left.Type;
1819 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1821 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1826 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1827 // i.e., not invoke op_Equality.
1829 static bool EqualsNullIsReferenceEquals (Type t)
1831 return t == TypeManager.object_type || t == TypeManager.string_type ||
1832 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
1835 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1837 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1838 "Possible unintended reference comparison; to get a value comparison, " +
1839 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1842 static void Warning_Constant_Result (Location loc, bool result, Type type)
1844 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1845 "This operation is undocumented and it is temporary supported for compatibility reasons only",
1846 TypeManager.CSharpName (type), result ? "true" : "false");
1849 Expression ResolveOperator (EmitContext ec)
1852 Type r = right.Type;
1854 if (oper == Operator.Equality || oper == Operator.Inequality){
1855 if (right.Type == TypeManager.null_type){
1856 if (TypeManager.IsGenericParameter (l)){
1857 if (l.BaseType == TypeManager.value_type) {
1858 Error_OperatorCannotBeApplied ();
1862 left = new BoxedCast (left, TypeManager.object_type);
1863 Type = TypeManager.bool_type;
1868 // 7.9.9 Equality operators and null
1870 // CSC 2 has this behavior, it allows structs to be compared
1871 // with the null literal *outside* of a generics context and
1872 // inlines that as true or false.
1874 // This is, in my opinion, completely wrong.
1876 if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType) {
1877 if (!TypeManager.IsPrimitiveType (l) && !TypeManager.IsEnumType (l)) {
1878 if (MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
1879 MemberLookup (ec.ContainerType, l, oper_names [(int)Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
1880 Error_OperatorCannotBeApplied ();
1885 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1886 return new BoolConstant (oper == Operator.Inequality, loc);
1890 if (left is NullLiteral){
1891 if (TypeManager.IsGenericParameter (r)){
1892 if (r.BaseType == TypeManager.value_type) {
1893 Error_OperatorCannotBeApplied ();
1897 right = new BoxedCast (right, TypeManager.object_type);
1898 Type = TypeManager.bool_type;
1903 // 7.9.9 Equality operators and null
1905 // CSC 2 has this behavior, it allows structs to be compared
1906 // with the null literal *outside* of a generics context and
1907 // inlines that as true or false.
1909 // This is, in my opinion, completely wrong.
1911 if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1912 if (!TypeManager.IsPrimitiveType (r) && !TypeManager.IsEnumType (r)) {
1913 if (MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Equality], MemberTypes.Method, AllBindingFlags, loc) == null &&
1914 MemberLookup (ec.ContainerType, r, oper_names [(int) Operator.Inequality], MemberTypes.Method, AllBindingFlags, loc) == null) {
1915 Error_OperatorCannotBeApplied ();
1920 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1921 return new BoolConstant (oper == Operator.Inequality, loc);
1926 // Optimize out call to op_Equality in a few cases.
1928 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1929 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1930 Type = TypeManager.bool_type;
1935 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1936 Type = TypeManager.bool_type;
1942 // Delegate equality
1944 MethodGroupExpr mg = null;
1945 Type delegate_type = null;
1946 if (left.eclass == ExprClass.MethodGroup) {
1947 if (!TypeManager.IsDelegateType(r)) {
1948 Error_OperatorCannotBeApplied(Location, OperName(oper),
1949 left.ExprClassName, right.ExprClassName);
1952 mg = (MethodGroupExpr)left;
1954 } else if (right.eclass == ExprClass.MethodGroup) {
1955 if (!TypeManager.IsDelegateType(l)) {
1956 Error_OperatorCannotBeApplied(Location, OperName(oper),
1957 left.ExprClassName, right.ExprClassName);
1960 mg = (MethodGroupExpr)right;
1965 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1969 // Find operator method
1970 string op = oper_names[(int)oper];
1971 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1972 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1974 ArrayList args = new ArrayList(2);
1975 args.Add(new Argument(e, Argument.AType.Expression));
1976 if (delegate_type == l)
1977 args.Insert(0, new Argument(left, Argument.AType.Expression));
1979 args.Add(new Argument(right, Argument.AType.Expression));
1981 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1984 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1985 Error_OperatorCannotBeApplied(Location, OperName(oper),
1986 left.ExprClassName, right.ExprClassName);
1993 // Do not perform operator overload resolution when both sides are
1996 MethodGroupExpr left_operators = null, right_operators = null;
1997 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1999 // Step 1: Perform Operator Overload location
2001 string op = oper_names [(int) oper];
2003 MethodGroupExpr union;
2004 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2006 right_operators = MemberLookup (
2007 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2008 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2010 union = left_operators;
2012 if (union != null) {
2013 ArrayList args = new ArrayList (2);
2014 args.Add (new Argument (left));
2015 args.Add (new Argument (right));
2017 union = union.OverloadResolve (ec, ref args, true, loc);
2019 return new UserOperatorCall (union, args, CreateExpressionTree, loc);
2024 // String concatenation
2026 // string operator + (string x, string y);
2027 // string operator + (string x, object y);
2028 // string operator + (object x, string y);
2030 if (oper == Operator.Addition && !TypeManager.IsDelegateType (l)) {
2032 // Either left or right expression is implicitly convertible to string
2034 if (OverloadResolve_PredefinedString (ec, oper)) {
2035 if (r == TypeManager.void_type || l == TypeManager.void_type) {
2036 Error_OperatorCannotBeApplied ();
2041 // Constants folding for strings and nulls
2043 if (left.Type == TypeManager.string_type && right.Type == TypeManager.string_type &&
2044 left is Constant && right is Constant) {
2045 string lvalue = (string)((Constant) left).GetValue ();
2046 string rvalue = (string)((Constant) right).GetValue ();
2047 return new StringConstant (lvalue + rvalue, left.Location);
2051 // Append to existing string concatenation
2053 if (left is StringConcat) {
2054 ((StringConcat) left).Append (ec, right);
2059 // Otherwise, start a new concat expression using converted expression
2061 return new StringConcat (ec, loc, left, right).Resolve (ec);
2065 // Transform a + ( - b) into a - b
2067 if (right is Unary){
2068 Unary right_unary = (Unary) right;
2070 if (right_unary.Oper == Unary.Operator.UnaryNegation){
2071 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
2076 if (oper == Operator.Equality || oper == Operator.Inequality){
2077 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2078 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2079 Error_OperatorCannotBeApplied ();
2083 type = TypeManager.bool_type;
2087 if (l.IsPointer || r.IsPointer) {
2088 if (l.IsPointer && r.IsPointer) {
2089 type = TypeManager.bool_type;
2093 if (l.IsPointer && r == TypeManager.null_type) {
2094 right = new EmptyConstantCast (NullPointer.Null, l);
2095 type = TypeManager.bool_type;
2099 if (r.IsPointer && l == TypeManager.null_type) {
2100 left = new EmptyConstantCast (NullPointer.Null, r);
2101 type = TypeManager.bool_type;
2107 if (l.IsGenericParameter && r.IsGenericParameter) {
2108 GenericConstraints l_gc, r_gc;
2110 l_gc = TypeManager.GetTypeParameterConstraints (l);
2111 r_gc = TypeManager.GetTypeParameterConstraints (r);
2113 if ((l_gc == null) || (r_gc == null) ||
2114 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
2115 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
2116 Error_OperatorCannotBeApplied ();
2124 // operator != (object a, object b)
2125 // operator == (object a, object b)
2127 // For this to be used, both arguments have to be reference-types.
2128 // Read the rationale on the spec (14.9.6)
2130 if (!(l.IsValueType || r.IsValueType)){
2131 type = TypeManager.bool_type;
2137 // Also, a standard conversion must exist from either one
2139 // NOTE: An interface is converted to the object before the
2140 // standard conversion is applied. It's not clear from the
2141 // standard but it looks like it works like that.
2144 l = TypeManager.object_type;
2146 r = TypeManager.object_type;
2148 bool left_to_right =
2149 Convert.ImplicitStandardConversionExists (left, r);
2150 bool right_to_left = !left_to_right &&
2151 Convert.ImplicitStandardConversionExists (right, l);
2153 if (!left_to_right && !right_to_left) {
2154 Error_OperatorCannotBeApplied ();
2158 if (left_to_right && left_operators != null &&
2159 Report.WarningLevel >= 2) {
2160 ArrayList args = new ArrayList (2);
2161 args.Add (new Argument (left, Argument.AType.Expression));
2162 args.Add (new Argument (left, Argument.AType.Expression));
2163 if (left_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
2164 Warning_UnintendedReferenceComparison (loc, "right", l);
2167 if (right_to_left && right_operators != null &&
2168 Report.WarningLevel >= 2) {
2169 ArrayList args = new ArrayList (2);
2170 args.Add (new Argument (right, Argument.AType.Expression));
2171 args.Add (new Argument (right, Argument.AType.Expression));
2172 if (right_operators.OverloadResolve (ec, ref args, true, Location.Null) != null)
2173 Warning_UnintendedReferenceComparison (loc, "left", r);
2177 // We are going to have to convert to an object to compare
2179 if (l != TypeManager.object_type)
2180 left = EmptyCast.Create (left, TypeManager.object_type);
2181 if (r != TypeManager.object_type)
2182 right = EmptyCast.Create (right, TypeManager.object_type);
2188 // Only perform numeric promotions on:
2189 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2191 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2192 if (TypeManager.IsDelegateType (l)){
2193 if (((right.eclass == ExprClass.MethodGroup) ||
2194 (r == TypeManager.anonymous_method_type))){
2195 if ((RootContext.Version != LanguageVersion.ISO_1)){
2196 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2204 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2206 ArrayList args = new ArrayList (2);
2208 args = new ArrayList (2);
2209 args.Add (new Argument (left, Argument.AType.Expression));
2210 args.Add (new Argument (right, Argument.AType.Expression));
2212 if (oper == Operator.Addition)
2213 method = TypeManager.delegate_combine_delegate_delegate;
2215 method = TypeManager.delegate_remove_delegate_delegate;
2217 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2218 Error_OperatorCannotBeApplied ();
2222 return new BinaryDelegate (l, method, args);
2227 // Pointer arithmetic:
2229 // T* operator + (T* x, int y);
2230 // T* operator + (T* x, uint y);
2231 // T* operator + (T* x, long y);
2232 // T* operator + (T* x, ulong y);
2234 // T* operator + (int y, T* x);
2235 // T* operator + (uint y, T *x);
2236 // T* operator + (long y, T *x);
2237 // T* operator + (ulong y, T *x);
2239 // T* operator - (T* x, int y);
2240 // T* operator - (T* x, uint y);
2241 // T* operator - (T* x, long y);
2242 // T* operator - (T* x, ulong y);
2244 // long operator - (T* x, T *y)
2247 if (r.IsPointer && oper == Operator.Subtraction){
2249 return new PointerArithmetic (
2250 false, left, right, TypeManager.int64_type,
2253 Expression t = Make32or64 (ec, right);
2255 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2257 } else if (r.IsPointer && oper == Operator.Addition){
2258 Expression t = Make32or64 (ec, left);
2260 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2265 // Enumeration operators
2267 bool lie = TypeManager.IsEnumType (l);
2268 bool rie = TypeManager.IsEnumType (r);
2272 // U operator - (E e, E f)
2274 if (oper == Operator.Subtraction){
2276 type = TypeManager.EnumToUnderlying (l);
2279 Error_OperatorCannotBeApplied ();
2285 // operator + (E e, U x)
2286 // operator - (E e, U x)
2288 if (oper == Operator.Addition || oper == Operator.Subtraction){
2289 Type enum_type = lie ? l : r;
2290 Type other_type = lie ? r : l;
2291 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2293 if (underlying_type != other_type){
2294 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2304 Error_OperatorCannotBeApplied ();
2313 temp = Convert.ImplicitConversion (ec, right, l, loc);
2317 Error_OperatorCannotBeApplied ();
2321 temp = Convert.ImplicitConversion (ec, left, r, loc);
2326 Error_OperatorCannotBeApplied ();
2331 if (oper == Operator.Equality || oper == Operator.Inequality ||
2332 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2333 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2334 if (left.Type != right.Type){
2335 Error_OperatorCannotBeApplied ();
2338 type = TypeManager.bool_type;
2342 if (oper == Operator.BitwiseAnd ||
2343 oper == Operator.BitwiseOr ||
2344 oper == Operator.ExclusiveOr){
2345 if (left.Type != right.Type){
2346 Error_OperatorCannotBeApplied ();
2352 Error_OperatorCannotBeApplied ();
2356 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2357 return CheckShiftArguments (ec);
2359 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2360 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2361 type = TypeManager.bool_type;
2365 Expression left_operators_e = l == TypeManager.bool_type ?
2366 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2367 Expression right_operators_e = r == TypeManager.bool_type ?
2368 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2370 if (left_operators_e != null && right_operators_e != null) {
2371 left = left_operators_e;
2372 right = right_operators_e;
2373 type = TypeManager.bool_type;
2377 Expression e = new ConditionalLogicalOperator (
2378 oper == Operator.LogicalAnd, left, right, l, loc);
2379 return e.Resolve (ec);
2382 Expression orig_left = left;
2383 Expression orig_right = right;
2386 // operator & (bool x, bool y)
2387 // operator | (bool x, bool y)
2388 // operator ^ (bool x, bool y)
2390 if (oper == Operator.BitwiseAnd ||
2391 oper == Operator.BitwiseOr ||
2392 oper == Operator.ExclusiveOr) {
2393 if (OverloadResolve_PredefinedIntegral (ec)) {
2394 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2395 Error_OperatorAmbiguous (loc, oper, l, r);
2399 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2400 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2401 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2402 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2403 TypeManager.CSharpName (r));
2406 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2407 Error_OperatorCannotBeApplied ();
2414 // Pointer comparison
2416 if (l.IsPointer && r.IsPointer){
2417 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2418 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2419 type = TypeManager.bool_type;
2424 if (OverloadResolve_PredefinedIntegral (ec)) {
2425 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2426 Error_OperatorAmbiguous (loc, oper, l, r);
2429 } else if (OverloadResolve_PredefinedFloating (ec)) {
2430 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2431 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2432 Error_OperatorAmbiguous (loc, oper, l, r);
2435 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2436 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2437 Error_OperatorAmbiguous (loc, oper, l, r);
2440 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2441 Error_OperatorCannotBeApplied ();
2445 if (oper == Operator.Equality ||
2446 oper == Operator.Inequality ||
2447 oper == Operator.LessThanOrEqual ||
2448 oper == Operator.LessThan ||
2449 oper == Operator.GreaterThanOrEqual ||
2450 oper == Operator.GreaterThan)
2451 type = TypeManager.bool_type;
2456 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2458 if (r == TypeManager.string_type)
2460 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2461 ec.ContainerType, lookup, oper_names [(int) oper],
2462 MemberTypes.Method, AllBindingFlags, loc);
2463 ArrayList args = new ArrayList (2);
2464 args.Add (new Argument (left, Argument.AType.Expression));
2465 args.Add (new Argument (right, Argument.AType.Expression));
2466 ops = ops.OverloadResolve (ec, ref args, true, Location.Null);
2467 return new BinaryMethod (type, (MethodInfo)ops, args);
2473 Constant EnumLiftUp (Constant left, Constant right)
2476 case Operator.BitwiseOr:
2477 case Operator.BitwiseAnd:
2478 case Operator.ExclusiveOr:
2479 case Operator.Equality:
2480 case Operator.Inequality:
2481 case Operator.LessThan:
2482 case Operator.LessThanOrEqual:
2483 case Operator.GreaterThan:
2484 case Operator.GreaterThanOrEqual:
2485 if (left is EnumConstant)
2488 if (left.IsZeroInteger)
2489 return new EnumConstant (left, right.Type);
2493 case Operator.Addition:
2494 case Operator.Subtraction:
2497 case Operator.Multiply:
2498 case Operator.Division:
2499 case Operator.Modulus:
2500 case Operator.LeftShift:
2501 case Operator.RightShift:
2502 if (right is EnumConstant || left is EnumConstant)
2506 Error_OperatorCannotBeApplied ();
2510 public override Expression DoResolve (EmitContext ec)
2515 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2516 left = ((ParenthesizedExpression) left).Expr;
2517 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2521 if (left.eclass == ExprClass.Type) {
2522 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2526 left = left.Resolve (ec);
2531 Constant lc = left as Constant;
2532 if (lc != null && lc.Type == TypeManager.bool_type &&
2533 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2534 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2536 // TODO: make a sense to resolve unreachable expression as we do for statement
2537 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2541 right = right.Resolve (ec);
2545 eclass = ExprClass.Value;
2546 Constant rc = right as Constant;
2548 // The conversion rules are ignored in enum context but why
2549 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2550 left = lc = EnumLiftUp (lc, rc);
2554 right = rc = EnumLiftUp (rc, lc);
2559 if (oper == Operator.BitwiseAnd) {
2560 if (rc != null && rc.IsZeroInteger) {
2561 return lc is EnumConstant ?
2562 new EnumConstant (rc, lc.Type):
2566 if (lc != null && lc.IsZeroInteger) {
2567 if (rc is EnumConstant)
2568 return new EnumConstant (lc, rc.Type);
2571 // Optimize cases that have no side-effects, to avoid
2572 // emitting code that gets popped
2574 if (right is FieldExpr)
2577 // Side effect code:
2578 return new SideEffectConstant (lc, right, loc);
2581 else if (oper == Operator.BitwiseOr) {
2582 if (lc is EnumConstant &&
2583 rc != null && rc.IsZeroInteger)
2585 if (rc is EnumConstant &&
2586 lc != null && lc.IsZeroInteger)
2588 } else if (oper == Operator.LogicalAnd) {
2589 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2591 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2595 if (rc != null && lc != null){
2596 int prev_e = Report.Errors;
2597 Expression e = ConstantFold.BinaryFold (
2598 ec, oper, lc, rc, loc);
2599 if (e != null || Report.Errors != prev_e)
2604 if ((left is NullLiteral || left.Type.IsValueType) &&
2605 (right is NullLiteral || right.Type.IsValueType) &&
2606 !(left is NullLiteral && right is NullLiteral) &&
2607 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2608 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2611 // Comparison warnings
2612 if (oper == Operator.Equality || oper == Operator.Inequality ||
2613 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2614 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2615 if (left.Equals (right)) {
2616 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2618 CheckUselessComparison (lc, right.Type);
2619 CheckUselessComparison (rc, left.Type);
2622 return ResolveOperator (ec);
2625 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2630 private void CheckUselessComparison (Constant c, Type type)
2632 if (c == null || !IsTypeIntegral (type)
2633 || c is StringConstant
2634 || c is BoolConstant
2635 || c is FloatConstant
2636 || c is DoubleConstant
2637 || c is DecimalConstant
2643 if (c is ULongConstant) {
2644 ulong uvalue = ((ULongConstant) c).Value;
2645 if (uvalue > long.MaxValue) {
2646 if (type == TypeManager.byte_type ||
2647 type == TypeManager.sbyte_type ||
2648 type == TypeManager.short_type ||
2649 type == TypeManager.ushort_type ||
2650 type == TypeManager.int32_type ||
2651 type == TypeManager.uint32_type ||
2652 type == TypeManager.int64_type ||
2653 type == TypeManager.char_type)
2654 WarnUselessComparison (type);
2657 value = (long) uvalue;
2659 else if (c is ByteConstant)
2660 value = ((ByteConstant) c).Value;
2661 else if (c is SByteConstant)
2662 value = ((SByteConstant) c).Value;
2663 else if (c is ShortConstant)
2664 value = ((ShortConstant) c).Value;
2665 else if (c is UShortConstant)
2666 value = ((UShortConstant) c).Value;
2667 else if (c is IntConstant)
2668 value = ((IntConstant) c).Value;
2669 else if (c is UIntConstant)
2670 value = ((UIntConstant) c).Value;
2671 else if (c is LongConstant)
2672 value = ((LongConstant) c).Value;
2673 else if (c is CharConstant)
2674 value = ((CharConstant)c).Value;
2679 if (IsValueOutOfRange (value, type))
2680 WarnUselessComparison (type);
2683 private bool IsValueOutOfRange (long value, Type type)
2685 if (IsTypeUnsigned (type) && value < 0)
2687 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2688 type == TypeManager.byte_type && value >= 0x100 ||
2689 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2690 type == TypeManager.ushort_type && value >= 0x10000 ||
2691 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2692 type == TypeManager.uint32_type && value >= 0x100000000;
2695 private static bool IsTypeIntegral (Type type)
2697 return type == TypeManager.uint64_type ||
2698 type == TypeManager.int64_type ||
2699 type == TypeManager.uint32_type ||
2700 type == TypeManager.int32_type ||
2701 type == TypeManager.ushort_type ||
2702 type == TypeManager.short_type ||
2703 type == TypeManager.sbyte_type ||
2704 type == TypeManager.byte_type ||
2705 type == TypeManager.char_type;
2708 private static bool IsTypeUnsigned (Type type)
2710 return type == TypeManager.uint64_type ||
2711 type == TypeManager.uint32_type ||
2712 type == TypeManager.ushort_type ||
2713 type == TypeManager.byte_type ||
2714 type == TypeManager.char_type;
2717 private void WarnUselessComparison (Type type)
2719 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}'",
2720 TypeManager.CSharpName (type));
2724 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2725 /// context of a conditional bool expression. This function will return
2726 /// false if it is was possible to use EmitBranchable, or true if it was.
2728 /// The expression's code is generated, and we will generate a branch to `target'
2729 /// if the resulting expression value is equal to isTrue
2731 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2733 ILGenerator ig = ec.ig;
2736 // This is more complicated than it looks, but its just to avoid
2737 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2738 // but on top of that we want for == and != to use a special path
2739 // if we are comparing against null
2741 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2742 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
2745 // put the constant on the rhs, for simplicity
2747 if (left is Constant) {
2748 Expression swap = right;
2753 if (((Constant) right).IsZeroInteger) {
2756 ig.Emit (OpCodes.Brtrue, target);
2758 ig.Emit (OpCodes.Brfalse, target);
2761 } else if (right is BoolConstant) {
2763 if (my_on_true != ((BoolConstant) right).Value)
2764 ig.Emit (OpCodes.Brtrue, target);
2766 ig.Emit (OpCodes.Brfalse, target);
2771 } else if (oper == Operator.LogicalAnd) {
2774 Label tests_end = ig.DefineLabel ();
2776 left.EmitBranchable (ec, tests_end, false);
2777 right.EmitBranchable (ec, target, true);
2778 ig.MarkLabel (tests_end);
2781 // This optimizes code like this
2782 // if (true && i > 4)
2784 if (!(left is Constant))
2785 left.EmitBranchable (ec, target, false);
2787 if (!(right is Constant))
2788 right.EmitBranchable (ec, target, false);
2793 } else if (oper == Operator.LogicalOr){
2795 left.EmitBranchable (ec, target, true);
2796 right.EmitBranchable (ec, target, true);
2799 Label tests_end = ig.DefineLabel ();
2800 left.EmitBranchable (ec, tests_end, true);
2801 right.EmitBranchable (ec, target, false);
2802 ig.MarkLabel (tests_end);
2807 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2808 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2809 oper == Operator.Equality || oper == Operator.Inequality)) {
2810 base.EmitBranchable (ec, target, on_true);
2818 bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2821 case Operator.Equality:
2823 ig.Emit (OpCodes.Beq, target);
2825 ig.Emit (OpCodes.Bne_Un, target);
2828 case Operator.Inequality:
2830 ig.Emit (OpCodes.Bne_Un, target);
2832 ig.Emit (OpCodes.Beq, target);
2835 case Operator.LessThan:
2838 ig.Emit (OpCodes.Blt_Un, target);
2840 ig.Emit (OpCodes.Blt, target);
2843 ig.Emit (OpCodes.Bge_Un, target);
2845 ig.Emit (OpCodes.Bge, target);
2848 case Operator.GreaterThan:
2851 ig.Emit (OpCodes.Bgt_Un, target);
2853 ig.Emit (OpCodes.Bgt, target);
2856 ig.Emit (OpCodes.Ble_Un, target);
2858 ig.Emit (OpCodes.Ble, target);
2861 case Operator.LessThanOrEqual:
2864 ig.Emit (OpCodes.Ble_Un, target);
2866 ig.Emit (OpCodes.Ble, target);
2869 ig.Emit (OpCodes.Bgt_Un, target);
2871 ig.Emit (OpCodes.Bgt, target);
2875 case Operator.GreaterThanOrEqual:
2878 ig.Emit (OpCodes.Bge_Un, target);
2880 ig.Emit (OpCodes.Bge, target);
2883 ig.Emit (OpCodes.Blt_Un, target);
2885 ig.Emit (OpCodes.Blt, target);
2888 Console.WriteLine (oper);
2889 throw new Exception ("what is THAT");
2893 public override void Emit (EmitContext ec)
2895 ILGenerator ig = ec.ig;
2900 // Handle short-circuit operators differently
2903 if (oper == Operator.LogicalAnd) {
2904 Label load_zero = ig.DefineLabel ();
2905 Label end = ig.DefineLabel ();
2907 left.EmitBranchable (ec, load_zero, false);
2909 ig.Emit (OpCodes.Br, end);
2911 ig.MarkLabel (load_zero);
2912 ig.Emit (OpCodes.Ldc_I4_0);
2915 } else if (oper == Operator.LogicalOr) {
2916 Label load_one = ig.DefineLabel ();
2917 Label end = ig.DefineLabel ();
2919 left.EmitBranchable (ec, load_one, true);
2921 ig.Emit (OpCodes.Br, end);
2923 ig.MarkLabel (load_one);
2924 ig.Emit (OpCodes.Ldc_I4_1);
2932 bool is_unsigned = IsUnsigned (left.Type);
2935 case Operator.Multiply:
2937 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2938 opcode = OpCodes.Mul_Ovf;
2939 else if (is_unsigned)
2940 opcode = OpCodes.Mul_Ovf_Un;
2942 opcode = OpCodes.Mul;
2944 opcode = OpCodes.Mul;
2948 case Operator.Division:
2950 opcode = OpCodes.Div_Un;
2952 opcode = OpCodes.Div;
2955 case Operator.Modulus:
2957 opcode = OpCodes.Rem_Un;
2959 opcode = OpCodes.Rem;
2962 case Operator.Addition:
2964 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2965 opcode = OpCodes.Add_Ovf;
2966 else if (is_unsigned)
2967 opcode = OpCodes.Add_Ovf_Un;
2969 opcode = OpCodes.Add;
2971 opcode = OpCodes.Add;
2974 case Operator.Subtraction:
2976 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2977 opcode = OpCodes.Sub_Ovf;
2978 else if (is_unsigned)
2979 opcode = OpCodes.Sub_Ovf_Un;
2981 opcode = OpCodes.Sub;
2983 opcode = OpCodes.Sub;
2986 case Operator.RightShift:
2988 opcode = OpCodes.Shr_Un;
2990 opcode = OpCodes.Shr;
2993 case Operator.LeftShift:
2994 opcode = OpCodes.Shl;
2997 case Operator.Equality:
2998 opcode = OpCodes.Ceq;
3001 case Operator.Inequality:
3002 ig.Emit (OpCodes.Ceq);
3003 ig.Emit (OpCodes.Ldc_I4_0);
3005 opcode = OpCodes.Ceq;
3008 case Operator.LessThan:
3010 opcode = OpCodes.Clt_Un;
3012 opcode = OpCodes.Clt;
3015 case Operator.GreaterThan:
3017 opcode = OpCodes.Cgt_Un;
3019 opcode = OpCodes.Cgt;
3022 case Operator.LessThanOrEqual:
3023 Type lt = left.Type;
3025 if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3026 ig.Emit (OpCodes.Cgt_Un);
3028 ig.Emit (OpCodes.Cgt);
3029 ig.Emit (OpCodes.Ldc_I4_0);
3031 opcode = OpCodes.Ceq;
3034 case Operator.GreaterThanOrEqual:
3035 Type le = left.Type;
3037 if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3038 ig.Emit (OpCodes.Clt_Un);
3040 ig.Emit (OpCodes.Clt);
3042 ig.Emit (OpCodes.Ldc_I4_0);
3044 opcode = OpCodes.Ceq;
3047 case Operator.BitwiseOr:
3048 opcode = OpCodes.Or;
3051 case Operator.BitwiseAnd:
3052 opcode = OpCodes.And;
3055 case Operator.ExclusiveOr:
3056 opcode = OpCodes.Xor;
3060 throw new Exception ("This should not happen: Operator = "
3061 + oper.ToString ());
3067 protected override void CloneTo (CloneContext clonectx, Expression t)
3069 Binary target = (Binary) t;
3071 target.left = left.Clone (clonectx);
3072 target.right = right.Clone (clonectx);
3075 public override Expression CreateExpressionTree (EmitContext ec)
3077 return CreateExpressionTree (ec, null);
3080 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3083 bool lift_arg = false;
3086 case Operator.Addition:
3087 if (method == null && ec.CheckState)
3088 method_name = "AddChecked";
3090 method_name = "Add";
3092 case Operator.BitwiseAnd:
3093 method_name = "And";
3095 case Operator.Division:
3096 method_name = "Divide";
3098 case Operator.Equality:
3099 method_name = "Equal";
3102 case Operator.ExclusiveOr:
3103 method_name = "ExclusiveOr";
3105 case Operator.GreaterThan:
3106 method_name = "GreaterThan";
3109 case Operator.GreaterThanOrEqual:
3110 method_name = "GreaterThanOrEqual";
3113 case Operator.LessThan:
3114 method_name = "LessThan";
3116 case Operator.LogicalAnd:
3117 method_name = "AndAlso";
3120 case Operator.BitwiseOr:
3124 case Operator.LogicalOr:
3125 method_name = "OrElse";
3128 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3131 ArrayList args = new ArrayList (2);
3132 args.Add (new Argument (left.CreateExpressionTree (ec)));
3133 args.Add (new Argument (right.CreateExpressionTree (ec)));
3134 if (method != null) {
3136 args.Add (new Argument (new BoolConstant (false, loc)));
3138 args.Add (new Argument (method.CreateExpressionTree (ec)));
3141 return CreateExpressionFactoryCall (method_name, args);
3146 // Object created by Binary when the binary operator uses an method instead of being
3147 // a binary operation that maps to a CIL binary operation.
3149 public class BinaryMethod : Expression {
3150 public MethodBase method;
3151 public ArrayList Arguments;
3153 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3158 eclass = ExprClass.Value;
3161 public override Expression DoResolve (EmitContext ec)
3166 public override void Emit (EmitContext ec)
3168 ILGenerator ig = ec.ig;
3170 Invocation.EmitArguments (ec, Arguments, false, null);
3172 if (method is MethodInfo)
3173 ig.Emit (OpCodes.Call, (MethodInfo) method);
3175 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3180 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3181 // b, c, d... may be strings or objects.
3183 public class StringConcat : Expression {
3184 ArrayList arguments;
3186 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3189 type = TypeManager.string_type;
3190 eclass = ExprClass.Value;
3192 arguments = new ArrayList (2);
3197 public override Expression DoResolve (EmitContext ec)
3202 public void Append (EmitContext ec, Expression operand)
3207 StringConstant sc = operand as StringConstant;
3209 if (arguments.Count != 0) {
3210 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3211 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3212 if (last_expr_constant != null) {
3213 last_argument.Expr = new StringConstant (
3214 last_expr_constant.Value + sc.Value, sc.Location);
3220 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3222 StringConcat concat_oper = operand as StringConcat;
3223 if (concat_oper != null) {
3224 arguments.AddRange (concat_oper.arguments);
3230 // Conversion to object
3232 if (operand.Type != TypeManager.string_type) {
3233 Expression expr = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3235 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3241 arguments.Add (new Argument (operand));
3244 Expression CreateConcatInvocation ()
3246 return new Invocation (
3247 new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
3251 public override void Emit (EmitContext ec)
3253 Expression concat = CreateConcatInvocation ();
3254 concat = concat.Resolve (ec);
3261 // Object created with +/= on delegates
3263 public class BinaryDelegate : Expression {
3267 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3272 eclass = ExprClass.Value;
3275 public override Expression DoResolve (EmitContext ec)
3280 public override void Emit (EmitContext ec)
3282 ILGenerator ig = ec.ig;
3284 Invocation.EmitArguments (ec, args, false, null);
3286 ig.Emit (OpCodes.Call, (MethodInfo) method);
3287 ig.Emit (OpCodes.Castclass, type);
3290 public Expression Right {
3292 Argument arg = (Argument) args [1];
3297 public bool IsAddition {
3299 return method == TypeManager.delegate_combine_delegate_delegate;
3305 // User-defined conditional logical operator
3307 public class ConditionalLogicalOperator : Expression {
3308 Expression left, right;
3310 Expression op_true, op_false;
3311 UserOperatorCall op;
3312 LocalTemporary left_temp;
3314 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3317 eclass = ExprClass.Value;
3321 this.is_and = is_and;
3324 public override Expression CreateExpressionTree (EmitContext ec)
3326 ArrayList args = new ArrayList (3);
3327 args.Add (new Argument (left.CreateExpressionTree (ec)));
3328 args.Add (new Argument (right.CreateExpressionTree (ec)));
3329 args.Add (new Argument (op.Method.CreateExpressionTree (ec)));
3330 return CreateExpressionFactoryCall (is_and ? "AndAlso" : "OrAlso", args);
3333 protected void Error19 ()
3335 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3338 protected void Error218 ()
3340 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3341 "declarations of operator true and operator false");
3344 public override Expression DoResolve (EmitContext ec)
3346 MethodGroupExpr operator_group;
3348 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3349 if (operator_group == null) {
3354 left_temp = new LocalTemporary (type);
3356 ArrayList arguments = new ArrayList (2);
3357 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3358 arguments.Add (new Argument (right, Argument.AType.Expression));
3359 operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
3360 if (operator_group == null) {
3365 MethodInfo method = (MethodInfo)operator_group;
3366 if (method.ReturnType != type) {
3367 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3368 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3372 op = new UserOperatorCall (operator_group, arguments, null, loc);
3374 op_true = GetOperatorTrue (ec, left_temp, loc);
3375 op_false = GetOperatorFalse (ec, left_temp, loc);
3376 if ((op_true == null) || (op_false == null)) {
3384 public override void Emit (EmitContext ec)
3386 ILGenerator ig = ec.ig;
3387 Label false_target = ig.DefineLabel ();
3388 Label end_target = ig.DefineLabel ();
3391 left_temp.Store (ec);
3393 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3394 left_temp.Emit (ec);
3395 ig.Emit (OpCodes.Br, end_target);
3396 ig.MarkLabel (false_target);
3398 ig.MarkLabel (end_target);
3400 // We release 'left_temp' here since 'op' may refer to it too
3401 left_temp.Release (ec);
3405 public class PointerArithmetic : Expression {
3406 Expression left, right;
3410 // We assume that `l' is always a pointer
3412 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3418 is_add = is_addition;
3421 public override Expression DoResolve (EmitContext ec)
3423 eclass = ExprClass.Variable;
3425 if (left.Type == TypeManager.void_ptr_type) {
3426 Error (242, "The operation in question is undefined on void pointers");
3433 public override void Emit (EmitContext ec)
3435 Type op_type = left.Type;
3436 ILGenerator ig = ec.ig;
3438 // It must be either array or fixed buffer
3439 Type element = TypeManager.HasElementType (op_type) ?
3440 element = TypeManager.GetElementType (op_type) :
3441 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3443 int size = GetTypeSize (element);
3444 Type rtype = right.Type;
3446 if (rtype.IsPointer){
3448 // handle (pointer - pointer)
3452 ig.Emit (OpCodes.Sub);
3456 ig.Emit (OpCodes.Sizeof, element);
3458 IntLiteral.EmitInt (ig, size);
3459 ig.Emit (OpCodes.Div);
3461 ig.Emit (OpCodes.Conv_I8);
3464 // handle + and - on (pointer op int)
3467 ig.Emit (OpCodes.Conv_I);
3469 Constant right_const = right as Constant;
3470 if (right_const != null && size != 0) {
3471 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3479 ig.Emit (OpCodes.Sizeof, element);
3481 IntLiteral.EmitInt (ig, size);
3482 if (rtype == TypeManager.int64_type)
3483 ig.Emit (OpCodes.Conv_I8);
3484 else if (rtype == TypeManager.uint64_type)
3485 ig.Emit (OpCodes.Conv_U8);
3486 ig.Emit (OpCodes.Mul);
3490 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3491 ig.Emit (OpCodes.Conv_I);
3494 ig.Emit (OpCodes.Add);
3496 ig.Emit (OpCodes.Sub);
3502 /// Implements the ternary conditional operator (?:)
3504 public class Conditional : Expression {
3505 Expression expr, true_expr, false_expr;
3507 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3510 this.true_expr = true_expr;
3511 this.false_expr = false_expr;
3512 this.loc = expr.Location;
3515 public Expression Expr {
3521 public Expression TrueExpr {
3527 public Expression FalseExpr {
3533 public override Expression CreateExpressionTree (EmitContext ec)
3535 ArrayList args = new ArrayList (3);
3536 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3537 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3538 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3539 return CreateExpressionFactoryCall ("Condition", args);
3542 public override Expression DoResolve (EmitContext ec)
3544 expr = expr.Resolve (ec);
3549 if (expr.Type != TypeManager.bool_type){
3550 expr = Expression.ResolveBoolean (
3557 Assign ass = expr as Assign;
3558 if (ass != null && ass.Source is Constant) {
3559 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3562 true_expr = true_expr.Resolve (ec);
3563 false_expr = false_expr.Resolve (ec);
3565 if (true_expr == null || false_expr == null)
3568 eclass = ExprClass.Value;
3569 if (true_expr.Type == false_expr.Type) {
3570 type = true_expr.Type;
3571 if (type == TypeManager.null_type) {
3572 // TODO: probably will have to implement ConditionalConstant
3573 // to call method without return constant as well
3574 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3579 Type true_type = true_expr.Type;
3580 Type false_type = false_expr.Type;
3583 // First, if an implicit conversion exists from true_expr
3584 // to false_expr, then the result type is of type false_expr.Type
3586 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3589 // Check if both can convert implicitl to each other's type
3591 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3593 "Can not compute type of conditional expression " +
3594 "as `" + TypeManager.CSharpName (true_expr.Type) +
3595 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3596 "' convert implicitly to each other");
3601 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3605 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3606 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3611 // Dead code optimalization
3612 if (expr is BoolConstant){
3613 BoolConstant bc = (BoolConstant) expr;
3615 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3616 return bc.Value ? true_expr : false_expr;
3622 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3627 public override void Emit (EmitContext ec)
3629 ILGenerator ig = ec.ig;
3630 Label false_target = ig.DefineLabel ();
3631 Label end_target = ig.DefineLabel ();
3633 expr.EmitBranchable (ec, false_target, false);
3634 true_expr.Emit (ec);
3636 if (type.IsInterface) {
3637 LocalBuilder temp = ec.GetTemporaryLocal (type);
3638 ig.Emit (OpCodes.Stloc, temp);
3639 ig.Emit (OpCodes.Ldloc, temp);
3640 ec.FreeTemporaryLocal (temp, type);
3643 ig.Emit (OpCodes.Br, end_target);
3644 ig.MarkLabel (false_target);
3645 false_expr.Emit (ec);
3646 ig.MarkLabel (end_target);
3649 protected override void CloneTo (CloneContext clonectx, Expression t)
3651 Conditional target = (Conditional) t;
3653 target.expr = expr.Clone (clonectx);
3654 target.true_expr = true_expr.Clone (clonectx);
3655 target.false_expr = false_expr.Clone (clonectx);
3659 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3661 LocalTemporary temp;
3663 public abstract Variable Variable {
3667 public abstract bool IsRef {
3671 public override void Emit (EmitContext ec)
3677 // This method is used by parameters that are references, that are
3678 // being passed as references: we only want to pass the pointer (that
3679 // is already stored in the parameter, not the address of the pointer,
3680 // and not the value of the variable).
3682 public void EmitLoad (EmitContext ec)
3684 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3686 Variable.EmitInstance (ec);
3690 public void Emit (EmitContext ec, bool leave_copy)
3692 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3698 // If we are a reference, we loaded on the stack a pointer
3699 // Now lets load the real value
3701 LoadFromPtr (ec.ig, type);
3705 ec.ig.Emit (OpCodes.Dup);
3707 if (IsRef || Variable.NeedsTemporary) {
3708 temp = new LocalTemporary (Type);
3714 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3715 bool prepare_for_load)
3717 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3720 ILGenerator ig = ec.ig;
3721 prepared = prepare_for_load;
3723 Variable.EmitInstance (ec);
3724 if (prepare_for_load) {
3725 if (Variable.HasInstance)
3726 ig.Emit (OpCodes.Dup);
3734 // HACK: variable is already emitted when source is an initializer
3735 if (source is NewInitialize)
3739 ig.Emit (OpCodes.Dup);
3740 if (IsRef || Variable.NeedsTemporary) {
3741 temp = new LocalTemporary (Type);
3747 StoreFromPtr (ig, type);
3749 Variable.EmitAssign (ec);
3757 public void AddressOf (EmitContext ec, AddressOp mode)
3759 Variable.EmitInstance (ec);
3760 Variable.EmitAddressOf (ec);
3767 public class LocalVariableReference : VariableReference, IVariable {
3768 public readonly string Name;
3770 public LocalInfo local_info;
3774 public LocalVariableReference (Block block, string name, Location l)
3779 eclass = ExprClass.Variable;
3783 // Setting `is_readonly' to false will allow you to create a writable
3784 // reference to a read-only variable. This is used by foreach and using.
3786 public LocalVariableReference (Block block, string name, Location l,
3787 LocalInfo local_info, bool is_readonly)
3788 : this (block, name, l)
3790 this.local_info = local_info;
3791 this.is_readonly = is_readonly;
3794 public VariableInfo VariableInfo {
3795 get { return local_info.VariableInfo; }
3798 public override bool IsRef {
3799 get { return false; }
3802 public bool IsReadOnly {
3803 get { return is_readonly; }
3806 public bool VerifyAssigned (EmitContext ec)
3808 VariableInfo variable_info = local_info.VariableInfo;
3809 return variable_info == null || variable_info.IsAssigned (ec, loc);
3812 void ResolveLocalInfo ()
3814 if (local_info == null) {
3815 local_info = Block.GetLocalInfo (Name);
3816 type = local_info.VariableType;
3817 is_readonly = local_info.ReadOnly;
3821 protected Expression DoResolveBase (EmitContext ec)
3823 type = local_info.VariableType;
3825 Expression e = Block.GetConstantExpression (Name);
3827 return e.Resolve (ec);
3829 if (!VerifyAssigned (ec))
3833 // If we are referencing a variable from the external block
3834 // flag it for capturing
3836 if (ec.MustCaptureVariable (local_info)) {
3837 if (local_info.AddressTaken){
3838 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3842 if (!ec.IsInProbingMode)
3844 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3845 variable = scope.AddLocal (local_info);
3846 type = variable.Type;
3853 public override Expression DoResolve (EmitContext ec)
3855 ResolveLocalInfo ();
3856 local_info.Used = true;
3858 if (type == null && local_info.Type is VarExpr) {
3859 local_info.VariableType = TypeManager.object_type;
3860 Error_VariableIsUsedBeforeItIsDeclared (Name);
3864 return DoResolveBase (ec);
3867 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3869 ResolveLocalInfo ();
3872 if (right_side == EmptyExpression.OutAccess)
3873 local_info.Used = true;
3875 // Infer implicitly typed local variable
3877 VarExpr ve = local_info.Type as VarExpr;
3879 ve.DoResolveLValue (ec, right_side);
3880 type = local_info.VariableType = ve.Type;
3887 if (right_side == EmptyExpression.OutAccess) {
3888 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3889 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3890 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3891 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3892 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3894 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3896 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3900 if (VariableInfo != null)
3901 VariableInfo.SetAssigned (ec);
3903 return DoResolveBase (ec);
3906 public bool VerifyFixed ()
3908 // A local Variable is always fixed.
3912 public override int GetHashCode ()
3914 return Name.GetHashCode ();
3917 public override bool Equals (object obj)
3919 LocalVariableReference lvr = obj as LocalVariableReference;
3923 return Name == lvr.Name && Block == lvr.Block;
3926 public override Variable Variable {
3927 get { return variable != null ? variable : local_info.Variable; }
3930 public override string ToString ()
3932 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3935 protected override void CloneTo (CloneContext clonectx, Expression t)
3937 LocalVariableReference target = (LocalVariableReference) t;
3939 target.Block = clonectx.LookupBlock (Block);
3940 if (local_info != null)
3941 target.local_info = clonectx.LookupVariable (local_info);
3946 /// This represents a reference to a parameter in the intermediate
3949 public class ParameterReference : VariableReference, IVariable {
3950 readonly ToplevelParameterInfo pi;
3951 readonly ToplevelBlock referenced;
3954 public bool is_ref, is_out;
3957 get { return is_out; }
3960 public override bool IsRef {
3961 get { return is_ref; }
3964 public string Name {
3965 get { return Parameter.Name; }
3968 public Parameter Parameter {
3969 get { return pi.Parameter; }
3972 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3975 this.referenced = referenced;
3977 eclass = ExprClass.Variable;
3980 public VariableInfo VariableInfo {
3981 get { return pi.VariableInfo; }
3984 public override Variable Variable {
3985 get { return variable != null ? variable : Parameter.Variable; }
3988 public bool VerifyFixed ()
3990 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3991 return Parameter.ModFlags == Parameter.Modifier.NONE;
3994 public bool IsAssigned (EmitContext ec, Location loc)
3996 // HACK: Variables are not captured in probing mode
3997 if (ec.IsInProbingMode)
4000 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
4003 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4007 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4009 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
4012 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
4016 public void SetAssigned (EmitContext ec)
4018 if (is_out && ec.DoFlowAnalysis)
4019 ec.CurrentBranching.SetAssigned (VariableInfo);
4022 public void SetFieldAssigned (EmitContext ec, string field_name)
4024 if (is_out && ec.DoFlowAnalysis)
4025 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
4028 protected bool DoResolveBase (EmitContext ec)
4030 Parameter par = Parameter;
4031 if (!par.Resolve (ec)) {
4035 type = par.ParameterType;
4036 Parameter.Modifier mod = par.ModFlags;
4037 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4038 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
4039 eclass = ExprClass.Variable;
4041 AnonymousContainer am = ec.CurrentAnonymousMethod;
4045 ToplevelBlock declared = pi.Block;
4046 if (is_ref && declared != referenced) {
4047 Report.Error (1628, Location,
4048 "Cannot use ref or out parameter `{0}' inside an " +
4049 "anonymous method block", par.Name);
4053 if (!am.IsIterator && declared == referenced)
4056 // Don't capture aruments when the probing is on
4057 if (!ec.IsInProbingMode) {
4058 ScopeInfo scope = declared.CreateScopeInfo ();
4059 variable = scope.AddParameter (par, pi.Index);
4060 type = variable.Type;
4065 public override int GetHashCode ()
4067 return Name.GetHashCode ();
4070 public override bool Equals (object obj)
4072 ParameterReference pr = obj as ParameterReference;
4076 return Name == pr.Name && referenced == pr.referenced;
4079 public override Expression CreateExpressionTree (EmitContext ec)
4081 return Parameter.ExpressionTreeVariableReference ();
4085 // Notice that for ref/out parameters, the type exposed is not the
4086 // same type exposed externally.
4089 // externally we expose "int&"
4090 // here we expose "int".
4092 // We record this in "is_ref". This means that the type system can treat
4093 // the type as it is expected, but when we generate the code, we generate
4094 // the alternate kind of code.
4096 public override Expression DoResolve (EmitContext ec)
4098 if (!DoResolveBase (ec))
4101 if (is_out && ec.DoFlowAnalysis &&
4102 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4108 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4110 if (!DoResolveBase (ec))
4113 // HACK: parameters are not captured when probing is on
4114 if (!ec.IsInProbingMode)
4120 static public void EmitLdArg (ILGenerator ig, int x)
4124 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4125 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4126 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4127 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4128 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4131 ig.Emit (OpCodes.Ldarg, x);
4134 public override string ToString ()
4136 return "ParameterReference[" + Name + "]";
4141 /// Used for arguments to New(), Invocation()
4143 public class Argument {
4144 public enum AType : byte {
4151 public static readonly Argument[] Empty = new Argument [0];
4153 public readonly AType ArgType;
4154 public Expression Expr;
4156 public Argument (Expression expr, AType type)
4159 this.ArgType = type;
4162 public Argument (Expression expr)
4165 this.ArgType = AType.Expression;
4170 if (ArgType == AType.Ref || ArgType == AType.Out)
4171 return TypeManager.GetReferenceType (Expr.Type);
4177 public Parameter.Modifier Modifier
4182 return Parameter.Modifier.OUT;
4185 return Parameter.Modifier.REF;
4188 return Parameter.Modifier.NONE;
4193 public string GetSignatureForError ()
4195 if (Expr.eclass == ExprClass.MethodGroup)
4196 return Expr.ExprClassName;
4198 return Expr.GetSignatureForError ();
4201 public bool ResolveMethodGroup (EmitContext ec)
4203 SimpleName sn = Expr as SimpleName;
4205 Expr = sn.GetMethodGroup ();
4207 // FIXME: csc doesn't report any error if you try to use `ref' or
4208 // `out' in a delegate creation expression.
4209 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4216 public bool Resolve (EmitContext ec, Location loc)
4218 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4219 // Verify that the argument is readable
4220 if (ArgType != AType.Out)
4221 Expr = Expr.Resolve (ec);
4223 // Verify that the argument is writeable
4224 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4225 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4227 return Expr != null;
4231 public void Emit (EmitContext ec)
4233 if (ArgType != AType.Ref && ArgType != AType.Out) {
4238 AddressOp mode = AddressOp.Store;
4239 if (ArgType == AType.Ref)
4240 mode |= AddressOp.Load;
4242 IMemoryLocation ml = (IMemoryLocation) Expr;
4243 ParameterReference pr = ml as ParameterReference;
4246 // ParameterReferences might already be references, so we want
4247 // to pass just the value
4249 if (pr != null && pr.IsRef)
4252 ml.AddressOf (ec, mode);
4255 public Argument Clone (CloneContext clonectx)
4257 return new Argument (Expr.Clone (clonectx), ArgType);
4262 /// Invocation of methods or delegates.
4264 public class Invocation : ExpressionStatement {
4265 protected ArrayList Arguments;
4267 protected MethodGroupExpr mg;
4268 bool arguments_resolved;
4271 // arguments is an ArrayList, but we do not want to typecast,
4272 // as it might be null.
4274 public Invocation (Expression expr, ArrayList arguments)
4276 SimpleName sn = expr as SimpleName;
4278 this.expr = sn.GetMethodGroup ();
4282 Arguments = arguments;
4283 loc = expr.Location;
4286 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4287 : this (expr, arguments)
4289 this.arguments_resolved = arguments_resolved;
4292 public static string FullMethodDesc (MethodBase mb)
4298 if (mb is MethodInfo) {
4299 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4303 sb = new StringBuilder ();
4305 sb.Append (TypeManager.CSharpSignature (mb));
4306 return sb.ToString ();
4309 public override Expression CreateExpressionTree (EmitContext ec)
4311 ArrayList args = new ArrayList (Arguments.Count + 3);
4313 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4315 args.Add (new Argument (new NullConstant (loc).CreateExpressionTree (ec)));
4317 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4318 foreach (Argument a in Arguments) {
4319 Expression e = a.Expr.CreateExpressionTree (ec);
4321 args.Add (new Argument (e));
4324 return CreateExpressionFactoryCall ("Call", args);
4327 public override Expression DoResolve (EmitContext ec)
4329 // Don't resolve already resolved expression
4330 if (eclass != ExprClass.Invalid)
4333 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4334 if (expr_resolved == null)
4337 mg = expr_resolved as MethodGroupExpr;
4339 Type expr_type = expr_resolved.Type;
4341 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4342 return (new DelegateInvocation (
4343 expr_resolved, Arguments, loc)).Resolve (ec);
4346 MemberExpr me = expr_resolved as MemberExpr;
4348 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4352 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name);
4354 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4355 expr_resolved.GetSignatureForError ());
4359 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4363 // Next, evaluate all the expressions in the argument list
4365 if (Arguments != null && !arguments_resolved) {
4366 for (int i = 0; i < Arguments.Count; ++i)
4368 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4373 mg = DoResolveOverload (ec);
4377 MethodInfo method = (MethodInfo)mg;
4378 if (method != null) {
4379 type = TypeManager.TypeToCoreType (method.ReturnType);
4381 // TODO: this is a copy of mg.ResolveMemberAccess method
4382 Expression iexpr = mg.InstanceExpression;
4383 if (method.IsStatic) {
4384 if (iexpr == null ||
4385 iexpr is This || iexpr is EmptyExpression ||
4386 mg.IdenticalTypeName) {
4387 mg.InstanceExpression = null;
4389 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4395 if (type.IsPointer){
4403 // Only base will allow this invocation to happen.
4405 if (mg.IsBase && method.IsAbstract){
4406 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4410 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4412 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4414 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4418 if (IsSpecialMethodInvocation (method)) {
4422 if (mg.InstanceExpression != null)
4423 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4425 eclass = ExprClass.Value;
4429 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4431 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4434 bool IsSpecialMethodInvocation (MethodBase method)
4436 if (!TypeManager.IsSpecialMethod (method))
4439 Report.SymbolRelatedToPreviousError (method);
4440 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4441 TypeManager.CSharpSignature (method, true));
4447 /// Emits a list of resolved Arguments that are in the arguments
4450 /// The MethodBase argument might be null if the
4451 /// emission of the arguments is known not to contain
4452 /// a `params' field (for example in constructors or other routines
4453 /// that keep their arguments in this structure)
4455 /// if `dup_args' is true, a copy of the arguments will be left
4456 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4457 /// which will be duplicated before any other args. Only EmitCall
4458 /// should be using this interface.
4460 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4462 if (arguments == null)
4465 int top = arguments.Count;
4466 LocalTemporary [] temps = null;
4468 if (dup_args && top != 0)
4469 temps = new LocalTemporary [top];
4471 int argument_index = 0;
4473 for (int i = 0; i < top; i++) {
4474 a = (Argument) arguments [argument_index++];
4477 ec.ig.Emit (OpCodes.Dup);
4478 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4483 if (this_arg != null)
4486 for (int i = 0; i < top; i ++) {
4487 temps [i].Emit (ec);
4488 temps [i].Release (ec);
4493 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4495 ParameterData pd = TypeManager.GetParameterData (mb);
4497 if (arguments == null)
4498 return new Type [0];
4500 Argument a = (Argument) arguments [pd.Count - 1];
4501 Arglist list = (Arglist) a.Expr;
4503 return list.ArgumentTypes;
4507 /// This checks the ConditionalAttribute on the method
4509 public static bool IsMethodExcluded (MethodBase method)
4511 if (method.IsConstructor)
4514 method = TypeManager.DropGenericMethodArguments (method);
4515 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4516 IMethodData md = TypeManager.GetMethod (method);
4518 return md.IsExcluded ();
4520 // For some methods (generated by delegate class) GetMethod returns null
4521 // because they are not included in builder_to_method table
4525 return AttributeTester.IsConditionalMethodExcluded (method);
4529 /// is_base tells whether we want to force the use of the `call'
4530 /// opcode instead of using callvirt. Call is required to call
4531 /// a specific method, while callvirt will always use the most
4532 /// recent method in the vtable.
4534 /// is_static tells whether this is an invocation on a static method
4536 /// instance_expr is an expression that represents the instance
4537 /// it must be non-null if is_static is false.
4539 /// method is the method to invoke.
4541 /// Arguments is the list of arguments to pass to the method or constructor.
4543 public static void EmitCall (EmitContext ec, bool is_base,
4544 Expression instance_expr,
4545 MethodBase method, ArrayList Arguments, Location loc)
4547 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4550 // `dup_args' leaves an extra copy of the arguments on the stack
4551 // `omit_args' does not leave any arguments at all.
4552 // So, basically, you could make one call with `dup_args' set to true,
4553 // and then another with `omit_args' set to true, and the two calls
4554 // would have the same set of arguments. However, each argument would
4555 // only have been evaluated once.
4556 public static void EmitCall (EmitContext ec, bool is_base,
4557 Expression instance_expr,
4558 MethodBase method, ArrayList Arguments, Location loc,
4559 bool dup_args, bool omit_args)
4561 ILGenerator ig = ec.ig;
4562 bool struct_call = false;
4563 bool this_call = false;
4564 LocalTemporary this_arg = null;
4566 Type decl_type = method.DeclaringType;
4568 if (!RootContext.StdLib) {
4569 // Replace any calls to the system's System.Array type with calls to
4570 // the newly created one.
4571 if (method == TypeManager.system_int_array_get_length)
4572 method = TypeManager.int_array_get_length;
4573 else if (method == TypeManager.system_int_array_get_rank)
4574 method = TypeManager.int_array_get_rank;
4575 else if (method == TypeManager.system_object_array_clone)
4576 method = TypeManager.object_array_clone;
4577 else if (method == TypeManager.system_int_array_get_length_int)
4578 method = TypeManager.int_array_get_length_int;
4579 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4580 method = TypeManager.int_array_get_lower_bound_int;
4581 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4582 method = TypeManager.int_array_get_upper_bound_int;
4583 else if (method == TypeManager.system_void_array_copyto_array_int)
4584 method = TypeManager.void_array_copyto_array_int;
4587 if (!ec.IsInObsoleteScope) {
4589 // This checks ObsoleteAttribute on the method and on the declaring type
4591 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4593 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4595 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4597 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4601 if (IsMethodExcluded (method))
4604 bool is_static = method.IsStatic;
4606 if (instance_expr == EmptyExpression.Null) {
4607 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4611 this_call = instance_expr is This;
4612 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4616 // If this is ourselves, push "this"
4620 Type iexpr_type = instance_expr.Type;
4623 // Push the instance expression
4625 if (TypeManager.IsValueType (iexpr_type)) {
4627 // Special case: calls to a function declared in a
4628 // reference-type with a value-type argument need
4629 // to have their value boxed.
4630 if (decl_type.IsValueType ||
4631 TypeManager.IsGenericParameter (iexpr_type)) {
4633 // If the expression implements IMemoryLocation, then
4634 // we can optimize and use AddressOf on the
4637 // If not we have to use some temporary storage for
4639 if (instance_expr is IMemoryLocation) {
4640 ((IMemoryLocation)instance_expr).
4641 AddressOf (ec, AddressOp.LoadStore);
4643 LocalTemporary temp = new LocalTemporary (iexpr_type);
4644 instance_expr.Emit (ec);
4646 temp.AddressOf (ec, AddressOp.Load);
4649 // avoid the overhead of doing this all the time.
4651 t = TypeManager.GetReferenceType (iexpr_type);
4653 instance_expr.Emit (ec);
4654 ig.Emit (OpCodes.Box, instance_expr.Type);
4655 t = TypeManager.object_type;
4658 instance_expr.Emit (ec);
4659 t = instance_expr.Type;
4663 ig.Emit (OpCodes.Dup);
4664 if (Arguments != null && Arguments.Count != 0) {
4665 this_arg = new LocalTemporary (t);
4666 this_arg.Store (ec);
4673 EmitArguments (ec, Arguments, dup_args, this_arg);
4676 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4677 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4681 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4682 call_op = OpCodes.Call;
4684 call_op = OpCodes.Callvirt;
4686 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4687 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4688 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4695 // and DoFoo is not virtual, you can omit the callvirt,
4696 // because you don't need the null checking behavior.
4698 if (method is MethodInfo)
4699 ig.Emit (call_op, (MethodInfo) method);
4701 ig.Emit (call_op, (ConstructorInfo) method);
4704 public override void Emit (EmitContext ec)
4706 mg.EmitCall (ec, Arguments);
4709 public override void EmitStatement (EmitContext ec)
4714 // Pop the return value if there is one
4716 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4717 ec.ig.Emit (OpCodes.Pop);
4720 protected override void CloneTo (CloneContext clonectx, Expression t)
4722 Invocation target = (Invocation) t;
4724 if (Arguments != null) {
4725 target.Arguments = new ArrayList (Arguments.Count);
4726 foreach (Argument a in Arguments)
4727 target.Arguments.Add (a.Clone (clonectx));
4730 target.expr = expr.Clone (clonectx);
4734 public class InvocationOrCast : ExpressionStatement
4737 Expression argument;
4739 public InvocationOrCast (Expression expr, Expression argument)
4742 this.argument = argument;
4743 this.loc = expr.Location;
4746 public override Expression DoResolve (EmitContext ec)
4749 // First try to resolve it as a cast.
4751 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4752 if ((te != null) && (te.eclass == ExprClass.Type)) {
4753 Cast cast = new Cast (te, argument, loc);
4754 return cast.Resolve (ec);
4758 // This can either be a type or a delegate invocation.
4759 // Let's just resolve it and see what we'll get.
4761 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4766 // Ok, so it's a Cast.
4768 if (expr.eclass == ExprClass.Type) {
4769 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4770 return cast.Resolve (ec);
4774 // It's a delegate invocation.
4776 if (!TypeManager.IsDelegateType (expr.Type)) {
4777 Error (149, "Method name expected");
4781 ArrayList args = new ArrayList ();
4782 args.Add (new Argument (argument, Argument.AType.Expression));
4783 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4784 return invocation.Resolve (ec);
4787 public override ExpressionStatement ResolveStatement (EmitContext ec)
4790 // First try to resolve it as a cast.
4792 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4793 if ((te != null) && (te.eclass == ExprClass.Type)) {
4794 Error_InvalidExpressionStatement ();
4799 // This can either be a type or a delegate invocation.
4800 // Let's just resolve it and see what we'll get.
4802 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4803 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4804 Error_InvalidExpressionStatement ();
4809 // It's a delegate invocation.
4811 if (!TypeManager.IsDelegateType (expr.Type)) {
4812 Error (149, "Method name expected");
4816 ArrayList args = new ArrayList ();
4817 args.Add (new Argument (argument, Argument.AType.Expression));
4818 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4819 return invocation.ResolveStatement (ec);
4822 public override void Emit (EmitContext ec)
4824 throw new Exception ("Cannot happen");
4827 public override void EmitStatement (EmitContext ec)
4829 throw new Exception ("Cannot happen");
4832 protected override void CloneTo (CloneContext clonectx, Expression t)
4834 InvocationOrCast target = (InvocationOrCast) t;
4836 target.expr = expr.Clone (clonectx);
4837 target.argument = argument.Clone (clonectx);
4842 // This class is used to "disable" the code generation for the
4843 // temporary variable when initializing value types.
4845 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4846 public void AddressOf (EmitContext ec, AddressOp Mode)
4853 /// Implements the new expression
4855 public class New : ExpressionStatement, IMemoryLocation {
4856 ArrayList Arguments;
4859 // During bootstrap, it contains the RequestedType,
4860 // but if `type' is not null, it *might* contain a NewDelegate
4861 // (because of field multi-initialization)
4863 public Expression RequestedType;
4865 MethodGroupExpr method;
4868 // If set, the new expression is for a value_target, and
4869 // we will not leave anything on the stack.
4871 protected Expression value_target;
4872 protected bool value_target_set;
4873 bool is_type_parameter = false;
4875 public New (Expression requested_type, ArrayList arguments, Location l)
4877 RequestedType = requested_type;
4878 Arguments = arguments;
4882 public bool SetTargetVariable (Expression value)
4884 value_target = value;
4885 value_target_set = true;
4886 if (!(value_target is IMemoryLocation)){
4887 Error_UnexpectedKind (null, "variable", loc);
4894 // This function is used to disable the following code sequence for
4895 // value type initialization:
4897 // AddressOf (temporary)
4901 // Instead the provide will have provided us with the address on the
4902 // stack to store the results.
4904 static Expression MyEmptyExpression;
4906 public void DisableTemporaryValueType ()
4908 if (MyEmptyExpression == null)
4909 MyEmptyExpression = new EmptyAddressOf ();
4912 // To enable this, look into:
4913 // test-34 and test-89 and self bootstrapping.
4915 // For instance, we can avoid a copy by using `newobj'
4916 // instead of Call + Push-temp on value types.
4917 // value_target = MyEmptyExpression;
4922 /// Converts complex core type syntax like 'new int ()' to simple constant
4924 public static Constant Constantify (Type t)
4926 if (t == TypeManager.int32_type)
4927 return new IntConstant (0, Location.Null);
4928 if (t == TypeManager.uint32_type)
4929 return new UIntConstant (0, Location.Null);
4930 if (t == TypeManager.int64_type)
4931 return new LongConstant (0, Location.Null);
4932 if (t == TypeManager.uint64_type)
4933 return new ULongConstant (0, Location.Null);
4934 if (t == TypeManager.float_type)
4935 return new FloatConstant (0, Location.Null);
4936 if (t == TypeManager.double_type)
4937 return new DoubleConstant (0, Location.Null);
4938 if (t == TypeManager.short_type)
4939 return new ShortConstant (0, Location.Null);
4940 if (t == TypeManager.ushort_type)
4941 return new UShortConstant (0, Location.Null);
4942 if (t == TypeManager.sbyte_type)
4943 return new SByteConstant (0, Location.Null);
4944 if (t == TypeManager.byte_type)
4945 return new ByteConstant (0, Location.Null);
4946 if (t == TypeManager.char_type)
4947 return new CharConstant ('\0', Location.Null);
4948 if (t == TypeManager.bool_type)
4949 return new BoolConstant (false, Location.Null);
4950 if (t == TypeManager.decimal_type)
4951 return new DecimalConstant (0, Location.Null);
4952 if (TypeManager.IsEnumType (t))
4953 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
4959 // Checks whether the type is an interface that has the
4960 // [ComImport, CoClass] attributes and must be treated
4963 public Expression CheckComImport (EmitContext ec)
4965 if (!type.IsInterface)
4969 // Turn the call into:
4970 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
4972 Type real_class = AttributeTester.GetCoClassAttribute (type);
4973 if (real_class == null)
4976 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
4977 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
4978 return cast.Resolve (ec);
4981 public override Expression DoResolve (EmitContext ec)
4984 // The New DoResolve might be called twice when initializing field
4985 // expressions (see EmitFieldInitializers, the call to
4986 // GetInitializerExpression will perform a resolve on the expression,
4987 // and later the assign will trigger another resolution
4989 // This leads to bugs (#37014)
4992 if (RequestedType is NewDelegate)
4993 return RequestedType;
4997 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5003 if (type == TypeManager.void_type) {
5004 Error_VoidInvalidInTheContext (loc);
5008 if (type.IsPointer) {
5009 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5010 TypeManager.CSharpName (type));
5014 if (Arguments == null) {
5015 Expression c = Constantify (type);
5020 if (TypeManager.IsDelegateType (type)) {
5021 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5022 if (RequestedType != null)
5023 if (!(RequestedType is DelegateCreation))
5024 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5025 return RequestedType;
5029 if (type.IsGenericParameter) {
5030 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5032 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5033 Error (304, String.Format (
5034 "Cannot create an instance of the " +
5035 "variable type '{0}' because it " +
5036 "doesn't have the new() constraint",
5041 if ((Arguments != null) && (Arguments.Count != 0)) {
5042 Error (417, String.Format (
5043 "`{0}': cannot provide arguments " +
5044 "when creating an instance of a " +
5045 "variable type.", type));
5049 is_type_parameter = true;
5050 eclass = ExprClass.Value;
5055 if (type.IsAbstract && type.IsSealed) {
5056 Report.SymbolRelatedToPreviousError (type);
5057 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5061 if (type.IsInterface || type.IsAbstract){
5062 if (!TypeManager.IsGenericType (type)) {
5063 RequestedType = CheckComImport (ec);
5064 if (RequestedType != null)
5065 return RequestedType;
5068 Report.SymbolRelatedToPreviousError (type);
5069 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5073 bool is_struct = type.IsValueType;
5074 eclass = ExprClass.Value;
5077 // SRE returns a match for .ctor () on structs (the object constructor),
5078 // so we have to manually ignore it.
5080 if (is_struct && Arguments == null)
5083 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5084 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5085 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5087 if (Arguments != null){
5088 foreach (Argument a in Arguments){
5089 if (!a.Resolve (ec, loc))
5097 method = ml as MethodGroupExpr;
5098 if (method == null) {
5099 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5103 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5110 bool DoEmitTypeParameter (EmitContext ec)
5113 ILGenerator ig = ec.ig;
5114 // IMemoryLocation ml;
5116 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5117 new Type [] { type });
5119 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5120 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5121 ig.Emit (OpCodes.Call, ci);
5125 // Allow DoEmit() to be called multiple times.
5126 // We need to create a new LocalTemporary each time since
5127 // you can't share LocalBuilders among ILGeneators.
5128 LocalTemporary temp = new LocalTemporary (type);
5130 Label label_activator = ig.DefineLabel ();
5131 Label label_end = ig.DefineLabel ();
5133 temp.AddressOf (ec, AddressOp.Store);
5134 ig.Emit (OpCodes.Initobj, type);
5137 ig.Emit (OpCodes.Box, type);
5138 ig.Emit (OpCodes.Brfalse, label_activator);
5140 temp.AddressOf (ec, AddressOp.Store);
5141 ig.Emit (OpCodes.Initobj, type);
5143 ig.Emit (OpCodes.Br, label_end);
5145 ig.MarkLabel (label_activator);
5147 ig.Emit (OpCodes.Call, ci);
5148 ig.MarkLabel (label_end);
5151 throw new InternalErrorException ();
5156 // This DoEmit can be invoked in two contexts:
5157 // * As a mechanism that will leave a value on the stack (new object)
5158 // * As one that wont (init struct)
5160 // You can control whether a value is required on the stack by passing
5161 // need_value_on_stack. The code *might* leave a value on the stack
5162 // so it must be popped manually
5164 // If we are dealing with a ValueType, we have a few
5165 // situations to deal with:
5167 // * The target is a ValueType, and we have been provided
5168 // the instance (this is easy, we are being assigned).
5170 // * The target of New is being passed as an argument,
5171 // to a boxing operation or a function that takes a
5174 // In this case, we need to create a temporary variable
5175 // that is the argument of New.
5177 // Returns whether a value is left on the stack
5179 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5181 bool is_value_type = TypeManager.IsValueType (type);
5182 ILGenerator ig = ec.ig;
5187 // Allow DoEmit() to be called multiple times.
5188 // We need to create a new LocalTemporary each time since
5189 // you can't share LocalBuilders among ILGeneators.
5190 if (!value_target_set)
5191 value_target = new LocalTemporary (type);
5193 ml = (IMemoryLocation) value_target;
5194 ml.AddressOf (ec, AddressOp.Store);
5198 method.EmitArguments (ec, Arguments);
5202 ig.Emit (OpCodes.Initobj, type);
5204 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5205 if (need_value_on_stack){
5206 value_target.Emit (ec);
5211 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5216 public override void Emit (EmitContext ec)
5218 if (is_type_parameter)
5219 DoEmitTypeParameter (ec);
5224 public override void EmitStatement (EmitContext ec)
5226 bool value_on_stack;
5228 if (is_type_parameter)
5229 value_on_stack = DoEmitTypeParameter (ec);
5231 value_on_stack = DoEmit (ec, false);
5234 ec.ig.Emit (OpCodes.Pop);
5238 public virtual bool HasInitializer {
5244 public void AddressOf (EmitContext ec, AddressOp Mode)
5246 if (is_type_parameter) {
5247 LocalTemporary temp = new LocalTemporary (type);
5248 DoEmitTypeParameter (ec);
5250 temp.AddressOf (ec, Mode);
5254 if (!type.IsValueType){
5256 // We throw an exception. So far, I believe we only need to support
5258 // foreach (int j in new StructType ())
5261 throw new Exception ("AddressOf should not be used for classes");
5264 if (!value_target_set)
5265 value_target = new LocalTemporary (type);
5266 IMemoryLocation ml = (IMemoryLocation) value_target;
5268 ml.AddressOf (ec, AddressOp.Store);
5269 if (method == null) {
5270 ec.ig.Emit (OpCodes.Initobj, type);
5272 method.EmitArguments (ec, Arguments);
5273 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5276 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5279 protected override void CloneTo (CloneContext clonectx, Expression t)
5281 New target = (New) t;
5283 target.RequestedType = RequestedType.Clone (clonectx);
5284 if (Arguments != null){
5285 target.Arguments = new ArrayList ();
5286 foreach (Argument a in Arguments){
5287 target.Arguments.Add (a.Clone (clonectx));
5294 /// 14.5.10.2: Represents an array creation expression.
5298 /// There are two possible scenarios here: one is an array creation
5299 /// expression that specifies the dimensions and optionally the
5300 /// initialization data and the other which does not need dimensions
5301 /// specified but where initialization data is mandatory.
5303 public class ArrayCreation : Expression {
5304 Expression requested_base_type;
5305 ArrayList initializers;
5308 // The list of Argument types.
5309 // This is used to construct the `newarray' or constructor signature
5311 protected ArrayList arguments;
5313 protected Type array_element_type;
5314 bool expect_initializers = false;
5315 int num_arguments = 0;
5316 protected int dimensions;
5317 protected readonly string rank;
5319 protected ArrayList array_data;
5323 // The number of constants in array initializers
5324 int const_initializers_count;
5325 bool only_constant_initializers;
5327 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5329 this.requested_base_type = requested_base_type;
5330 this.initializers = initializers;
5334 arguments = new ArrayList ();
5336 foreach (Expression e in exprs) {
5337 arguments.Add (new Argument (e, Argument.AType.Expression));
5342 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5344 this.requested_base_type = requested_base_type;
5345 this.initializers = initializers;
5349 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5351 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5353 //dimensions = tmp.Length - 1;
5354 expect_initializers = true;
5357 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5359 StringBuilder sb = new StringBuilder (rank);
5362 for (int i = 1; i < idx_count; i++)
5367 return new ComposedCast (base_type, sb.ToString (), loc);
5370 void Error_IncorrectArrayInitializer ()
5372 Error (178, "Invalid rank specifier: expected `,' or `]'");
5375 protected override void Error_NegativeArrayIndex (Location loc)
5377 Report.Error (248, loc, "Cannot create an array with a negative size");
5380 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5382 if (specified_dims) {
5383 Argument a = (Argument) arguments [idx];
5385 if (!a.Resolve (ec, loc))
5388 Constant c = a.Expr as Constant;
5390 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5394 Report.Error (150, a.Expr.Location, "A constant value is expected");
5398 int value = (int) c.GetValue ();
5400 if (value != probe.Count) {
5401 Error_IncorrectArrayInitializer ();
5405 bounds [idx] = value;
5408 int child_bounds = -1;
5409 only_constant_initializers = true;
5410 for (int i = 0; i < probe.Count; ++i) {
5411 object o = probe [i];
5412 if (o is ArrayList) {
5413 ArrayList sub_probe = o as ArrayList;
5414 int current_bounds = sub_probe.Count;
5416 if (child_bounds == -1)
5417 child_bounds = current_bounds;
5419 else if (child_bounds != current_bounds){
5420 Error_IncorrectArrayInitializer ();
5423 if (idx + 1 >= dimensions){
5424 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5428 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5432 if (child_bounds != -1){
5433 Error_IncorrectArrayInitializer ();
5437 Expression element = ResolveArrayElement (ec, (Expression) o);
5438 if (element == null)
5441 // Initializers with the default values can be ignored
5442 Constant c = element as Constant;
5444 if (c.IsDefaultInitializer (array_element_type)) {
5448 ++const_initializers_count;
5451 only_constant_initializers = false;
5454 array_data.Add (element);
5461 public override Expression CreateExpressionTree (EmitContext ec)
5463 if (dimensions != 1) {
5464 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5468 ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5469 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5470 if (array_data != null) {
5471 foreach (Expression e in array_data)
5472 args.Add (new Argument (e.CreateExpressionTree (ec)));
5475 return CreateExpressionFactoryCall ("NewArrayInit", args);
5478 public void UpdateIndices ()
5481 for (ArrayList probe = initializers; probe != null;) {
5482 if (probe.Count > 0 && probe [0] is ArrayList) {
5483 Expression e = new IntConstant (probe.Count, Location.Null);
5484 arguments.Add (new Argument (e, Argument.AType.Expression));
5486 bounds [i++] = probe.Count;
5488 probe = (ArrayList) probe [0];
5491 Expression e = new IntConstant (probe.Count, Location.Null);
5492 arguments.Add (new Argument (e, Argument.AType.Expression));
5494 bounds [i++] = probe.Count;
5501 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5503 element = element.Resolve (ec);
5504 if (element == null)
5507 return Convert.ImplicitConversionRequired (
5508 ec, element, array_element_type, loc);
5511 protected bool ResolveInitializers (EmitContext ec)
5513 if (initializers == null) {
5514 return !expect_initializers;
5518 // We use this to store all the date values in the order in which we
5519 // will need to store them in the byte blob later
5521 array_data = new ArrayList ();
5522 bounds = new System.Collections.Specialized.HybridDictionary ();
5524 if (arguments != null)
5525 return CheckIndices (ec, initializers, 0, true);
5527 arguments = new ArrayList ();
5529 if (!CheckIndices (ec, initializers, 0, false))
5538 // Resolved the type of the array
5540 bool ResolveArrayType (EmitContext ec)
5542 if (requested_base_type == null) {
5543 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5547 StringBuilder array_qualifier = new StringBuilder (rank);
5550 // `In the first form allocates an array instace of the type that results
5551 // from deleting each of the individual expression from the expression list'
5553 if (num_arguments > 0) {
5554 array_qualifier.Append ("[");
5555 for (int i = num_arguments-1; i > 0; i--)
5556 array_qualifier.Append (",");
5557 array_qualifier.Append ("]");
5563 TypeExpr array_type_expr;
5564 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5565 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5566 if (array_type_expr == null)
5569 type = array_type_expr.Type;
5570 array_element_type = TypeManager.GetElementType (type);
5571 dimensions = type.GetArrayRank ();
5576 public override Expression DoResolve (EmitContext ec)
5581 if (!ResolveArrayType (ec))
5584 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5585 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5586 TypeManager.CSharpName (array_element_type));
5590 // First step is to validate the initializers and fill
5591 // in any missing bits
5593 if (!ResolveInitializers (ec))
5596 if (arguments.Count != dimensions) {
5597 Error_IncorrectArrayInitializer ();
5600 foreach (Argument a in arguments){
5601 if (!a.Resolve (ec, loc))
5604 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5607 eclass = ExprClass.Value;
5611 MethodInfo GetArrayMethod (int arguments)
5613 ModuleBuilder mb = CodeGen.Module.Builder;
5615 Type[] arg_types = new Type[arguments];
5616 for (int i = 0; i < arguments; i++)
5617 arg_types[i] = TypeManager.int32_type;
5619 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5623 Report.Error (-6, "New invocation: Can not find a constructor for " +
5624 "this argument list");
5631 byte [] MakeByteBlob ()
5636 int count = array_data.Count;
5638 if (array_element_type.IsEnum)
5639 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5641 factor = GetTypeSize (array_element_type);
5643 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5645 data = new byte [(count * factor + 3) & ~3];
5648 for (int i = 0; i < count; ++i) {
5649 object v = array_data [i];
5651 if (v is EnumConstant)
5652 v = ((EnumConstant) v).Child;
5654 if (v is Constant && !(v is StringConstant))
5655 v = ((Constant) v).GetValue ();
5661 if (array_element_type == TypeManager.int64_type){
5662 if (!(v is Expression)){
5663 long val = (long) v;
5665 for (int j = 0; j < factor; ++j) {
5666 data [idx + j] = (byte) (val & 0xFF);
5670 } else if (array_element_type == TypeManager.uint64_type){
5671 if (!(v is Expression)){
5672 ulong val = (ulong) v;
5674 for (int j = 0; j < factor; ++j) {
5675 data [idx + j] = (byte) (val & 0xFF);
5679 } else if (array_element_type == TypeManager.float_type) {
5680 if (!(v is Expression)){
5681 element = BitConverter.GetBytes ((float) v);
5683 for (int j = 0; j < factor; ++j)
5684 data [idx + j] = element [j];
5685 if (!BitConverter.IsLittleEndian)
5686 System.Array.Reverse (data, idx, 4);
5688 } else if (array_element_type == TypeManager.double_type) {
5689 if (!(v is Expression)){
5690 element = BitConverter.GetBytes ((double) v);
5692 for (int j = 0; j < factor; ++j)
5693 data [idx + j] = element [j];
5695 // FIXME: Handle the ARM float format.
5696 if (!BitConverter.IsLittleEndian)
5697 System.Array.Reverse (data, idx, 8);
5699 } else if (array_element_type == TypeManager.char_type){
5700 if (!(v is Expression)){
5701 int val = (int) ((char) v);
5703 data [idx] = (byte) (val & 0xff);
5704 data [idx+1] = (byte) (val >> 8);
5706 } else if (array_element_type == TypeManager.short_type){
5707 if (!(v is Expression)){
5708 int val = (int) ((short) v);
5710 data [idx] = (byte) (val & 0xff);
5711 data [idx+1] = (byte) (val >> 8);
5713 } else if (array_element_type == TypeManager.ushort_type){
5714 if (!(v is Expression)){
5715 int val = (int) ((ushort) v);
5717 data [idx] = (byte) (val & 0xff);
5718 data [idx+1] = (byte) (val >> 8);
5720 } else if (array_element_type == TypeManager.int32_type) {
5721 if (!(v is Expression)){
5724 data [idx] = (byte) (val & 0xff);
5725 data [idx+1] = (byte) ((val >> 8) & 0xff);
5726 data [idx+2] = (byte) ((val >> 16) & 0xff);
5727 data [idx+3] = (byte) (val >> 24);
5729 } else if (array_element_type == TypeManager.uint32_type) {
5730 if (!(v is Expression)){
5731 uint val = (uint) v;
5733 data [idx] = (byte) (val & 0xff);
5734 data [idx+1] = (byte) ((val >> 8) & 0xff);
5735 data [idx+2] = (byte) ((val >> 16) & 0xff);
5736 data [idx+3] = (byte) (val >> 24);
5738 } else if (array_element_type == TypeManager.sbyte_type) {
5739 if (!(v is Expression)){
5740 sbyte val = (sbyte) v;
5741 data [idx] = (byte) val;
5743 } else if (array_element_type == TypeManager.byte_type) {
5744 if (!(v is Expression)){
5745 byte val = (byte) v;
5746 data [idx] = (byte) val;
5748 } else if (array_element_type == TypeManager.bool_type) {
5749 if (!(v is Expression)){
5750 bool val = (bool) v;
5751 data [idx] = (byte) (val ? 1 : 0);
5753 } else if (array_element_type == TypeManager.decimal_type){
5754 if (!(v is Expression)){
5755 int [] bits = Decimal.GetBits ((decimal) v);
5758 // FIXME: For some reason, this doesn't work on the MS runtime.
5759 int [] nbits = new int [4];
5760 nbits [0] = bits [3];
5761 nbits [1] = bits [2];
5762 nbits [2] = bits [0];
5763 nbits [3] = bits [1];
5765 for (int j = 0; j < 4; j++){
5766 data [p++] = (byte) (nbits [j] & 0xff);
5767 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5768 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5769 data [p++] = (byte) (nbits [j] >> 24);
5773 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5782 // Emits the initializers for the array
5784 void EmitStaticInitializers (EmitContext ec)
5787 // First, the static data
5790 ILGenerator ig = ec.ig;
5792 byte [] data = MakeByteBlob ();
5794 fb = RootContext.MakeStaticData (data);
5796 ig.Emit (OpCodes.Dup);
5797 ig.Emit (OpCodes.Ldtoken, fb);
5798 ig.Emit (OpCodes.Call,
5799 TypeManager.void_initializearray_array_fieldhandle);
5803 // Emits pieces of the array that can not be computed at compile
5804 // time (variables and string locations).
5806 // This always expect the top value on the stack to be the array
5808 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5810 ILGenerator ig = ec.ig;
5811 int dims = bounds.Count;
5812 int [] current_pos = new int [dims];
5814 MethodInfo set = null;
5817 Type [] args = new Type [dims + 1];
5819 for (int j = 0; j < dims; j++)
5820 args [j] = TypeManager.int32_type;
5821 args [dims] = array_element_type;
5823 set = CodeGen.Module.Builder.GetArrayMethod (
5825 CallingConventions.HasThis | CallingConventions.Standard,
5826 TypeManager.void_type, args);
5829 for (int i = 0; i < array_data.Count; i++){
5831 Expression e = (Expression)array_data [i];
5833 // Constant can be initialized via StaticInitializer
5834 if (e != null && !(!emitConstants && e is Constant)) {
5835 Type etype = e.Type;
5837 ig.Emit (OpCodes.Dup);
5839 for (int idx = 0; idx < dims; idx++)
5840 IntConstant.EmitInt (ig, current_pos [idx]);
5843 // If we are dealing with a struct, get the
5844 // address of it, so we can store it.
5846 if ((dims == 1) && etype.IsValueType &&
5847 (!TypeManager.IsBuiltinOrEnum (etype) ||
5848 etype == TypeManager.decimal_type)) {
5853 // Let new know that we are providing
5854 // the address where to store the results
5856 n.DisableTemporaryValueType ();
5859 ig.Emit (OpCodes.Ldelema, etype);
5865 bool is_stobj, has_type_arg;
5866 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5868 ig.Emit (OpCodes.Stobj, etype);
5869 else if (has_type_arg)
5870 ig.Emit (op, etype);
5874 ig.Emit (OpCodes.Call, set);
5881 for (int j = dims - 1; j >= 0; j--){
5883 if (current_pos [j] < (int) bounds [j])
5885 current_pos [j] = 0;
5890 public override void Emit (EmitContext ec)
5892 ILGenerator ig = ec.ig;
5894 foreach (Argument a in arguments)
5897 if (arguments.Count == 1)
5898 ig.Emit (OpCodes.Newarr, array_element_type);
5900 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5903 if (initializers == null)
5906 // Emit static initializer for arrays which have contain more than 4 items and
5907 // the static initializer will initialize at least 25% of array values.
5908 // NOTE: const_initializers_count does not contain default constant values.
5909 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5910 TypeManager.IsPrimitiveType (array_element_type)) {
5911 EmitStaticInitializers (ec);
5913 if (!only_constant_initializers)
5914 EmitDynamicInitializers (ec, false);
5916 EmitDynamicInitializers (ec, true);
5920 public override bool GetAttributableValue (Type value_type, out object value)
5922 if (arguments.Count != 1) {
5923 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
5924 return base.GetAttributableValue (null, out value);
5927 if (array_data == null) {
5928 Constant c = (Constant)((Argument)arguments [0]).Expr;
5929 if (c.IsDefaultValue) {
5930 value = Array.CreateInstance (array_element_type, 0);
5933 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
5934 return base.GetAttributableValue (null, out value);
5937 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
5938 object element_value;
5939 for (int i = 0; i < ret.Length; ++i)
5941 Expression e = (Expression)array_data [i];
5943 // Is null when an initializer is optimized (value == predefined value)
5947 if (!e.GetAttributableValue (array_element_type, out element_value)) {
5951 ret.SetValue (element_value, i);
5957 protected override void CloneTo (CloneContext clonectx, Expression t)
5959 ArrayCreation target = (ArrayCreation) t;
5961 if (requested_base_type != null)
5962 target.requested_base_type = requested_base_type.Clone (clonectx);
5964 if (arguments != null){
5965 target.arguments = new ArrayList (arguments.Count);
5966 foreach (Argument a in arguments)
5967 target.arguments.Add (a.Clone (clonectx));
5970 if (initializers != null){
5971 target.initializers = new ArrayList (initializers.Count);
5972 foreach (Expression initializer in initializers)
5973 target.initializers.Add (initializer.Clone (clonectx));
5979 // Represents an implicitly typed array epxression
5981 public class ImplicitlyTypedArrayCreation : ArrayCreation
5983 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
5984 : base (null, rank, initializers, loc)
5986 if (RootContext.Version <= LanguageVersion.ISO_2)
5987 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
5989 if (rank.Length > 2) {
5990 while (rank [++dimensions] == ',');
5996 public override Expression DoResolve (EmitContext ec)
6001 if (!ResolveInitializers (ec))
6004 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6005 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6006 arguments.Count != dimensions) {
6007 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6012 // At this point we found common base type for all initializer elements
6013 // but we have to be sure that all static initializer elements are of
6016 UnifyInitializerElement (ec);
6018 type = TypeManager.GetConstructedType (array_element_type, rank);
6019 eclass = ExprClass.Value;
6024 // Converts static initializer only
6026 void UnifyInitializerElement (EmitContext ec)
6028 for (int i = 0; i < array_data.Count; ++i) {
6029 Expression e = (Expression)array_data[i];
6031 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6035 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6037 element = element.Resolve (ec);
6038 if (element == null)
6041 if (array_element_type == null) {
6042 array_element_type = element.Type;
6046 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6050 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6051 array_element_type = element.Type;
6055 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6060 public sealed class CompilerGeneratedThis : This
6062 public static This Instance = new CompilerGeneratedThis ();
6064 private CompilerGeneratedThis ()
6065 : base (Location.Null)
6069 public override Expression DoResolve (EmitContext ec)
6071 eclass = ExprClass.Variable;
6072 type = ec.ContainerType;
6073 variable = new SimpleThis (type);
6079 /// Represents the `this' construct
6082 public class This : VariableReference, IVariable
6085 VariableInfo variable_info;
6086 protected Variable variable;
6089 public This (Block block, Location loc)
6095 public This (Location loc)
6100 public VariableInfo VariableInfo {
6101 get { return variable_info; }
6104 public bool VerifyFixed ()
6106 return !TypeManager.IsValueType (Type);
6109 public override bool IsRef {
6110 get { return is_struct; }
6113 public override Variable Variable {
6114 get { return variable; }
6117 public bool ResolveBase (EmitContext ec)
6119 eclass = ExprClass.Variable;
6121 if (ec.TypeContainer.CurrentType != null)
6122 type = ec.TypeContainer.CurrentType;
6124 type = ec.ContainerType;
6126 is_struct = ec.TypeContainer is Struct;
6129 Error (26, "Keyword `this' is not valid in a static property, " +
6130 "static method, or static field initializer");
6134 if (block != null) {
6135 if (block.Toplevel.ThisVariable != null)
6136 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6138 AnonymousContainer am = ec.CurrentAnonymousMethod;
6139 if (is_struct && (am != null) && !am.IsIterator) {
6140 Report.Error (1673, loc, "Anonymous methods inside structs " +
6141 "cannot access instance members of `this'. " +
6142 "Consider copying `this' to a local variable " +
6143 "outside the anonymous method and using the " +
6147 RootScopeInfo host = block.Toplevel.RootScope;
6148 if ((host != null) && !ec.IsConstructor &&
6149 (!is_struct || host.IsIterator)) {
6150 variable = host.CaptureThis ();
6151 type = variable.Type;
6156 if (variable == null)
6157 variable = new SimpleThis (type);
6163 // Called from Invocation to check if the invocation is correct
6165 public override void CheckMarshalByRefAccess (EmitContext ec)
6167 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6168 !variable_info.IsAssigned (ec)) {
6169 Error (188, "The `this' object cannot be used before all of its " +
6170 "fields are assigned to");
6171 variable_info.SetAssigned (ec);
6175 public override Expression CreateExpressionTree (EmitContext ec)
6177 ArrayList args = new ArrayList (2);
6178 args.Add (new Argument (this));
6179 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6180 return CreateExpressionFactoryCall ("Constant", args);
6183 public override Expression DoResolve (EmitContext ec)
6185 if (!ResolveBase (ec))
6189 if (ec.IsInFieldInitializer) {
6190 Error (27, "Keyword `this' is not available in the current context");
6197 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6199 if (!ResolveBase (ec))
6202 if (variable_info != null)
6203 variable_info.SetAssigned (ec);
6205 if (ec.TypeContainer is Class){
6206 Error (1604, "Cannot assign to 'this' because it is read-only");
6212 public override int GetHashCode()
6214 return block.GetHashCode ();
6217 public override bool Equals (object obj)
6219 This t = obj as This;
6223 return block == t.block;
6226 protected class SimpleThis : Variable
6230 public SimpleThis (Type type)
6235 public override Type Type {
6236 get { return type; }
6239 public override bool HasInstance {
6240 get { return false; }
6243 public override bool NeedsTemporary {
6244 get { return false; }
6247 public override void EmitInstance (EmitContext ec)
6252 public override void Emit (EmitContext ec)
6254 ec.ig.Emit (OpCodes.Ldarg_0);
6257 public override void EmitAssign (EmitContext ec)
6259 throw new InvalidOperationException ();
6262 public override void EmitAddressOf (EmitContext ec)
6264 ec.ig.Emit (OpCodes.Ldarg_0);
6268 protected override void CloneTo (CloneContext clonectx, Expression t)
6270 This target = (This) t;
6272 target.block = clonectx.LookupBlock (block);
6277 /// Represents the `__arglist' construct
6279 public class ArglistAccess : Expression
6281 public ArglistAccess (Location loc)
6286 public override Expression DoResolve (EmitContext ec)
6288 eclass = ExprClass.Variable;
6289 type = TypeManager.runtime_argument_handle_type;
6291 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6293 Error (190, "The __arglist construct is valid only within " +
6294 "a variable argument method");
6301 public override void Emit (EmitContext ec)
6303 ec.ig.Emit (OpCodes.Arglist);
6306 protected override void CloneTo (CloneContext clonectx, Expression target)
6313 /// Represents the `__arglist (....)' construct
6315 public class Arglist : Expression
6317 Argument[] Arguments;
6319 public Arglist (Location loc)
6320 : this (Argument.Empty, loc)
6324 public Arglist (Argument[] args, Location l)
6330 public Type[] ArgumentTypes {
6332 Type[] retval = new Type [Arguments.Length];
6333 for (int i = 0; i < Arguments.Length; i++)
6334 retval [i] = Arguments [i].Type;
6339 public override Expression CreateExpressionTree (EmitContext ec)
6341 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6345 public override Expression DoResolve (EmitContext ec)
6347 eclass = ExprClass.Variable;
6348 type = TypeManager.runtime_argument_handle_type;
6350 foreach (Argument arg in Arguments) {
6351 if (!arg.Resolve (ec, loc))
6358 public override void Emit (EmitContext ec)
6360 foreach (Argument arg in Arguments)
6364 protected override void CloneTo (CloneContext clonectx, Expression t)
6366 Arglist target = (Arglist) t;
6368 target.Arguments = new Argument [Arguments.Length];
6369 for (int i = 0; i < Arguments.Length; i++)
6370 target.Arguments [i] = Arguments [i].Clone (clonectx);
6375 // This produces the value that renders an instance, used by the iterators code
6377 public class ProxyInstance : Expression, IMemoryLocation {
6378 public override Expression DoResolve (EmitContext ec)
6380 eclass = ExprClass.Variable;
6381 type = ec.ContainerType;
6385 public override void Emit (EmitContext ec)
6387 ec.ig.Emit (OpCodes.Ldarg_0);
6391 public void AddressOf (EmitContext ec, AddressOp mode)
6393 ec.ig.Emit (OpCodes.Ldarg_0);
6398 /// Implements the typeof operator
6400 public class TypeOf : Expression {
6401 Expression QueriedType;
6402 protected Type typearg;
6404 public TypeOf (Expression queried_type, Location l)
6406 QueriedType = queried_type;
6410 public override Expression DoResolve (EmitContext ec)
6412 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6416 typearg = texpr.Type;
6418 if (typearg == TypeManager.void_type) {
6419 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6423 if (typearg.IsPointer && !ec.InUnsafe){
6428 type = TypeManager.type_type;
6429 // Even though what is returned is a type object, it's treated as a value by the compiler.
6430 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6431 eclass = ExprClass.Value;
6435 public override void Emit (EmitContext ec)
6437 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6438 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6441 public override bool GetAttributableValue (Type value_type, out object value)
6443 if (TypeManager.ContainsGenericParameters (typearg) &&
6444 !TypeManager.IsGenericTypeDefinition (typearg)) {
6445 Report.SymbolRelatedToPreviousError (typearg);
6446 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6447 TypeManager.CSharpName (typearg));
6452 if (value_type == TypeManager.object_type) {
6453 value = (object)typearg;
6460 public Type TypeArgument
6468 protected override void CloneTo (CloneContext clonectx, Expression t)
6470 TypeOf target = (TypeOf) t;
6472 target.QueriedType = QueriedType.Clone (clonectx);
6477 /// Implements the `typeof (void)' operator
6479 public class TypeOfVoid : TypeOf {
6480 public TypeOfVoid (Location l) : base (null, l)
6485 public override Expression DoResolve (EmitContext ec)
6487 type = TypeManager.type_type;
6488 typearg = TypeManager.void_type;
6489 // See description in TypeOf.
6490 eclass = ExprClass.Value;
6495 internal class TypeOfMethod : Expression
6497 readonly MethodInfo method;
6498 static MethodInfo get_type_from_handle;
6500 static TypeOfMethod ()
6502 get_type_from_handle = typeof (MethodBase).GetMethod ("GetMethodFromHandle",
6503 new Type [] { TypeManager.runtime_method_handle_type });
6506 public TypeOfMethod (MethodInfo method, Location loc)
6508 this.method = method;
6512 public override Expression DoResolve (EmitContext ec)
6514 type = typeof (MethodBase);
6515 eclass = ExprClass.Value;
6519 public override void Emit (EmitContext ec)
6521 ec.ig.Emit (OpCodes.Ldtoken, method);
6522 ec.ig.Emit (OpCodes.Call, get_type_from_handle);
6527 /// Implements the sizeof expression
6529 public class SizeOf : Expression {
6530 readonly Expression QueriedType;
6533 public SizeOf (Expression queried_type, Location l)
6535 this.QueriedType = queried_type;
6539 public override Expression DoResolve (EmitContext ec)
6541 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6546 if (texpr is TypeParameterExpr){
6547 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6552 type_queried = texpr.Type;
6553 if (type_queried.IsEnum)
6554 type_queried = TypeManager.EnumToUnderlying (type_queried);
6556 if (type_queried == TypeManager.void_type) {
6557 Expression.Error_VoidInvalidInTheContext (loc);
6561 int size_of = GetTypeSize (type_queried);
6563 return new IntConstant (size_of, loc);
6567 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)",
6568 TypeManager.CSharpName (type_queried));
6572 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6576 type = TypeManager.int32_type;
6577 eclass = ExprClass.Value;
6581 public override void Emit (EmitContext ec)
6583 int size = GetTypeSize (type_queried);
6586 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6588 IntConstant.EmitInt (ec.ig, size);
6591 protected override void CloneTo (CloneContext clonectx, Expression t)
6597 /// Implements the qualified-alias-member (::) expression.
6599 public class QualifiedAliasMember : Expression
6601 string alias, identifier;
6603 public QualifiedAliasMember (string alias, string identifier, Location l)
6606 this.identifier = identifier;
6610 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6612 if (alias == "global")
6613 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6615 int errors = Report.Errors;
6616 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6618 if (errors == Report.Errors)
6619 Report.Error (432, loc, "Alias `{0}' not found", alias);
6622 if (fne.eclass != ExprClass.Namespace) {
6624 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6627 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6630 public override Expression DoResolve (EmitContext ec)
6632 FullNamedExpression fne;
6633 if (alias == "global") {
6634 fne = RootNamespace.Global;
6636 int errors = Report.Errors;
6637 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6639 if (errors == Report.Errors)
6640 Report.Error (432, loc, "Alias `{0}' not found", alias);
6645 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6649 if (!(retval is FullNamedExpression)) {
6650 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6654 // We defer this check till the end to match the behaviour of CSC
6655 if (fne.eclass != ExprClass.Namespace) {
6656 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6662 public override void Emit (EmitContext ec)
6664 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6668 public override string ToString ()
6670 return alias + "::" + identifier;
6673 public override string GetSignatureForError ()
6678 protected override void CloneTo (CloneContext clonectx, Expression t)
6685 /// Implements the member access expression
6687 public class MemberAccess : Expression {
6688 public readonly string Identifier;
6690 readonly TypeArguments args;
6692 public MemberAccess (Expression expr, string id)
6693 : this (expr, id, expr.Location)
6697 public MemberAccess (Expression expr, string identifier, Location loc)
6700 Identifier = identifier;
6704 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6705 : this (expr, identifier, loc)
6710 protected string LookupIdentifier {
6711 get { return MemberName.MakeName (Identifier, args); }
6714 // TODO: this method has very poor performace for Enum fields and
6715 // probably for other constants as well
6716 Expression DoResolve (EmitContext ec, Expression right_side)
6719 throw new Exception ();
6722 // Resolve the expression with flow analysis turned off, we'll do the definite
6723 // assignment checks later. This is because we don't know yet what the expression
6724 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6725 // definite assignment check on the actual field and not on the whole struct.
6728 SimpleName original = expr as SimpleName;
6729 Expression expr_resolved = expr.Resolve (ec,
6730 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6731 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6733 if (expr_resolved == null)
6736 if (expr_resolved is Namespace) {
6737 Namespace ns = (Namespace) expr_resolved;
6738 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6740 if ((retval != null) && (args != null))
6741 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6745 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6749 Type expr_type = expr_resolved.Type;
6750 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6751 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6754 if (expr_type == TypeManager.anonymous_method_type){
6755 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6759 Constant c = expr_resolved as Constant;
6760 if (c != null && c.GetValue () == null) {
6761 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6762 "System.NullReferenceException");
6766 if (!args.Resolve (ec))
6770 Expression member_lookup;
6771 member_lookup = MemberLookup (
6772 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6774 if ((member_lookup == null) && (args != null)) {
6775 member_lookup = MemberLookup (
6776 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6779 if (member_lookup == null) {
6780 ExprClass expr_eclass = expr_resolved.eclass;
6783 // Extension methods are not allowed on all expression types
6785 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
6786 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
6787 expr_eclass == ExprClass.EventAccess) {
6788 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
6789 if (ex_method_lookup != null) {
6790 ex_method_lookup.ExtensionExpression = expr_resolved;
6793 ex_method_lookup.SetTypeArguments (args);
6796 return ex_method_lookup.DoResolve (ec);
6800 expr = expr_resolved;
6801 Error_MemberLookupFailed (
6802 ec.ContainerType, expr_type, expr_type, Identifier, null,
6803 AllMemberTypes, AllBindingFlags);
6807 TypeExpr texpr = member_lookup as TypeExpr;
6808 if (texpr != null) {
6809 if (!(expr_resolved is TypeExpr) &&
6810 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6811 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6812 Identifier, member_lookup.GetSignatureForError ());
6816 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6817 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6818 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6823 ConstructedType ct = expr_resolved as ConstructedType;
6826 // When looking up a nested type in a generic instance
6827 // via reflection, we always get a generic type definition
6828 // and not a generic instance - so we have to do this here.
6830 // See gtest-172-lib.cs and gtest-172.cs for an example.
6832 ct = new ConstructedType (
6833 member_lookup.Type, ct.TypeArguments, loc);
6835 return ct.ResolveAsTypeStep (ec, false);
6838 return member_lookup;
6841 MemberExpr me = (MemberExpr) member_lookup;
6842 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6847 me.SetTypeArguments (args);
6850 if (original != null && !TypeManager.IsValueType (expr_type)) {
6851 if (me.IsInstance) {
6852 LocalVariableReference var = expr_resolved as LocalVariableReference;
6853 if (var != null && !var.VerifyAssigned (ec))
6858 // The following DoResolve/DoResolveLValue will do the definite assignment
6861 if (right_side != null)
6862 return me.DoResolveLValue (ec, right_side);
6864 return me.DoResolve (ec);
6867 public override Expression DoResolve (EmitContext ec)
6869 return DoResolve (ec, null);
6872 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6874 return DoResolve (ec, right_side);
6877 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6879 return ResolveNamespaceOrType (ec, silent);
6882 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6884 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6886 if (new_expr == null)
6889 if (new_expr is Namespace) {
6890 Namespace ns = (Namespace) new_expr;
6891 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6893 if ((retval != null) && (args != null))
6894 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6896 if (!silent && retval == null)
6897 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6901 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6902 if (tnew_expr == null)
6905 Type expr_type = tnew_expr.Type;
6907 if (expr_type.IsPointer){
6908 Error (23, "The `.' operator can not be applied to pointer operands (" +
6909 TypeManager.CSharpName (expr_type) + ")");
6913 Expression member_lookup = MemberLookup (
6914 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6915 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6916 if (member_lookup == null) {
6920 member_lookup = MemberLookup (
6921 rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
6922 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6924 if (member_lookup != null) {
6925 tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
6926 if (tnew_expr == null)
6929 Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
6933 member_lookup = MemberLookup (
6934 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6935 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6937 if (member_lookup == null) {
6938 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6939 Identifier, new_expr.GetSignatureForError ());
6941 // TODO: Report.SymbolRelatedToPreviousError
6942 member_lookup.Error_UnexpectedKind (null, "type", loc);
6947 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6952 TypeArguments the_args = args;
6953 Type declaring_type = texpr.Type.DeclaringType;
6954 if (TypeManager.HasGenericArguments (declaring_type)) {
6955 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
6956 expr_type = expr_type.BaseType;
6959 TypeArguments new_args = new TypeArguments (loc);
6960 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
6961 new_args.Add (new TypeExpression (decl, loc));
6964 new_args.Add (args);
6966 the_args = new_args;
6969 if (the_args != null) {
6970 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6971 return ctype.ResolveAsTypeStep (rc, false);
6978 public override void Emit (EmitContext ec)
6980 throw new Exception ("Should not happen");
6983 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
6985 if (RootContext.Version > LanguageVersion.ISO_2 &&
6986 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
6987 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
6988 "extension method `{1}' of type `{0}' could be found " +
6989 "(are you missing a using directive or an assembly reference?)",
6990 TypeManager.CSharpName (type), name);
6994 base.Error_TypeDoesNotContainDefinition (type, name);
6997 public override string ToString ()
6999 return expr + "." + MemberName.MakeName (Identifier, args);
7002 public override string GetSignatureForError ()
7004 return expr.GetSignatureForError () + "." + Identifier;
7007 protected override void CloneTo (CloneContext clonectx, Expression t)
7009 MemberAccess target = (MemberAccess) t;
7011 target.expr = expr.Clone (clonectx);
7016 /// Implements checked expressions
7018 public class CheckedExpr : Expression {
7020 public Expression Expr;
7022 public CheckedExpr (Expression e, Location l)
7028 public override Expression CreateExpressionTree (EmitContext ec)
7030 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7031 return Expr.CreateExpressionTree (ec);
7034 public override Expression DoResolve (EmitContext ec)
7036 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7037 Expr = Expr.Resolve (ec);
7042 if (Expr is Constant)
7045 eclass = Expr.eclass;
7050 public override void Emit (EmitContext ec)
7052 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7056 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7058 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7059 Expr.EmitBranchable (ec, target, on_true);
7062 protected override void CloneTo (CloneContext clonectx, Expression t)
7064 CheckedExpr target = (CheckedExpr) t;
7066 target.Expr = Expr.Clone (clonectx);
7071 /// Implements the unchecked expression
7073 public class UnCheckedExpr : Expression {
7075 public Expression Expr;
7077 public UnCheckedExpr (Expression e, Location l)
7083 public override Expression CreateExpressionTree (EmitContext ec)
7085 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7086 return Expr.CreateExpressionTree (ec);
7089 public override Expression DoResolve (EmitContext ec)
7091 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7092 Expr = Expr.Resolve (ec);
7097 if (Expr is Constant)
7100 eclass = Expr.eclass;
7105 public override void Emit (EmitContext ec)
7107 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7111 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7113 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7114 Expr.EmitBranchable (ec, target, on_true);
7117 protected override void CloneTo (CloneContext clonectx, Expression t)
7119 UnCheckedExpr target = (UnCheckedExpr) t;
7121 target.Expr = Expr.Clone (clonectx);
7126 /// An Element Access expression.
7128 /// During semantic analysis these are transformed into
7129 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7131 public class ElementAccess : Expression {
7132 public ArrayList Arguments;
7133 public Expression Expr;
7135 public ElementAccess (Expression e, ArrayList e_list)
7144 Arguments = new ArrayList ();
7145 foreach (Expression tmp in e_list)
7146 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7150 bool CommonResolve (EmitContext ec)
7152 Expr = Expr.Resolve (ec);
7154 if (Arguments == null)
7157 foreach (Argument a in Arguments){
7158 if (!a.Resolve (ec, loc))
7162 return Expr != null;
7165 public override Expression CreateExpressionTree (EmitContext ec)
7167 ArrayList args = new ArrayList (Arguments.Count + 1);
7168 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7169 foreach (Argument a in Arguments)
7170 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7172 return CreateExpressionFactoryCall ("ArrayIndex", args);
7175 Expression MakePointerAccess (EmitContext ec, Type t)
7177 if (t == TypeManager.void_ptr_type){
7178 Error (242, "The array index operation is not valid on void pointers");
7181 if (Arguments.Count != 1){
7182 Error (196, "A pointer must be indexed by only one value");
7187 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7190 return new Indirection (p, loc).Resolve (ec);
7193 public override Expression DoResolve (EmitContext ec)
7195 if (!CommonResolve (ec))
7199 // We perform some simple tests, and then to "split" the emit and store
7200 // code we create an instance of a different class, and return that.
7202 // I am experimenting with this pattern.
7206 if (t == TypeManager.array_type){
7207 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7212 return (new ArrayAccess (this, loc)).Resolve (ec);
7214 return MakePointerAccess (ec, t);
7216 FieldExpr fe = Expr as FieldExpr;
7218 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7220 return MakePointerAccess (ec, ff.ElementType);
7223 return (new IndexerAccess (this, loc)).Resolve (ec);
7226 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7228 if (!CommonResolve (ec))
7233 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7236 return MakePointerAccess (ec, type);
7238 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7239 Error_CannotModifyIntermediateExpressionValue (ec);
7241 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7244 public override void Emit (EmitContext ec)
7246 throw new Exception ("Should never be reached");
7249 public override string GetSignatureForError ()
7251 return Expr.GetSignatureForError ();
7254 protected override void CloneTo (CloneContext clonectx, Expression t)
7256 ElementAccess target = (ElementAccess) t;
7258 target.Expr = Expr.Clone (clonectx);
7259 target.Arguments = new ArrayList (Arguments.Count);
7260 foreach (Argument a in Arguments)
7261 target.Arguments.Add (a.Clone (clonectx));
7266 /// Implements array access
7268 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7270 // Points to our "data" repository
7274 LocalTemporary temp;
7275 LocalTemporary prepared_value;
7279 public ArrayAccess (ElementAccess ea_data, Location l)
7282 eclass = ExprClass.Variable;
7286 public override Expression CreateExpressionTree (EmitContext ec)
7288 return ea.CreateExpressionTree (ec);
7291 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7293 return DoResolve (ec);
7296 public override Expression DoResolve (EmitContext ec)
7299 ExprClass eclass = ea.Expr.eclass;
7301 // As long as the type is valid
7302 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7303 eclass == ExprClass.Value)) {
7304 ea.Expr.Error_UnexpectedKind ("variable or value");
7309 Type t = ea.Expr.Type;
7310 if (t.GetArrayRank () != ea.Arguments.Count) {
7311 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7312 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7316 type = TypeManager.GetElementType (t);
7317 if (type.IsPointer && !ec.InUnsafe) {
7318 UnsafeError (ea.Location);
7322 foreach (Argument a in ea.Arguments) {
7323 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7326 eclass = ExprClass.Variable;
7332 /// Emits the right opcode to load an object of Type `t'
7333 /// from an array of T
7335 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7338 MethodInfo get = FetchGetMethod ();
7339 ig.Emit (OpCodes.Call, get);
7343 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7344 ig.Emit (OpCodes.Ldelem_U1);
7345 else if (type == TypeManager.sbyte_type)
7346 ig.Emit (OpCodes.Ldelem_I1);
7347 else if (type == TypeManager.short_type)
7348 ig.Emit (OpCodes.Ldelem_I2);
7349 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7350 ig.Emit (OpCodes.Ldelem_U2);
7351 else if (type == TypeManager.int32_type)
7352 ig.Emit (OpCodes.Ldelem_I4);
7353 else if (type == TypeManager.uint32_type)
7354 ig.Emit (OpCodes.Ldelem_U4);
7355 else if (type == TypeManager.uint64_type)
7356 ig.Emit (OpCodes.Ldelem_I8);
7357 else if (type == TypeManager.int64_type)
7358 ig.Emit (OpCodes.Ldelem_I8);
7359 else if (type == TypeManager.float_type)
7360 ig.Emit (OpCodes.Ldelem_R4);
7361 else if (type == TypeManager.double_type)
7362 ig.Emit (OpCodes.Ldelem_R8);
7363 else if (type == TypeManager.intptr_type)
7364 ig.Emit (OpCodes.Ldelem_I);
7365 else if (TypeManager.IsEnumType (type)){
7366 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
7367 } else if (type.IsValueType){
7368 ig.Emit (OpCodes.Ldelema, type);
7369 ig.Emit (OpCodes.Ldobj, type);
7371 } else if (type.IsGenericParameter) {
7372 ig.Emit (OpCodes.Ldelem, type);
7374 } else if (type.IsPointer)
7375 ig.Emit (OpCodes.Ldelem_I);
7377 ig.Emit (OpCodes.Ldelem_Ref);
7380 protected override void Error_NegativeArrayIndex (Location loc)
7382 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7386 /// Returns the right opcode to store an object of Type `t'
7387 /// from an array of T.
7389 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7391 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7392 has_type_arg = false; is_stobj = false;
7393 t = TypeManager.TypeToCoreType (t);
7394 if (TypeManager.IsEnumType (t))
7395 t = TypeManager.EnumToUnderlying (t);
7396 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7397 t == TypeManager.bool_type)
7398 return OpCodes.Stelem_I1;
7399 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7400 t == TypeManager.char_type)
7401 return OpCodes.Stelem_I2;
7402 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7403 return OpCodes.Stelem_I4;
7404 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7405 return OpCodes.Stelem_I8;
7406 else if (t == TypeManager.float_type)
7407 return OpCodes.Stelem_R4;
7408 else if (t == TypeManager.double_type)
7409 return OpCodes.Stelem_R8;
7410 else if (t == TypeManager.intptr_type) {
7411 has_type_arg = true;
7413 return OpCodes.Stobj;
7414 } else if (t.IsValueType) {
7415 has_type_arg = true;
7417 return OpCodes.Stobj;
7419 } else if (t.IsGenericParameter) {
7420 has_type_arg = true;
7421 return OpCodes.Stelem;
7424 } else if (t.IsPointer)
7425 return OpCodes.Stelem_I;
7427 return OpCodes.Stelem_Ref;
7430 MethodInfo FetchGetMethod ()
7432 ModuleBuilder mb = CodeGen.Module.Builder;
7433 int arg_count = ea.Arguments.Count;
7434 Type [] args = new Type [arg_count];
7437 for (int i = 0; i < arg_count; i++){
7438 //args [i++] = a.Type;
7439 args [i] = TypeManager.int32_type;
7442 get = mb.GetArrayMethod (
7443 ea.Expr.Type, "Get",
7444 CallingConventions.HasThis |
7445 CallingConventions.Standard,
7451 MethodInfo FetchAddressMethod ()
7453 ModuleBuilder mb = CodeGen.Module.Builder;
7454 int arg_count = ea.Arguments.Count;
7455 Type [] args = new Type [arg_count];
7459 ret_type = TypeManager.GetReferenceType (type);
7461 for (int i = 0; i < arg_count; i++){
7462 //args [i++] = a.Type;
7463 args [i] = TypeManager.int32_type;
7466 address = mb.GetArrayMethod (
7467 ea.Expr.Type, "Address",
7468 CallingConventions.HasThis |
7469 CallingConventions.Standard,
7476 // Load the array arguments into the stack.
7478 // If we have been requested to cache the values (cached_locations array
7479 // initialized), then load the arguments the first time and store them
7480 // in locals. otherwise load from local variables.
7482 // prepare_for_load is used in compound assignments to cache original index
7483 // values ( label[idx++] += s )
7485 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
7489 LocalTemporary[] indexes = null;
7490 if (prepare_for_load) {
7491 ec.ig.Emit (OpCodes.Dup);
7492 indexes = new LocalTemporary [ea.Arguments.Count];
7495 for (int i = 0; i < ea.Arguments.Count; ++i) {
7496 ((Argument)ea.Arguments [i]).Emit (ec);
7497 if (!prepare_for_load)
7500 // Keep original array index value on the stack
7501 ec.ig.Emit (OpCodes.Dup);
7503 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7504 indexes [i].Store (ec);
7510 public void Emit (EmitContext ec, bool leave_copy)
7512 int rank = ea.Expr.Type.GetArrayRank ();
7513 ILGenerator ig = ec.ig;
7515 if (prepared_value != null) {
7516 prepared_value.Emit (ec);
7517 } else if (prepared) {
7518 LoadFromPtr (ig, this.type);
7520 LoadArrayAndArguments (ec, false);
7521 EmitLoadOpcode (ig, type, rank);
7525 ig.Emit (OpCodes.Dup);
7526 temp = new LocalTemporary (this.type);
7531 public override void Emit (EmitContext ec)
7536 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7538 int rank = ea.Expr.Type.GetArrayRank ();
7539 ILGenerator ig = ec.ig;
7540 Type t = source.Type;
7541 prepared = prepare_for_load && !(source is StringConcat);
7544 AddressOf (ec, AddressOp.LoadStore);
7545 ec.ig.Emit (OpCodes.Dup);
7547 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7548 prepare_for_load && (source is StringConcat));
7550 if (original_indexes_values != null) {
7551 prepared_value = new LocalTemporary (type);
7552 EmitLoadOpcode (ig, type, rank);
7553 prepared_value.Store (ec);
7554 foreach (LocalTemporary lt in original_indexes_values) {
7562 bool is_stobj, has_type_arg;
7563 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7567 // The stobj opcode used by value types will need
7568 // an address on the stack, not really an array/array
7572 ig.Emit (OpCodes.Ldelema, t);
7577 ec.ig.Emit (OpCodes.Dup);
7578 temp = new LocalTemporary (this.type);
7583 StoreFromPtr (ig, t);
7585 ig.Emit (OpCodes.Stobj, t);
7586 else if (has_type_arg)
7593 ec.ig.Emit (OpCodes.Dup);
7594 temp = new LocalTemporary (this.type);
7599 StoreFromPtr (ig, t);
7601 int arg_count = ea.Arguments.Count;
7602 Type [] args = new Type [arg_count + 1];
7603 for (int i = 0; i < arg_count; i++) {
7604 //args [i++] = a.Type;
7605 args [i] = TypeManager.int32_type;
7607 args [arg_count] = type;
7609 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7610 ea.Expr.Type, "Set",
7611 CallingConventions.HasThis |
7612 CallingConventions.Standard,
7613 TypeManager.void_type, args);
7615 ig.Emit (OpCodes.Call, set);
7625 public void AddressOf (EmitContext ec, AddressOp mode)
7627 int rank = ea.Expr.Type.GetArrayRank ();
7628 ILGenerator ig = ec.ig;
7630 LoadArrayAndArguments (ec, false);
7633 ig.Emit (OpCodes.Ldelema, type);
7635 MethodInfo address = FetchAddressMethod ();
7636 ig.Emit (OpCodes.Call, address);
7640 public void EmitGetLength (EmitContext ec, int dim)
7642 int rank = ea.Expr.Type.GetArrayRank ();
7643 ILGenerator ig = ec.ig;
7647 ig.Emit (OpCodes.Ldlen);
7648 ig.Emit (OpCodes.Conv_I4);
7650 IntLiteral.EmitInt (ig, dim);
7651 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7657 /// Expressions that represent an indexer call.
7659 public class IndexerAccess : Expression, IAssignMethod
7661 class IndexerMethodGroupExpr : MethodGroupExpr
7663 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7666 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7669 public override string Name {
7675 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7678 // Here is the trick, decrease number of arguments by 1 when only
7679 // available property method is setter. This makes overload resolution
7680 // work correctly for indexers.
7683 if (method.Name [0] == 'g')
7684 return parameters.Count;
7686 return parameters.Count - 1;
7692 // Contains either property getter or setter
7693 public ArrayList Methods;
7694 public ArrayList Properties;
7700 void Append (Type caller_type, MemberInfo [] mi)
7705 foreach (PropertyInfo property in mi) {
7706 MethodInfo accessor = property.GetGetMethod (true);
7707 if (accessor == null)
7708 accessor = property.GetSetMethod (true);
7710 if (Methods == null) {
7711 Methods = new ArrayList ();
7712 Properties = new ArrayList ();
7715 Methods.Add (accessor);
7716 Properties.Add (property);
7720 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7722 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7724 return TypeManager.MemberLookup (
7725 caller_type, caller_type, lookup_type, MemberTypes.Property,
7726 BindingFlags.Public | BindingFlags.Instance |
7727 BindingFlags.DeclaredOnly, p_name, null);
7730 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7732 Indexers ix = new Indexers ();
7735 if (lookup_type.IsGenericParameter) {
7736 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7740 if (gc.HasClassConstraint)
7741 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7743 Type[] ifaces = gc.InterfaceConstraints;
7744 foreach (Type itype in ifaces)
7745 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7751 Type copy = lookup_type;
7752 while (copy != TypeManager.object_type && copy != null){
7753 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7754 copy = copy.BaseType;
7757 if (lookup_type.IsInterface) {
7758 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7759 if (ifaces != null) {
7760 foreach (Type itype in ifaces)
7761 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7776 // Points to our "data" repository
7778 MethodInfo get, set;
7779 bool is_base_indexer;
7781 LocalTemporary temp;
7782 LocalTemporary prepared_value;
7783 Expression set_expr;
7785 protected Type indexer_type;
7786 protected Type current_type;
7787 protected Expression instance_expr;
7788 protected ArrayList arguments;
7790 public IndexerAccess (ElementAccess ea, Location loc)
7791 : this (ea.Expr, false, loc)
7793 this.arguments = ea.Arguments;
7796 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7799 this.instance_expr = instance_expr;
7800 this.is_base_indexer = is_base_indexer;
7801 this.eclass = ExprClass.Value;
7805 static string GetAccessorName (AccessorType at)
7807 if (at == AccessorType.Set)
7810 if (at == AccessorType.Get)
7813 throw new NotImplementedException (at.ToString ());
7816 protected virtual bool CommonResolve (EmitContext ec)
7818 indexer_type = instance_expr.Type;
7819 current_type = ec.ContainerType;
7824 public override Expression DoResolve (EmitContext ec)
7826 return ResolveAccessor (ec, AccessorType.Get);
7829 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7831 if (right_side == EmptyExpression.OutAccess) {
7832 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7833 GetSignatureForError ());
7837 // if the indexer returns a value type, and we try to set a field in it
7838 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7839 Error_CannotModifyIntermediateExpressionValue (ec);
7842 Expression e = ResolveAccessor (ec, AccessorType.Set);
7846 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
7850 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
7852 if (!CommonResolve (ec))
7855 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7856 if (ilist.Methods == null) {
7857 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7858 TypeManager.CSharpName (indexer_type));
7862 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
7863 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
7867 MethodInfo mi = (MethodInfo) mg;
7868 PropertyInfo pi = null;
7869 for (int i = 0; i < ilist.Methods.Count; ++i) {
7870 if (ilist.Methods [i] == mi) {
7871 pi = (PropertyInfo) ilist.Properties [i];
7876 type = pi.PropertyType;
7877 if (type.IsPointer && !ec.InUnsafe)
7880 MethodInfo accessor;
7881 if (accessorType == AccessorType.Get) {
7882 accessor = get = pi.GetGetMethod (true);
7884 accessor = set = pi.GetSetMethod (true);
7885 if (accessor == null && pi.GetGetMethod (true) != null) {
7886 Report.SymbolRelatedToPreviousError (pi);
7887 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
7888 TypeManager.GetFullNameSignature (pi));
7893 if (accessor == null) {
7894 Report.SymbolRelatedToPreviousError (pi);
7895 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
7896 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7901 // Only base will allow this invocation to happen.
7903 if (accessor.IsAbstract && this is BaseIndexerAccess) {
7904 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
7907 bool must_do_cs1540_check;
7908 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
7910 set = pi.GetSetMethod (true);
7912 get = pi.GetGetMethod (true);
7914 if (set != null && get != null &&
7915 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
7916 Report.SymbolRelatedToPreviousError (accessor);
7917 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
7918 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7920 Report.SymbolRelatedToPreviousError (pi);
7921 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
7925 instance_expr.CheckMarshalByRefAccess (ec);
7926 eclass = ExprClass.IndexerAccess;
7930 public void Emit (EmitContext ec, bool leave_copy)
7933 prepared_value.Emit (ec);
7935 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7936 arguments, loc, false, false);
7940 ec.ig.Emit (OpCodes.Dup);
7941 temp = new LocalTemporary (Type);
7947 // source is ignored, because we already have a copy of it from the
7948 // LValue resolution and we have already constructed a pre-cached
7949 // version of the arguments (ea.set_arguments);
7951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7953 prepared = prepare_for_load;
7954 Expression value = set_expr;
7957 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7958 arguments, loc, true, false);
7960 prepared_value = new LocalTemporary (type);
7961 prepared_value.Store (ec);
7963 prepared_value.Release (ec);
7966 ec.ig.Emit (OpCodes.Dup);
7967 temp = new LocalTemporary (Type);
7970 } else if (leave_copy) {
7971 temp = new LocalTemporary (Type);
7977 arguments.Add (new Argument (value, Argument.AType.Expression));
7978 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
7986 public override void Emit (EmitContext ec)
7991 public override string GetSignatureForError ()
7993 return TypeManager.CSharpSignature (get != null ? get : set, false);
7996 protected override void CloneTo (CloneContext clonectx, Expression t)
7998 IndexerAccess target = (IndexerAccess) t;
8000 if (arguments != null){
8001 target.arguments = new ArrayList ();
8002 foreach (Argument a in arguments)
8003 target.arguments.Add (a.Clone (clonectx));
8005 if (instance_expr != null)
8006 target.instance_expr = instance_expr.Clone (clonectx);
8011 /// The base operator for method names
8013 public class BaseAccess : Expression {
8014 public readonly string Identifier;
8017 public BaseAccess (string member, Location l)
8019 this.Identifier = member;
8023 public BaseAccess (string member, TypeArguments args, Location l)
8029 public override Expression DoResolve (EmitContext ec)
8031 Expression c = CommonResolve (ec);
8037 // MethodGroups use this opportunity to flag an error on lacking ()
8039 if (!(c is MethodGroupExpr))
8040 return c.Resolve (ec);
8044 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8046 Expression c = CommonResolve (ec);
8052 // MethodGroups use this opportunity to flag an error on lacking ()
8054 if (! (c is MethodGroupExpr))
8055 return c.DoResolveLValue (ec, right_side);
8060 Expression CommonResolve (EmitContext ec)
8062 Expression member_lookup;
8063 Type current_type = ec.ContainerType;
8064 Type base_type = current_type.BaseType;
8067 Error (1511, "Keyword `base' is not available in a static method");
8071 if (ec.IsInFieldInitializer){
8072 Error (1512, "Keyword `base' is not available in the current context");
8076 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8077 AllMemberTypes, AllBindingFlags, loc);
8078 if (member_lookup == null) {
8079 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8080 null, AllMemberTypes, AllBindingFlags);
8087 left = new TypeExpression (base_type, loc);
8089 left = ec.GetThis (loc);
8091 MemberExpr me = (MemberExpr) member_lookup;
8092 me = me.ResolveMemberAccess (ec, left, loc, null);
8099 me.SetTypeArguments (args);
8105 public override void Emit (EmitContext ec)
8107 throw new Exception ("Should never be called");
8110 protected override void CloneTo (CloneContext clonectx, Expression t)
8112 BaseAccess target = (BaseAccess) t;
8115 target.args = args.Clone ();
8120 /// The base indexer operator
8122 public class BaseIndexerAccess : IndexerAccess {
8123 public BaseIndexerAccess (ArrayList args, Location loc)
8124 : base (null, true, loc)
8126 arguments = new ArrayList ();
8127 foreach (Expression tmp in args)
8128 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8131 protected override bool CommonResolve (EmitContext ec)
8133 instance_expr = ec.GetThis (loc);
8135 current_type = ec.ContainerType.BaseType;
8136 indexer_type = current_type;
8138 foreach (Argument a in arguments){
8139 if (!a.Resolve (ec, loc))
8148 /// This class exists solely to pass the Type around and to be a dummy
8149 /// that can be passed to the conversion functions (this is used by
8150 /// foreach implementation to typecast the object return value from
8151 /// get_Current into the proper type. All code has been generated and
8152 /// we only care about the side effect conversions to be performed
8154 /// This is also now used as a placeholder where a no-action expression
8155 /// is needed (the `New' class).
8157 public class EmptyExpression : Expression {
8158 public static readonly EmptyExpression Null = new EmptyExpression ();
8160 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8161 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8162 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8164 static EmptyExpression temp = new EmptyExpression ();
8165 public static EmptyExpression Grab ()
8167 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8172 public static void Release (EmptyExpression e)
8177 // TODO: should be protected
8178 public EmptyExpression ()
8180 type = TypeManager.object_type;
8181 eclass = ExprClass.Value;
8182 loc = Location.Null;
8185 public EmptyExpression (Type t)
8188 eclass = ExprClass.Value;
8189 loc = Location.Null;
8192 public override Expression DoResolve (EmitContext ec)
8197 public override void Emit (EmitContext ec)
8199 // nothing, as we only exist to not do anything.
8203 // This is just because we might want to reuse this bad boy
8204 // instead of creating gazillions of EmptyExpressions.
8205 // (CanImplicitConversion uses it)
8207 public void SetType (Type t)
8214 // Empty statement expression
8216 public sealed class EmptyExpressionStatement : ExpressionStatement
8218 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8220 private EmptyExpressionStatement ()
8222 type = TypeManager.object_type;
8223 eclass = ExprClass.Value;
8224 loc = Location.Null;
8227 public override void EmitStatement (EmitContext ec)
8232 public override Expression DoResolve (EmitContext ec)
8237 public override void Emit (EmitContext ec)
8243 public class UserCast : Expression {
8247 public UserCast (MethodInfo method, Expression source, Location l)
8249 this.method = method;
8250 this.source = source;
8251 type = method.ReturnType;
8252 eclass = ExprClass.Value;
8256 public Expression Source {
8262 public override Expression CreateExpressionTree (EmitContext ec)
8264 ArrayList args = new ArrayList (2);
8265 args.Add (new Argument (source.CreateExpressionTree (ec)));
8266 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8267 args.Add (new Argument (new Cast (new TypeExpression (typeof (MethodInfo), loc),
8268 new TypeOfMethod (method, loc))));
8269 return CreateExpressionFactoryCall ("Convert", args);
8272 public override Expression DoResolve (EmitContext ec)
8275 // We are born fully resolved
8280 public override void Emit (EmitContext ec)
8283 ec.ig.Emit (OpCodes.Call, method);
8288 // This class is used to "construct" the type during a typecast
8289 // operation. Since the Type.GetType class in .NET can parse
8290 // the type specification, we just use this to construct the type
8291 // one bit at a time.
8293 public class ComposedCast : TypeExpr {
8297 public ComposedCast (Expression left, string dim)
8298 : this (left, dim, left.Location)
8302 public ComposedCast (Expression left, string dim, Location l)
8309 public Expression RemoveNullable ()
8311 if (dim.EndsWith ("?")) {
8312 dim = dim.Substring (0, dim.Length - 1);
8313 if (dim.Length == 0)
8320 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8322 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8326 Type ltype = lexpr.Type;
8327 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8328 Error_VoidInvalidInTheContext (loc);
8333 if ((dim.Length > 0) && (dim [0] == '?')) {
8334 TypeExpr nullable = new NullableType (left, loc);
8336 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8337 return nullable.ResolveAsTypeTerminal (ec, false);
8341 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8344 if (dim != "" && dim [0] == '[' &&
8345 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8346 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8351 type = TypeManager.GetConstructedType (ltype, dim);
8356 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8358 if (type.IsPointer && !ec.IsInUnsafeScope){
8363 eclass = ExprClass.Type;
8367 public override string Name {
8368 get { return left + dim; }
8371 public override string FullName {
8372 get { return type.FullName; }
8375 public override string GetSignatureForError ()
8377 return left.GetSignatureForError () + dim;
8380 protected override void CloneTo (CloneContext clonectx, Expression t)
8382 ComposedCast target = (ComposedCast) t;
8384 target.left = left.Clone (clonectx);
8388 public class FixedBufferPtr : Expression {
8391 public FixedBufferPtr (Expression array, Type array_type, Location l)
8396 type = TypeManager.GetPointerType (array_type);
8397 eclass = ExprClass.Value;
8400 public override void Emit(EmitContext ec)
8405 public override Expression DoResolve (EmitContext ec)
8408 // We are born fully resolved
8416 // This class is used to represent the address of an array, used
8417 // only by the Fixed statement, this generates "&a [0]" construct
8418 // for fixed (char *pa = a)
8420 public class ArrayPtr : FixedBufferPtr {
8423 public ArrayPtr (Expression array, Type array_type, Location l):
8424 base (array, array_type, l)
8426 this.array_type = array_type;
8429 public override void Emit (EmitContext ec)
8433 ILGenerator ig = ec.ig;
8434 IntLiteral.EmitInt (ig, 0);
8435 ig.Emit (OpCodes.Ldelema, array_type);
8440 // Encapsulates a conversion rules required for array indexes
8442 public class ArrayIndexCast : Expression
8446 public ArrayIndexCast (Expression expr)
8449 this.loc = expr.Location;
8452 public override Expression CreateExpressionTree (EmitContext ec)
8454 ArrayList args = new ArrayList (2);
8455 args.Add (new Argument (expr.CreateExpressionTree (ec)));
8456 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8457 return CreateExpressionFactoryCall ("ConvertChecked", args);
8460 public override Expression DoResolve (EmitContext ec)
8463 eclass = expr.eclass;
8467 public override void Emit (EmitContext ec)
8471 if (type == TypeManager.int32_type)
8474 if (type == TypeManager.uint32_type)
8475 ec.ig.Emit (OpCodes.Conv_U);
8476 else if (type == TypeManager.int64_type)
8477 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8478 else if (type == TypeManager.uint64_type)
8479 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8481 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8486 // Used by the fixed statement
8488 public class StringPtr : Expression {
8491 public StringPtr (LocalBuilder b, Location l)
8494 eclass = ExprClass.Value;
8495 type = TypeManager.char_ptr_type;
8499 public override Expression DoResolve (EmitContext ec)
8501 // This should never be invoked, we are born in fully
8502 // initialized state.
8507 public override void Emit (EmitContext ec)
8509 ILGenerator ig = ec.ig;
8511 ig.Emit (OpCodes.Ldloc, b);
8512 ig.Emit (OpCodes.Conv_I);
8513 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8514 ig.Emit (OpCodes.Add);
8519 // Implements the `stackalloc' keyword
8521 public class StackAlloc : Expression {
8526 public StackAlloc (Expression type, Expression count, Location l)
8533 public override Expression DoResolve (EmitContext ec)
8535 count = count.Resolve (ec);
8539 if (count.Type != TypeManager.int32_type){
8540 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8545 Constant c = count as Constant;
8546 if (c != null && c.IsNegative) {
8547 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8551 if (ec.InCatch || ec.InFinally) {
8552 Error (255, "Cannot use stackalloc in finally or catch");
8556 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8562 if (!TypeManager.VerifyUnManaged (otype, loc))
8565 type = TypeManager.GetPointerType (otype);
8566 eclass = ExprClass.Value;
8571 public override void Emit (EmitContext ec)
8573 int size = GetTypeSize (otype);
8574 ILGenerator ig = ec.ig;
8577 ig.Emit (OpCodes.Sizeof, otype);
8579 IntConstant.EmitInt (ig, size);
8581 ig.Emit (OpCodes.Mul);
8582 ig.Emit (OpCodes.Localloc);
8585 protected override void CloneTo (CloneContext clonectx, Expression t)
8587 StackAlloc target = (StackAlloc) t;
8588 target.count = count.Clone (clonectx);
8589 target.t = t.Clone (clonectx);
8594 // An object initializer expression
8596 public class ElementInitializer : Expression
8598 Expression initializer;
8599 public readonly string Name;
8601 public ElementInitializer (string name, Expression initializer, Location loc)
8604 this.initializer = initializer;
8608 protected override void CloneTo (CloneContext clonectx, Expression t)
8610 if (initializer == null)
8613 ElementInitializer target = (ElementInitializer) t;
8614 target.initializer = initializer.Clone (clonectx);
8617 public override Expression DoResolve (EmitContext ec)
8619 if (initializer == null)
8620 return EmptyExpressionStatement.Instance;
8622 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8623 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8625 if (element_member == null)
8628 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8630 if (initializer is CollectionOrObjectInitializers) {
8631 Expression previous = ec.CurrentInitializerVariable;
8632 ec.CurrentInitializerVariable = element_member;
8633 initializer = initializer.Resolve (ec);
8634 ec.CurrentInitializerVariable = previous;
8638 Assign a = new Assign (element_member, initializer, loc);
8639 if (a.Resolve (ec) == null)
8643 // Ignore field initializers with default value
8645 Constant c = a.Source as Constant;
8646 if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
8647 return EmptyExpressionStatement.Instance;
8652 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8654 MemberInfo member = members [0];
8655 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8656 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8657 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8659 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8660 TypeManager.GetFullNameSignature (member));
8665 public override void Emit (EmitContext ec)
8667 throw new NotSupportedException ("Should not be reached");
8672 // A collection initializer expression
8674 public class CollectionElementInitializer : Expression
8676 public class ElementInitializerArgument : Argument
8678 public ElementInitializerArgument (Expression e)
8684 ArrayList arguments;
8686 public CollectionElementInitializer (Expression argument)
8688 arguments = new ArrayList (1);
8689 arguments.Add (argument);
8690 this.loc = argument.Location;
8693 public CollectionElementInitializer (ArrayList arguments, Location loc)
8695 this.arguments = arguments;
8699 protected override void CloneTo (CloneContext clonectx, Expression t)
8701 CollectionElementInitializer target = (CollectionElementInitializer) t;
8702 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8703 foreach (Expression e in arguments)
8704 t_arguments.Add (e.Clone (clonectx));
8707 public override Expression DoResolve (EmitContext ec)
8709 // TODO: We should call a constructor which takes element counts argument,
8710 // for know types like List<T>, Dictionary<T, U>
8712 for (int i = 0; i < arguments.Count; ++i)
8713 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8715 Expression add_method = new Invocation (
8716 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8719 add_method = add_method.Resolve (ec);
8724 public override void Emit (EmitContext ec)
8726 throw new NotSupportedException ("Should not be reached");
8731 // A block of object or collection initializers
8733 public class CollectionOrObjectInitializers : ExpressionStatement
8735 ArrayList initializers;
8737 public static readonly CollectionOrObjectInitializers Empty =
8738 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8740 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8742 this.initializers = initializers;
8746 public bool IsEmpty {
8748 return initializers.Count == 0;
8752 protected override void CloneTo (CloneContext clonectx, Expression target)
8754 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8756 t.initializers = new ArrayList (initializers.Count);
8757 foreach (Expression e in initializers)
8758 t.initializers.Add (e.Clone (clonectx));
8761 public override Expression DoResolve (EmitContext ec)
8763 bool is_elements_initialization = false;
8764 ArrayList element_names = null;
8765 for (int i = 0; i < initializers.Count; ++i) {
8766 Expression initializer = (Expression) initializers [i];
8767 ElementInitializer element_initializer = initializer as ElementInitializer;
8770 if (element_initializer != null) {
8771 is_elements_initialization = true;
8772 element_names = new ArrayList (initializers.Count);
8773 element_names.Add (element_initializer.Name);
8775 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8776 TypeManager.ienumerable_type)) {
8777 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8778 "object initializer because type `{1}' does not implement `{2}' interface",
8779 ec.CurrentInitializerVariable.GetSignatureForError (),
8780 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8781 TypeManager.CSharpName (TypeManager.ienumerable_type));
8786 if (is_elements_initialization == (element_initializer == null)) {
8787 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8788 is_elements_initialization ? "object initializer" : "collection initializer");
8792 if (is_elements_initialization) {
8793 if (element_names.Contains (element_initializer.Name)) {
8794 Report.Error (1912, element_initializer.Location,
8795 "An object initializer includes more than one member `{0}' initialization",
8796 element_initializer.Name);
8798 element_names.Add (element_initializer.Name);
8803 Expression e = initializer.Resolve (ec);
8804 if (e == EmptyExpressionStatement.Instance)
8805 initializers.RemoveAt (i--);
8807 initializers [i] = e;
8810 type = typeof (CollectionOrObjectInitializers);
8811 eclass = ExprClass.Variable;
8815 public override void Emit (EmitContext ec)
8820 public override void EmitStatement (EmitContext ec)
8822 foreach (ExpressionStatement e in initializers)
8823 e.EmitStatement (ec);
8828 // New expression with element/object initializers
8830 public class NewInitialize : New
8833 // This class serves as a proxy for variable initializer target instances.
8834 // A real variable is assigned later when we resolve left side of an
8837 sealed class InitializerTargetExpression : Expression, IMemoryLocation
8839 NewInitialize new_instance;
8841 public InitializerTargetExpression (NewInitialize newInstance)
8843 this.type = newInstance.type;
8844 this.loc = newInstance.loc;
8845 this.eclass = newInstance.eclass;
8846 this.new_instance = newInstance;
8849 public override Expression DoResolve (EmitContext ec)
8854 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8859 public override void Emit (EmitContext ec)
8861 new_instance.value_target.Emit (ec);
8864 #region IMemoryLocation Members
8866 public void AddressOf (EmitContext ec, AddressOp mode)
8868 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
8874 CollectionOrObjectInitializers initializers;
8876 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8877 : base (requested_type, arguments, l)
8879 this.initializers = initializers;
8882 protected override void CloneTo (CloneContext clonectx, Expression t)
8884 base.CloneTo (clonectx, t);
8886 NewInitialize target = (NewInitialize) t;
8887 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
8890 public override Expression DoResolve (EmitContext ec)
8892 if (eclass != ExprClass.Invalid)
8895 Expression e = base.DoResolve (ec);
8899 // Empty initializer can be optimized to simple new
8900 if (initializers.IsEmpty)
8903 Expression previous = ec.CurrentInitializerVariable;
8904 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
8905 initializers.Resolve (ec);
8906 ec.CurrentInitializerVariable = previous;
8910 public override void Emit (EmitContext ec)
8915 // If target is a value, let's use it
8917 VariableReference variable = value_target as VariableReference;
8918 if (variable != null) {
8920 StoreFromPtr (ec.ig, type);
8922 variable.Variable.EmitAssign (ec);
8924 if (value_target == null || value_target_set)
8925 value_target = new LocalTemporary (type);
8927 ((LocalTemporary) value_target).Store (ec);
8930 initializers.Emit (ec);
8932 if (variable == null)
8933 value_target.Emit (ec);
8936 public override void EmitStatement (EmitContext ec)
8938 if (initializers.IsEmpty) {
8939 base.EmitStatement (ec);
8945 if (value_target == null) {
8946 LocalTemporary variable = new LocalTemporary (type);
8947 variable.Store (ec);
8948 value_target = variable;
8951 initializers.EmitStatement (ec);
8954 public override bool HasInitializer {
8956 return !initializers.IsEmpty;
8961 public class AnonymousTypeDeclaration : Expression
8963 ArrayList parameters;
8964 readonly TypeContainer parent;
8965 static readonly ArrayList EmptyParameters = new ArrayList (0);
8967 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8969 this.parameters = parameters;
8970 this.parent = parent;
8974 protected override void CloneTo (CloneContext clonectx, Expression target)
8976 if (parameters == null)
8979 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
8980 t.parameters = new ArrayList (parameters.Count);
8981 foreach (AnonymousTypeParameter atp in parameters)
8982 t.parameters.Add (atp.Clone (clonectx));
8985 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
8987 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8991 type = AnonymousTypeClass.Create (parent, parameters, loc);
8996 type.DefineMembers ();
9000 RootContext.ToplevelTypes.AddAnonymousType (type);
9004 public override Expression DoResolve (EmitContext ec)
9006 AnonymousTypeClass anonymous_type;
9008 if (parameters == null) {
9009 anonymous_type = CreateAnonymousType (EmptyParameters);
9010 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9011 null, loc).Resolve (ec);
9015 ArrayList arguments = new ArrayList (parameters.Count);
9016 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9017 for (int i = 0; i < parameters.Count; ++i) {
9018 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9024 arguments.Add (new Argument (e));
9025 t_args [i] = new TypeExpression (e.Type, e.Location);
9031 anonymous_type = CreateAnonymousType (parameters);
9032 if (anonymous_type == null)
9035 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9036 new TypeArguments (loc, t_args), loc);
9038 return new New (te, arguments, loc).Resolve (ec);
9041 public override void Emit (EmitContext ec)
9043 throw new InternalErrorException ("Should not be reached");
9047 public class AnonymousTypeParameter : Expression
9049 public readonly string Name;
9050 Expression initializer;
9052 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9056 this.initializer = initializer;
9059 public AnonymousTypeParameter (Parameter parameter)
9061 this.Name = parameter.Name;
9062 this.loc = parameter.Location;
9063 this.initializer = new SimpleName (Name, loc);
9066 protected override void CloneTo (CloneContext clonectx, Expression target)
9068 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9069 t.initializer = initializer.Clone (clonectx);
9072 public override bool Equals (object o)
9074 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9075 return other != null && Name == other.Name;
9078 public override int GetHashCode ()
9080 return Name.GetHashCode ();
9083 public override Expression DoResolve (EmitContext ec)
9085 Expression e = initializer.Resolve (ec);
9090 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9091 type == TypeManager.anonymous_method_type || type.IsPointer) {
9092 Error_InvalidInitializer (e);
9099 protected virtual void Error_InvalidInitializer (Expression initializer)
9101 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9102 Name, initializer.GetSignatureForError ());
9105 public override void Emit (EmitContext ec)
9107 throw new InternalErrorException ("Should not be reached");