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 = TypeManager.TypeToCoreType (((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 NullLiteral (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";
594 case Operator.LogicalNot:
598 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
601 ArrayList args = new ArrayList (2);
602 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
604 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
605 return CreateExpressionFactoryCall (method_name, args);
608 public override Expression DoResolve (EmitContext ec)
610 if (Oper == Operator.AddressOf) {
611 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
613 if (Expr == null || Expr.eclass != ExprClass.Variable){
614 Error (211, "Cannot take the address of the given expression");
619 Expr = Expr.Resolve (ec);
625 if (TypeManager.IsNullableValueType (Expr.Type))
626 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
629 eclass = ExprClass.Value;
630 return ResolveOperator (ec);
633 public override Expression DoResolveLValue (EmitContext ec, Expression right)
635 if (Oper == Operator.Indirection)
636 return DoResolve (ec);
641 public override void Emit (EmitContext ec)
643 ILGenerator ig = ec.ig;
646 case Operator.UnaryPlus:
647 throw new Exception ("This should be caught by Resolve");
649 case Operator.UnaryNegation:
650 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
651 ig.Emit (OpCodes.Ldc_I4_0);
652 if (type == TypeManager.int64_type)
653 ig.Emit (OpCodes.Conv_U8);
655 ig.Emit (OpCodes.Sub_Ovf);
658 ig.Emit (OpCodes.Neg);
663 case Operator.LogicalNot:
665 ig.Emit (OpCodes.Ldc_I4_0);
666 ig.Emit (OpCodes.Ceq);
669 case Operator.OnesComplement:
671 ig.Emit (OpCodes.Not);
674 case Operator.AddressOf:
675 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
679 throw new Exception ("This should not happen: Operator = "
684 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
686 if (Oper == Operator.LogicalNot)
687 Expr.EmitBranchable (ec, target, !on_true);
689 base.EmitBranchable (ec, target, on_true);
692 public override string ToString ()
694 return "Unary (" + Oper + ", " + Expr + ")";
697 protected override void CloneTo (CloneContext clonectx, Expression t)
699 Unary target = (Unary) t;
701 target.Expr = Expr.Clone (clonectx);
706 // Unary operators are turned into Indirection expressions
707 // after semantic analysis (this is so we can take the address
708 // of an indirection).
710 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
712 LocalTemporary temporary;
715 public Indirection (Expression expr, Location l)
718 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
719 eclass = ExprClass.Variable;
723 public override void Emit (EmitContext ec)
728 LoadFromPtr (ec.ig, Type);
731 public void Emit (EmitContext ec, bool leave_copy)
735 ec.ig.Emit (OpCodes.Dup);
736 temporary = new LocalTemporary (expr.Type);
737 temporary.Store (ec);
741 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
743 prepared = prepare_for_load;
747 if (prepare_for_load)
748 ec.ig.Emit (OpCodes.Dup);
752 ec.ig.Emit (OpCodes.Dup);
753 temporary = new LocalTemporary (expr.Type);
754 temporary.Store (ec);
757 StoreFromPtr (ec.ig, type);
759 if (temporary != null) {
761 temporary.Release (ec);
765 public void AddressOf (EmitContext ec, AddressOp Mode)
770 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
772 return DoResolve (ec);
775 public override Expression DoResolve (EmitContext ec)
778 // Born fully resolved
783 public override string ToString ()
785 return "*(" + expr + ")";
788 #region IVariable Members
790 public VariableInfo VariableInfo {
794 public bool VerifyFixed ()
796 // A pointer-indirection is always fixed.
804 /// Unary Mutator expressions (pre and post ++ and --)
808 /// UnaryMutator implements ++ and -- expressions. It derives from
809 /// ExpressionStatement becuase the pre/post increment/decrement
810 /// operators can be used in a statement context.
812 /// FIXME: Idea, we could split this up in two classes, one simpler
813 /// for the common case, and one with the extra fields for more complex
814 /// classes (indexers require temporary access; overloaded require method)
817 public class UnaryMutator : ExpressionStatement {
819 public enum Mode : byte {
826 PreDecrement = IsDecrement,
827 PostIncrement = IsPost,
828 PostDecrement = IsPost | IsDecrement
832 bool is_expr = false;
833 bool recurse = false;
838 // This is expensive for the simplest case.
840 UserOperatorCall method;
842 public UnaryMutator (Mode m, Expression e, Location l)
849 static string OperName (Mode mode)
851 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
856 /// Returns whether an object of type `t' can be incremented
857 /// or decremented with add/sub (ie, basically whether we can
858 /// use pre-post incr-decr operations on it, but it is not a
859 /// System.Decimal, which we require operator overloading to catch)
861 static bool IsIncrementableNumber (Type t)
863 return (t == TypeManager.sbyte_type) ||
864 (t == TypeManager.byte_type) ||
865 (t == TypeManager.short_type) ||
866 (t == TypeManager.ushort_type) ||
867 (t == TypeManager.int32_type) ||
868 (t == TypeManager.uint32_type) ||
869 (t == TypeManager.int64_type) ||
870 (t == TypeManager.uint64_type) ||
871 (t == TypeManager.char_type) ||
872 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
873 (t == TypeManager.float_type) ||
874 (t == TypeManager.double_type) ||
875 (t.IsPointer && t != TypeManager.void_ptr_type);
878 Expression ResolveOperator (EmitContext ec)
880 Type expr_type = expr.Type;
883 // Step 1: Perform Operator Overload location
888 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
889 op_name = "op_Increment";
891 op_name = "op_Decrement";
893 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
896 method = UserOperatorCall.MakeSimpleCall (
897 ec, (MethodGroupExpr) mg, expr, loc);
900 } else if (!IsIncrementableNumber (expr_type)) {
901 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
902 TypeManager.CSharpName (expr_type) + "'");
907 // The operand of the prefix/postfix increment decrement operators
908 // should be an expression that is classified as a variable,
909 // a property access or an indexer access
912 if (expr.eclass == ExprClass.Variable){
913 LocalVariableReference var = expr as LocalVariableReference;
914 if ((var != null) && var.IsReadOnly) {
915 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
918 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
919 expr = expr.ResolveLValue (ec, this, Location);
923 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
930 public override Expression DoResolve (EmitContext ec)
932 expr = expr.Resolve (ec);
937 eclass = ExprClass.Value;
940 if (TypeManager.IsNullableValueType (expr.Type))
941 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
944 return ResolveOperator (ec);
948 // Loads the proper "1" into the stack based on the type, then it emits the
949 // opcode for the operation requested
951 void LoadOneAndEmitOp (EmitContext ec, Type t)
954 // Measure if getting the typecode and using that is more/less efficient
955 // that comparing types. t.GetTypeCode() is an internal call.
957 ILGenerator ig = ec.ig;
959 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
960 LongConstant.EmitLong (ig, 1);
961 else if (t == TypeManager.double_type)
962 ig.Emit (OpCodes.Ldc_R8, 1.0);
963 else if (t == TypeManager.float_type)
964 ig.Emit (OpCodes.Ldc_R4, 1.0F);
965 else if (t.IsPointer){
966 Type et = TypeManager.GetElementType (t);
967 int n = GetTypeSize (et);
970 ig.Emit (OpCodes.Sizeof, et);
972 IntConstant.EmitInt (ig, n);
974 ig.Emit (OpCodes.Ldc_I4_1);
977 // Now emit the operation
980 if (t == TypeManager.int32_type ||
981 t == TypeManager.int64_type){
982 if ((mode & Mode.IsDecrement) != 0)
983 ig.Emit (OpCodes.Sub_Ovf);
985 ig.Emit (OpCodes.Add_Ovf);
986 } else if (t == TypeManager.uint32_type ||
987 t == TypeManager.uint64_type){
988 if ((mode & Mode.IsDecrement) != 0)
989 ig.Emit (OpCodes.Sub_Ovf_Un);
991 ig.Emit (OpCodes.Add_Ovf_Un);
993 if ((mode & Mode.IsDecrement) != 0)
994 ig.Emit (OpCodes.Sub_Ovf);
996 ig.Emit (OpCodes.Add_Ovf);
999 if ((mode & Mode.IsDecrement) != 0)
1000 ig.Emit (OpCodes.Sub);
1002 ig.Emit (OpCodes.Add);
1005 if (t == TypeManager.sbyte_type){
1007 ig.Emit (OpCodes.Conv_Ovf_I1);
1009 ig.Emit (OpCodes.Conv_I1);
1010 } else if (t == TypeManager.byte_type){
1012 ig.Emit (OpCodes.Conv_Ovf_U1);
1014 ig.Emit (OpCodes.Conv_U1);
1015 } else if (t == TypeManager.short_type){
1017 ig.Emit (OpCodes.Conv_Ovf_I2);
1019 ig.Emit (OpCodes.Conv_I2);
1020 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1022 ig.Emit (OpCodes.Conv_Ovf_U2);
1024 ig.Emit (OpCodes.Conv_U2);
1029 void EmitCode (EmitContext ec, bool is_expr)
1032 this.is_expr = is_expr;
1033 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1036 public override void Emit (EmitContext ec)
1039 // We use recurse to allow ourselfs to be the source
1040 // of an assignment. This little hack prevents us from
1041 // having to allocate another expression
1044 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1046 LoadOneAndEmitOp (ec, expr.Type);
1048 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1053 EmitCode (ec, true);
1056 public override void EmitStatement (EmitContext ec)
1058 EmitCode (ec, false);
1061 protected override void CloneTo (CloneContext clonectx, Expression t)
1063 UnaryMutator target = (UnaryMutator) t;
1065 target.expr = expr.Clone (clonectx);
1070 /// Base class for the `Is' and `As' classes.
1074 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1077 public abstract class Probe : Expression {
1078 public Expression ProbeType;
1079 protected Expression expr;
1080 protected TypeExpr probe_type_expr;
1082 public Probe (Expression expr, Expression probe_type, Location l)
1084 ProbeType = probe_type;
1089 public Expression Expr {
1095 public override Expression DoResolve (EmitContext ec)
1097 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1098 if (probe_type_expr == null)
1101 expr = expr.Resolve (ec);
1105 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1106 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1111 if (expr.Type == TypeManager.anonymous_method_type) {
1112 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1120 protected abstract string OperatorName { get; }
1122 protected override void CloneTo (CloneContext clonectx, Expression t)
1124 Probe target = (Probe) t;
1126 target.expr = expr.Clone (clonectx);
1127 target.ProbeType = ProbeType.Clone (clonectx);
1133 /// Implementation of the `is' operator.
1135 public class Is : Probe {
1136 public Is (Expression expr, Expression probe_type, Location l)
1137 : base (expr, probe_type, l)
1141 public override void Emit (EmitContext ec)
1143 ILGenerator ig = ec.ig;
1146 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1147 ig.Emit (OpCodes.Ldnull);
1148 ig.Emit (OpCodes.Cgt_Un);
1151 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1153 ILGenerator ig = ec.ig;
1156 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1157 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1160 Expression CreateConstantResult (bool result)
1163 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1164 TypeManager.CSharpName (probe_type_expr.Type));
1166 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1167 TypeManager.CSharpName (probe_type_expr.Type));
1169 return new BoolConstant (result, loc);
1172 public override Expression DoResolve (EmitContext ec)
1174 if (base.DoResolve (ec) == null)
1178 bool d_is_nullable = false;
1180 if (expr is Constant) {
1182 // If E is a method group or the null literal, of if the type of E is a reference
1183 // type or a nullable type and the value of E is null, the result is false
1186 return CreateConstantResult (false);
1187 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1188 d = TypeManager.GetTypeArguments (d) [0];
1189 d_is_nullable = true;
1192 type = TypeManager.bool_type;
1193 eclass = ExprClass.Value;
1194 Type t = probe_type_expr.Type;
1195 bool t_is_nullable = false;
1196 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1197 t = TypeManager.GetTypeArguments (t) [0];
1198 t_is_nullable = true;
1201 if (t.IsValueType) {
1204 // D and T are the same value types but D can be null
1206 if (d_is_nullable && !t_is_nullable)
1207 return Nullable.HasValue.Create (expr, ec);
1210 // The result is true if D and T are the same value types
1212 return CreateConstantResult (true);
1215 if (TypeManager.IsGenericParameter (d))
1216 return ResolveGenericParameter (t, d);
1219 // An unboxing conversion exists
1221 if (Convert.ExplicitReferenceConversionExists (d, t))
1224 if (TypeManager.IsGenericParameter (t))
1225 return ResolveGenericParameter (d, t);
1227 if (d.IsValueType) {
1229 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1230 return CreateConstantResult (true);
1232 if (TypeManager.IsGenericParameter (d))
1233 return ResolveGenericParameter (t, d);
1235 if (TypeManager.ContainsGenericParameters (d))
1238 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1239 Convert.ExplicitReferenceConversionExists (d, t)) {
1245 return CreateConstantResult (false);
1248 Expression ResolveGenericParameter (Type d, Type t)
1251 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1252 if (constraints != null) {
1253 if (constraints.IsReferenceType && d.IsValueType)
1254 return CreateConstantResult (false);
1256 if (constraints.IsValueType && !d.IsValueType)
1257 return CreateConstantResult (false);
1260 expr = new BoxedCast (expr, d);
1267 protected override string OperatorName {
1268 get { return "is"; }
1273 /// Implementation of the `as' operator.
1275 public class As : Probe {
1276 public As (Expression expr, Expression probe_type, Location l)
1277 : base (expr, probe_type, l)
1281 bool do_isinst = false;
1282 Expression resolved_type;
1284 public override void Emit (EmitContext ec)
1286 ILGenerator ig = ec.ig;
1291 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1294 if (TypeManager.IsNullableType (type))
1295 ig.Emit (OpCodes.Unbox_Any, type);
1299 static void Error_CannotConvertType (Type source, Type target, Location loc)
1301 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1302 TypeManager.CSharpName (source),
1303 TypeManager.CSharpName (target));
1306 public override Expression DoResolve (EmitContext ec)
1308 if (resolved_type == null) {
1309 resolved_type = base.DoResolve (ec);
1311 if (resolved_type == null)
1315 type = probe_type_expr.Type;
1316 eclass = ExprClass.Value;
1317 Type etype = expr.Type;
1319 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1320 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1321 TypeManager.CSharpName (type));
1328 // If the type is a type parameter, ensure
1329 // that it is constrained by a class
1331 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1333 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1336 if (constraints == null)
1339 if (!constraints.HasClassConstraint)
1340 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1344 Report.Error (413, loc,
1345 "The as operator requires that the `{0}' type parameter be constrained by a class",
1346 probe_type_expr.GetSignatureForError ());
1351 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1352 return Nullable.LiftedNull.CreateFromExpression (this);
1355 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1362 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1363 if (TypeManager.IsGenericParameter (etype))
1364 expr = new BoxedCast (expr, etype);
1370 if (TypeManager.ContainsGenericParameters (etype) ||
1371 TypeManager.ContainsGenericParameters (type)) {
1372 expr = new BoxedCast (expr, etype);
1377 Error_CannotConvertType (etype, type, loc);
1381 protected override string OperatorName {
1382 get { return "as"; }
1385 public override bool GetAttributableValue (Type value_type, out object value)
1387 return expr.GetAttributableValue (value_type, out value);
1392 /// This represents a typecast in the source language.
1394 /// FIXME: Cast expressions have an unusual set of parsing
1395 /// rules, we need to figure those out.
1397 public class Cast : Expression {
1398 Expression target_type;
1401 public Cast (Expression cast_type, Expression expr)
1402 : this (cast_type, expr, cast_type.Location)
1406 public Cast (Expression cast_type, Expression expr, Location loc)
1408 this.target_type = cast_type;
1412 if (target_type == TypeManager.system_void_expr)
1413 Error_VoidInvalidInTheContext (loc);
1416 public Expression TargetType {
1417 get { return target_type; }
1420 public Expression Expr {
1421 get { return expr; }
1424 public override Expression DoResolve (EmitContext ec)
1426 expr = expr.Resolve (ec);
1430 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1436 if (type.IsAbstract && type.IsSealed) {
1437 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1441 eclass = ExprClass.Value;
1443 Constant c = expr as Constant;
1445 c = c.TryReduce (ec, type, loc);
1450 if (type.IsPointer && !ec.InUnsafe) {
1454 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1458 public override void Emit (EmitContext ec)
1460 throw new Exception ("Should not happen");
1463 protected override void CloneTo (CloneContext clonectx, Expression t)
1465 Cast target = (Cast) t;
1467 target.target_type = target_type.Clone (clonectx);
1468 target.expr = expr.Clone (clonectx);
1473 // C# 2.0 Default value expression
1475 public class DefaultValueExpression : Expression
1479 public DefaultValueExpression (Expression expr, Location loc)
1485 public override Expression CreateExpressionTree (EmitContext ec)
1487 ArrayList args = new ArrayList (2);
1488 args.Add (new Argument (this));
1489 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1490 return CreateExpressionFactoryCall ("Constant", args);
1493 public override Expression DoResolve (EmitContext ec)
1495 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1501 if (type == TypeManager.void_type) {
1502 Error_VoidInvalidInTheContext (loc);
1506 if (TypeManager.IsGenericParameter (type)) {
1507 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1508 if (constraints != null && constraints.IsReferenceType)
1509 return new EmptyConstantCast (new NullLiteral (Location), type);
1511 Constant c = New.Constantify (type);
1513 return new EmptyConstantCast (c, type);
1515 if (!TypeManager.IsValueType (type))
1516 return new EmptyConstantCast (new NullLiteral (Location), type);
1518 eclass = ExprClass.Variable;
1522 public override void Emit (EmitContext ec)
1524 LocalTemporary temp_storage = new LocalTemporary(type);
1526 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1527 ec.ig.Emit(OpCodes.Initobj, type);
1528 temp_storage.Emit(ec);
1531 protected override void CloneTo (CloneContext clonectx, Expression t)
1533 DefaultValueExpression target = (DefaultValueExpression) t;
1535 target.expr = expr.Clone (clonectx);
1540 /// Binary operators
1542 public class Binary : Expression {
1544 protected class PredefinedOperator {
1545 protected readonly Type left;
1546 protected readonly Type right;
1547 public readonly Operator OperatorsMask;
1548 public Type ReturnType;
1550 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1551 : this (ltype, rtype, op_mask, ltype)
1555 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1556 : this (type, type, op_mask, return_type)
1560 public PredefinedOperator (Type type, Operator op_mask)
1561 : this (type, type, op_mask, type)
1565 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1567 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1568 throw new InternalErrorException ("Only masked values can be used");
1572 this.OperatorsMask = op_mask;
1573 this.ReturnType = return_type;
1576 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1578 b.type = ReturnType;
1581 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1584 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1589 public bool IsPrimitiveApplicable (Type type)
1592 // We are dealing with primitive types only
1594 return left == type;
1597 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr, bool lnull, bool rnull)
1600 return Convert.ImplicitConversionExists (ec, rexpr, right);
1602 return Convert.ImplicitConversionExists (ec, lexpr, left);
1604 if (TypeManager.IsEqual (left, lexpr.Type) &&
1605 TypeManager.IsEqual (right, rexpr.Type))
1608 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1609 Convert.ImplicitConversionExists (ec, rexpr, right);
1612 public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
1615 if (left != null && best_operator.left != null) {
1616 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1620 // When second arguments are same as the first one, the result is same
1622 if (left != right || best_operator.left != best_operator.right) {
1623 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1626 if (result == 0 || result > 2)
1629 return result == 1 ? best_operator : this;
1633 class PredefinedStringOperator : PredefinedOperator {
1634 public PredefinedStringOperator (Type type, Operator op_mask)
1635 : base (type, op_mask, type)
1637 ReturnType = TypeManager.string_type;
1640 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1641 : base (ltype, rtype, op_mask)
1643 ReturnType = TypeManager.string_type;
1646 public override Expression ConvertResult (EmitContext ec, Binary b)
1649 // Use original expression for nullable arguments
1651 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1653 b.left = unwrap.Original;
1655 unwrap = b.right as Nullable.Unwrap;
1657 b.right = unwrap.Original;
1659 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1660 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1663 // Start a new concat expression using converted expression
1665 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1669 class PredefinedShiftOperator : PredefinedOperator {
1670 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1671 base (ltype, TypeManager.int32_type, op_mask)
1675 public override Expression ConvertResult (EmitContext ec, Binary b)
1677 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1679 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1681 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1684 // b = b.left >> b.right & (0x1f|0x3f)
1686 b.right = new Binary (Operator.BitwiseAnd,
1687 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1690 // Expression tree representation does not use & mask
1692 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1693 b.type = ReturnType;
1698 class PredefinedPointerOperator : PredefinedOperator {
1699 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1700 : base (ltype, rtype, op_mask)
1704 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1705 : base (type, op_mask, return_type)
1709 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr, bool lnull, bool rnull)
1712 if (!lexpr.Type.IsPointer)
1715 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1719 if (right == null) {
1720 if (!rexpr.Type.IsPointer)
1723 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1730 public override Expression ConvertResult (EmitContext ec, Binary b)
1732 base.ConvertResult (ec, b);
1734 Type r_type = ReturnType;
1735 if (r_type == null) {
1736 r_type = b.left.Type;
1738 r_type = b.right.Type;
1741 return new PointerArithmetic (b.oper == Operator.Addition,
1742 b.left, b.right, r_type, b.loc).Resolve (ec);
1747 public enum Operator {
1748 Multiply = 0 | ArithmeticMask,
1749 Division = 1 | ArithmeticMask,
1750 Modulus = 2 | ArithmeticMask,
1751 Addition = 3 | ArithmeticMask | AdditionMask,
1752 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1754 LeftShift = 5 | ShiftMask,
1755 RightShift = 6 | ShiftMask,
1757 LessThan = 7 | ComparisonMask | RelationalMask,
1758 GreaterThan = 8 | ComparisonMask | RelationalMask,
1759 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1760 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1761 Equality = 11 | ComparisonMask | EqualityMask,
1762 Inequality = 12 | ComparisonMask | EqualityMask,
1764 BitwiseAnd = 13 | BitwiseMask,
1765 ExclusiveOr = 14 | BitwiseMask,
1766 BitwiseOr = 15 | BitwiseMask,
1768 LogicalAnd = 16 | LogicalMask,
1769 LogicalOr = 17 | LogicalMask,
1774 ValuesOnlyMask = ArithmeticMask - 1,
1775 ArithmeticMask = 1 << 5,
1777 ComparisonMask = 1 << 7,
1778 EqualityMask = 1 << 8,
1779 BitwiseMask = 1 << 9,
1780 LogicalMask = 1 << 10,
1781 AdditionMask = 1 << 11,
1782 SubtractionMask = 1 << 12,
1783 RelationalMask = 1 << 13
1786 readonly Operator oper;
1787 protected Expression left, right;
1788 readonly bool is_compound;
1790 // This must be kept in sync with Operator!!!
1791 public static readonly string [] oper_names;
1793 static PredefinedOperator [] standard_operators;
1794 static PredefinedOperator [] pointer_operators;
1798 oper_names = new string [18];
1800 oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
1801 oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
1802 oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
1803 oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
1804 oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
1805 oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
1806 oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
1807 oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
1808 oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
1809 oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
1810 oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
1811 oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
1812 oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
1813 oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
1814 oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
1815 oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
1816 oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
1817 oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
1820 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1821 : this (oper, left, right)
1823 this.is_compound = isCompound;
1826 public Binary (Operator oper, Expression left, Expression right)
1831 this.loc = left.Location;
1834 public Operator Oper {
1841 /// Returns a stringified representation of the Operator
1843 string OperName (Operator oper)
1847 case Operator.Multiply:
1850 case Operator.Division:
1853 case Operator.Modulus:
1856 case Operator.Addition:
1859 case Operator.Subtraction:
1862 case Operator.LeftShift:
1865 case Operator.RightShift:
1868 case Operator.LessThan:
1871 case Operator.GreaterThan:
1874 case Operator.LessThanOrEqual:
1877 case Operator.GreaterThanOrEqual:
1880 case Operator.Equality:
1883 case Operator.Inequality:
1886 case Operator.BitwiseAnd:
1889 case Operator.BitwiseOr:
1892 case Operator.ExclusiveOr:
1895 case Operator.LogicalOr:
1898 case Operator.LogicalAnd:
1902 s = oper.ToString ();
1912 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1914 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1917 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1919 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1923 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1926 // TODO: This should be handled as Type of method group in CSharpName
1927 if (left.eclass == ExprClass.MethodGroup)
1928 l = left.ExprClassName;
1930 l = TypeManager.CSharpName (left.Type);
1932 if (right.eclass == ExprClass.MethodGroup)
1933 r = left.ExprClassName;
1935 r = TypeManager.CSharpName (right.Type);
1937 Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
1940 public static string GetOperatorMetadataName (Operator op)
1942 return oper_names [(int)(op & Operator.ValuesOnlyMask)];
1945 static bool IsUnsigned (Type t)
1948 t = TypeManager.GetElementType (t);
1950 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1951 t == TypeManager.ushort_type || t == TypeManager.byte_type);
1954 Expression ResolveOperator (EmitContext ec)
1957 Type r = right.Type;
1959 bool primitives_only = false;
1962 // Handles predefined primitive types
1964 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
1965 if ((oper & Operator.ShiftMask) == 0) {
1966 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
1969 primitives_only = true;
1973 if (l.IsPointer || r.IsPointer)
1974 return ResolveOperatorPointer (ec, l, r);
1977 bool lenum = TypeManager.IsEnumType (l);
1978 bool renum = TypeManager.IsEnumType (r);
1979 if (lenum || renum) {
1980 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
1982 // TODO: Can this be ambiguous
1988 if (oper == Operator.Addition || oper == Operator.Subtraction) {
1989 if (TypeManager.IsDelegateType (l))
1990 return ResolveOperatorDelegateBinary (ec, l, r);
1994 expr = ResolveUserOperator (ec, l, r);
1998 // Predefined reference types equality
1999 if ((oper & Operator.EqualityMask) != 0) {
2000 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2006 if (standard_operators == null)
2007 CreateStandardOperatorsTable ();
2009 return ResolveOperatorPredefined (ec, standard_operators, primitives_only);
2012 Constant EnumLiftUp (Constant left, Constant right)
2015 case Operator.BitwiseOr:
2016 case Operator.BitwiseAnd:
2017 case Operator.ExclusiveOr:
2018 case Operator.Equality:
2019 case Operator.Inequality:
2020 case Operator.LessThan:
2021 case Operator.LessThanOrEqual:
2022 case Operator.GreaterThan:
2023 case Operator.GreaterThanOrEqual:
2024 if (left is EnumConstant)
2027 if (left.IsZeroInteger)
2028 return new EnumConstant (left, right.Type);
2032 case Operator.Addition:
2033 case Operator.Subtraction:
2036 case Operator.Multiply:
2037 case Operator.Division:
2038 case Operator.Modulus:
2039 case Operator.LeftShift:
2040 case Operator.RightShift:
2041 if (right is EnumConstant || left is EnumConstant)
2045 Error_OperatorCannotBeApplied (this.left, this.right);
2050 // The `|' operator used on types which were extended is dangerous
2052 void CheckBitwiseOrOnSignExtended ()
2054 OpcodeCast lcast = left as OpcodeCast;
2055 if (lcast != null) {
2056 if (IsUnsigned (lcast.UnderlyingType))
2060 OpcodeCast rcast = right as OpcodeCast;
2061 if (rcast != null) {
2062 if (IsUnsigned (rcast.UnderlyingType))
2066 if (lcast == null && rcast == null)
2069 // FIXME: consider constants
2071 Report.Warning (675, 3, loc,
2072 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2073 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2076 static void CreatePointerOperatorsTable ()
2078 ArrayList temp = new ArrayList ();
2081 // Pointer arithmetic:
2083 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2084 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2085 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2086 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2088 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2089 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2090 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2091 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2094 // T* operator + (int y, T* x);
2095 // T* operator + (uint y, T *x);
2096 // T* operator + (long y, T *x);
2097 // T* operator + (ulong y, T *x);
2099 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
2100 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
2101 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
2102 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
2105 // long operator - (T* x, T *y)
2107 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2109 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2112 static void CreateStandardOperatorsTable ()
2114 ArrayList temp = new ArrayList ();
2115 Type bool_type = TypeManager.bool_type;
2117 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2118 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2119 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2120 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2121 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2122 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2124 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2125 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2126 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2127 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2128 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2129 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2131 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2133 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2134 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2135 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2137 temp.Add (new PredefinedOperator (bool_type,
2138 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2140 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2141 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2142 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2143 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2145 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2149 // Rules used during binary numeric promotion
2151 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2156 Constant c = prim_expr as Constant;
2158 temp = c.ConvertImplicitly (type);
2165 if (type == TypeManager.uint32_type) {
2166 etype = prim_expr.Type;
2167 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2168 type = TypeManager.int64_type;
2170 if (type != second_expr.Type) {
2171 c = second_expr as Constant;
2173 temp = c.ConvertImplicitly (type);
2175 temp = Convert.ImplicitNumericConversion (second_expr, type);
2181 } else if (type == TypeManager.uint64_type) {
2183 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2185 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2186 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2190 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2199 // 7.2.6.2 Binary numeric promotions
2201 public bool DoBinaryOperatorPromotion (EmitContext ec)
2203 Type ltype = left.Type;
2204 Type rtype = right.Type;
2207 foreach (Type t in ConstantFold.binary_promotions) {
2209 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2212 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2215 Type int32 = TypeManager.int32_type;
2216 if (ltype != int32) {
2217 Constant c = left as Constant;
2219 temp = c.ImplicitConversionRequired (int32, loc);
2221 temp = Convert.ImplicitNumericConversion (left, int32);
2228 if (rtype != int32) {
2229 Constant c = right as Constant;
2231 temp = c.ImplicitConversionRequired (int32, loc);
2233 temp = Convert.ImplicitNumericConversion (right, int32);
2243 public override Expression DoResolve (EmitContext ec)
2248 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2249 left = ((ParenthesizedExpression) left).Expr;
2250 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2254 if (left.eclass == ExprClass.Type) {
2255 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2259 left = left.Resolve (ec);
2264 Constant lc = left as Constant;
2266 if (lc != null && lc.Type == TypeManager.bool_type &&
2267 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2268 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2270 // FIXME: resolve right expression as unreachable
2271 // right.Resolve (ec);
2273 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2277 right = right.Resolve (ec);
2281 eclass = ExprClass.Value;
2282 Constant rc = right as Constant;
2284 // The conversion rules are ignored in enum context but why
2285 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2286 left = lc = EnumLiftUp (lc, rc);
2290 right = rc = EnumLiftUp (rc, lc);
2295 if (rc != null && lc != null) {
2296 int prev_e = Report.Errors;
2297 Expression e = ConstantFold.BinaryFold (
2298 ec, oper, lc, rc, loc);
2299 if (e != null || Report.Errors != prev_e)
2302 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2303 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2305 if ((ResolveOperator (ec)) == null) {
2306 Error_OperatorCannotBeApplied (left, right);
2315 // TODO: there must be better way how to check that the expression
2316 // does not have any mutator
2317 if (right is MemberExpr)
2320 // The result is a constant with side-effect
2321 return new SideEffectConstant (lc, right, loc);
2325 // Comparison warnings
2326 if ((oper & Operator.ComparisonMask) != 0) {
2327 if (left.Equals (right)) {
2328 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2330 CheckUselessComparison (lc, right.Type);
2331 CheckUselessComparison (rc, left.Type);
2334 if ((TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2335 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)) &&
2336 !(this is Nullable.LiftedBinaryOperator))
2337 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2339 return DoResolveCore (ec, left, right);
2342 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2344 Expression expr = ResolveOperator (ec);
2346 Error_OperatorCannotBeApplied (left_orig, right_orig);
2348 if (left == null || right == null)
2349 throw new InternalErrorException ("Invalid conversion");
2351 if (oper == Operator.BitwiseOr)
2352 CheckBitwiseOrOnSignExtended ();
2358 // D operator + (D x, D y)
2359 // D operator - (D x, D y)
2361 Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
2363 if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
2364 if ((RootContext.Version != LanguageVersion.ISO_1)) {
2365 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2372 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
2377 ArrayList args = new ArrayList (2);
2379 args = new ArrayList (2);
2380 args.Add (new Argument (left, Argument.AType.Expression));
2381 args.Add (new Argument (right, Argument.AType.Expression));
2383 if (oper == Operator.Addition) {
2384 if (TypeManager.delegate_combine_delegate_delegate == null) {
2385 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2386 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2389 method = TypeManager.delegate_combine_delegate_delegate;
2391 if (TypeManager.delegate_remove_delegate_delegate == null) {
2392 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2393 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2396 method = TypeManager.delegate_remove_delegate_delegate;
2399 return new BinaryDelegate (l, method, args);
2403 // Enumeration operators
2405 Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2409 if (lenum || renum) {
2411 // bool operator == (E x, E y);
2412 // bool operator != (E x, E y);
2413 // bool operator < (E x, E y);
2414 // bool operator > (E x, E y);
2415 // bool operator <= (E x, E y);
2416 // bool operator >= (E x, E y);
2418 if ((oper & Operator.ComparisonMask) != 0) {
2419 type = TypeManager.bool_type;
2420 } else if ((oper & Operator.BitwiseMask) != 0) {
2425 if (!TypeManager.IsEqual (ltype, rtype)) {
2427 temp = Convert.ImplicitConversion (ec, left, rtype, loc);
2432 temp = Convert.ImplicitConversion (ec, right, ltype, loc);
2443 Type underlying_type;
2444 if (lenum && !renum) {
2446 // E operator + (E e, U x)
2447 // E operator - (E e, U x)
2449 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2450 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2451 temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
2465 // E operator + (U x, E e)
2467 if (oper == Operator.Addition) {
2468 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2469 temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
2480 // U operator - (E e, E f)
2482 if (oper == Operator.Subtraction) {
2483 if (!TypeManager.IsEqual (ltype, rtype))
2486 type = TypeManager.GetEnumUnderlyingType (ltype);
2494 // 7.9.6 Reference type equality operators
2496 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2499 // operator != (object a, object b)
2500 // operator == (object a, object b)
2503 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2505 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2508 type = TypeManager.bool_type;
2509 GenericConstraints constraints;
2511 bool lgen = TypeManager.IsGenericParameter (l);
2513 if (TypeManager.IsEqual (l, r)) {
2516 // Only allow to compare same reference type parameter
2518 constraints = TypeManager.GetTypeParameterConstraints (l);
2519 if (constraints != null && constraints.IsReferenceType)
2525 if (l == TypeManager.anonymous_method_type)
2528 if (TypeManager.IsValueType (l))
2534 bool rgen = TypeManager.IsGenericParameter (r);
2537 // a, Both operands are reference-type values or the value null
2538 // b, One operand is a value of type T where T is a type-parameter and
2539 // the other operand is the value null. Furthermore T does not have the
2540 // value type constrain
2542 if (left is NullLiteral || right is NullLiteral) {
2544 constraints = TypeManager.GetTypeParameterConstraints (l);
2545 if (constraints != null && constraints.HasValueTypeConstraint)
2548 left = new BoxedCast (left, TypeManager.object_type);
2553 constraints = TypeManager.GetTypeParameterConstraints (r);
2554 if (constraints != null && constraints.HasValueTypeConstraint)
2557 right = new BoxedCast (right, TypeManager.object_type);
2563 // An interface is converted to the object before the
2564 // standard conversion is applied. It's not clear from the
2565 // standard but it looks like it works like that.
2568 constraints = TypeManager.GetTypeParameterConstraints (l);
2569 if (constraints == null || constraints.IsReferenceType)
2571 } else if (l.IsInterface) {
2572 l = TypeManager.object_type;
2576 constraints = TypeManager.GetTypeParameterConstraints (r);
2577 if (constraints == null || constraints.IsReferenceType)
2579 } else if (r.IsInterface) {
2580 r = TypeManager.object_type;
2583 const string ref_comparison = "Possible unintended reference comparison. " +
2584 "Consider casting the {0} side of the expression to `string' to compare the values";
2587 // A standard implicit conversion exists from the type of either
2588 // operand to the type of the other operand
2590 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2591 if (l == TypeManager.string_type)
2592 Report.Warning (253, 2, loc, ref_comparison, "right");
2597 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2598 if (r == TypeManager.string_type)
2599 Report.Warning (252, 2, loc, ref_comparison, "left");
2608 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2611 // bool operator == (void* x, void* y);
2612 // bool operator != (void* x, void* y);
2613 // bool operator < (void* x, void* y);
2614 // bool operator > (void* x, void* y);
2615 // bool operator <= (void* x, void* y);
2616 // bool operator >= (void* x, void* y);
2618 if ((oper & Operator.ComparisonMask) != 0) {
2621 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2628 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2634 type = TypeManager.bool_type;
2638 if (pointer_operators == null)
2639 CreatePointerOperatorsTable ();
2641 return ResolveOperatorPredefined (ec, pointer_operators, false);
2645 // Build-in operators method overloading
2647 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
2649 PredefinedOperator best_operator = null;
2651 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2653 bool left_is_null = left is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
2654 bool right_is_null = right is NullLiteral && RootContext.Version >= LanguageVersion.ISO_2;
2656 foreach (PredefinedOperator po in operators) {
2657 if ((po.OperatorsMask & oper_mask) == 0)
2660 if (primitives_only) {
2661 if (!po.IsPrimitiveApplicable (l))
2664 if (!po.IsApplicable (ec, left, right, left_is_null, right_is_null))
2668 if (best_operator == null) {
2670 if (primitives_only)
2676 best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
2678 if (best_operator == null) {
2679 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2680 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2687 if (best_operator == null)
2690 return best_operator.ConvertResult (ec, this);
2694 // Performs user-operator overloading
2696 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
2699 if (oper == Operator.LogicalAnd)
2700 user_oper = Operator.BitwiseAnd;
2701 else if (oper == Operator.LogicalOr)
2702 user_oper = Operator.BitwiseOr;
2706 string op = GetOperatorMetadataName (user_oper);
2708 MethodGroupExpr union;
2709 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2710 if (!TypeManager.IsEqual (r, l)) {
2711 MethodGroupExpr right_operators = MemberLookup (
2712 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2713 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2715 union = left_operators;
2720 ArrayList args = new ArrayList (2);
2721 Argument larg = new Argument (left);
2723 Argument rarg = new Argument (right);
2728 // Aparrently user-operators use different overloading rules especially for lifted arguments.
2729 // Some details are in 6.4.2, 7.2.7
2730 // Case 1: Arguments can be lifted for equal operators when the return type is bool and both
2731 // arguments are of same type and they are convertible.
2733 union = union.OverloadResolve (ec, ref args, true, loc);
2737 if (user_oper != oper) {
2738 // FIXME: This has to derive from UserOperatorCall to handle expression tree
2739 return new ConditionalLogicalOperator (oper == Operator.LogicalAnd,
2740 left, right, left.Type, loc).Resolve (ec);
2744 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2745 // and not invoke user operator
2747 if ((oper & Operator.EqualityMask) != 0) {
2748 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
2749 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
2750 type = TypeManager.bool_type;
2751 // FIXME: this breaks expression tree
2752 if (left is NullLiteral || right is NullLiteral)
2754 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
2756 // Two System.Delegate(s) are never equal
2764 // TODO: CreateExpressionTree is allocated every time
2765 return new UserOperatorCall (union, args, CreateExpressionTree, loc);
2768 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2773 private void CheckUselessComparison (Constant c, Type type)
2775 if (c == null || !IsTypeIntegral (type)
2776 || c is StringConstant
2777 || c is BoolConstant
2778 || c is FloatConstant
2779 || c is DoubleConstant
2780 || c is DecimalConstant
2786 if (c is ULongConstant) {
2787 ulong uvalue = ((ULongConstant) c).Value;
2788 if (uvalue > long.MaxValue) {
2789 if (type == TypeManager.byte_type ||
2790 type == TypeManager.sbyte_type ||
2791 type == TypeManager.short_type ||
2792 type == TypeManager.ushort_type ||
2793 type == TypeManager.int32_type ||
2794 type == TypeManager.uint32_type ||
2795 type == TypeManager.int64_type ||
2796 type == TypeManager.char_type)
2797 WarnUselessComparison (type);
2800 value = (long) uvalue;
2802 else if (c is ByteConstant)
2803 value = ((ByteConstant) c).Value;
2804 else if (c is SByteConstant)
2805 value = ((SByteConstant) c).Value;
2806 else if (c is ShortConstant)
2807 value = ((ShortConstant) c).Value;
2808 else if (c is UShortConstant)
2809 value = ((UShortConstant) c).Value;
2810 else if (c is IntConstant)
2811 value = ((IntConstant) c).Value;
2812 else if (c is UIntConstant)
2813 value = ((UIntConstant) c).Value;
2814 else if (c is LongConstant)
2815 value = ((LongConstant) c).Value;
2816 else if (c is CharConstant)
2817 value = ((CharConstant)c).Value;
2822 if (IsValueOutOfRange (value, type))
2823 WarnUselessComparison (type);
2826 private bool IsValueOutOfRange (long value, Type type)
2828 if (IsTypeUnsigned (type) && value < 0)
2830 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2831 type == TypeManager.byte_type && value >= 0x100 ||
2832 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2833 type == TypeManager.ushort_type && value >= 0x10000 ||
2834 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2835 type == TypeManager.uint32_type && value >= 0x100000000;
2838 static bool IsBuildInEqualityOperator (Type t)
2840 return t == TypeManager.object_type || t == TypeManager.string_type ||
2841 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
2844 private static bool IsTypeIntegral (Type type)
2846 return type == TypeManager.uint64_type ||
2847 type == TypeManager.int64_type ||
2848 type == TypeManager.uint32_type ||
2849 type == TypeManager.int32_type ||
2850 type == TypeManager.ushort_type ||
2851 type == TypeManager.short_type ||
2852 type == TypeManager.sbyte_type ||
2853 type == TypeManager.byte_type ||
2854 type == TypeManager.char_type;
2857 private static bool IsTypeUnsigned (Type type)
2859 return type == TypeManager.uint64_type ||
2860 type == TypeManager.uint32_type ||
2861 type == TypeManager.ushort_type ||
2862 type == TypeManager.byte_type ||
2863 type == TypeManager.char_type;
2866 private void WarnUselessComparison (Type type)
2868 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}'",
2869 TypeManager.CSharpName (type));
2873 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2874 /// context of a conditional bool expression. This function will return
2875 /// false if it is was possible to use EmitBranchable, or true if it was.
2877 /// The expression's code is generated, and we will generate a branch to `target'
2878 /// if the resulting expression value is equal to isTrue
2880 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2882 ILGenerator ig = ec.ig;
2885 // This is more complicated than it looks, but its just to avoid
2886 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2887 // but on top of that we want for == and != to use a special path
2888 // if we are comparing against null
2890 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2891 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
2894 // put the constant on the rhs, for simplicity
2896 if (left is Constant) {
2897 Expression swap = right;
2902 if (((Constant) right).IsZeroInteger) {
2905 ig.Emit (OpCodes.Brtrue, target);
2907 ig.Emit (OpCodes.Brfalse, target);
2910 } else if (right is BoolConstant) {
2912 if (my_on_true != ((BoolConstant) right).Value)
2913 ig.Emit (OpCodes.Brtrue, target);
2915 ig.Emit (OpCodes.Brfalse, target);
2920 } else if (oper == Operator.LogicalAnd) {
2923 Label tests_end = ig.DefineLabel ();
2925 left.EmitBranchable (ec, tests_end, false);
2926 right.EmitBranchable (ec, target, true);
2927 ig.MarkLabel (tests_end);
2930 // This optimizes code like this
2931 // if (true && i > 4)
2933 if (!(left is Constant))
2934 left.EmitBranchable (ec, target, false);
2936 if (!(right is Constant))
2937 right.EmitBranchable (ec, target, false);
2942 } else if (oper == Operator.LogicalOr){
2944 left.EmitBranchable (ec, target, true);
2945 right.EmitBranchable (ec, target, true);
2948 Label tests_end = ig.DefineLabel ();
2949 left.EmitBranchable (ec, tests_end, true);
2950 right.EmitBranchable (ec, target, false);
2951 ig.MarkLabel (tests_end);
2956 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2957 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2958 oper == Operator.Equality || oper == Operator.Inequality)) {
2959 base.EmitBranchable (ec, target, on_true);
2967 bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2970 case Operator.Equality:
2972 ig.Emit (OpCodes.Beq, target);
2974 ig.Emit (OpCodes.Bne_Un, target);
2977 case Operator.Inequality:
2979 ig.Emit (OpCodes.Bne_Un, target);
2981 ig.Emit (OpCodes.Beq, target);
2984 case Operator.LessThan:
2987 ig.Emit (OpCodes.Blt_Un, target);
2989 ig.Emit (OpCodes.Blt, target);
2992 ig.Emit (OpCodes.Bge_Un, target);
2994 ig.Emit (OpCodes.Bge, target);
2997 case Operator.GreaterThan:
3000 ig.Emit (OpCodes.Bgt_Un, target);
3002 ig.Emit (OpCodes.Bgt, target);
3005 ig.Emit (OpCodes.Ble_Un, target);
3007 ig.Emit (OpCodes.Ble, target);
3010 case Operator.LessThanOrEqual:
3013 ig.Emit (OpCodes.Ble_Un, target);
3015 ig.Emit (OpCodes.Ble, target);
3018 ig.Emit (OpCodes.Bgt_Un, target);
3020 ig.Emit (OpCodes.Bgt, target);
3024 case Operator.GreaterThanOrEqual:
3027 ig.Emit (OpCodes.Bge_Un, target);
3029 ig.Emit (OpCodes.Bge, target);
3032 ig.Emit (OpCodes.Blt_Un, target);
3034 ig.Emit (OpCodes.Blt, target);
3037 throw new InternalErrorException (oper.ToString ());
3041 public override void Emit (EmitContext ec)
3046 protected void EmitOperator (EmitContext ec)
3048 ILGenerator ig = ec.ig;
3051 // Handle short-circuit operators differently
3054 if ((oper & Operator.LogicalMask) != 0) {
3055 Label load_result = ig.DefineLabel ();
3056 Label end = ig.DefineLabel ();
3058 bool is_or = oper == Operator.LogicalOr;
3059 left.EmitBranchable (ec, load_result, is_or);
3061 ig.Emit (OpCodes.Br_S, end);
3063 ig.MarkLabel (load_result);
3064 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3072 // Optimize zero-based operations
3074 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3076 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3077 Constant rc = right as Constant;
3078 if (rc != null && rc.IsDefaultValue) {
3087 bool is_unsigned = IsUnsigned (l);
3090 case Operator.Multiply:
3092 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3093 opcode = OpCodes.Mul_Ovf;
3094 else if (is_unsigned)
3095 opcode = OpCodes.Mul_Ovf_Un;
3097 opcode = OpCodes.Mul;
3099 opcode = OpCodes.Mul;
3103 case Operator.Division:
3105 opcode = OpCodes.Div_Un;
3107 opcode = OpCodes.Div;
3110 case Operator.Modulus:
3112 opcode = OpCodes.Rem_Un;
3114 opcode = OpCodes.Rem;
3117 case Operator.Addition:
3119 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3120 opcode = OpCodes.Add_Ovf;
3121 else if (is_unsigned)
3122 opcode = OpCodes.Add_Ovf_Un;
3124 opcode = OpCodes.Add;
3126 opcode = OpCodes.Add;
3129 case Operator.Subtraction:
3131 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3132 opcode = OpCodes.Sub_Ovf;
3133 else if (is_unsigned)
3134 opcode = OpCodes.Sub_Ovf_Un;
3136 opcode = OpCodes.Sub;
3138 opcode = OpCodes.Sub;
3141 case Operator.RightShift:
3143 opcode = OpCodes.Shr_Un;
3145 opcode = OpCodes.Shr;
3148 case Operator.LeftShift:
3149 opcode = OpCodes.Shl;
3152 case Operator.Equality:
3153 opcode = OpCodes.Ceq;
3156 case Operator.Inequality:
3157 ig.Emit (OpCodes.Ceq);
3158 ig.Emit (OpCodes.Ldc_I4_0);
3160 opcode = OpCodes.Ceq;
3163 case Operator.LessThan:
3165 opcode = OpCodes.Clt_Un;
3167 opcode = OpCodes.Clt;
3170 case Operator.GreaterThan:
3172 opcode = OpCodes.Cgt_Un;
3174 opcode = OpCodes.Cgt;
3177 case Operator.LessThanOrEqual:
3178 Type lt = left.Type;
3180 if (is_unsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3181 ig.Emit (OpCodes.Cgt_Un);
3183 ig.Emit (OpCodes.Cgt);
3184 ig.Emit (OpCodes.Ldc_I4_0);
3186 opcode = OpCodes.Ceq;
3189 case Operator.GreaterThanOrEqual:
3190 Type le = left.Type;
3192 if (is_unsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3193 ig.Emit (OpCodes.Clt_Un);
3195 ig.Emit (OpCodes.Clt);
3197 ig.Emit (OpCodes.Ldc_I4_0);
3199 opcode = OpCodes.Ceq;
3202 case Operator.BitwiseOr:
3203 opcode = OpCodes.Or;
3206 case Operator.BitwiseAnd:
3207 opcode = OpCodes.And;
3210 case Operator.ExclusiveOr:
3211 opcode = OpCodes.Xor;
3215 throw new InternalErrorException (oper.ToString ());
3221 protected override void CloneTo (CloneContext clonectx, Expression t)
3223 Binary target = (Binary) t;
3225 target.left = left.Clone (clonectx);
3226 target.right = right.Clone (clonectx);
3229 public override Expression CreateExpressionTree (EmitContext ec)
3231 return CreateExpressionTree (ec, null);
3234 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3237 bool lift_arg = false;
3240 case Operator.Addition:
3241 if (method == null && ec.CheckState)
3242 method_name = "AddChecked";
3244 method_name = "Add";
3246 case Operator.BitwiseAnd:
3247 method_name = "And";
3249 case Operator.Division:
3250 method_name = "Divide";
3252 case Operator.Equality:
3253 method_name = "Equal";
3256 case Operator.ExclusiveOr:
3257 method_name = "ExclusiveOr";
3259 case Operator.GreaterThan:
3260 method_name = "GreaterThan";
3263 case Operator.GreaterThanOrEqual:
3264 method_name = "GreaterThanOrEqual";
3267 case Operator.LessThan:
3268 method_name = "LessThan";
3270 case Operator.LogicalAnd:
3271 method_name = "AndAlso";
3273 case Operator.Inequality:
3274 method_name = "NotEqual";
3277 case Operator.RightShift:
3278 method_name = "RightShift";
3281 case Operator.BitwiseOr:
3285 case Operator.LogicalOr:
3286 method_name = "OrElse";
3289 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3292 ArrayList args = new ArrayList (2);
3293 args.Add (new Argument (left.CreateExpressionTree (ec)));
3294 args.Add (new Argument (right.CreateExpressionTree (ec)));
3295 if (method != null) {
3297 args.Add (new Argument (new BoolConstant (false, loc)));
3299 args.Add (new Argument (method.CreateExpressionTree (ec)));
3302 return CreateExpressionFactoryCall (method_name, args);
3307 // Object created by Binary when the binary operator uses an method instead of being
3308 // a binary operation that maps to a CIL binary operation.
3310 public class BinaryMethod : Expression {
3311 public MethodBase method;
3312 public ArrayList Arguments;
3314 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3319 eclass = ExprClass.Value;
3322 public override Expression DoResolve (EmitContext ec)
3327 public override void Emit (EmitContext ec)
3329 ILGenerator ig = ec.ig;
3331 Invocation.EmitArguments (ec, Arguments, false, null);
3333 if (method is MethodInfo)
3334 ig.Emit (OpCodes.Call, (MethodInfo) method);
3336 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3341 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3342 // b, c, d... may be strings or objects.
3344 public class StringConcat : Expression {
3345 ArrayList arguments;
3347 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3350 type = TypeManager.string_type;
3351 eclass = ExprClass.Value;
3353 arguments = new ArrayList (2);
3358 public override Expression DoResolve (EmitContext ec)
3363 public void Append (EmitContext ec, Expression operand)
3368 StringConstant sc = operand as StringConstant;
3370 if (arguments.Count != 0) {
3371 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3372 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3373 if (last_expr_constant != null) {
3374 last_argument.Expr = new StringConstant (
3375 last_expr_constant.Value + sc.Value, sc.Location);
3381 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3383 StringConcat concat_oper = operand as StringConcat;
3384 if (concat_oper != null) {
3385 arguments.AddRange (concat_oper.arguments);
3390 arguments.Add (new Argument (operand));
3393 Expression CreateConcatInvocation ()
3395 return new Invocation (
3396 new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc),
3400 public override void Emit (EmitContext ec)
3402 Expression concat = CreateConcatInvocation ();
3403 concat = concat.Resolve (ec);
3410 // Object created with +/= on delegates
3412 public class BinaryDelegate : Expression {
3416 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3421 eclass = ExprClass.Value;
3424 public override Expression DoResolve (EmitContext ec)
3429 public override void Emit (EmitContext ec)
3431 ILGenerator ig = ec.ig;
3433 Invocation.EmitArguments (ec, args, false, null);
3435 ig.Emit (OpCodes.Call, (MethodInfo) method);
3436 ig.Emit (OpCodes.Castclass, type);
3439 public Expression Right {
3441 Argument arg = (Argument) args [1];
3446 public bool IsAddition {
3448 return method == TypeManager.delegate_combine_delegate_delegate;
3454 // User-defined conditional logical operator
3456 public class ConditionalLogicalOperator : Expression {
3457 Expression left, right;
3459 Expression op_true, op_false;
3460 UserOperatorCall op;
3461 LocalTemporary left_temp;
3463 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3466 eclass = ExprClass.Value;
3470 this.is_and = is_and;
3473 public override Expression CreateExpressionTree (EmitContext ec)
3475 ArrayList args = new ArrayList (3);
3476 args.Add (new Argument (left.CreateExpressionTree (ec)));
3477 args.Add (new Argument (right.CreateExpressionTree (ec)));
3478 args.Add (new Argument (op.Method.CreateExpressionTree (ec)));
3479 return CreateExpressionFactoryCall (is_and ? "AndAlso" : "OrElse", args);
3482 protected void Error19 ()
3484 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3487 protected void Error218 ()
3489 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3490 "declarations of operator true and operator false");
3493 public override Expression DoResolve (EmitContext ec)
3495 MethodGroupExpr operator_group;
3497 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3498 if (operator_group == null) {
3503 left_temp = new LocalTemporary (type);
3505 ArrayList arguments = new ArrayList (2);
3506 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3507 arguments.Add (new Argument (right, Argument.AType.Expression));
3508 operator_group = operator_group.OverloadResolve (ec, ref arguments, false, loc);
3509 if (operator_group == null) {
3514 MethodInfo method = (MethodInfo)operator_group;
3515 if (method.ReturnType != type) {
3516 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3517 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3521 op = new UserOperatorCall (operator_group, arguments, null, loc);
3523 op_true = GetOperatorTrue (ec, left_temp, loc);
3524 op_false = GetOperatorFalse (ec, left_temp, loc);
3525 if ((op_true == null) || (op_false == null)) {
3533 public override void Emit (EmitContext ec)
3535 ILGenerator ig = ec.ig;
3536 Label false_target = ig.DefineLabel ();
3537 Label end_target = ig.DefineLabel ();
3540 left_temp.Store (ec);
3542 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3543 left_temp.Emit (ec);
3544 ig.Emit (OpCodes.Br, end_target);
3545 ig.MarkLabel (false_target);
3547 ig.MarkLabel (end_target);
3549 // We release 'left_temp' here since 'op' may refer to it too
3550 left_temp.Release (ec);
3554 public class PointerArithmetic : Expression {
3555 Expression left, right;
3559 // We assume that `l' is always a pointer
3561 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3567 is_add = is_addition;
3570 public override Expression DoResolve (EmitContext ec)
3572 eclass = ExprClass.Variable;
3574 if (left.Type == TypeManager.void_ptr_type) {
3575 Error (242, "The operation in question is undefined on void pointers");
3582 public override void Emit (EmitContext ec)
3584 Type op_type = left.Type;
3585 ILGenerator ig = ec.ig;
3587 // It must be either array or fixed buffer
3588 Type element = TypeManager.HasElementType (op_type) ?
3589 element = TypeManager.GetElementType (op_type) :
3590 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3592 int size = GetTypeSize (element);
3593 Type rtype = right.Type;
3595 if (rtype.IsPointer){
3597 // handle (pointer - pointer)
3601 ig.Emit (OpCodes.Sub);
3605 ig.Emit (OpCodes.Sizeof, element);
3607 IntLiteral.EmitInt (ig, size);
3608 ig.Emit (OpCodes.Div);
3610 ig.Emit (OpCodes.Conv_I8);
3613 // handle + and - on (pointer op int)
3616 ig.Emit (OpCodes.Conv_I);
3618 Constant right_const = right as Constant;
3619 if (right_const != null && size != 0) {
3620 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3628 ig.Emit (OpCodes.Sizeof, element);
3630 IntLiteral.EmitInt (ig, size);
3631 if (rtype == TypeManager.int64_type)
3632 ig.Emit (OpCodes.Conv_I8);
3633 else if (rtype == TypeManager.uint64_type)
3634 ig.Emit (OpCodes.Conv_U8);
3635 ig.Emit (OpCodes.Mul);
3639 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3640 ig.Emit (OpCodes.Conv_I);
3643 ig.Emit (OpCodes.Add);
3645 ig.Emit (OpCodes.Sub);
3651 /// Implements the ternary conditional operator (?:)
3653 public class Conditional : Expression {
3654 Expression expr, true_expr, false_expr;
3656 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3659 this.true_expr = true_expr;
3660 this.false_expr = false_expr;
3661 this.loc = expr.Location;
3664 public Expression Expr {
3670 public Expression TrueExpr {
3676 public Expression FalseExpr {
3682 public override Expression CreateExpressionTree (EmitContext ec)
3684 ArrayList args = new ArrayList (3);
3685 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3686 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3687 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3688 return CreateExpressionFactoryCall ("Condition", args);
3691 public override Expression DoResolve (EmitContext ec)
3693 expr = expr.Resolve (ec);
3698 if (expr.Type != TypeManager.bool_type){
3699 expr = Expression.ResolveBoolean (
3706 Assign ass = expr as Assign;
3707 if (ass != null && ass.Source is Constant) {
3708 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3711 true_expr = true_expr.Resolve (ec);
3712 false_expr = false_expr.Resolve (ec);
3714 if (true_expr == null || false_expr == null)
3717 eclass = ExprClass.Value;
3718 if (true_expr.Type == false_expr.Type) {
3719 type = true_expr.Type;
3720 if (type == TypeManager.null_type) {
3721 // TODO: probably will have to implement ConditionalConstant
3722 // to call method without return constant as well
3723 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3728 Type true_type = true_expr.Type;
3729 Type false_type = false_expr.Type;
3732 // First, if an implicit conversion exists from true_expr
3733 // to false_expr, then the result type is of type false_expr.Type
3735 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3738 // Check if both can convert implicitl to each other's type
3740 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3742 "Can not compute type of conditional expression " +
3743 "as `" + TypeManager.CSharpName (true_expr.Type) +
3744 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3745 "' convert implicitly to each other");
3750 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3754 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3755 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3760 // Dead code optimalization
3761 if (expr is BoolConstant){
3762 BoolConstant bc = (BoolConstant) expr;
3764 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3765 return bc.Value ? true_expr : false_expr;
3771 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3776 public override void Emit (EmitContext ec)
3778 ILGenerator ig = ec.ig;
3779 Label false_target = ig.DefineLabel ();
3780 Label end_target = ig.DefineLabel ();
3782 expr.EmitBranchable (ec, false_target, false);
3783 true_expr.Emit (ec);
3785 if (type.IsInterface) {
3786 LocalBuilder temp = ec.GetTemporaryLocal (type);
3787 ig.Emit (OpCodes.Stloc, temp);
3788 ig.Emit (OpCodes.Ldloc, temp);
3789 ec.FreeTemporaryLocal (temp, type);
3792 ig.Emit (OpCodes.Br, end_target);
3793 ig.MarkLabel (false_target);
3794 false_expr.Emit (ec);
3795 ig.MarkLabel (end_target);
3798 protected override void CloneTo (CloneContext clonectx, Expression t)
3800 Conditional target = (Conditional) t;
3802 target.expr = expr.Clone (clonectx);
3803 target.true_expr = true_expr.Clone (clonectx);
3804 target.false_expr = false_expr.Clone (clonectx);
3808 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3810 LocalTemporary temp;
3812 public abstract Variable Variable {
3816 public abstract bool IsRef {
3820 public override void Emit (EmitContext ec)
3826 // This method is used by parameters that are references, that are
3827 // being passed as references: we only want to pass the pointer (that
3828 // is already stored in the parameter, not the address of the pointer,
3829 // and not the value of the variable).
3831 public void EmitLoad (EmitContext ec)
3833 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3835 Variable.EmitInstance (ec);
3839 public void Emit (EmitContext ec, bool leave_copy)
3841 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3847 // If we are a reference, we loaded on the stack a pointer
3848 // Now lets load the real value
3850 LoadFromPtr (ec.ig, type);
3854 ec.ig.Emit (OpCodes.Dup);
3856 if (IsRef || Variable.NeedsTemporary) {
3857 temp = new LocalTemporary (Type);
3863 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3864 bool prepare_for_load)
3866 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3869 ILGenerator ig = ec.ig;
3870 prepared = prepare_for_load;
3872 Variable.EmitInstance (ec);
3873 if (prepare_for_load) {
3874 if (Variable.HasInstance)
3875 ig.Emit (OpCodes.Dup);
3883 // HACK: variable is already emitted when source is an initializer
3884 if (source is NewInitialize)
3888 ig.Emit (OpCodes.Dup);
3889 if (IsRef || Variable.NeedsTemporary) {
3890 temp = new LocalTemporary (Type);
3896 StoreFromPtr (ig, type);
3898 Variable.EmitAssign (ec);
3906 public void AddressOf (EmitContext ec, AddressOp mode)
3908 Variable.EmitInstance (ec);
3909 Variable.EmitAddressOf (ec);
3916 public class LocalVariableReference : VariableReference, IVariable {
3917 public readonly string Name;
3919 public LocalInfo local_info;
3923 public LocalVariableReference (Block block, string name, Location l)
3928 eclass = ExprClass.Variable;
3932 // Setting `is_readonly' to false will allow you to create a writable
3933 // reference to a read-only variable. This is used by foreach and using.
3935 public LocalVariableReference (Block block, string name, Location l,
3936 LocalInfo local_info, bool is_readonly)
3937 : this (block, name, l)
3939 this.local_info = local_info;
3940 this.is_readonly = is_readonly;
3943 public VariableInfo VariableInfo {
3944 get { return local_info.VariableInfo; }
3947 public override bool IsRef {
3948 get { return false; }
3951 public bool IsReadOnly {
3952 get { return is_readonly; }
3955 public bool VerifyAssigned (EmitContext ec)
3957 VariableInfo variable_info = local_info.VariableInfo;
3958 return variable_info == null || variable_info.IsAssigned (ec, loc);
3961 void ResolveLocalInfo ()
3963 if (local_info == null) {
3964 local_info = Block.GetLocalInfo (Name);
3965 type = local_info.VariableType;
3966 is_readonly = local_info.ReadOnly;
3970 protected Expression DoResolveBase (EmitContext ec)
3972 type = local_info.VariableType;
3974 Expression e = Block.GetConstantExpression (Name);
3976 return e.Resolve (ec);
3978 if (!VerifyAssigned (ec))
3982 // If we are referencing a variable from the external block
3983 // flag it for capturing
3985 if (ec.MustCaptureVariable (local_info)) {
3986 if (local_info.AddressTaken){
3987 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3991 if (!ec.IsInProbingMode)
3993 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3994 variable = scope.AddLocal (local_info);
3995 type = variable.Type;
4002 public override Expression DoResolve (EmitContext ec)
4004 ResolveLocalInfo ();
4005 local_info.Used = true;
4007 if (type == null && local_info.Type is VarExpr) {
4008 local_info.VariableType = TypeManager.object_type;
4009 Error_VariableIsUsedBeforeItIsDeclared (Name);
4013 return DoResolveBase (ec);
4016 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4018 ResolveLocalInfo ();
4021 if (right_side == EmptyExpression.OutAccess)
4022 local_info.Used = true;
4024 // Infer implicitly typed local variable
4026 VarExpr ve = local_info.Type as VarExpr;
4028 ve.DoResolveLValue (ec, right_side);
4029 type = local_info.VariableType = ve.Type;
4036 if (right_side == EmptyExpression.OutAccess) {
4037 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4038 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4039 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4040 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4041 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4043 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4045 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4049 if (VariableInfo != null)
4050 VariableInfo.SetAssigned (ec);
4052 return DoResolveBase (ec);
4055 public bool VerifyFixed ()
4057 // A local Variable is always fixed.
4061 public override int GetHashCode ()
4063 return Name.GetHashCode ();
4066 public override bool Equals (object obj)
4068 LocalVariableReference lvr = obj as LocalVariableReference;
4072 return Name == lvr.Name && Block == lvr.Block;
4075 public override Variable Variable {
4076 get { return variable != null ? variable : local_info.Variable; }
4079 public override string ToString ()
4081 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4084 protected override void CloneTo (CloneContext clonectx, Expression t)
4086 LocalVariableReference target = (LocalVariableReference) t;
4088 target.Block = clonectx.LookupBlock (Block);
4089 if (local_info != null)
4090 target.local_info = clonectx.LookupVariable (local_info);
4095 /// This represents a reference to a parameter in the intermediate
4098 public class ParameterReference : VariableReference, IVariable {
4099 readonly ToplevelParameterInfo pi;
4100 readonly ToplevelBlock referenced;
4103 public bool is_ref, is_out;
4106 get { return is_out; }
4109 public override bool IsRef {
4110 get { return is_ref; }
4113 public string Name {
4114 get { return Parameter.Name; }
4117 public Parameter Parameter {
4118 get { return pi.Parameter; }
4121 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4124 this.referenced = referenced;
4126 eclass = ExprClass.Variable;
4129 public VariableInfo VariableInfo {
4130 get { return pi.VariableInfo; }
4133 public override Variable Variable {
4134 get { return variable != null ? variable : Parameter.Variable; }
4137 public bool VerifyFixed ()
4139 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4140 return Parameter.ModFlags == Parameter.Modifier.NONE;
4143 public bool IsAssigned (EmitContext ec, Location loc)
4145 // HACK: Variables are not captured in probing mode
4146 if (ec.IsInProbingMode)
4149 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
4152 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4156 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4158 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
4161 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
4165 public void SetAssigned (EmitContext ec)
4167 if (is_out && ec.DoFlowAnalysis)
4168 ec.CurrentBranching.SetAssigned (VariableInfo);
4171 public void SetFieldAssigned (EmitContext ec, string field_name)
4173 if (is_out && ec.DoFlowAnalysis)
4174 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
4177 protected bool DoResolveBase (EmitContext ec)
4179 Parameter par = Parameter;
4180 if (!par.Resolve (ec)) {
4184 type = par.ParameterType;
4185 Parameter.Modifier mod = par.ModFlags;
4186 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4187 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
4188 eclass = ExprClass.Variable;
4190 AnonymousContainer am = ec.CurrentAnonymousMethod;
4194 ToplevelBlock declared = pi.Block;
4195 if (is_ref && declared != referenced) {
4196 Report.Error (1628, Location,
4197 "Cannot use ref or out parameter `{0}' inside an " +
4198 "anonymous method block", par.Name);
4202 if (!am.IsIterator && declared == referenced)
4205 // Don't capture aruments when the probing is on
4206 if (!ec.IsInProbingMode) {
4207 ScopeInfo scope = declared.CreateScopeInfo ();
4208 variable = scope.AddParameter (par, pi.Index);
4209 type = variable.Type;
4214 public override int GetHashCode ()
4216 return Name.GetHashCode ();
4219 public override bool Equals (object obj)
4221 ParameterReference pr = obj as ParameterReference;
4225 return Name == pr.Name && referenced == pr.referenced;
4228 public override Expression CreateExpressionTree (EmitContext ec)
4230 return Parameter.ExpressionTreeVariableReference ();
4234 // Notice that for ref/out parameters, the type exposed is not the
4235 // same type exposed externally.
4238 // externally we expose "int&"
4239 // here we expose "int".
4241 // We record this in "is_ref". This means that the type system can treat
4242 // the type as it is expected, but when we generate the code, we generate
4243 // the alternate kind of code.
4245 public override Expression DoResolve (EmitContext ec)
4247 if (!DoResolveBase (ec))
4250 if (is_out && ec.DoFlowAnalysis &&
4251 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4257 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4259 if (!DoResolveBase (ec))
4262 // HACK: parameters are not captured when probing is on
4263 if (!ec.IsInProbingMode)
4269 static public void EmitLdArg (ILGenerator ig, int x)
4273 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4274 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4275 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4276 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4277 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4280 ig.Emit (OpCodes.Ldarg, x);
4283 public override string ToString ()
4285 return "ParameterReference[" + Name + "]";
4290 /// Used for arguments to New(), Invocation()
4292 public class Argument {
4293 public enum AType : byte {
4300 public static readonly Argument[] Empty = new Argument [0];
4302 public readonly AType ArgType;
4303 public Expression Expr;
4305 public Argument (Expression expr, AType type)
4308 this.ArgType = type;
4311 public Argument (Expression expr)
4314 this.ArgType = AType.Expression;
4319 if (ArgType == AType.Ref || ArgType == AType.Out)
4320 return TypeManager.GetReferenceType (Expr.Type);
4326 public Parameter.Modifier Modifier
4331 return Parameter.Modifier.OUT;
4334 return Parameter.Modifier.REF;
4337 return Parameter.Modifier.NONE;
4342 public string GetSignatureForError ()
4344 if (Expr.eclass == ExprClass.MethodGroup)
4345 return Expr.ExprClassName;
4347 return Expr.GetSignatureForError ();
4350 public bool ResolveMethodGroup (EmitContext ec)
4352 SimpleName sn = Expr as SimpleName;
4354 Expr = sn.GetMethodGroup ();
4356 // FIXME: csc doesn't report any error if you try to use `ref' or
4357 // `out' in a delegate creation expression.
4358 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4365 public bool Resolve (EmitContext ec, Location loc)
4367 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4368 // Verify that the argument is readable
4369 if (ArgType != AType.Out)
4370 Expr = Expr.Resolve (ec);
4372 // Verify that the argument is writeable
4373 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4374 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4376 return Expr != null;
4380 public void Emit (EmitContext ec)
4382 if (ArgType != AType.Ref && ArgType != AType.Out) {
4387 AddressOp mode = AddressOp.Store;
4388 if (ArgType == AType.Ref)
4389 mode |= AddressOp.Load;
4391 IMemoryLocation ml = (IMemoryLocation) Expr;
4392 ParameterReference pr = ml as ParameterReference;
4395 // ParameterReferences might already be references, so we want
4396 // to pass just the value
4398 if (pr != null && pr.IsRef)
4401 ml.AddressOf (ec, mode);
4404 public Argument Clone (CloneContext clonectx)
4406 return new Argument (Expr.Clone (clonectx), ArgType);
4411 /// Invocation of methods or delegates.
4413 public class Invocation : ExpressionStatement {
4414 protected ArrayList Arguments;
4416 protected MethodGroupExpr mg;
4417 bool arguments_resolved;
4420 // arguments is an ArrayList, but we do not want to typecast,
4421 // as it might be null.
4423 public Invocation (Expression expr, ArrayList arguments)
4425 SimpleName sn = expr as SimpleName;
4427 this.expr = sn.GetMethodGroup ();
4431 Arguments = arguments;
4432 loc = expr.Location;
4435 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4436 : this (expr, arguments)
4438 this.arguments_resolved = arguments_resolved;
4441 public override Expression CreateExpressionTree (EmitContext ec)
4446 // Special conversion for nested expression trees
4448 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4449 args = new ArrayList (1);
4450 args.Add (new Argument (this));
4451 return CreateExpressionFactoryCall ("Quote", args);
4454 args = new ArrayList (Arguments.Count + 3);
4456 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4458 args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
4460 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4461 foreach (Argument a in Arguments) {
4462 Expression e = a.Expr.CreateExpressionTree (ec);
4464 args.Add (new Argument (e));
4467 return CreateExpressionFactoryCall ("Call", args);
4470 public override Expression DoResolve (EmitContext ec)
4472 // Don't resolve already resolved expression
4473 if (eclass != ExprClass.Invalid)
4476 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4477 if (expr_resolved == null)
4480 mg = expr_resolved as MethodGroupExpr;
4482 Type expr_type = expr_resolved.Type;
4484 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4485 return (new DelegateInvocation (
4486 expr_resolved, Arguments, loc)).Resolve (ec);
4489 MemberExpr me = expr_resolved as MemberExpr;
4491 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4495 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name);
4497 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4498 expr_resolved.GetSignatureForError ());
4502 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4506 // Next, evaluate all the expressions in the argument list
4508 if (Arguments != null && !arguments_resolved) {
4509 for (int i = 0; i < Arguments.Count; ++i)
4511 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4516 mg = DoResolveOverload (ec);
4520 MethodInfo method = (MethodInfo)mg;
4521 if (method != null) {
4522 type = TypeManager.TypeToCoreType (method.ReturnType);
4524 // TODO: this is a copy of mg.ResolveMemberAccess method
4525 Expression iexpr = mg.InstanceExpression;
4526 if (method.IsStatic) {
4527 if (iexpr == null ||
4528 iexpr is This || iexpr is EmptyExpression ||
4529 mg.IdenticalTypeName) {
4530 mg.InstanceExpression = null;
4532 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4538 if (type.IsPointer){
4546 // Only base will allow this invocation to happen.
4548 if (mg.IsBase && method.IsAbstract){
4549 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4553 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4555 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4557 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4561 if (IsSpecialMethodInvocation (method)) {
4565 if (mg.InstanceExpression != null)
4566 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4568 eclass = ExprClass.Value;
4572 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4574 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4577 bool IsSpecialMethodInvocation (MethodBase method)
4579 if (!TypeManager.IsSpecialMethod (method))
4582 Report.SymbolRelatedToPreviousError (method);
4583 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4584 TypeManager.CSharpSignature (method, true));
4590 /// Emits a list of resolved Arguments that are in the arguments
4593 /// The MethodBase argument might be null if the
4594 /// emission of the arguments is known not to contain
4595 /// a `params' field (for example in constructors or other routines
4596 /// that keep their arguments in this structure)
4598 /// if `dup_args' is true, a copy of the arguments will be left
4599 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4600 /// which will be duplicated before any other args. Only EmitCall
4601 /// should be using this interface.
4603 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4605 if (arguments == null)
4608 int top = arguments.Count;
4609 LocalTemporary [] temps = null;
4611 if (dup_args && top != 0)
4612 temps = new LocalTemporary [top];
4614 int argument_index = 0;
4616 for (int i = 0; i < top; i++) {
4617 a = (Argument) arguments [argument_index++];
4620 ec.ig.Emit (OpCodes.Dup);
4621 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4626 if (this_arg != null)
4629 for (int i = 0; i < top; i ++) {
4630 temps [i].Emit (ec);
4631 temps [i].Release (ec);
4636 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4638 ParameterData pd = TypeManager.GetParameterData (mb);
4640 if (arguments == null)
4641 return new Type [0];
4643 Argument a = (Argument) arguments [pd.Count - 1];
4644 Arglist list = (Arglist) a.Expr;
4646 return list.ArgumentTypes;
4650 /// This checks the ConditionalAttribute on the method
4652 public static bool IsMethodExcluded (MethodBase method)
4654 if (method.IsConstructor)
4657 method = TypeManager.DropGenericMethodArguments (method);
4658 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4659 IMethodData md = TypeManager.GetMethod (method);
4661 return md.IsExcluded ();
4663 // For some methods (generated by delegate class) GetMethod returns null
4664 // because they are not included in builder_to_method table
4668 return AttributeTester.IsConditionalMethodExcluded (method);
4672 /// is_base tells whether we want to force the use of the `call'
4673 /// opcode instead of using callvirt. Call is required to call
4674 /// a specific method, while callvirt will always use the most
4675 /// recent method in the vtable.
4677 /// is_static tells whether this is an invocation on a static method
4679 /// instance_expr is an expression that represents the instance
4680 /// it must be non-null if is_static is false.
4682 /// method is the method to invoke.
4684 /// Arguments is the list of arguments to pass to the method or constructor.
4686 public static void EmitCall (EmitContext ec, bool is_base,
4687 Expression instance_expr,
4688 MethodBase method, ArrayList Arguments, Location loc)
4690 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4693 // `dup_args' leaves an extra copy of the arguments on the stack
4694 // `omit_args' does not leave any arguments at all.
4695 // So, basically, you could make one call with `dup_args' set to true,
4696 // and then another with `omit_args' set to true, and the two calls
4697 // would have the same set of arguments. However, each argument would
4698 // only have been evaluated once.
4699 public static void EmitCall (EmitContext ec, bool is_base,
4700 Expression instance_expr,
4701 MethodBase method, ArrayList Arguments, Location loc,
4702 bool dup_args, bool omit_args)
4704 ILGenerator ig = ec.ig;
4705 bool struct_call = false;
4706 bool this_call = false;
4707 LocalTemporary this_arg = null;
4709 Type decl_type = method.DeclaringType;
4711 if (!ec.IsInObsoleteScope) {
4713 // This checks ObsoleteAttribute on the method and on the declaring type
4715 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4717 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4719 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4721 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4725 if (IsMethodExcluded (method))
4728 bool is_static = method.IsStatic;
4730 if (instance_expr == EmptyExpression.Null) {
4731 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4735 this_call = instance_expr is This;
4736 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4740 // If this is ourselves, push "this"
4744 Type iexpr_type = instance_expr.Type;
4747 // Push the instance expression
4749 if (TypeManager.IsValueType (iexpr_type)) {
4751 // Special case: calls to a function declared in a
4752 // reference-type with a value-type argument need
4753 // to have their value boxed.
4754 if (decl_type.IsValueType ||
4755 TypeManager.IsGenericParameter (iexpr_type)) {
4757 // If the expression implements IMemoryLocation, then
4758 // we can optimize and use AddressOf on the
4761 // If not we have to use some temporary storage for
4763 if (instance_expr is IMemoryLocation) {
4764 ((IMemoryLocation)instance_expr).
4765 AddressOf (ec, AddressOp.LoadStore);
4767 LocalTemporary temp = new LocalTemporary (iexpr_type);
4768 instance_expr.Emit (ec);
4770 temp.AddressOf (ec, AddressOp.Load);
4773 // avoid the overhead of doing this all the time.
4775 t = TypeManager.GetReferenceType (iexpr_type);
4777 instance_expr.Emit (ec);
4778 ig.Emit (OpCodes.Box, instance_expr.Type);
4779 t = TypeManager.object_type;
4782 instance_expr.Emit (ec);
4783 t = instance_expr.Type;
4787 ig.Emit (OpCodes.Dup);
4788 if (Arguments != null && Arguments.Count != 0) {
4789 this_arg = new LocalTemporary (t);
4790 this_arg.Store (ec);
4797 EmitArguments (ec, Arguments, dup_args, this_arg);
4800 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4801 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4805 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4806 call_op = OpCodes.Call;
4808 call_op = OpCodes.Callvirt;
4810 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4811 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4812 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4819 // and DoFoo is not virtual, you can omit the callvirt,
4820 // because you don't need the null checking behavior.
4822 if (method is MethodInfo)
4823 ig.Emit (call_op, (MethodInfo) method);
4825 ig.Emit (call_op, (ConstructorInfo) method);
4828 public override void Emit (EmitContext ec)
4830 mg.EmitCall (ec, Arguments);
4833 public override void EmitStatement (EmitContext ec)
4838 // Pop the return value if there is one
4840 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4841 ec.ig.Emit (OpCodes.Pop);
4844 protected override void CloneTo (CloneContext clonectx, Expression t)
4846 Invocation target = (Invocation) t;
4848 if (Arguments != null) {
4849 target.Arguments = new ArrayList (Arguments.Count);
4850 foreach (Argument a in Arguments)
4851 target.Arguments.Add (a.Clone (clonectx));
4854 target.expr = expr.Clone (clonectx);
4858 public class InvocationOrCast : ExpressionStatement
4861 Expression argument;
4863 public InvocationOrCast (Expression expr, Expression argument)
4866 this.argument = argument;
4867 this.loc = expr.Location;
4870 public override Expression DoResolve (EmitContext ec)
4873 // First try to resolve it as a cast.
4875 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4876 if ((te != null) && (te.eclass == ExprClass.Type)) {
4877 Cast cast = new Cast (te, argument, loc);
4878 return cast.Resolve (ec);
4882 // This can either be a type or a delegate invocation.
4883 // Let's just resolve it and see what we'll get.
4885 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4890 // Ok, so it's a Cast.
4892 if (expr.eclass == ExprClass.Type) {
4893 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4894 return cast.Resolve (ec);
4898 // It's a delegate invocation.
4900 if (!TypeManager.IsDelegateType (expr.Type)) {
4901 Error (149, "Method name expected");
4905 ArrayList args = new ArrayList ();
4906 args.Add (new Argument (argument, Argument.AType.Expression));
4907 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4908 return invocation.Resolve (ec);
4911 public override ExpressionStatement ResolveStatement (EmitContext ec)
4914 // First try to resolve it as a cast.
4916 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4917 if ((te != null) && (te.eclass == ExprClass.Type)) {
4918 Error_InvalidExpressionStatement ();
4923 // This can either be a type or a delegate invocation.
4924 // Let's just resolve it and see what we'll get.
4926 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4927 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4928 Error_InvalidExpressionStatement ();
4933 // It's a delegate invocation.
4935 if (!TypeManager.IsDelegateType (expr.Type)) {
4936 Error (149, "Method name expected");
4940 ArrayList args = new ArrayList ();
4941 args.Add (new Argument (argument, Argument.AType.Expression));
4942 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4943 return invocation.ResolveStatement (ec);
4946 public override void Emit (EmitContext ec)
4948 throw new Exception ("Cannot happen");
4951 public override void EmitStatement (EmitContext ec)
4953 throw new Exception ("Cannot happen");
4956 protected override void CloneTo (CloneContext clonectx, Expression t)
4958 InvocationOrCast target = (InvocationOrCast) t;
4960 target.expr = expr.Clone (clonectx);
4961 target.argument = argument.Clone (clonectx);
4966 // This class is used to "disable" the code generation for the
4967 // temporary variable when initializing value types.
4969 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4970 public void AddressOf (EmitContext ec, AddressOp Mode)
4977 /// Implements the new expression
4979 public class New : ExpressionStatement, IMemoryLocation {
4980 ArrayList Arguments;
4983 // During bootstrap, it contains the RequestedType,
4984 // but if `type' is not null, it *might* contain a NewDelegate
4985 // (because of field multi-initialization)
4987 public Expression RequestedType;
4989 MethodGroupExpr method;
4992 // If set, the new expression is for a value_target, and
4993 // we will not leave anything on the stack.
4995 protected Expression value_target;
4996 protected bool value_target_set;
4997 bool is_type_parameter = false;
4999 public New (Expression requested_type, ArrayList arguments, Location l)
5001 RequestedType = requested_type;
5002 Arguments = arguments;
5006 public bool SetTargetVariable (Expression value)
5008 value_target = value;
5009 value_target_set = true;
5010 if (!(value_target is IMemoryLocation)){
5011 Error_UnexpectedKind (null, "variable", loc);
5018 // This function is used to disable the following code sequence for
5019 // value type initialization:
5021 // AddressOf (temporary)
5025 // Instead the provide will have provided us with the address on the
5026 // stack to store the results.
5028 static Expression MyEmptyExpression;
5030 public void DisableTemporaryValueType ()
5032 if (MyEmptyExpression == null)
5033 MyEmptyExpression = new EmptyAddressOf ();
5036 // To enable this, look into:
5037 // test-34 and test-89 and self bootstrapping.
5039 // For instance, we can avoid a copy by using `newobj'
5040 // instead of Call + Push-temp on value types.
5041 // value_target = MyEmptyExpression;
5046 /// Converts complex core type syntax like 'new int ()' to simple constant
5048 public static Constant Constantify (Type t)
5050 if (t == TypeManager.int32_type)
5051 return new IntConstant (0, Location.Null);
5052 if (t == TypeManager.uint32_type)
5053 return new UIntConstant (0, Location.Null);
5054 if (t == TypeManager.int64_type)
5055 return new LongConstant (0, Location.Null);
5056 if (t == TypeManager.uint64_type)
5057 return new ULongConstant (0, Location.Null);
5058 if (t == TypeManager.float_type)
5059 return new FloatConstant (0, Location.Null);
5060 if (t == TypeManager.double_type)
5061 return new DoubleConstant (0, Location.Null);
5062 if (t == TypeManager.short_type)
5063 return new ShortConstant (0, Location.Null);
5064 if (t == TypeManager.ushort_type)
5065 return new UShortConstant (0, Location.Null);
5066 if (t == TypeManager.sbyte_type)
5067 return new SByteConstant (0, Location.Null);
5068 if (t == TypeManager.byte_type)
5069 return new ByteConstant (0, Location.Null);
5070 if (t == TypeManager.char_type)
5071 return new CharConstant ('\0', Location.Null);
5072 if (t == TypeManager.bool_type)
5073 return new BoolConstant (false, Location.Null);
5074 if (t == TypeManager.decimal_type)
5075 return new DecimalConstant (0, Location.Null);
5076 if (TypeManager.IsEnumType (t))
5077 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5083 // Checks whether the type is an interface that has the
5084 // [ComImport, CoClass] attributes and must be treated
5087 public Expression CheckComImport (EmitContext ec)
5089 if (!type.IsInterface)
5093 // Turn the call into:
5094 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5096 Type real_class = AttributeTester.GetCoClassAttribute (type);
5097 if (real_class == null)
5100 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5101 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5102 return cast.Resolve (ec);
5105 public override Expression DoResolve (EmitContext ec)
5108 // The New DoResolve might be called twice when initializing field
5109 // expressions (see EmitFieldInitializers, the call to
5110 // GetInitializerExpression will perform a resolve on the expression,
5111 // and later the assign will trigger another resolution
5113 // This leads to bugs (#37014)
5116 if (RequestedType is NewDelegate)
5117 return RequestedType;
5121 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5127 if (type == TypeManager.void_type) {
5128 Error_VoidInvalidInTheContext (loc);
5132 if (type.IsPointer) {
5133 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5134 TypeManager.CSharpName (type));
5138 if (Arguments == null) {
5139 Expression c = Constantify (type);
5144 if (TypeManager.IsDelegateType (type)) {
5145 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5146 if (RequestedType != null)
5147 if (!(RequestedType is DelegateCreation))
5148 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5149 return RequestedType;
5153 if (type.IsGenericParameter) {
5154 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5156 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5157 Error (304, String.Format (
5158 "Cannot create an instance of the " +
5159 "variable type '{0}' because it " +
5160 "doesn't have the new() constraint",
5165 if ((Arguments != null) && (Arguments.Count != 0)) {
5166 Error (417, String.Format (
5167 "`{0}': cannot provide arguments " +
5168 "when creating an instance of a " +
5169 "variable type.", type));
5173 if (TypeManager.activator_create_instance == null) {
5174 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5175 if (activator_type != null) {
5176 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5177 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5181 is_type_parameter = true;
5182 eclass = ExprClass.Value;
5187 if (type.IsAbstract && type.IsSealed) {
5188 Report.SymbolRelatedToPreviousError (type);
5189 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5193 if (type.IsInterface || type.IsAbstract){
5194 if (!TypeManager.IsGenericType (type)) {
5195 RequestedType = CheckComImport (ec);
5196 if (RequestedType != null)
5197 return RequestedType;
5200 Report.SymbolRelatedToPreviousError (type);
5201 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5205 bool is_struct = type.IsValueType;
5206 eclass = ExprClass.Value;
5209 // SRE returns a match for .ctor () on structs (the object constructor),
5210 // so we have to manually ignore it.
5212 if (is_struct && Arguments == null)
5215 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5216 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5217 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5219 if (Arguments != null){
5220 foreach (Argument a in Arguments){
5221 if (!a.Resolve (ec, loc))
5229 method = ml as MethodGroupExpr;
5230 if (method == null) {
5231 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5235 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5242 bool DoEmitTypeParameter (EmitContext ec)
5245 ILGenerator ig = ec.ig;
5246 // IMemoryLocation ml;
5248 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5249 new Type [] { type });
5251 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5252 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5253 ig.Emit (OpCodes.Call, ci);
5257 // Allow DoEmit() to be called multiple times.
5258 // We need to create a new LocalTemporary each time since
5259 // you can't share LocalBuilders among ILGeneators.
5260 LocalTemporary temp = new LocalTemporary (type);
5262 Label label_activator = ig.DefineLabel ();
5263 Label label_end = ig.DefineLabel ();
5265 temp.AddressOf (ec, AddressOp.Store);
5266 ig.Emit (OpCodes.Initobj, type);
5269 ig.Emit (OpCodes.Box, type);
5270 ig.Emit (OpCodes.Brfalse, label_activator);
5272 temp.AddressOf (ec, AddressOp.Store);
5273 ig.Emit (OpCodes.Initobj, type);
5275 ig.Emit (OpCodes.Br, label_end);
5277 ig.MarkLabel (label_activator);
5279 ig.Emit (OpCodes.Call, ci);
5280 ig.MarkLabel (label_end);
5283 throw new InternalErrorException ();
5288 // This DoEmit can be invoked in two contexts:
5289 // * As a mechanism that will leave a value on the stack (new object)
5290 // * As one that wont (init struct)
5292 // You can control whether a value is required on the stack by passing
5293 // need_value_on_stack. The code *might* leave a value on the stack
5294 // so it must be popped manually
5296 // If we are dealing with a ValueType, we have a few
5297 // situations to deal with:
5299 // * The target is a ValueType, and we have been provided
5300 // the instance (this is easy, we are being assigned).
5302 // * The target of New is being passed as an argument,
5303 // to a boxing operation or a function that takes a
5306 // In this case, we need to create a temporary variable
5307 // that is the argument of New.
5309 // Returns whether a value is left on the stack
5311 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5313 bool is_value_type = TypeManager.IsValueType (type);
5314 ILGenerator ig = ec.ig;
5319 // Allow DoEmit() to be called multiple times.
5320 // We need to create a new LocalTemporary each time since
5321 // you can't share LocalBuilders among ILGeneators.
5322 if (!value_target_set)
5323 value_target = new LocalTemporary (type);
5325 ml = (IMemoryLocation) value_target;
5326 ml.AddressOf (ec, AddressOp.Store);
5330 method.EmitArguments (ec, Arguments);
5334 ig.Emit (OpCodes.Initobj, type);
5336 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5337 if (need_value_on_stack){
5338 value_target.Emit (ec);
5343 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5348 public override void Emit (EmitContext ec)
5350 if (is_type_parameter)
5351 DoEmitTypeParameter (ec);
5356 public override void EmitStatement (EmitContext ec)
5358 bool value_on_stack;
5360 if (is_type_parameter)
5361 value_on_stack = DoEmitTypeParameter (ec);
5363 value_on_stack = DoEmit (ec, false);
5366 ec.ig.Emit (OpCodes.Pop);
5370 public virtual bool HasInitializer {
5376 public void AddressOf (EmitContext ec, AddressOp Mode)
5378 if (is_type_parameter) {
5379 LocalTemporary temp = new LocalTemporary (type);
5380 DoEmitTypeParameter (ec);
5382 temp.AddressOf (ec, Mode);
5386 if (!type.IsValueType){
5388 // We throw an exception. So far, I believe we only need to support
5390 // foreach (int j in new StructType ())
5393 throw new Exception ("AddressOf should not be used for classes");
5396 if (!value_target_set)
5397 value_target = new LocalTemporary (type);
5398 IMemoryLocation ml = (IMemoryLocation) value_target;
5400 ml.AddressOf (ec, AddressOp.Store);
5401 if (method == null) {
5402 ec.ig.Emit (OpCodes.Initobj, type);
5404 method.EmitArguments (ec, Arguments);
5405 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5408 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5411 protected override void CloneTo (CloneContext clonectx, Expression t)
5413 New target = (New) t;
5415 target.RequestedType = RequestedType.Clone (clonectx);
5416 if (Arguments != null){
5417 target.Arguments = new ArrayList ();
5418 foreach (Argument a in Arguments){
5419 target.Arguments.Add (a.Clone (clonectx));
5426 /// 14.5.10.2: Represents an array creation expression.
5430 /// There are two possible scenarios here: one is an array creation
5431 /// expression that specifies the dimensions and optionally the
5432 /// initialization data and the other which does not need dimensions
5433 /// specified but where initialization data is mandatory.
5435 public class ArrayCreation : Expression {
5436 Expression requested_base_type;
5437 ArrayList initializers;
5440 // The list of Argument types.
5441 // This is used to construct the `newarray' or constructor signature
5443 protected ArrayList arguments;
5445 protected Type array_element_type;
5446 bool expect_initializers = false;
5447 int num_arguments = 0;
5448 protected int dimensions;
5449 protected readonly string rank;
5451 protected ArrayList array_data;
5455 // The number of constants in array initializers
5456 int const_initializers_count;
5457 bool only_constant_initializers;
5459 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5461 this.requested_base_type = requested_base_type;
5462 this.initializers = initializers;
5466 arguments = new ArrayList ();
5468 foreach (Expression e in exprs) {
5469 arguments.Add (new Argument (e, Argument.AType.Expression));
5474 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5476 this.requested_base_type = requested_base_type;
5477 this.initializers = initializers;
5481 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5483 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5485 //dimensions = tmp.Length - 1;
5486 expect_initializers = true;
5489 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5491 StringBuilder sb = new StringBuilder (rank);
5494 for (int i = 1; i < idx_count; i++)
5499 return new ComposedCast (base_type, sb.ToString (), loc);
5502 void Error_IncorrectArrayInitializer ()
5504 Error (178, "Invalid rank specifier: expected `,' or `]'");
5507 protected override void Error_NegativeArrayIndex (Location loc)
5509 Report.Error (248, loc, "Cannot create an array with a negative size");
5512 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5514 if (specified_dims) {
5515 Argument a = (Argument) arguments [idx];
5517 if (!a.Resolve (ec, loc))
5520 Constant c = a.Expr as Constant;
5522 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5526 Report.Error (150, a.Expr.Location, "A constant value is expected");
5530 int value = (int) c.GetValue ();
5532 if (value != probe.Count) {
5533 Error_IncorrectArrayInitializer ();
5537 bounds [idx] = value;
5540 int child_bounds = -1;
5541 only_constant_initializers = true;
5542 for (int i = 0; i < probe.Count; ++i) {
5543 object o = probe [i];
5544 if (o is ArrayList) {
5545 ArrayList sub_probe = o as ArrayList;
5546 int current_bounds = sub_probe.Count;
5548 if (child_bounds == -1)
5549 child_bounds = current_bounds;
5551 else if (child_bounds != current_bounds){
5552 Error_IncorrectArrayInitializer ();
5555 if (idx + 1 >= dimensions){
5556 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5560 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5564 if (child_bounds != -1){
5565 Error_IncorrectArrayInitializer ();
5569 Expression element = ResolveArrayElement (ec, (Expression) o);
5570 if (element == null)
5573 // Initializers with the default values can be ignored
5574 Constant c = element as Constant;
5576 if (c.IsDefaultInitializer (array_element_type)) {
5580 ++const_initializers_count;
5583 only_constant_initializers = false;
5586 array_data.Add (element);
5593 public override Expression CreateExpressionTree (EmitContext ec)
5595 if (dimensions != 1) {
5596 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5600 ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5601 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5602 if (array_data != null) {
5603 foreach (Expression e in array_data)
5604 args.Add (new Argument (e.CreateExpressionTree (ec)));
5607 return CreateExpressionFactoryCall ("NewArrayInit", args);
5610 public void UpdateIndices ()
5613 for (ArrayList probe = initializers; probe != null;) {
5614 if (probe.Count > 0 && probe [0] is ArrayList) {
5615 Expression e = new IntConstant (probe.Count, Location.Null);
5616 arguments.Add (new Argument (e, Argument.AType.Expression));
5618 bounds [i++] = probe.Count;
5620 probe = (ArrayList) probe [0];
5623 Expression e = new IntConstant (probe.Count, Location.Null);
5624 arguments.Add (new Argument (e, Argument.AType.Expression));
5626 bounds [i++] = probe.Count;
5633 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5635 element = element.Resolve (ec);
5636 if (element == null)
5639 return Convert.ImplicitConversionRequired (
5640 ec, element, array_element_type, loc);
5643 protected bool ResolveInitializers (EmitContext ec)
5645 if (initializers == null) {
5646 return !expect_initializers;
5650 // We use this to store all the date values in the order in which we
5651 // will need to store them in the byte blob later
5653 array_data = new ArrayList ();
5654 bounds = new System.Collections.Specialized.HybridDictionary ();
5656 if (arguments != null)
5657 return CheckIndices (ec, initializers, 0, true);
5659 arguments = new ArrayList ();
5661 if (!CheckIndices (ec, initializers, 0, false))
5670 // Resolved the type of the array
5672 bool ResolveArrayType (EmitContext ec)
5674 if (requested_base_type == null) {
5675 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5679 StringBuilder array_qualifier = new StringBuilder (rank);
5682 // `In the first form allocates an array instace of the type that results
5683 // from deleting each of the individual expression from the expression list'
5685 if (num_arguments > 0) {
5686 array_qualifier.Append ("[");
5687 for (int i = num_arguments-1; i > 0; i--)
5688 array_qualifier.Append (",");
5689 array_qualifier.Append ("]");
5695 TypeExpr array_type_expr;
5696 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5697 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5698 if (array_type_expr == null)
5701 type = array_type_expr.Type;
5702 array_element_type = TypeManager.GetElementType (type);
5703 dimensions = type.GetArrayRank ();
5708 public override Expression DoResolve (EmitContext ec)
5713 if (!ResolveArrayType (ec))
5716 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5717 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5718 TypeManager.CSharpName (array_element_type));
5722 // First step is to validate the initializers and fill
5723 // in any missing bits
5725 if (!ResolveInitializers (ec))
5728 if (arguments.Count != dimensions) {
5729 Error_IncorrectArrayInitializer ();
5732 foreach (Argument a in arguments){
5733 if (!a.Resolve (ec, loc))
5736 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5739 eclass = ExprClass.Value;
5743 MethodInfo GetArrayMethod (int arguments)
5745 ModuleBuilder mb = CodeGen.Module.Builder;
5747 Type[] arg_types = new Type[arguments];
5748 for (int i = 0; i < arguments; i++)
5749 arg_types[i] = TypeManager.int32_type;
5751 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5755 Report.Error (-6, "New invocation: Can not find a constructor for " +
5756 "this argument list");
5763 byte [] MakeByteBlob ()
5768 int count = array_data.Count;
5770 if (TypeManager.IsEnumType (array_element_type))
5771 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
5773 factor = GetTypeSize (array_element_type);
5775 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5777 data = new byte [(count * factor + 3) & ~3];
5780 for (int i = 0; i < count; ++i) {
5781 object v = array_data [i];
5783 if (v is EnumConstant)
5784 v = ((EnumConstant) v).Child;
5786 if (v is Constant && !(v is StringConstant))
5787 v = ((Constant) v).GetValue ();
5793 if (array_element_type == TypeManager.int64_type){
5794 if (!(v is Expression)){
5795 long val = (long) v;
5797 for (int j = 0; j < factor; ++j) {
5798 data [idx + j] = (byte) (val & 0xFF);
5802 } else if (array_element_type == TypeManager.uint64_type){
5803 if (!(v is Expression)){
5804 ulong val = (ulong) v;
5806 for (int j = 0; j < factor; ++j) {
5807 data [idx + j] = (byte) (val & 0xFF);
5811 } else if (array_element_type == TypeManager.float_type) {
5812 if (!(v is Expression)){
5813 element = BitConverter.GetBytes ((float) v);
5815 for (int j = 0; j < factor; ++j)
5816 data [idx + j] = element [j];
5817 if (!BitConverter.IsLittleEndian)
5818 System.Array.Reverse (data, idx, 4);
5820 } else if (array_element_type == TypeManager.double_type) {
5821 if (!(v is Expression)){
5822 element = BitConverter.GetBytes ((double) v);
5824 for (int j = 0; j < factor; ++j)
5825 data [idx + j] = element [j];
5827 // FIXME: Handle the ARM float format.
5828 if (!BitConverter.IsLittleEndian)
5829 System.Array.Reverse (data, idx, 8);
5831 } else if (array_element_type == TypeManager.char_type){
5832 if (!(v is Expression)){
5833 int val = (int) ((char) v);
5835 data [idx] = (byte) (val & 0xff);
5836 data [idx+1] = (byte) (val >> 8);
5838 } else if (array_element_type == TypeManager.short_type){
5839 if (!(v is Expression)){
5840 int val = (int) ((short) v);
5842 data [idx] = (byte) (val & 0xff);
5843 data [idx+1] = (byte) (val >> 8);
5845 } else if (array_element_type == TypeManager.ushort_type){
5846 if (!(v is Expression)){
5847 int val = (int) ((ushort) v);
5849 data [idx] = (byte) (val & 0xff);
5850 data [idx+1] = (byte) (val >> 8);
5852 } else if (array_element_type == TypeManager.int32_type) {
5853 if (!(v is Expression)){
5856 data [idx] = (byte) (val & 0xff);
5857 data [idx+1] = (byte) ((val >> 8) & 0xff);
5858 data [idx+2] = (byte) ((val >> 16) & 0xff);
5859 data [idx+3] = (byte) (val >> 24);
5861 } else if (array_element_type == TypeManager.uint32_type) {
5862 if (!(v is Expression)){
5863 uint val = (uint) v;
5865 data [idx] = (byte) (val & 0xff);
5866 data [idx+1] = (byte) ((val >> 8) & 0xff);
5867 data [idx+2] = (byte) ((val >> 16) & 0xff);
5868 data [idx+3] = (byte) (val >> 24);
5870 } else if (array_element_type == TypeManager.sbyte_type) {
5871 if (!(v is Expression)){
5872 sbyte val = (sbyte) v;
5873 data [idx] = (byte) val;
5875 } else if (array_element_type == TypeManager.byte_type) {
5876 if (!(v is Expression)){
5877 byte val = (byte) v;
5878 data [idx] = (byte) val;
5880 } else if (array_element_type == TypeManager.bool_type) {
5881 if (!(v is Expression)){
5882 bool val = (bool) v;
5883 data [idx] = (byte) (val ? 1 : 0);
5885 } else if (array_element_type == TypeManager.decimal_type){
5886 if (!(v is Expression)){
5887 int [] bits = Decimal.GetBits ((decimal) v);
5890 // FIXME: For some reason, this doesn't work on the MS runtime.
5891 int [] nbits = new int [4];
5892 nbits [0] = bits [3];
5893 nbits [1] = bits [2];
5894 nbits [2] = bits [0];
5895 nbits [3] = bits [1];
5897 for (int j = 0; j < 4; j++){
5898 data [p++] = (byte) (nbits [j] & 0xff);
5899 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5900 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5901 data [p++] = (byte) (nbits [j] >> 24);
5905 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5914 // Emits the initializers for the array
5916 void EmitStaticInitializers (EmitContext ec)
5918 // FIXME: This should go to Resolve !
5919 if (TypeManager.void_initializearray_array_fieldhandle == null) {
5920 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
5921 TypeManager.runtime_helpers_type, "InitializeArray", loc,
5922 TypeManager.array_type, TypeManager.runtime_field_handle_type);
5923 if (TypeManager.void_initializearray_array_fieldhandle == null)
5928 // First, the static data
5931 ILGenerator ig = ec.ig;
5933 byte [] data = MakeByteBlob ();
5935 fb = RootContext.MakeStaticData (data);
5937 ig.Emit (OpCodes.Dup);
5938 ig.Emit (OpCodes.Ldtoken, fb);
5939 ig.Emit (OpCodes.Call,
5940 TypeManager.void_initializearray_array_fieldhandle);
5944 // Emits pieces of the array that can not be computed at compile
5945 // time (variables and string locations).
5947 // This always expect the top value on the stack to be the array
5949 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5951 ILGenerator ig = ec.ig;
5952 int dims = bounds.Count;
5953 int [] current_pos = new int [dims];
5955 MethodInfo set = null;
5958 Type [] args = new Type [dims + 1];
5960 for (int j = 0; j < dims; j++)
5961 args [j] = TypeManager.int32_type;
5962 args [dims] = array_element_type;
5964 set = CodeGen.Module.Builder.GetArrayMethod (
5966 CallingConventions.HasThis | CallingConventions.Standard,
5967 TypeManager.void_type, args);
5970 for (int i = 0; i < array_data.Count; i++){
5972 Expression e = (Expression)array_data [i];
5974 // Constant can be initialized via StaticInitializer
5975 if (e != null && !(!emitConstants && e is Constant)) {
5976 Type etype = e.Type;
5978 ig.Emit (OpCodes.Dup);
5980 for (int idx = 0; idx < dims; idx++)
5981 IntConstant.EmitInt (ig, current_pos [idx]);
5984 // If we are dealing with a struct, get the
5985 // address of it, so we can store it.
5987 if ((dims == 1) && etype.IsValueType &&
5988 (!TypeManager.IsBuiltinOrEnum (etype) ||
5989 etype == TypeManager.decimal_type)) {
5994 // Let new know that we are providing
5995 // the address where to store the results
5997 n.DisableTemporaryValueType ();
6000 ig.Emit (OpCodes.Ldelema, etype);
6006 bool is_stobj, has_type_arg;
6007 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6009 ig.Emit (OpCodes.Stobj, etype);
6010 else if (has_type_arg)
6011 ig.Emit (op, etype);
6015 ig.Emit (OpCodes.Call, set);
6022 for (int j = dims - 1; j >= 0; j--){
6024 if (current_pos [j] < (int) bounds [j])
6026 current_pos [j] = 0;
6031 public override void Emit (EmitContext ec)
6033 ILGenerator ig = ec.ig;
6035 foreach (Argument a in arguments)
6038 if (arguments.Count == 1)
6039 ig.Emit (OpCodes.Newarr, array_element_type);
6041 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6044 if (initializers == null)
6047 // Emit static initializer for arrays which have contain more than 4 items and
6048 // the static initializer will initialize at least 25% of array values.
6049 // NOTE: const_initializers_count does not contain default constant values.
6050 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6051 TypeManager.IsPrimitiveType (array_element_type)) {
6052 EmitStaticInitializers (ec);
6054 if (!only_constant_initializers)
6055 EmitDynamicInitializers (ec, false);
6057 EmitDynamicInitializers (ec, true);
6061 public override bool GetAttributableValue (Type value_type, out object value)
6063 if (arguments.Count != 1) {
6064 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6065 return base.GetAttributableValue (null, out value);
6068 if (array_data == null) {
6069 Constant c = (Constant)((Argument)arguments [0]).Expr;
6070 if (c.IsDefaultValue) {
6071 value = Array.CreateInstance (array_element_type, 0);
6074 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6075 return base.GetAttributableValue (null, out value);
6078 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6079 object element_value;
6080 for (int i = 0; i < ret.Length; ++i)
6082 Expression e = (Expression)array_data [i];
6084 // Is null when an initializer is optimized (value == predefined value)
6088 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6092 ret.SetValue (element_value, i);
6098 protected override void CloneTo (CloneContext clonectx, Expression t)
6100 ArrayCreation target = (ArrayCreation) t;
6102 if (requested_base_type != null)
6103 target.requested_base_type = requested_base_type.Clone (clonectx);
6105 if (arguments != null){
6106 target.arguments = new ArrayList (arguments.Count);
6107 foreach (Argument a in arguments)
6108 target.arguments.Add (a.Clone (clonectx));
6111 if (initializers != null){
6112 target.initializers = new ArrayList (initializers.Count);
6113 foreach (object initializer in initializers)
6114 if (initializer is ArrayList) {
6115 ArrayList this_al = (ArrayList)initializer;
6116 ArrayList al = new ArrayList (this_al.Count);
6117 target.initializers.Add (al);
6118 foreach (Expression e in this_al)
6119 al.Add (e.Clone (clonectx));
6121 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6128 // Represents an implicitly typed array epxression
6130 public class ImplicitlyTypedArrayCreation : ArrayCreation
6132 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6133 : base (null, rank, initializers, loc)
6135 if (RootContext.Version <= LanguageVersion.ISO_2)
6136 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6138 if (rank.Length > 2) {
6139 while (rank [++dimensions] == ',');
6145 public override Expression DoResolve (EmitContext ec)
6150 if (!ResolveInitializers (ec))
6153 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6154 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6155 arguments.Count != dimensions) {
6156 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6161 // At this point we found common base type for all initializer elements
6162 // but we have to be sure that all static initializer elements are of
6165 UnifyInitializerElement (ec);
6167 type = TypeManager.GetConstructedType (array_element_type, rank);
6168 eclass = ExprClass.Value;
6173 // Converts static initializer only
6175 void UnifyInitializerElement (EmitContext ec)
6177 for (int i = 0; i < array_data.Count; ++i) {
6178 Expression e = (Expression)array_data[i];
6180 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6184 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6186 element = element.Resolve (ec);
6187 if (element == null)
6190 if (array_element_type == null) {
6191 array_element_type = element.Type;
6195 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6199 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6200 array_element_type = element.Type;
6204 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6209 public sealed class CompilerGeneratedThis : This
6211 public static This Instance = new CompilerGeneratedThis ();
6213 private CompilerGeneratedThis ()
6214 : base (Location.Null)
6218 public override Expression DoResolve (EmitContext ec)
6220 eclass = ExprClass.Variable;
6221 type = ec.ContainerType;
6222 variable = new SimpleThis (type);
6228 /// Represents the `this' construct
6231 public class This : VariableReference, IVariable
6234 VariableInfo variable_info;
6235 protected Variable variable;
6238 public This (Block block, Location loc)
6244 public This (Location loc)
6249 public VariableInfo VariableInfo {
6250 get { return variable_info; }
6253 public bool VerifyFixed ()
6255 return !TypeManager.IsValueType (Type);
6258 public override bool IsRef {
6259 get { return is_struct; }
6262 public override Variable Variable {
6263 get { return variable; }
6266 public bool ResolveBase (EmitContext ec)
6268 eclass = ExprClass.Variable;
6270 if (ec.TypeContainer.CurrentType != null)
6271 type = ec.TypeContainer.CurrentType;
6273 type = ec.ContainerType;
6275 is_struct = ec.TypeContainer is Struct;
6278 Error (26, "Keyword `this' is not valid in a static property, " +
6279 "static method, or static field initializer");
6283 if (block != null) {
6284 if (block.Toplevel.ThisVariable != null)
6285 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6287 AnonymousContainer am = ec.CurrentAnonymousMethod;
6288 if (is_struct && (am != null) && !am.IsIterator) {
6289 Report.Error (1673, loc, "Anonymous methods inside structs " +
6290 "cannot access instance members of `this'. " +
6291 "Consider copying `this' to a local variable " +
6292 "outside the anonymous method and using the " +
6296 RootScopeInfo host = block.Toplevel.RootScope;
6297 if ((host != null) && !ec.IsConstructor &&
6298 (!is_struct || host.IsIterator)) {
6299 variable = host.CaptureThis ();
6300 type = variable.Type;
6305 if (variable == null)
6306 variable = new SimpleThis (type);
6312 // Called from Invocation to check if the invocation is correct
6314 public override void CheckMarshalByRefAccess (EmitContext ec)
6316 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6317 !variable_info.IsAssigned (ec)) {
6318 Error (188, "The `this' object cannot be used before all of its " +
6319 "fields are assigned to");
6320 variable_info.SetAssigned (ec);
6324 public override Expression CreateExpressionTree (EmitContext ec)
6326 ArrayList args = new ArrayList (2);
6327 args.Add (new Argument (this));
6328 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6329 return CreateExpressionFactoryCall ("Constant", args);
6332 public override Expression DoResolve (EmitContext ec)
6334 if (!ResolveBase (ec))
6338 if (ec.IsInFieldInitializer) {
6339 Error (27, "Keyword `this' is not available in the current context");
6346 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6348 if (!ResolveBase (ec))
6351 if (variable_info != null)
6352 variable_info.SetAssigned (ec);
6354 if (ec.TypeContainer is Class){
6355 Error (1604, "Cannot assign to 'this' because it is read-only");
6361 public override int GetHashCode()
6363 return block.GetHashCode ();
6366 public override bool Equals (object obj)
6368 This t = obj as This;
6372 return block == t.block;
6375 protected class SimpleThis : Variable
6379 public SimpleThis (Type type)
6384 public override Type Type {
6385 get { return type; }
6388 public override bool HasInstance {
6389 get { return false; }
6392 public override bool NeedsTemporary {
6393 get { return false; }
6396 public override void EmitInstance (EmitContext ec)
6401 public override void Emit (EmitContext ec)
6403 ec.ig.Emit (OpCodes.Ldarg_0);
6406 public override void EmitAssign (EmitContext ec)
6408 throw new InvalidOperationException ();
6411 public override void EmitAddressOf (EmitContext ec)
6413 ec.ig.Emit (OpCodes.Ldarg_0);
6417 protected override void CloneTo (CloneContext clonectx, Expression t)
6419 This target = (This) t;
6421 target.block = clonectx.LookupBlock (block);
6426 /// Represents the `__arglist' construct
6428 public class ArglistAccess : Expression
6430 public ArglistAccess (Location loc)
6435 public override Expression DoResolve (EmitContext ec)
6437 eclass = ExprClass.Variable;
6438 type = TypeManager.runtime_argument_handle_type;
6440 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6442 Error (190, "The __arglist construct is valid only within " +
6443 "a variable argument method");
6450 public override void Emit (EmitContext ec)
6452 ec.ig.Emit (OpCodes.Arglist);
6455 protected override void CloneTo (CloneContext clonectx, Expression target)
6462 /// Represents the `__arglist (....)' construct
6464 public class Arglist : Expression
6466 Argument[] Arguments;
6468 public Arglist (Location loc)
6469 : this (Argument.Empty, loc)
6473 public Arglist (Argument[] args, Location l)
6479 public Type[] ArgumentTypes {
6481 Type[] retval = new Type [Arguments.Length];
6482 for (int i = 0; i < Arguments.Length; i++)
6483 retval [i] = Arguments [i].Type;
6488 public override Expression CreateExpressionTree (EmitContext ec)
6490 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6494 public override Expression DoResolve (EmitContext ec)
6496 eclass = ExprClass.Variable;
6497 type = TypeManager.runtime_argument_handle_type;
6499 foreach (Argument arg in Arguments) {
6500 if (!arg.Resolve (ec, loc))
6507 public override void Emit (EmitContext ec)
6509 foreach (Argument arg in Arguments)
6513 protected override void CloneTo (CloneContext clonectx, Expression t)
6515 Arglist target = (Arglist) t;
6517 target.Arguments = new Argument [Arguments.Length];
6518 for (int i = 0; i < Arguments.Length; i++)
6519 target.Arguments [i] = Arguments [i].Clone (clonectx);
6524 // This produces the value that renders an instance, used by the iterators code
6526 public class ProxyInstance : Expression, IMemoryLocation {
6527 public override Expression DoResolve (EmitContext ec)
6529 eclass = ExprClass.Variable;
6530 type = ec.ContainerType;
6534 public override void Emit (EmitContext ec)
6536 ec.ig.Emit (OpCodes.Ldarg_0);
6540 public void AddressOf (EmitContext ec, AddressOp mode)
6542 ec.ig.Emit (OpCodes.Ldarg_0);
6547 /// Implements the typeof operator
6549 public class TypeOf : Expression {
6550 Expression QueriedType;
6551 protected Type typearg;
6553 public TypeOf (Expression queried_type, Location l)
6555 QueriedType = queried_type;
6559 public override Expression DoResolve (EmitContext ec)
6561 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6565 typearg = texpr.Type;
6567 if (typearg == TypeManager.void_type) {
6568 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6572 if (typearg.IsPointer && !ec.InUnsafe){
6577 type = TypeManager.type_type;
6579 return DoResolveBase ();
6582 protected Expression DoResolveBase ()
6584 if (TypeManager.system_type_get_type_from_handle == null) {
6585 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6586 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6589 // Even though what is returned is a type object, it's treated as a value by the compiler.
6590 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6591 eclass = ExprClass.Value;
6595 public override void Emit (EmitContext ec)
6597 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6598 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6601 public override bool GetAttributableValue (Type value_type, out object value)
6603 if (TypeManager.ContainsGenericParameters (typearg) &&
6604 !TypeManager.IsGenericTypeDefinition (typearg)) {
6605 Report.SymbolRelatedToPreviousError (typearg);
6606 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6607 TypeManager.CSharpName (typearg));
6612 if (value_type == TypeManager.object_type) {
6613 value = (object)typearg;
6620 public Type TypeArgument
6628 protected override void CloneTo (CloneContext clonectx, Expression t)
6630 TypeOf target = (TypeOf) t;
6632 target.QueriedType = QueriedType.Clone (clonectx);
6637 /// Implements the `typeof (void)' operator
6639 public class TypeOfVoid : TypeOf {
6640 public TypeOfVoid (Location l) : base (null, l)
6645 public override Expression DoResolve (EmitContext ec)
6647 type = TypeManager.type_type;
6648 typearg = TypeManager.void_type;
6650 return DoResolveBase ();
6654 internal class TypeOfMethod : Expression
6656 readonly MethodInfo method;
6658 public TypeOfMethod (MethodInfo method, Location loc)
6660 this.method = method;
6664 public override Expression DoResolve (EmitContext ec)
6666 if (TypeManager.methodbase_get_type_from_handle == null) {
6667 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
6668 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
6670 if (t != null && handle_type != null)
6671 TypeManager.methodbase_get_type_from_handle = TypeManager.GetPredefinedMethod (t,
6672 "GetMethodFromHandle", loc, handle_type);
6675 type = typeof (MethodBase);
6676 eclass = ExprClass.Value;
6680 public override void Emit (EmitContext ec)
6682 ec.ig.Emit (OpCodes.Ldtoken, method);
6683 ec.ig.Emit (OpCodes.Call, TypeManager.methodbase_get_type_from_handle);
6688 /// Implements the sizeof expression
6690 public class SizeOf : Expression {
6691 readonly Expression QueriedType;
6694 public SizeOf (Expression queried_type, Location l)
6696 this.QueriedType = queried_type;
6700 public override Expression DoResolve (EmitContext ec)
6702 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6707 if (texpr is TypeParameterExpr){
6708 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6713 type_queried = texpr.Type;
6714 if (TypeManager.IsEnumType (type_queried))
6715 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
6717 if (type_queried == TypeManager.void_type) {
6718 Expression.Error_VoidInvalidInTheContext (loc);
6722 int size_of = GetTypeSize (type_queried);
6724 return new IntConstant (size_of, loc);
6728 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)",
6729 TypeManager.CSharpName (type_queried));
6733 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6737 type = TypeManager.int32_type;
6738 eclass = ExprClass.Value;
6742 public override void Emit (EmitContext ec)
6744 int size = GetTypeSize (type_queried);
6747 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6749 IntConstant.EmitInt (ec.ig, size);
6752 protected override void CloneTo (CloneContext clonectx, Expression t)
6758 /// Implements the qualified-alias-member (::) expression.
6760 public class QualifiedAliasMember : Expression
6762 string alias, identifier;
6764 public QualifiedAliasMember (string alias, string identifier, Location l)
6767 this.identifier = identifier;
6771 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6773 if (alias == "global")
6774 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6776 int errors = Report.Errors;
6777 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6779 if (errors == Report.Errors)
6780 Report.Error (432, loc, "Alias `{0}' not found", alias);
6783 if (fne.eclass != ExprClass.Namespace) {
6785 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6788 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6791 public override Expression DoResolve (EmitContext ec)
6793 FullNamedExpression fne;
6794 if (alias == "global") {
6795 fne = RootNamespace.Global;
6797 int errors = Report.Errors;
6798 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6800 if (errors == Report.Errors)
6801 Report.Error (432, loc, "Alias `{0}' not found", alias);
6806 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6810 if (!(retval is FullNamedExpression)) {
6811 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6815 // We defer this check till the end to match the behaviour of CSC
6816 if (fne.eclass != ExprClass.Namespace) {
6817 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6823 public override void Emit (EmitContext ec)
6825 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6829 public override string ToString ()
6831 return alias + "::" + identifier;
6834 public override string GetSignatureForError ()
6839 protected override void CloneTo (CloneContext clonectx, Expression t)
6846 /// Implements the member access expression
6848 public class MemberAccess : Expression {
6849 public readonly string Identifier;
6851 readonly TypeArguments args;
6853 public MemberAccess (Expression expr, string id)
6854 : this (expr, id, expr.Location)
6858 public MemberAccess (Expression expr, string identifier, Location loc)
6861 Identifier = identifier;
6865 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6866 : this (expr, identifier, loc)
6871 protected string LookupIdentifier {
6872 get { return MemberName.MakeName (Identifier, args); }
6875 // TODO: this method has very poor performace for Enum fields and
6876 // probably for other constants as well
6877 Expression DoResolve (EmitContext ec, Expression right_side)
6880 throw new Exception ();
6883 // Resolve the expression with flow analysis turned off, we'll do the definite
6884 // assignment checks later. This is because we don't know yet what the expression
6885 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6886 // definite assignment check on the actual field and not on the whole struct.
6889 SimpleName original = expr as SimpleName;
6890 Expression expr_resolved = expr.Resolve (ec,
6891 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6892 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6894 if (expr_resolved == null)
6897 if (expr_resolved is Namespace) {
6898 Namespace ns = (Namespace) expr_resolved;
6899 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6901 if ((retval != null) && (args != null))
6902 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6906 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6910 Type expr_type = expr_resolved.Type;
6911 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6912 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6915 if (expr_type == TypeManager.anonymous_method_type){
6916 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6920 Constant c = expr_resolved as Constant;
6921 if (c != null && c.GetValue () == null) {
6922 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6923 "System.NullReferenceException");
6927 if (!args.Resolve (ec))
6931 Expression member_lookup;
6932 member_lookup = MemberLookup (
6933 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6935 if ((member_lookup == null) && (args != null)) {
6936 member_lookup = MemberLookup (
6937 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6940 if (member_lookup == null) {
6941 ExprClass expr_eclass = expr_resolved.eclass;
6944 // Extension methods are not allowed on all expression types
6946 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
6947 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
6948 expr_eclass == ExprClass.EventAccess) {
6949 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
6950 if (ex_method_lookup != null) {
6951 ex_method_lookup.ExtensionExpression = expr_resolved;
6954 ex_method_lookup.SetTypeArguments (args);
6957 return ex_method_lookup.DoResolve (ec);
6961 expr = expr_resolved;
6962 Error_MemberLookupFailed (
6963 ec.ContainerType, expr_type, expr_type, Identifier, null,
6964 AllMemberTypes, AllBindingFlags);
6968 TypeExpr texpr = member_lookup as TypeExpr;
6969 if (texpr != null) {
6970 if (!(expr_resolved is TypeExpr) &&
6971 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6972 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6973 Identifier, member_lookup.GetSignatureForError ());
6977 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6978 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6979 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6984 ConstructedType ct = expr_resolved as ConstructedType;
6987 // When looking up a nested type in a generic instance
6988 // via reflection, we always get a generic type definition
6989 // and not a generic instance - so we have to do this here.
6991 // See gtest-172-lib.cs and gtest-172.cs for an example.
6993 ct = new ConstructedType (
6994 member_lookup.Type, ct.TypeArguments, loc);
6996 return ct.ResolveAsTypeStep (ec, false);
6999 return member_lookup;
7002 MemberExpr me = (MemberExpr) member_lookup;
7003 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7008 me.SetTypeArguments (args);
7011 if (original != null && !TypeManager.IsValueType (expr_type)) {
7012 if (me.IsInstance) {
7013 LocalVariableReference var = expr_resolved as LocalVariableReference;
7014 if (var != null && !var.VerifyAssigned (ec))
7019 // The following DoResolve/DoResolveLValue will do the definite assignment
7022 if (right_side != null)
7023 return me.DoResolveLValue (ec, right_side);
7025 return me.DoResolve (ec);
7028 public override Expression DoResolve (EmitContext ec)
7030 return DoResolve (ec, null);
7033 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7035 return DoResolve (ec, right_side);
7038 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7040 return ResolveNamespaceOrType (ec, silent);
7043 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7045 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7047 if (new_expr == null)
7050 if (new_expr is Namespace) {
7051 Namespace ns = (Namespace) new_expr;
7052 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7054 if ((retval != null) && (args != null))
7055 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
7057 if (!silent && retval == null)
7058 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7062 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7063 if (tnew_expr == null)
7066 Type expr_type = tnew_expr.Type;
7068 if (expr_type.IsPointer){
7069 Error (23, "The `.' operator can not be applied to pointer operands (" +
7070 TypeManager.CSharpName (expr_type) + ")");
7074 Expression member_lookup = MemberLookup (
7075 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7076 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7077 if (member_lookup == null) {
7081 member_lookup = MemberLookup (
7082 rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
7083 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7085 if (member_lookup != null) {
7086 tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
7087 if (tnew_expr == null)
7090 Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
7094 member_lookup = MemberLookup (
7095 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7096 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7098 if (member_lookup == null) {
7099 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7100 Identifier, new_expr.GetSignatureForError ());
7102 // TODO: Report.SymbolRelatedToPreviousError
7103 member_lookup.Error_UnexpectedKind (null, "type", loc);
7108 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7113 TypeArguments the_args = args;
7114 Type declaring_type = texpr.Type.DeclaringType;
7115 if (TypeManager.HasGenericArguments (declaring_type)) {
7116 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7117 expr_type = expr_type.BaseType;
7120 TypeArguments new_args = new TypeArguments (loc);
7121 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7122 new_args.Add (new TypeExpression (decl, loc));
7125 new_args.Add (args);
7127 the_args = new_args;
7130 if (the_args != null) {
7131 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7132 return ctype.ResolveAsTypeStep (rc, false);
7139 public override void Emit (EmitContext ec)
7141 throw new Exception ("Should not happen");
7144 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7146 if (RootContext.Version > LanguageVersion.ISO_2 &&
7147 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7148 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7149 "extension method `{1}' of type `{0}' could be found " +
7150 "(are you missing a using directive or an assembly reference?)",
7151 TypeManager.CSharpName (type), name);
7155 base.Error_TypeDoesNotContainDefinition (type, name);
7158 public override string ToString ()
7160 return expr + "." + MemberName.MakeName (Identifier, args);
7163 public override string GetSignatureForError ()
7165 return expr.GetSignatureForError () + "." + Identifier;
7168 protected override void CloneTo (CloneContext clonectx, Expression t)
7170 MemberAccess target = (MemberAccess) t;
7172 target.expr = expr.Clone (clonectx);
7177 /// Implements checked expressions
7179 public class CheckedExpr : Expression {
7181 public Expression Expr;
7183 public CheckedExpr (Expression e, Location l)
7189 public override Expression CreateExpressionTree (EmitContext ec)
7191 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7192 return Expr.CreateExpressionTree (ec);
7195 public override Expression DoResolve (EmitContext ec)
7197 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7198 Expr = Expr.Resolve (ec);
7203 if (Expr is Constant)
7206 eclass = Expr.eclass;
7211 public override void Emit (EmitContext ec)
7213 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7217 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7219 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7220 Expr.EmitBranchable (ec, target, on_true);
7223 protected override void CloneTo (CloneContext clonectx, Expression t)
7225 CheckedExpr target = (CheckedExpr) t;
7227 target.Expr = Expr.Clone (clonectx);
7232 /// Implements the unchecked expression
7234 public class UnCheckedExpr : Expression {
7236 public Expression Expr;
7238 public UnCheckedExpr (Expression e, Location l)
7244 public override Expression CreateExpressionTree (EmitContext ec)
7246 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7247 return Expr.CreateExpressionTree (ec);
7250 public override Expression DoResolve (EmitContext ec)
7252 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7253 Expr = Expr.Resolve (ec);
7258 if (Expr is Constant)
7261 eclass = Expr.eclass;
7266 public override void Emit (EmitContext ec)
7268 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7272 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7274 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7275 Expr.EmitBranchable (ec, target, on_true);
7278 protected override void CloneTo (CloneContext clonectx, Expression t)
7280 UnCheckedExpr target = (UnCheckedExpr) t;
7282 target.Expr = Expr.Clone (clonectx);
7287 /// An Element Access expression.
7289 /// During semantic analysis these are transformed into
7290 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7292 public class ElementAccess : Expression {
7293 public ArrayList Arguments;
7294 public Expression Expr;
7296 public ElementAccess (Expression e, ArrayList e_list)
7305 Arguments = new ArrayList ();
7306 foreach (Expression tmp in e_list)
7307 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7311 bool CommonResolve (EmitContext ec)
7313 Expr = Expr.Resolve (ec);
7315 if (Arguments == null)
7318 foreach (Argument a in Arguments){
7319 if (!a.Resolve (ec, loc))
7323 return Expr != null;
7326 public override Expression CreateExpressionTree (EmitContext ec)
7328 ArrayList args = new ArrayList (Arguments.Count + 1);
7329 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7330 foreach (Argument a in Arguments)
7331 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7333 return CreateExpressionFactoryCall ("ArrayIndex", args);
7336 Expression MakePointerAccess (EmitContext ec, Type t)
7338 if (t == TypeManager.void_ptr_type){
7339 Error (242, "The array index operation is not valid on void pointers");
7342 if (Arguments.Count != 1){
7343 Error (196, "A pointer must be indexed by only one value");
7348 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7351 return new Indirection (p, loc).Resolve (ec);
7354 public override Expression DoResolve (EmitContext ec)
7356 if (!CommonResolve (ec))
7360 // We perform some simple tests, and then to "split" the emit and store
7361 // code we create an instance of a different class, and return that.
7363 // I am experimenting with this pattern.
7367 if (t == TypeManager.array_type){
7368 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7373 return (new ArrayAccess (this, loc)).Resolve (ec);
7375 return MakePointerAccess (ec, t);
7377 FieldExpr fe = Expr as FieldExpr;
7379 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7381 return MakePointerAccess (ec, ff.ElementType);
7384 return (new IndexerAccess (this, loc)).Resolve (ec);
7387 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7389 if (!CommonResolve (ec))
7394 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7397 return MakePointerAccess (ec, type);
7399 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7400 Error_CannotModifyIntermediateExpressionValue (ec);
7402 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7405 public override void Emit (EmitContext ec)
7407 throw new Exception ("Should never be reached");
7410 public override string GetSignatureForError ()
7412 return Expr.GetSignatureForError ();
7415 protected override void CloneTo (CloneContext clonectx, Expression t)
7417 ElementAccess target = (ElementAccess) t;
7419 target.Expr = Expr.Clone (clonectx);
7420 target.Arguments = new ArrayList (Arguments.Count);
7421 foreach (Argument a in Arguments)
7422 target.Arguments.Add (a.Clone (clonectx));
7427 /// Implements array access
7429 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7431 // Points to our "data" repository
7435 LocalTemporary temp;
7436 LocalTemporary prepared_value;
7440 public ArrayAccess (ElementAccess ea_data, Location l)
7443 eclass = ExprClass.Variable;
7447 public override Expression CreateExpressionTree (EmitContext ec)
7449 return ea.CreateExpressionTree (ec);
7452 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7454 return DoResolve (ec);
7457 public override Expression DoResolve (EmitContext ec)
7460 ExprClass eclass = ea.Expr.eclass;
7462 // As long as the type is valid
7463 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7464 eclass == ExprClass.Value)) {
7465 ea.Expr.Error_UnexpectedKind ("variable or value");
7470 Type t = ea.Expr.Type;
7471 int rank = ea.Arguments.Count;
7472 if (t.GetArrayRank () != rank) {
7473 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7474 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7478 if (rank != 1 && TypeManager.int_getlength_int == null) {
7479 TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
7480 TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
7483 type = TypeManager.GetElementType (t);
7484 if (type.IsPointer && !ec.InUnsafe) {
7485 UnsafeError (ea.Location);
7489 foreach (Argument a in ea.Arguments) {
7490 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7493 eclass = ExprClass.Variable;
7499 /// Emits the right opcode to load an object of Type `t'
7500 /// from an array of T
7502 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7505 MethodInfo get = FetchGetMethod ();
7506 ig.Emit (OpCodes.Call, get);
7510 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7511 ig.Emit (OpCodes.Ldelem_U1);
7512 else if (type == TypeManager.sbyte_type)
7513 ig.Emit (OpCodes.Ldelem_I1);
7514 else if (type == TypeManager.short_type)
7515 ig.Emit (OpCodes.Ldelem_I2);
7516 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7517 ig.Emit (OpCodes.Ldelem_U2);
7518 else if (type == TypeManager.int32_type)
7519 ig.Emit (OpCodes.Ldelem_I4);
7520 else if (type == TypeManager.uint32_type)
7521 ig.Emit (OpCodes.Ldelem_U4);
7522 else if (type == TypeManager.uint64_type)
7523 ig.Emit (OpCodes.Ldelem_I8);
7524 else if (type == TypeManager.int64_type)
7525 ig.Emit (OpCodes.Ldelem_I8);
7526 else if (type == TypeManager.float_type)
7527 ig.Emit (OpCodes.Ldelem_R4);
7528 else if (type == TypeManager.double_type)
7529 ig.Emit (OpCodes.Ldelem_R8);
7530 else if (type == TypeManager.intptr_type)
7531 ig.Emit (OpCodes.Ldelem_I);
7532 else if (TypeManager.IsEnumType (type)){
7533 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7534 } else if (type.IsValueType){
7535 ig.Emit (OpCodes.Ldelema, type);
7536 ig.Emit (OpCodes.Ldobj, type);
7538 } else if (type.IsGenericParameter) {
7539 ig.Emit (OpCodes.Ldelem, type);
7541 } else if (type.IsPointer)
7542 ig.Emit (OpCodes.Ldelem_I);
7544 ig.Emit (OpCodes.Ldelem_Ref);
7547 protected override void Error_NegativeArrayIndex (Location loc)
7549 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7553 /// Returns the right opcode to store an object of Type `t'
7554 /// from an array of T.
7556 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7558 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7559 has_type_arg = false; is_stobj = false;
7560 t = TypeManager.TypeToCoreType (t);
7561 if (TypeManager.IsEnumType (t))
7562 t = TypeManager.GetEnumUnderlyingType (t);
7563 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7564 t == TypeManager.bool_type)
7565 return OpCodes.Stelem_I1;
7566 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7567 t == TypeManager.char_type)
7568 return OpCodes.Stelem_I2;
7569 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7570 return OpCodes.Stelem_I4;
7571 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7572 return OpCodes.Stelem_I8;
7573 else if (t == TypeManager.float_type)
7574 return OpCodes.Stelem_R4;
7575 else if (t == TypeManager.double_type)
7576 return OpCodes.Stelem_R8;
7577 else if (t == TypeManager.intptr_type) {
7578 has_type_arg = true;
7580 return OpCodes.Stobj;
7581 } else if (t.IsValueType) {
7582 has_type_arg = true;
7584 return OpCodes.Stobj;
7586 } else if (t.IsGenericParameter) {
7587 has_type_arg = true;
7588 return OpCodes.Stelem;
7591 } else if (t.IsPointer)
7592 return OpCodes.Stelem_I;
7594 return OpCodes.Stelem_Ref;
7597 MethodInfo FetchGetMethod ()
7599 ModuleBuilder mb = CodeGen.Module.Builder;
7600 int arg_count = ea.Arguments.Count;
7601 Type [] args = new Type [arg_count];
7604 for (int i = 0; i < arg_count; i++){
7605 //args [i++] = a.Type;
7606 args [i] = TypeManager.int32_type;
7609 get = mb.GetArrayMethod (
7610 ea.Expr.Type, "Get",
7611 CallingConventions.HasThis |
7612 CallingConventions.Standard,
7618 MethodInfo FetchAddressMethod ()
7620 ModuleBuilder mb = CodeGen.Module.Builder;
7621 int arg_count = ea.Arguments.Count;
7622 Type [] args = new Type [arg_count];
7626 ret_type = TypeManager.GetReferenceType (type);
7628 for (int i = 0; i < arg_count; i++){
7629 //args [i++] = a.Type;
7630 args [i] = TypeManager.int32_type;
7633 address = mb.GetArrayMethod (
7634 ea.Expr.Type, "Address",
7635 CallingConventions.HasThis |
7636 CallingConventions.Standard,
7643 // Load the array arguments into the stack.
7645 // If we have been requested to cache the values (cached_locations array
7646 // initialized), then load the arguments the first time and store them
7647 // in locals. otherwise load from local variables.
7649 // prepare_for_load is used in compound assignments to cache original index
7650 // values ( label[idx++] += s )
7652 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
7656 LocalTemporary[] indexes = null;
7657 if (prepare_for_load) {
7658 ec.ig.Emit (OpCodes.Dup);
7659 indexes = new LocalTemporary [ea.Arguments.Count];
7662 for (int i = 0; i < ea.Arguments.Count; ++i) {
7663 ((Argument)ea.Arguments [i]).Emit (ec);
7664 if (!prepare_for_load)
7667 // Keep original array index value on the stack
7668 ec.ig.Emit (OpCodes.Dup);
7670 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7671 indexes [i].Store (ec);
7677 public void Emit (EmitContext ec, bool leave_copy)
7679 int rank = ea.Expr.Type.GetArrayRank ();
7680 ILGenerator ig = ec.ig;
7682 if (prepared_value != null) {
7683 prepared_value.Emit (ec);
7684 } else if (prepared) {
7685 LoadFromPtr (ig, this.type);
7687 LoadArrayAndArguments (ec, false);
7688 EmitLoadOpcode (ig, type, rank);
7692 ig.Emit (OpCodes.Dup);
7693 temp = new LocalTemporary (this.type);
7698 public override void Emit (EmitContext ec)
7703 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7705 int rank = ea.Expr.Type.GetArrayRank ();
7706 ILGenerator ig = ec.ig;
7707 Type t = source.Type;
7708 prepared = prepare_for_load && !(source is StringConcat);
7711 AddressOf (ec, AddressOp.LoadStore);
7712 ec.ig.Emit (OpCodes.Dup);
7714 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7715 prepare_for_load && (source is StringConcat));
7717 if (original_indexes_values != null) {
7718 prepared_value = new LocalTemporary (type);
7719 EmitLoadOpcode (ig, type, rank);
7720 prepared_value.Store (ec);
7721 foreach (LocalTemporary lt in original_indexes_values) {
7729 bool is_stobj, has_type_arg;
7730 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7734 // The stobj opcode used by value types will need
7735 // an address on the stack, not really an array/array
7739 ig.Emit (OpCodes.Ldelema, t);
7744 ec.ig.Emit (OpCodes.Dup);
7745 temp = new LocalTemporary (this.type);
7750 StoreFromPtr (ig, t);
7752 ig.Emit (OpCodes.Stobj, t);
7753 else if (has_type_arg)
7760 ec.ig.Emit (OpCodes.Dup);
7761 temp = new LocalTemporary (this.type);
7766 StoreFromPtr (ig, t);
7768 int arg_count = ea.Arguments.Count;
7769 Type [] args = new Type [arg_count + 1];
7770 for (int i = 0; i < arg_count; i++) {
7771 //args [i++] = a.Type;
7772 args [i] = TypeManager.int32_type;
7774 args [arg_count] = type;
7776 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7777 ea.Expr.Type, "Set",
7778 CallingConventions.HasThis |
7779 CallingConventions.Standard,
7780 TypeManager.void_type, args);
7782 ig.Emit (OpCodes.Call, set);
7792 public void AddressOf (EmitContext ec, AddressOp mode)
7794 int rank = ea.Expr.Type.GetArrayRank ();
7795 ILGenerator ig = ec.ig;
7797 LoadArrayAndArguments (ec, false);
7800 ig.Emit (OpCodes.Ldelema, type);
7802 MethodInfo address = FetchAddressMethod ();
7803 ig.Emit (OpCodes.Call, address);
7807 public void EmitGetLength (EmitContext ec, int dim)
7809 int rank = ea.Expr.Type.GetArrayRank ();
7810 ILGenerator ig = ec.ig;
7814 ig.Emit (OpCodes.Ldlen);
7815 ig.Emit (OpCodes.Conv_I4);
7817 IntLiteral.EmitInt (ig, dim);
7818 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7824 /// Expressions that represent an indexer call.
7826 public class IndexerAccess : Expression, IAssignMethod
7828 class IndexerMethodGroupExpr : MethodGroupExpr
7830 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7833 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7836 public override string Name {
7842 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7845 // Here is the trick, decrease number of arguments by 1 when only
7846 // available property method is setter. This makes overload resolution
7847 // work correctly for indexers.
7850 if (method.Name [0] == 'g')
7851 return parameters.Count;
7853 return parameters.Count - 1;
7859 // Contains either property getter or setter
7860 public ArrayList Methods;
7861 public ArrayList Properties;
7867 void Append (Type caller_type, MemberInfo [] mi)
7872 foreach (PropertyInfo property in mi) {
7873 MethodInfo accessor = property.GetGetMethod (true);
7874 if (accessor == null)
7875 accessor = property.GetSetMethod (true);
7877 if (Methods == null) {
7878 Methods = new ArrayList ();
7879 Properties = new ArrayList ();
7882 Methods.Add (accessor);
7883 Properties.Add (property);
7887 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7889 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7891 return TypeManager.MemberLookup (
7892 caller_type, caller_type, lookup_type, MemberTypes.Property,
7893 BindingFlags.Public | BindingFlags.Instance |
7894 BindingFlags.DeclaredOnly, p_name, null);
7897 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7899 Indexers ix = new Indexers ();
7902 if (lookup_type.IsGenericParameter) {
7903 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7907 if (gc.HasClassConstraint)
7908 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7910 Type[] ifaces = gc.InterfaceConstraints;
7911 foreach (Type itype in ifaces)
7912 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7918 Type copy = lookup_type;
7919 while (copy != TypeManager.object_type && copy != null){
7920 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7921 copy = copy.BaseType;
7924 if (lookup_type.IsInterface) {
7925 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7926 if (ifaces != null) {
7927 foreach (Type itype in ifaces)
7928 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7943 // Points to our "data" repository
7945 MethodInfo get, set;
7946 bool is_base_indexer;
7948 LocalTemporary temp;
7949 LocalTemporary prepared_value;
7950 Expression set_expr;
7952 protected Type indexer_type;
7953 protected Type current_type;
7954 protected Expression instance_expr;
7955 protected ArrayList arguments;
7957 public IndexerAccess (ElementAccess ea, Location loc)
7958 : this (ea.Expr, false, loc)
7960 this.arguments = ea.Arguments;
7963 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7966 this.instance_expr = instance_expr;
7967 this.is_base_indexer = is_base_indexer;
7968 this.eclass = ExprClass.Value;
7972 static string GetAccessorName (AccessorType at)
7974 if (at == AccessorType.Set)
7977 if (at == AccessorType.Get)
7980 throw new NotImplementedException (at.ToString ());
7983 protected virtual bool CommonResolve (EmitContext ec)
7985 indexer_type = instance_expr.Type;
7986 current_type = ec.ContainerType;
7991 public override Expression DoResolve (EmitContext ec)
7993 return ResolveAccessor (ec, AccessorType.Get);
7996 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7998 if (right_side == EmptyExpression.OutAccess) {
7999 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8000 GetSignatureForError ());
8004 // if the indexer returns a value type, and we try to set a field in it
8005 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8006 Error_CannotModifyIntermediateExpressionValue (ec);
8009 Expression e = ResolveAccessor (ec, AccessorType.Set);
8013 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8017 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8019 if (!CommonResolve (ec))
8022 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8023 if (ilist.Methods == null) {
8024 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8025 TypeManager.CSharpName (indexer_type));
8029 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8030 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8034 MethodInfo mi = (MethodInfo) mg;
8035 PropertyInfo pi = null;
8036 for (int i = 0; i < ilist.Methods.Count; ++i) {
8037 if (ilist.Methods [i] == mi) {
8038 pi = (PropertyInfo) ilist.Properties [i];
8043 type = TypeManager.TypeToCoreType (pi.PropertyType);
8044 if (type.IsPointer && !ec.InUnsafe)
8047 MethodInfo accessor;
8048 if (accessorType == AccessorType.Get) {
8049 accessor = get = pi.GetGetMethod (true);
8051 accessor = set = pi.GetSetMethod (true);
8052 if (accessor == null && pi.GetGetMethod (true) != null) {
8053 Report.SymbolRelatedToPreviousError (pi);
8054 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8055 TypeManager.GetFullNameSignature (pi));
8060 if (accessor == null) {
8061 Report.SymbolRelatedToPreviousError (pi);
8062 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8063 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8068 // Only base will allow this invocation to happen.
8070 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8071 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8074 bool must_do_cs1540_check;
8075 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8077 set = pi.GetSetMethod (true);
8079 get = pi.GetGetMethod (true);
8081 if (set != null && get != null &&
8082 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8083 Report.SymbolRelatedToPreviousError (accessor);
8084 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8085 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8087 Report.SymbolRelatedToPreviousError (pi);
8088 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8092 instance_expr.CheckMarshalByRefAccess (ec);
8093 eclass = ExprClass.IndexerAccess;
8097 public void Emit (EmitContext ec, bool leave_copy)
8100 prepared_value.Emit (ec);
8102 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8103 arguments, loc, false, false);
8107 ec.ig.Emit (OpCodes.Dup);
8108 temp = new LocalTemporary (Type);
8114 // source is ignored, because we already have a copy of it from the
8115 // LValue resolution and we have already constructed a pre-cached
8116 // version of the arguments (ea.set_arguments);
8118 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8120 prepared = prepare_for_load;
8121 Expression value = set_expr;
8124 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8125 arguments, loc, true, false);
8127 prepared_value = new LocalTemporary (type);
8128 prepared_value.Store (ec);
8130 prepared_value.Release (ec);
8133 ec.ig.Emit (OpCodes.Dup);
8134 temp = new LocalTemporary (Type);
8137 } else if (leave_copy) {
8138 temp = new LocalTemporary (Type);
8144 arguments.Add (new Argument (value, Argument.AType.Expression));
8145 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8153 public override void Emit (EmitContext ec)
8158 public override string GetSignatureForError ()
8160 return TypeManager.CSharpSignature (get != null ? get : set, false);
8163 protected override void CloneTo (CloneContext clonectx, Expression t)
8165 IndexerAccess target = (IndexerAccess) t;
8167 if (arguments != null){
8168 target.arguments = new ArrayList ();
8169 foreach (Argument a in arguments)
8170 target.arguments.Add (a.Clone (clonectx));
8172 if (instance_expr != null)
8173 target.instance_expr = instance_expr.Clone (clonectx);
8178 /// The base operator for method names
8180 public class BaseAccess : Expression {
8181 public readonly string Identifier;
8184 public BaseAccess (string member, Location l)
8186 this.Identifier = member;
8190 public BaseAccess (string member, TypeArguments args, Location l)
8196 public override Expression DoResolve (EmitContext ec)
8198 Expression c = CommonResolve (ec);
8204 // MethodGroups use this opportunity to flag an error on lacking ()
8206 if (!(c is MethodGroupExpr))
8207 return c.Resolve (ec);
8211 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8213 Expression c = CommonResolve (ec);
8219 // MethodGroups use this opportunity to flag an error on lacking ()
8221 if (! (c is MethodGroupExpr))
8222 return c.DoResolveLValue (ec, right_side);
8227 Expression CommonResolve (EmitContext ec)
8229 Expression member_lookup;
8230 Type current_type = ec.ContainerType;
8231 Type base_type = current_type.BaseType;
8234 Error (1511, "Keyword `base' is not available in a static method");
8238 if (ec.IsInFieldInitializer){
8239 Error (1512, "Keyword `base' is not available in the current context");
8243 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8244 AllMemberTypes, AllBindingFlags, loc);
8245 if (member_lookup == null) {
8246 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8247 null, AllMemberTypes, AllBindingFlags);
8254 left = new TypeExpression (base_type, loc);
8256 left = ec.GetThis (loc);
8258 MemberExpr me = (MemberExpr) member_lookup;
8259 me = me.ResolveMemberAccess (ec, left, loc, null);
8266 me.SetTypeArguments (args);
8272 public override void Emit (EmitContext ec)
8274 throw new Exception ("Should never be called");
8277 protected override void CloneTo (CloneContext clonectx, Expression t)
8279 BaseAccess target = (BaseAccess) t;
8282 target.args = args.Clone ();
8287 /// The base indexer operator
8289 public class BaseIndexerAccess : IndexerAccess {
8290 public BaseIndexerAccess (ArrayList args, Location loc)
8291 : base (null, true, loc)
8293 arguments = new ArrayList ();
8294 foreach (Expression tmp in args)
8295 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8298 protected override bool CommonResolve (EmitContext ec)
8300 instance_expr = ec.GetThis (loc);
8302 current_type = ec.ContainerType.BaseType;
8303 indexer_type = current_type;
8305 foreach (Argument a in arguments){
8306 if (!a.Resolve (ec, loc))
8315 /// This class exists solely to pass the Type around and to be a dummy
8316 /// that can be passed to the conversion functions (this is used by
8317 /// foreach implementation to typecast the object return value from
8318 /// get_Current into the proper type. All code has been generated and
8319 /// we only care about the side effect conversions to be performed
8321 /// This is also now used as a placeholder where a no-action expression
8322 /// is needed (the `New' class).
8324 public class EmptyExpression : Expression {
8325 public static readonly EmptyExpression Null = new EmptyExpression ();
8327 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8328 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8329 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8331 static EmptyExpression temp = new EmptyExpression ();
8332 public static EmptyExpression Grab ()
8334 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8339 public static void Release (EmptyExpression e)
8344 // TODO: should be protected
8345 public EmptyExpression ()
8347 type = TypeManager.object_type;
8348 eclass = ExprClass.Value;
8349 loc = Location.Null;
8352 public EmptyExpression (Type t)
8355 eclass = ExprClass.Value;
8356 loc = Location.Null;
8359 public override Expression DoResolve (EmitContext ec)
8364 public override void Emit (EmitContext ec)
8366 // nothing, as we only exist to not do anything.
8370 // This is just because we might want to reuse this bad boy
8371 // instead of creating gazillions of EmptyExpressions.
8372 // (CanImplicitConversion uses it)
8374 public void SetType (Type t)
8381 // Empty statement expression
8383 public sealed class EmptyExpressionStatement : ExpressionStatement
8385 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8387 private EmptyExpressionStatement ()
8389 type = TypeManager.object_type;
8390 eclass = ExprClass.Value;
8391 loc = Location.Null;
8394 public override void EmitStatement (EmitContext ec)
8399 public override Expression DoResolve (EmitContext ec)
8404 public override void Emit (EmitContext ec)
8410 public class UserCast : Expression {
8414 public UserCast (MethodInfo method, Expression source, Location l)
8416 this.method = method;
8417 this.source = source;
8418 type = TypeManager.TypeToCoreType (method.ReturnType);
8419 eclass = ExprClass.Value;
8423 public Expression Source {
8429 public override Expression CreateExpressionTree (EmitContext ec)
8431 ArrayList args = new ArrayList (2);
8432 args.Add (new Argument (source.CreateExpressionTree (ec)));
8433 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8434 args.Add (new Argument (new Cast (new TypeExpression (typeof (MethodInfo), loc),
8435 new TypeOfMethod (method, loc))));
8436 return CreateExpressionFactoryCall ("Convert", args);
8439 public override Expression DoResolve (EmitContext ec)
8442 // We are born fully resolved
8447 public override void Emit (EmitContext ec)
8450 ec.ig.Emit (OpCodes.Call, method);
8455 // This class is used to "construct" the type during a typecast
8456 // operation. Since the Type.GetType class in .NET can parse
8457 // the type specification, we just use this to construct the type
8458 // one bit at a time.
8460 public class ComposedCast : TypeExpr {
8464 public ComposedCast (Expression left, string dim)
8465 : this (left, dim, left.Location)
8469 public ComposedCast (Expression left, string dim, Location l)
8476 public Expression RemoveNullable ()
8478 if (dim.EndsWith ("?")) {
8479 dim = dim.Substring (0, dim.Length - 1);
8480 if (dim.Length == 0)
8487 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8489 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8493 Type ltype = lexpr.Type;
8494 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8495 Error_VoidInvalidInTheContext (loc);
8500 if ((dim.Length > 0) && (dim [0] == '?')) {
8501 TypeExpr nullable = new Nullable.NullableType (left, loc);
8503 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8504 return nullable.ResolveAsTypeTerminal (ec, false);
8508 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8511 if (dim != "" && dim [0] == '[' &&
8512 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8513 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8518 type = TypeManager.GetConstructedType (ltype, dim);
8523 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8525 if (type.IsPointer && !ec.IsInUnsafeScope){
8530 eclass = ExprClass.Type;
8534 public override string Name {
8535 get { return left + dim; }
8538 public override string FullName {
8539 get { return type.FullName; }
8542 public override string GetSignatureForError ()
8544 return left.GetSignatureForError () + dim;
8547 protected override void CloneTo (CloneContext clonectx, Expression t)
8549 ComposedCast target = (ComposedCast) t;
8551 target.left = left.Clone (clonectx);
8555 public class FixedBufferPtr : Expression {
8558 public FixedBufferPtr (Expression array, Type array_type, Location l)
8563 type = TypeManager.GetPointerType (array_type);
8564 eclass = ExprClass.Value;
8567 public override void Emit(EmitContext ec)
8572 public override Expression DoResolve (EmitContext ec)
8575 // We are born fully resolved
8583 // This class is used to represent the address of an array, used
8584 // only by the Fixed statement, this generates "&a [0]" construct
8585 // for fixed (char *pa = a)
8587 public class ArrayPtr : FixedBufferPtr {
8590 public ArrayPtr (Expression array, Type array_type, Location l):
8591 base (array, array_type, l)
8593 this.array_type = array_type;
8596 public override void Emit (EmitContext ec)
8600 ILGenerator ig = ec.ig;
8601 IntLiteral.EmitInt (ig, 0);
8602 ig.Emit (OpCodes.Ldelema, array_type);
8607 // Encapsulates a conversion rules required for array indexes
8609 public class ArrayIndexCast : Expression
8613 public ArrayIndexCast (Expression expr)
8616 this.loc = expr.Location;
8619 public override Expression CreateExpressionTree (EmitContext ec)
8621 ArrayList args = new ArrayList (2);
8622 args.Add (new Argument (expr.CreateExpressionTree (ec)));
8623 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8624 return CreateExpressionFactoryCall ("ConvertChecked", args);
8627 public override Expression DoResolve (EmitContext ec)
8630 eclass = expr.eclass;
8634 public override void Emit (EmitContext ec)
8638 if (type == TypeManager.int32_type)
8641 if (type == TypeManager.uint32_type)
8642 ec.ig.Emit (OpCodes.Conv_U);
8643 else if (type == TypeManager.int64_type)
8644 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8645 else if (type == TypeManager.uint64_type)
8646 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8648 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8653 // Used by the fixed statement
8655 public class StringPtr : Expression {
8658 public StringPtr (LocalBuilder b, Location l)
8661 eclass = ExprClass.Value;
8662 type = TypeManager.char_ptr_type;
8666 public override Expression DoResolve (EmitContext ec)
8668 // This should never be invoked, we are born in fully
8669 // initialized state.
8674 public override void Emit (EmitContext ec)
8676 if (TypeManager.int_get_offset_to_string_data == null) {
8677 // TODO: Move to resolve !!
8678 TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
8679 TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
8682 ILGenerator ig = ec.ig;
8684 ig.Emit (OpCodes.Ldloc, b);
8685 ig.Emit (OpCodes.Conv_I);
8686 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8687 ig.Emit (OpCodes.Add);
8692 // Implements the `stackalloc' keyword
8694 public class StackAlloc : Expression {
8699 public StackAlloc (Expression type, Expression count, Location l)
8706 public override Expression DoResolve (EmitContext ec)
8708 count = count.Resolve (ec);
8712 if (count.Type != TypeManager.int32_type){
8713 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8718 Constant c = count as Constant;
8719 if (c != null && c.IsNegative) {
8720 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8724 if (ec.InCatch || ec.InFinally) {
8725 Error (255, "Cannot use stackalloc in finally or catch");
8729 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8735 if (!TypeManager.VerifyUnManaged (otype, loc))
8738 type = TypeManager.GetPointerType (otype);
8739 eclass = ExprClass.Value;
8744 public override void Emit (EmitContext ec)
8746 int size = GetTypeSize (otype);
8747 ILGenerator ig = ec.ig;
8750 ig.Emit (OpCodes.Sizeof, otype);
8752 IntConstant.EmitInt (ig, size);
8754 ig.Emit (OpCodes.Mul);
8755 ig.Emit (OpCodes.Localloc);
8758 protected override void CloneTo (CloneContext clonectx, Expression t)
8760 StackAlloc target = (StackAlloc) t;
8761 target.count = count.Clone (clonectx);
8762 target.t = t.Clone (clonectx);
8767 // An object initializer expression
8769 public class ElementInitializer : Expression
8771 Expression initializer;
8772 public readonly string Name;
8774 public ElementInitializer (string name, Expression initializer, Location loc)
8777 this.initializer = initializer;
8781 protected override void CloneTo (CloneContext clonectx, Expression t)
8783 if (initializer == null)
8786 ElementInitializer target = (ElementInitializer) t;
8787 target.initializer = initializer.Clone (clonectx);
8790 public override Expression DoResolve (EmitContext ec)
8792 if (initializer == null)
8793 return EmptyExpressionStatement.Instance;
8795 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8796 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8798 if (element_member == null)
8801 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8803 if (initializer is CollectionOrObjectInitializers) {
8804 Expression previous = ec.CurrentInitializerVariable;
8805 ec.CurrentInitializerVariable = element_member;
8806 initializer = initializer.Resolve (ec);
8807 ec.CurrentInitializerVariable = previous;
8811 Assign a = new Assign (element_member, initializer, loc);
8812 if (a.Resolve (ec) == null)
8816 // Ignore field initializers with default value
8818 Constant c = a.Source as Constant;
8819 if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
8820 return EmptyExpressionStatement.Instance;
8825 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8827 MemberInfo member = members [0];
8828 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8829 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8830 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8832 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8833 TypeManager.GetFullNameSignature (member));
8838 public override void Emit (EmitContext ec)
8840 throw new NotSupportedException ("Should not be reached");
8845 // A collection initializer expression
8847 public class CollectionElementInitializer : Expression
8849 public class ElementInitializerArgument : Argument
8851 public ElementInitializerArgument (Expression e)
8857 ArrayList arguments;
8859 public CollectionElementInitializer (Expression argument)
8861 arguments = new ArrayList (1);
8862 arguments.Add (argument);
8863 this.loc = argument.Location;
8866 public CollectionElementInitializer (ArrayList arguments, Location loc)
8868 this.arguments = arguments;
8872 protected override void CloneTo (CloneContext clonectx, Expression t)
8874 CollectionElementInitializer target = (CollectionElementInitializer) t;
8875 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8876 foreach (Expression e in arguments)
8877 t_arguments.Add (e.Clone (clonectx));
8880 public override Expression DoResolve (EmitContext ec)
8882 // TODO: We should call a constructor which takes element counts argument,
8883 // for know types like List<T>, Dictionary<T, U>
8885 for (int i = 0; i < arguments.Count; ++i)
8886 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8888 Expression add_method = new Invocation (
8889 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8892 add_method = add_method.Resolve (ec);
8897 public override void Emit (EmitContext ec)
8899 throw new NotSupportedException ("Should not be reached");
8904 // A block of object or collection initializers
8906 public class CollectionOrObjectInitializers : ExpressionStatement
8908 ArrayList initializers;
8910 public static readonly CollectionOrObjectInitializers Empty =
8911 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8913 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8915 this.initializers = initializers;
8919 public bool IsEmpty {
8921 return initializers.Count == 0;
8925 protected override void CloneTo (CloneContext clonectx, Expression target)
8927 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8929 t.initializers = new ArrayList (initializers.Count);
8930 foreach (Expression e in initializers)
8931 t.initializers.Add (e.Clone (clonectx));
8934 public override Expression DoResolve (EmitContext ec)
8936 bool is_elements_initialization = false;
8937 ArrayList element_names = null;
8938 for (int i = 0; i < initializers.Count; ++i) {
8939 Expression initializer = (Expression) initializers [i];
8940 ElementInitializer element_initializer = initializer as ElementInitializer;
8943 if (element_initializer != null) {
8944 is_elements_initialization = true;
8945 element_names = new ArrayList (initializers.Count);
8946 element_names.Add (element_initializer.Name);
8948 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8949 TypeManager.ienumerable_type)) {
8950 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8951 "object initializer because type `{1}' does not implement `{2}' interface",
8952 ec.CurrentInitializerVariable.GetSignatureForError (),
8953 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8954 TypeManager.CSharpName (TypeManager.ienumerable_type));
8959 if (is_elements_initialization == (element_initializer == null)) {
8960 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8961 is_elements_initialization ? "object initializer" : "collection initializer");
8965 if (is_elements_initialization) {
8966 if (element_names.Contains (element_initializer.Name)) {
8967 Report.Error (1912, element_initializer.Location,
8968 "An object initializer includes more than one member `{0}' initialization",
8969 element_initializer.Name);
8971 element_names.Add (element_initializer.Name);
8976 Expression e = initializer.Resolve (ec);
8977 if (e == EmptyExpressionStatement.Instance)
8978 initializers.RemoveAt (i--);
8980 initializers [i] = e;
8983 type = typeof (CollectionOrObjectInitializers);
8984 eclass = ExprClass.Variable;
8988 public override void Emit (EmitContext ec)
8993 public override void EmitStatement (EmitContext ec)
8995 foreach (ExpressionStatement e in initializers)
8996 e.EmitStatement (ec);
9001 // New expression with element/object initializers
9003 public class NewInitialize : New
9006 // This class serves as a proxy for variable initializer target instances.
9007 // A real variable is assigned later when we resolve left side of an
9010 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9012 NewInitialize new_instance;
9014 public InitializerTargetExpression (NewInitialize newInstance)
9016 this.type = newInstance.type;
9017 this.loc = newInstance.loc;
9018 this.eclass = newInstance.eclass;
9019 this.new_instance = newInstance;
9022 public override Expression DoResolve (EmitContext ec)
9027 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9032 public override void Emit (EmitContext ec)
9034 new_instance.value_target.Emit (ec);
9037 #region IMemoryLocation Members
9039 public void AddressOf (EmitContext ec, AddressOp mode)
9041 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9047 CollectionOrObjectInitializers initializers;
9049 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9050 : base (requested_type, arguments, l)
9052 this.initializers = initializers;
9055 protected override void CloneTo (CloneContext clonectx, Expression t)
9057 base.CloneTo (clonectx, t);
9059 NewInitialize target = (NewInitialize) t;
9060 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9063 public override Expression DoResolve (EmitContext ec)
9065 if (eclass != ExprClass.Invalid)
9068 Expression e = base.DoResolve (ec);
9072 // Empty initializer can be optimized to simple new
9073 if (initializers.IsEmpty)
9076 Expression previous = ec.CurrentInitializerVariable;
9077 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9078 initializers.Resolve (ec);
9079 ec.CurrentInitializerVariable = previous;
9083 public override void Emit (EmitContext ec)
9088 // If target is a value, let's use it
9090 VariableReference variable = value_target as VariableReference;
9091 if (variable != null) {
9093 StoreFromPtr (ec.ig, type);
9095 variable.Variable.EmitAssign (ec);
9097 if (value_target == null || value_target_set)
9098 value_target = new LocalTemporary (type);
9100 ((LocalTemporary) value_target).Store (ec);
9103 initializers.Emit (ec);
9105 if (variable == null)
9106 value_target.Emit (ec);
9109 public override void EmitStatement (EmitContext ec)
9111 if (initializers.IsEmpty) {
9112 base.EmitStatement (ec);
9118 if (value_target == null) {
9119 LocalTemporary variable = new LocalTemporary (type);
9120 variable.Store (ec);
9121 value_target = variable;
9124 initializers.EmitStatement (ec);
9127 public override bool HasInitializer {
9129 return !initializers.IsEmpty;
9134 public class AnonymousTypeDeclaration : Expression
9136 ArrayList parameters;
9137 readonly TypeContainer parent;
9138 static readonly ArrayList EmptyParameters = new ArrayList (0);
9140 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9142 this.parameters = parameters;
9143 this.parent = parent;
9147 protected override void CloneTo (CloneContext clonectx, Expression target)
9149 if (parameters == null)
9152 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9153 t.parameters = new ArrayList (parameters.Count);
9154 foreach (AnonymousTypeParameter atp in parameters)
9155 t.parameters.Add (atp.Clone (clonectx));
9158 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9160 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9164 type = AnonymousTypeClass.Create (parent, parameters, loc);
9169 type.DefineMembers ();
9173 RootContext.ToplevelTypes.AddAnonymousType (type);
9177 public override Expression DoResolve (EmitContext ec)
9179 AnonymousTypeClass anonymous_type;
9181 if (parameters == null) {
9182 anonymous_type = CreateAnonymousType (EmptyParameters);
9183 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9184 null, loc).Resolve (ec);
9188 ArrayList arguments = new ArrayList (parameters.Count);
9189 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9190 for (int i = 0; i < parameters.Count; ++i) {
9191 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9197 arguments.Add (new Argument (e));
9198 t_args [i] = new TypeExpression (e.Type, e.Location);
9204 anonymous_type = CreateAnonymousType (parameters);
9205 if (anonymous_type == null)
9208 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9209 new TypeArguments (loc, t_args), loc);
9211 return new New (te, arguments, loc).Resolve (ec);
9214 public override void Emit (EmitContext ec)
9216 throw new InternalErrorException ("Should not be reached");
9220 public class AnonymousTypeParameter : Expression
9222 public readonly string Name;
9223 Expression initializer;
9225 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9229 this.initializer = initializer;
9232 public AnonymousTypeParameter (Parameter parameter)
9234 this.Name = parameter.Name;
9235 this.loc = parameter.Location;
9236 this.initializer = new SimpleName (Name, loc);
9239 protected override void CloneTo (CloneContext clonectx, Expression target)
9241 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9242 t.initializer = initializer.Clone (clonectx);
9245 public override bool Equals (object o)
9247 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9248 return other != null && Name == other.Name;
9251 public override int GetHashCode ()
9253 return Name.GetHashCode ();
9256 public override Expression DoResolve (EmitContext ec)
9258 Expression e = initializer.Resolve (ec);
9263 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9264 type == TypeManager.anonymous_method_type || type.IsPointer) {
9265 Error_InvalidInitializer (e);
9272 protected virtual void Error_InvalidInitializer (Expression initializer)
9274 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9275 Name, initializer.GetSignatureForError ());
9278 public override void Emit (EmitContext ec)
9280 throw new InternalErrorException ("Should not be reached");