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 protected readonly ArrayList arguments;
28 protected 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)
1599 if (TypeManager.IsEqual (left, lexpr.Type) &&
1600 TypeManager.IsEqual (right, rexpr.Type))
1603 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1604 Convert.ImplicitConversionExists (ec, rexpr, right);
1607 public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
1610 if (left != null && best_operator.left != null) {
1611 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1615 // When second arguments are same as the first one, the result is same
1617 if (left != right || best_operator.left != best_operator.right) {
1618 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1621 if (result == 0 || result > 2)
1624 return result == 1 ? best_operator : this;
1628 class PredefinedStringOperator : PredefinedOperator {
1629 public PredefinedStringOperator (Type type, Operator op_mask)
1630 : base (type, op_mask, type)
1632 ReturnType = TypeManager.string_type;
1635 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1636 : base (ltype, rtype, op_mask)
1638 ReturnType = TypeManager.string_type;
1641 public override Expression ConvertResult (EmitContext ec, Binary b)
1644 // Use original expression for nullable arguments
1646 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1648 b.left = unwrap.Original;
1650 unwrap = b.right as Nullable.Unwrap;
1652 b.right = unwrap.Original;
1654 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1655 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1658 // Start a new concat expression using converted expression
1660 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1664 class PredefinedShiftOperator : PredefinedOperator {
1665 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1666 base (ltype, TypeManager.int32_type, op_mask)
1670 public override Expression ConvertResult (EmitContext ec, Binary b)
1672 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1674 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1676 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1679 // b = b.left >> b.right & (0x1f|0x3f)
1681 b.right = new Binary (Operator.BitwiseAnd,
1682 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1685 // Expression tree representation does not use & mask
1687 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1688 b.type = ReturnType;
1693 class PredefinedPointerOperator : PredefinedOperator {
1694 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1695 : base (ltype, rtype, op_mask)
1699 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1700 : base (type, op_mask, return_type)
1704 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1707 if (!lexpr.Type.IsPointer)
1710 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1714 if (right == null) {
1715 if (!rexpr.Type.IsPointer)
1718 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1725 public override Expression ConvertResult (EmitContext ec, Binary b)
1727 base.ConvertResult (ec, b);
1729 Type r_type = ReturnType;
1730 if (r_type == null) {
1731 r_type = b.left.Type;
1733 r_type = b.right.Type;
1736 return new PointerArithmetic (b.oper == Operator.Addition,
1737 b.left, b.right, r_type, b.loc).Resolve (ec);
1742 public enum Operator {
1743 Multiply = 0 | ArithmeticMask,
1744 Division = 1 | ArithmeticMask,
1745 Modulus = 2 | ArithmeticMask,
1746 Addition = 3 | ArithmeticMask | AdditionMask,
1747 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1749 LeftShift = 5 | ShiftMask,
1750 RightShift = 6 | ShiftMask,
1752 LessThan = 7 | ComparisonMask | RelationalMask,
1753 GreaterThan = 8 | ComparisonMask | RelationalMask,
1754 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1755 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1756 Equality = 11 | ComparisonMask | EqualityMask,
1757 Inequality = 12 | ComparisonMask | EqualityMask,
1759 BitwiseAnd = 13 | BitwiseMask,
1760 ExclusiveOr = 14 | BitwiseMask,
1761 BitwiseOr = 15 | BitwiseMask,
1763 LogicalAnd = 16 | LogicalMask,
1764 LogicalOr = 17 | LogicalMask,
1769 ValuesOnlyMask = ArithmeticMask - 1,
1770 ArithmeticMask = 1 << 5,
1772 ComparisonMask = 1 << 7,
1773 EqualityMask = 1 << 8,
1774 BitwiseMask = 1 << 9,
1775 LogicalMask = 1 << 10,
1776 AdditionMask = 1 << 11,
1777 SubtractionMask = 1 << 12,
1778 RelationalMask = 1 << 13
1781 readonly Operator oper;
1782 protected Expression left, right;
1783 readonly bool is_compound;
1785 // This must be kept in sync with Operator!!!
1786 public static readonly string [] oper_names;
1788 static PredefinedOperator [] standard_operators;
1789 static PredefinedOperator [] pointer_operators;
1793 oper_names = new string [18];
1795 oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
1796 oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
1797 oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
1798 oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
1799 oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
1800 oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
1801 oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
1802 oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
1803 oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
1804 oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
1805 oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
1806 oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
1807 oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
1808 oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
1809 oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
1810 oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
1811 oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
1812 oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
1815 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1816 : this (oper, left, right)
1818 this.is_compound = isCompound;
1821 public Binary (Operator oper, Expression left, Expression right)
1826 this.loc = left.Location;
1829 public Operator Oper {
1836 /// Returns a stringified representation of the Operator
1838 string OperName (Operator oper)
1842 case Operator.Multiply:
1845 case Operator.Division:
1848 case Operator.Modulus:
1851 case Operator.Addition:
1854 case Operator.Subtraction:
1857 case Operator.LeftShift:
1860 case Operator.RightShift:
1863 case Operator.LessThan:
1866 case Operator.GreaterThan:
1869 case Operator.LessThanOrEqual:
1872 case Operator.GreaterThanOrEqual:
1875 case Operator.Equality:
1878 case Operator.Inequality:
1881 case Operator.BitwiseAnd:
1884 case Operator.BitwiseOr:
1887 case Operator.ExclusiveOr:
1890 case Operator.LogicalOr:
1893 case Operator.LogicalAnd:
1897 s = oper.ToString ();
1907 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1909 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1912 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1914 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1918 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
1921 // TODO: This should be handled as Type of method group in CSharpName
1922 if (left.eclass == ExprClass.MethodGroup)
1923 l = left.ExprClassName;
1925 l = TypeManager.CSharpName (left.Type);
1927 if (right.eclass == ExprClass.MethodGroup)
1928 r = right.ExprClassName;
1930 r = TypeManager.CSharpName (right.Type);
1932 Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
1935 public static string GetOperatorMetadataName (Operator op)
1937 return oper_names [(int)(op & Operator.ValuesOnlyMask)];
1940 static bool IsUnsigned (Type t)
1943 t = TypeManager.GetElementType (t);
1945 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1946 t == TypeManager.ushort_type || t == TypeManager.byte_type);
1949 static bool IsFloat (Type t)
1951 return t == TypeManager.float_type || t == TypeManager.double_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 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2338 return DoResolveCore (ec, left, right);
2341 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2343 Expression expr = ResolveOperator (ec);
2345 Error_OperatorCannotBeApplied (left_orig, right_orig);
2347 if (left == null || right == null)
2348 throw new InternalErrorException ("Invalid conversion");
2350 if (oper == Operator.BitwiseOr)
2351 CheckBitwiseOrOnSignExtended ();
2357 // D operator + (D x, D y)
2358 // D operator - (D x, D y)
2360 Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
2362 if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
2363 if ((RootContext.Version != LanguageVersion.ISO_1)) {
2364 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2371 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
2376 ArrayList args = new ArrayList (2);
2378 args = new ArrayList (2);
2379 args.Add (new Argument (left, Argument.AType.Expression));
2380 args.Add (new Argument (right, Argument.AType.Expression));
2382 if (oper == Operator.Addition) {
2383 if (TypeManager.delegate_combine_delegate_delegate == null) {
2384 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2385 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2388 method = TypeManager.delegate_combine_delegate_delegate;
2390 if (TypeManager.delegate_remove_delegate_delegate == null) {
2391 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2392 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2395 method = TypeManager.delegate_remove_delegate_delegate;
2398 return new BinaryDelegate (l, method, args);
2402 // Enumeration operators
2404 Binary ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2408 if (lenum || renum) {
2410 // bool operator == (E x, E y);
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);
2417 if ((oper & Operator.ComparisonMask) != 0) {
2418 type = TypeManager.bool_type;
2419 } else if ((oper & Operator.BitwiseMask) != 0) {
2424 if (!TypeManager.IsEqual (ltype, rtype)) {
2426 temp = Convert.ImplicitConversion (ec, left, rtype, loc);
2431 temp = Convert.ImplicitConversion (ec, right, ltype, loc);
2442 Type underlying_type;
2443 if (lenum && !renum) {
2445 // E operator + (E e, U x)
2446 // E operator - (E e, U x)
2448 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2449 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2450 temp = Convert.ImplicitConversion (ec, right, underlying_type, loc);
2464 // E operator + (U x, E e)
2466 if (oper == Operator.Addition) {
2467 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2468 temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
2479 // U operator - (E e, E f)
2481 if (oper == Operator.Subtraction) {
2482 if (!TypeManager.IsEqual (ltype, rtype))
2485 type = TypeManager.GetEnumUnderlyingType (ltype);
2493 // 7.9.6 Reference type equality operators
2495 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2498 // operator != (object a, object b)
2499 // operator == (object a, object b)
2502 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2504 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2507 type = TypeManager.bool_type;
2508 GenericConstraints constraints;
2510 bool lgen = TypeManager.IsGenericParameter (l);
2512 if (TypeManager.IsEqual (l, r)) {
2515 // Only allow to compare same reference type parameter
2517 constraints = TypeManager.GetTypeParameterConstraints (l);
2518 if (constraints != null && constraints.IsReferenceType)
2524 if (l == TypeManager.anonymous_method_type)
2527 if (TypeManager.IsValueType (l))
2533 bool rgen = TypeManager.IsGenericParameter (r);
2536 // a, Both operands are reference-type values or the value null
2537 // b, One operand is a value of type T where T is a type-parameter and
2538 // the other operand is the value null. Furthermore T does not have the
2539 // value type constrain
2541 if (left is NullLiteral || right is NullLiteral) {
2543 constraints = TypeManager.GetTypeParameterConstraints (l);
2544 if (constraints != null && constraints.HasValueTypeConstraint)
2547 left = new BoxedCast (left, TypeManager.object_type);
2552 constraints = TypeManager.GetTypeParameterConstraints (r);
2553 if (constraints != null && constraints.HasValueTypeConstraint)
2556 right = new BoxedCast (right, TypeManager.object_type);
2562 // An interface is converted to the object before the
2563 // standard conversion is applied. It's not clear from the
2564 // standard but it looks like it works like that.
2567 constraints = TypeManager.GetTypeParameterConstraints (l);
2568 if (constraints == null || constraints.IsReferenceType)
2570 } else if (l.IsInterface) {
2571 l = TypeManager.object_type;
2575 constraints = TypeManager.GetTypeParameterConstraints (r);
2576 if (constraints == null || constraints.IsReferenceType)
2578 } else if (r.IsInterface) {
2579 r = TypeManager.object_type;
2582 const string ref_comparison = "Possible unintended reference comparison. " +
2583 "Consider casting the {0} side of the expression to `string' to compare the values";
2586 // A standard implicit conversion exists from the type of either
2587 // operand to the type of the other operand
2589 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2590 if (l == TypeManager.string_type)
2591 Report.Warning (253, 2, loc, ref_comparison, "right");
2596 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2597 if (r == TypeManager.string_type)
2598 Report.Warning (252, 2, loc, ref_comparison, "left");
2607 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2610 // bool operator == (void* x, void* y);
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);
2617 if ((oper & Operator.ComparisonMask) != 0) {
2620 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2627 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2633 type = TypeManager.bool_type;
2637 if (pointer_operators == null)
2638 CreatePointerOperatorsTable ();
2640 return ResolveOperatorPredefined (ec, pointer_operators, false);
2644 // Build-in operators method overloading
2646 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only)
2648 PredefinedOperator best_operator = null;
2650 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2652 foreach (PredefinedOperator po in operators) {
2653 if ((po.OperatorsMask & oper_mask) == 0)
2656 if (primitives_only) {
2657 if (!po.IsPrimitiveApplicable (l))
2660 if (!po.IsApplicable (ec, left, right))
2664 if (best_operator == null) {
2666 if (primitives_only)
2672 best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
2674 if (best_operator == null) {
2675 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2676 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2683 if (best_operator == null)
2686 return best_operator.ConvertResult (ec, this);
2690 // Performs user-operator overloading
2692 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
2695 if (oper == Operator.LogicalAnd)
2696 user_oper = Operator.BitwiseAnd;
2697 else if (oper == Operator.LogicalOr)
2698 user_oper = Operator.BitwiseOr;
2702 string op = GetOperatorMetadataName (user_oper);
2704 MethodGroupExpr union;
2705 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2706 if (!TypeManager.IsEqual (r, l)) {
2707 MethodGroupExpr right_operators = MemberLookup (
2708 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2709 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2711 union = left_operators;
2716 ArrayList args = new ArrayList (2);
2717 Argument larg = new Argument (left);
2719 Argument rarg = new Argument (right);
2722 union = union.OverloadResolve (ec, ref args, true, loc);
2726 Expression oper_expr;
2728 // TODO: CreateExpressionTree is allocated every time
2729 if (user_oper != oper) {
2730 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
2731 oper == Operator.LogicalAnd, loc).Resolve (ec);
2733 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
2736 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2737 // and not invoke user operator
2739 if ((oper & Operator.EqualityMask) != 0) {
2740 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
2741 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
2742 type = TypeManager.bool_type;
2743 if (left is NullLiteral || right is NullLiteral)
2744 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
2745 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
2747 // Two System.Delegate(s) are never equal
2759 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2764 private void CheckUselessComparison (Constant c, Type type)
2766 if (c == null || !IsTypeIntegral (type)
2767 || c is StringConstant
2768 || c is BoolConstant
2769 || c is FloatConstant
2770 || c is DoubleConstant
2771 || c is DecimalConstant
2777 if (c is ULongConstant) {
2778 ulong uvalue = ((ULongConstant) c).Value;
2779 if (uvalue > long.MaxValue) {
2780 if (type == TypeManager.byte_type ||
2781 type == TypeManager.sbyte_type ||
2782 type == TypeManager.short_type ||
2783 type == TypeManager.ushort_type ||
2784 type == TypeManager.int32_type ||
2785 type == TypeManager.uint32_type ||
2786 type == TypeManager.int64_type ||
2787 type == TypeManager.char_type)
2788 WarnUselessComparison (type);
2791 value = (long) uvalue;
2793 else if (c is ByteConstant)
2794 value = ((ByteConstant) c).Value;
2795 else if (c is SByteConstant)
2796 value = ((SByteConstant) c).Value;
2797 else if (c is ShortConstant)
2798 value = ((ShortConstant) c).Value;
2799 else if (c is UShortConstant)
2800 value = ((UShortConstant) c).Value;
2801 else if (c is IntConstant)
2802 value = ((IntConstant) c).Value;
2803 else if (c is UIntConstant)
2804 value = ((UIntConstant) c).Value;
2805 else if (c is LongConstant)
2806 value = ((LongConstant) c).Value;
2807 else if (c is CharConstant)
2808 value = ((CharConstant)c).Value;
2813 if (IsValueOutOfRange (value, type))
2814 WarnUselessComparison (type);
2817 private bool IsValueOutOfRange (long value, Type type)
2819 if (IsTypeUnsigned (type) && value < 0)
2821 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2822 type == TypeManager.byte_type && value >= 0x100 ||
2823 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2824 type == TypeManager.ushort_type && value >= 0x10000 ||
2825 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2826 type == TypeManager.uint32_type && value >= 0x100000000;
2829 static bool IsBuildInEqualityOperator (Type t)
2831 return t == TypeManager.object_type || t == TypeManager.string_type ||
2832 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
2835 private static bool IsTypeIntegral (Type type)
2837 return type == TypeManager.uint64_type ||
2838 type == TypeManager.int64_type ||
2839 type == TypeManager.uint32_type ||
2840 type == TypeManager.int32_type ||
2841 type == TypeManager.ushort_type ||
2842 type == TypeManager.short_type ||
2843 type == TypeManager.sbyte_type ||
2844 type == TypeManager.byte_type ||
2845 type == TypeManager.char_type;
2848 private static bool IsTypeUnsigned (Type type)
2850 return type == TypeManager.uint64_type ||
2851 type == TypeManager.uint32_type ||
2852 type == TypeManager.ushort_type ||
2853 type == TypeManager.byte_type ||
2854 type == TypeManager.char_type;
2857 private void WarnUselessComparison (Type type)
2859 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}'",
2860 TypeManager.CSharpName (type));
2864 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2865 /// context of a conditional bool expression. This function will return
2866 /// false if it is was possible to use EmitBranchable, or true if it was.
2868 /// The expression's code is generated, and we will generate a branch to `target'
2869 /// if the resulting expression value is equal to isTrue
2871 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2873 ILGenerator ig = ec.ig;
2876 // This is more complicated than it looks, but its just to avoid
2877 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2878 // but on top of that we want for == and != to use a special path
2879 // if we are comparing against null
2881 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2882 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
2885 // put the constant on the rhs, for simplicity
2887 if (left is Constant) {
2888 Expression swap = right;
2893 if (((Constant) right).IsZeroInteger) {
2896 ig.Emit (OpCodes.Brtrue, target);
2898 ig.Emit (OpCodes.Brfalse, target);
2901 } else if (right is BoolConstant) {
2903 if (my_on_true != ((BoolConstant) right).Value)
2904 ig.Emit (OpCodes.Brtrue, target);
2906 ig.Emit (OpCodes.Brfalse, target);
2911 } else if (oper == Operator.LogicalAnd) {
2914 Label tests_end = ig.DefineLabel ();
2916 left.EmitBranchable (ec, tests_end, false);
2917 right.EmitBranchable (ec, target, true);
2918 ig.MarkLabel (tests_end);
2921 // This optimizes code like this
2922 // if (true && i > 4)
2924 if (!(left is Constant))
2925 left.EmitBranchable (ec, target, false);
2927 if (!(right is Constant))
2928 right.EmitBranchable (ec, target, false);
2933 } else if (oper == Operator.LogicalOr){
2935 left.EmitBranchable (ec, target, true);
2936 right.EmitBranchable (ec, target, true);
2939 Label tests_end = ig.DefineLabel ();
2940 left.EmitBranchable (ec, tests_end, true);
2941 right.EmitBranchable (ec, target, false);
2942 ig.MarkLabel (tests_end);
2947 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2948 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2949 oper == Operator.Equality || oper == Operator.Inequality)) {
2950 base.EmitBranchable (ec, target, on_true);
2958 bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2961 case Operator.Equality:
2963 ig.Emit (OpCodes.Beq, target);
2965 ig.Emit (OpCodes.Bne_Un, target);
2968 case Operator.Inequality:
2970 ig.Emit (OpCodes.Bne_Un, target);
2972 ig.Emit (OpCodes.Beq, target);
2975 case Operator.LessThan:
2978 ig.Emit (OpCodes.Blt_Un, target);
2980 ig.Emit (OpCodes.Blt, target);
2983 ig.Emit (OpCodes.Bge_Un, target);
2985 ig.Emit (OpCodes.Bge, target);
2988 case Operator.GreaterThan:
2991 ig.Emit (OpCodes.Bgt_Un, target);
2993 ig.Emit (OpCodes.Bgt, target);
2996 ig.Emit (OpCodes.Ble_Un, target);
2998 ig.Emit (OpCodes.Ble, target);
3001 case Operator.LessThanOrEqual:
3004 ig.Emit (OpCodes.Ble_Un, target);
3006 ig.Emit (OpCodes.Ble, target);
3009 ig.Emit (OpCodes.Bgt_Un, target);
3011 ig.Emit (OpCodes.Bgt, target);
3015 case Operator.GreaterThanOrEqual:
3018 ig.Emit (OpCodes.Bge_Un, target);
3020 ig.Emit (OpCodes.Bge, target);
3023 ig.Emit (OpCodes.Blt_Un, target);
3025 ig.Emit (OpCodes.Blt, target);
3028 throw new InternalErrorException (oper.ToString ());
3032 public override void Emit (EmitContext ec)
3037 protected void EmitOperator (EmitContext ec)
3039 ILGenerator ig = ec.ig;
3042 // Handle short-circuit operators differently
3045 if ((oper & Operator.LogicalMask) != 0) {
3046 Label load_result = ig.DefineLabel ();
3047 Label end = ig.DefineLabel ();
3049 bool is_or = oper == Operator.LogicalOr;
3050 left.EmitBranchable (ec, load_result, is_or);
3052 ig.Emit (OpCodes.Br_S, end);
3054 ig.MarkLabel (load_result);
3055 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3063 // Optimize zero-based operations
3065 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3067 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3068 Constant rc = right as Constant;
3069 if (rc != null && rc.IsDefaultValue) {
3080 case Operator.Multiply:
3082 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3083 opcode = OpCodes.Mul_Ovf;
3084 else if (!IsFloat (l))
3085 opcode = OpCodes.Mul_Ovf_Un;
3087 opcode = OpCodes.Mul;
3089 opcode = OpCodes.Mul;
3093 case Operator.Division:
3095 opcode = OpCodes.Div_Un;
3097 opcode = OpCodes.Div;
3100 case Operator.Modulus:
3102 opcode = OpCodes.Rem_Un;
3104 opcode = OpCodes.Rem;
3107 case Operator.Addition:
3109 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3110 opcode = OpCodes.Add_Ovf;
3111 else if (!IsFloat (l))
3112 opcode = OpCodes.Add_Ovf_Un;
3114 opcode = OpCodes.Add;
3116 opcode = OpCodes.Add;
3119 case Operator.Subtraction:
3121 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3122 opcode = OpCodes.Sub_Ovf;
3123 else if (!IsFloat (l))
3124 opcode = OpCodes.Sub_Ovf_Un;
3126 opcode = OpCodes.Sub;
3128 opcode = OpCodes.Sub;
3131 case Operator.RightShift:
3133 opcode = OpCodes.Shr_Un;
3135 opcode = OpCodes.Shr;
3138 case Operator.LeftShift:
3139 opcode = OpCodes.Shl;
3142 case Operator.Equality:
3143 opcode = OpCodes.Ceq;
3146 case Operator.Inequality:
3147 ig.Emit (OpCodes.Ceq);
3148 ig.Emit (OpCodes.Ldc_I4_0);
3150 opcode = OpCodes.Ceq;
3153 case Operator.LessThan:
3155 opcode = OpCodes.Clt_Un;
3157 opcode = OpCodes.Clt;
3160 case Operator.GreaterThan:
3162 opcode = OpCodes.Cgt_Un;
3164 opcode = OpCodes.Cgt;
3167 case Operator.LessThanOrEqual:
3168 if (IsUnsigned (l) || IsFloat (l))
3169 ig.Emit (OpCodes.Cgt_Un);
3171 ig.Emit (OpCodes.Cgt);
3172 ig.Emit (OpCodes.Ldc_I4_0);
3174 opcode = OpCodes.Ceq;
3177 case Operator.GreaterThanOrEqual:
3178 if (IsUnsigned (l) || IsFloat (l))
3179 ig.Emit (OpCodes.Clt_Un);
3181 ig.Emit (OpCodes.Clt);
3183 ig.Emit (OpCodes.Ldc_I4_0);
3185 opcode = OpCodes.Ceq;
3188 case Operator.BitwiseOr:
3189 opcode = OpCodes.Or;
3192 case Operator.BitwiseAnd:
3193 opcode = OpCodes.And;
3196 case Operator.ExclusiveOr:
3197 opcode = OpCodes.Xor;
3201 throw new InternalErrorException (oper.ToString ());
3207 protected override void CloneTo (CloneContext clonectx, Expression t)
3209 Binary target = (Binary) t;
3211 target.left = left.Clone (clonectx);
3212 target.right = right.Clone (clonectx);
3215 public override Expression CreateExpressionTree (EmitContext ec)
3217 return CreateExpressionTree (ec, null);
3220 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3223 bool lift_arg = false;
3226 case Operator.Addition:
3227 if (method == null && ec.CheckState && !IsFloat (left.Type))
3228 method_name = "AddChecked";
3230 method_name = "Add";
3232 case Operator.BitwiseAnd:
3233 method_name = "And";
3235 case Operator.BitwiseOr:
3238 case Operator.Division:
3239 method_name = "Divide";
3241 case Operator.Equality:
3242 method_name = "Equal";
3245 case Operator.ExclusiveOr:
3246 method_name = "ExclusiveOr";
3248 case Operator.GreaterThan:
3249 method_name = "GreaterThan";
3252 case Operator.GreaterThanOrEqual:
3253 method_name = "GreaterThanOrEqual";
3256 case Operator.Inequality:
3257 method_name = "NotEqual";
3260 case Operator.LeftShift:
3261 method_name = "LeftShift";
3263 case Operator.LessThan:
3264 method_name = "LessThan";
3267 case Operator.LessThanOrEqual:
3268 method_name = "LessThanOrEqual";
3271 case Operator.LogicalAnd:
3272 method_name = "AndAlso";
3274 case Operator.LogicalOr:
3275 method_name = "OrElse";
3277 case Operator.Modulus:
3278 method_name = "Modulo";
3280 case Operator.Multiply:
3281 if (method == null && ec.CheckState && !IsFloat (left.Type))
3282 method_name = "MultiplyChecked";
3284 method_name = "Multiply";
3286 case Operator.RightShift:
3287 method_name = "RightShift";
3289 case Operator.Subtraction:
3290 if (method == null && ec.CheckState && !IsFloat (left.Type))
3291 method_name = "SubtractChecked";
3293 method_name = "Subtract";
3297 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3300 ArrayList args = new ArrayList (2);
3301 args.Add (new Argument (left.CreateExpressionTree (ec)));
3302 args.Add (new Argument (right.CreateExpressionTree (ec)));
3303 if (method != null) {
3305 args.Add (new Argument (new BoolConstant (false, loc)));
3307 args.Add (new Argument (method.CreateExpressionTree (ec)));
3310 return CreateExpressionFactoryCall (method_name, args);
3315 // Object created by Binary when the binary operator uses an method instead of being
3316 // a binary operation that maps to a CIL binary operation.
3318 public class BinaryMethod : Expression {
3319 public MethodBase method;
3320 public ArrayList Arguments;
3322 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3327 eclass = ExprClass.Value;
3330 public override Expression DoResolve (EmitContext ec)
3335 public override void Emit (EmitContext ec)
3337 ILGenerator ig = ec.ig;
3339 Invocation.EmitArguments (ec, Arguments, false, null);
3341 if (method is MethodInfo)
3342 ig.Emit (OpCodes.Call, (MethodInfo) method);
3344 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3349 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3350 // b, c, d... may be strings or objects.
3352 public class StringConcat : Expression {
3353 ArrayList arguments;
3355 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3358 type = TypeManager.string_type;
3359 eclass = ExprClass.Value;
3361 arguments = new ArrayList (2);
3366 public override Expression CreateExpressionTree (EmitContext ec)
3368 Argument arg = (Argument) arguments [0];
3369 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3373 // Creates nested calls tree from an array of arguments used for IL emit
3375 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3377 ArrayList concat_args = new ArrayList (2);
3378 ArrayList add_args = new ArrayList (3);
3380 concat_args.Add (left);
3381 add_args.Add (new Argument (left_etree));
3383 concat_args.Add (arguments [pos]);
3384 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3386 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3390 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3394 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3396 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3397 if (++pos == arguments.Count)
3400 left = new Argument (new EmptyExpression (method.Type));
3401 return CreateExpressionAddCall (ec, left, expr, pos);
3404 public override Expression DoResolve (EmitContext ec)
3409 public void Append (EmitContext ec, Expression operand)
3414 StringConstant sc = operand as StringConstant;
3416 if (arguments.Count != 0) {
3417 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3418 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3419 if (last_expr_constant != null) {
3420 last_argument.Expr = new StringConstant (
3421 last_expr_constant.Value + sc.Value, sc.Location);
3427 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3429 StringConcat concat_oper = operand as StringConcat;
3430 if (concat_oper != null) {
3431 arguments.AddRange (concat_oper.arguments);
3436 arguments.Add (new Argument (operand));
3439 Expression CreateConcatMemberExpression ()
3441 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3444 public override void Emit (EmitContext ec)
3446 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3447 concat = concat.Resolve (ec);
3454 // Object created with +/= on delegates
3456 public class BinaryDelegate : Expression {
3460 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3465 eclass = ExprClass.Value;
3468 public override Expression DoResolve (EmitContext ec)
3473 public override void Emit (EmitContext ec)
3475 ILGenerator ig = ec.ig;
3477 Invocation.EmitArguments (ec, args, false, null);
3479 ig.Emit (OpCodes.Call, (MethodInfo) method);
3480 ig.Emit (OpCodes.Castclass, type);
3483 public Expression Right {
3485 Argument arg = (Argument) args [1];
3490 public bool IsAddition {
3492 return method == TypeManager.delegate_combine_delegate_delegate;
3498 // User-defined conditional logical operator
3500 public class ConditionalLogicalOperator : UserOperatorCall {
3501 readonly bool is_and;
3504 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3505 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3506 : base (oper_method, arguments, expr_tree, loc)
3508 this.is_and = is_and;
3511 public override Expression DoResolve (EmitContext ec)
3513 MethodInfo method = (MethodInfo)mg;
3514 type = TypeManager.TypeToCoreType (method.ReturnType);
3515 ParameterData pd = TypeManager.GetParameterData (method);
3516 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3517 Report.Error (217, loc,
3518 "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
3519 TypeManager.CSharpSignature (method));
3523 Expression left_dup = new EmptyExpression (type);
3524 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3525 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3526 if (op_true == null || op_false == null) {
3527 Report.Error (218, loc,
3528 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3529 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3533 oper = is_and ? op_false : op_true;
3534 eclass = ExprClass.Value;
3538 public override void Emit (EmitContext ec)
3540 ILGenerator ig = ec.ig;
3541 Label end_target = ig.DefineLabel ();
3544 // Emit and duplicate left argument
3546 ((Argument)arguments [0]).Expr.Emit (ec);
3547 ig.Emit (OpCodes.Dup);
3548 arguments.RemoveAt (0);
3550 oper.EmitBranchable (ec, end_target, true);
3552 ig.MarkLabel (end_target);
3556 public class PointerArithmetic : Expression {
3557 Expression left, right;
3561 // We assume that `l' is always a pointer
3563 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3569 is_add = is_addition;
3572 public override Expression DoResolve (EmitContext ec)
3574 eclass = ExprClass.Variable;
3576 if (left.Type == TypeManager.void_ptr_type) {
3577 Error (242, "The operation in question is undefined on void pointers");
3584 public override void Emit (EmitContext ec)
3586 Type op_type = left.Type;
3587 ILGenerator ig = ec.ig;
3589 // It must be either array or fixed buffer
3590 Type element = TypeManager.HasElementType (op_type) ?
3591 element = TypeManager.GetElementType (op_type) :
3592 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3594 int size = GetTypeSize (element);
3595 Type rtype = right.Type;
3597 if (rtype.IsPointer){
3599 // handle (pointer - pointer)
3603 ig.Emit (OpCodes.Sub);
3607 ig.Emit (OpCodes.Sizeof, element);
3609 IntLiteral.EmitInt (ig, size);
3610 ig.Emit (OpCodes.Div);
3612 ig.Emit (OpCodes.Conv_I8);
3615 // handle + and - on (pointer op int)
3618 ig.Emit (OpCodes.Conv_I);
3620 Constant right_const = right as Constant;
3621 if (right_const != null && size != 0) {
3622 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3630 ig.Emit (OpCodes.Sizeof, element);
3632 IntLiteral.EmitInt (ig, size);
3633 if (rtype == TypeManager.int64_type)
3634 ig.Emit (OpCodes.Conv_I8);
3635 else if (rtype == TypeManager.uint64_type)
3636 ig.Emit (OpCodes.Conv_U8);
3637 ig.Emit (OpCodes.Mul);
3641 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3642 ig.Emit (OpCodes.Conv_I);
3645 ig.Emit (OpCodes.Add);
3647 ig.Emit (OpCodes.Sub);
3653 /// Implements the ternary conditional operator (?:)
3655 public class Conditional : Expression {
3656 Expression expr, true_expr, false_expr;
3658 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3661 this.true_expr = true_expr;
3662 this.false_expr = false_expr;
3663 this.loc = expr.Location;
3666 public Expression Expr {
3672 public Expression TrueExpr {
3678 public Expression FalseExpr {
3684 public override Expression CreateExpressionTree (EmitContext ec)
3686 ArrayList args = new ArrayList (3);
3687 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3688 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3689 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3690 return CreateExpressionFactoryCall ("Condition", args);
3693 public override Expression DoResolve (EmitContext ec)
3695 expr = expr.Resolve (ec);
3700 if (expr.Type != TypeManager.bool_type){
3701 expr = Expression.ResolveBoolean (
3708 Assign ass = expr as Assign;
3709 if (ass != null && ass.Source is Constant) {
3710 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3713 true_expr = true_expr.Resolve (ec);
3714 false_expr = false_expr.Resolve (ec);
3716 if (true_expr == null || false_expr == null)
3719 eclass = ExprClass.Value;
3720 if (true_expr.Type == false_expr.Type) {
3721 type = true_expr.Type;
3722 if (type == TypeManager.null_type) {
3723 // TODO: probably will have to implement ConditionalConstant
3724 // to call method without return constant as well
3725 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3730 Type true_type = true_expr.Type;
3731 Type false_type = false_expr.Type;
3734 // First, if an implicit conversion exists from true_expr
3735 // to false_expr, then the result type is of type false_expr.Type
3737 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3740 // Check if both can convert implicitl to each other's type
3742 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3744 "Can not compute type of conditional expression " +
3745 "as `" + TypeManager.CSharpName (true_expr.Type) +
3746 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3747 "' convert implicitly to each other");
3752 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3756 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3757 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3762 // Dead code optimalization
3763 if (expr is BoolConstant){
3764 BoolConstant bc = (BoolConstant) expr;
3766 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3767 return bc.Value ? true_expr : false_expr;
3773 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3778 public override void Emit (EmitContext ec)
3780 ILGenerator ig = ec.ig;
3781 Label false_target = ig.DefineLabel ();
3782 Label end_target = ig.DefineLabel ();
3784 expr.EmitBranchable (ec, false_target, false);
3785 true_expr.Emit (ec);
3787 if (type.IsInterface) {
3788 LocalBuilder temp = ec.GetTemporaryLocal (type);
3789 ig.Emit (OpCodes.Stloc, temp);
3790 ig.Emit (OpCodes.Ldloc, temp);
3791 ec.FreeTemporaryLocal (temp, type);
3794 ig.Emit (OpCodes.Br, end_target);
3795 ig.MarkLabel (false_target);
3796 false_expr.Emit (ec);
3797 ig.MarkLabel (end_target);
3800 protected override void CloneTo (CloneContext clonectx, Expression t)
3802 Conditional target = (Conditional) t;
3804 target.expr = expr.Clone (clonectx);
3805 target.true_expr = true_expr.Clone (clonectx);
3806 target.false_expr = false_expr.Clone (clonectx);
3810 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3812 LocalTemporary temp;
3814 public abstract Variable Variable {
3818 public abstract bool IsRef {
3822 public override void Emit (EmitContext ec)
3828 // This method is used by parameters that are references, that are
3829 // being passed as references: we only want to pass the pointer (that
3830 // is already stored in the parameter, not the address of the pointer,
3831 // and not the value of the variable).
3833 public void EmitLoad (EmitContext ec)
3835 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3837 Variable.EmitInstance (ec);
3841 public void Emit (EmitContext ec, bool leave_copy)
3843 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3849 // If we are a reference, we loaded on the stack a pointer
3850 // Now lets load the real value
3852 LoadFromPtr (ec.ig, type);
3856 ec.ig.Emit (OpCodes.Dup);
3858 if (IsRef || Variable.NeedsTemporary) {
3859 temp = new LocalTemporary (Type);
3865 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3866 bool prepare_for_load)
3868 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3871 ILGenerator ig = ec.ig;
3872 prepared = prepare_for_load;
3874 Variable.EmitInstance (ec);
3875 if (prepare_for_load) {
3876 if (Variable.HasInstance)
3877 ig.Emit (OpCodes.Dup);
3885 // HACK: variable is already emitted when source is an initializer
3886 if (source is NewInitialize)
3890 ig.Emit (OpCodes.Dup);
3891 if (IsRef || Variable.NeedsTemporary) {
3892 temp = new LocalTemporary (Type);
3898 StoreFromPtr (ig, type);
3900 Variable.EmitAssign (ec);
3908 public void AddressOf (EmitContext ec, AddressOp mode)
3910 Variable.EmitInstance (ec);
3911 Variable.EmitAddressOf (ec);
3918 public class LocalVariableReference : VariableReference, IVariable {
3919 public readonly string Name;
3921 public LocalInfo local_info;
3925 public LocalVariableReference (Block block, string name, Location l)
3930 eclass = ExprClass.Variable;
3934 // Setting `is_readonly' to false will allow you to create a writable
3935 // reference to a read-only variable. This is used by foreach and using.
3937 public LocalVariableReference (Block block, string name, Location l,
3938 LocalInfo local_info, bool is_readonly)
3939 : this (block, name, l)
3941 this.local_info = local_info;
3942 this.is_readonly = is_readonly;
3945 public VariableInfo VariableInfo {
3946 get { return local_info.VariableInfo; }
3949 public override bool IsRef {
3950 get { return false; }
3953 public bool IsReadOnly {
3954 get { return is_readonly; }
3957 public bool VerifyAssigned (EmitContext ec)
3959 VariableInfo variable_info = local_info.VariableInfo;
3960 return variable_info == null || variable_info.IsAssigned (ec, loc);
3963 void ResolveLocalInfo ()
3965 if (local_info == null) {
3966 local_info = Block.GetLocalInfo (Name);
3967 type = local_info.VariableType;
3968 is_readonly = local_info.ReadOnly;
3972 public override Expression CreateExpressionTree (EmitContext ec)
3974 ArrayList arg = new ArrayList (1);
3975 arg.Add (new Argument (this));
3976 return CreateExpressionFactoryCall ("Constant", arg);
3979 protected Expression DoResolveBase (EmitContext ec)
3981 type = local_info.VariableType;
3983 Expression e = Block.GetConstantExpression (Name);
3985 return e.Resolve (ec);
3987 if (!VerifyAssigned (ec))
3991 // If we are referencing a variable from the external block
3992 // flag it for capturing
3994 if (ec.MustCaptureVariable (local_info)) {
3995 if (local_info.AddressTaken){
3996 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
4000 if (!ec.IsInProbingMode)
4002 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
4003 variable = scope.AddLocal (local_info);
4004 type = variable.Type;
4011 public override Expression DoResolve (EmitContext ec)
4013 ResolveLocalInfo ();
4014 local_info.Used = true;
4016 if (type == null && local_info.Type is VarExpr) {
4017 local_info.VariableType = TypeManager.object_type;
4018 Error_VariableIsUsedBeforeItIsDeclared (Name);
4022 return DoResolveBase (ec);
4025 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4027 ResolveLocalInfo ();
4030 if (right_side == EmptyExpression.OutAccess)
4031 local_info.Used = true;
4033 // Infer implicitly typed local variable
4035 VarExpr ve = local_info.Type as VarExpr;
4037 ve.DoResolveLValue (ec, right_side);
4038 type = local_info.VariableType = ve.Type;
4045 if (right_side == EmptyExpression.OutAccess) {
4046 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4047 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4048 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4049 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4050 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4052 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4054 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4058 if (VariableInfo != null)
4059 VariableInfo.SetAssigned (ec);
4061 return DoResolveBase (ec);
4064 public bool VerifyFixed ()
4066 // A local Variable is always fixed.
4070 public override int GetHashCode ()
4072 return Name.GetHashCode ();
4075 public override bool Equals (object obj)
4077 LocalVariableReference lvr = obj as LocalVariableReference;
4081 return Name == lvr.Name && Block == lvr.Block;
4084 public override Variable Variable {
4085 get { return variable != null ? variable : local_info.Variable; }
4088 public override string ToString ()
4090 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4093 protected override void CloneTo (CloneContext clonectx, Expression t)
4095 LocalVariableReference target = (LocalVariableReference) t;
4097 target.Block = clonectx.LookupBlock (Block);
4098 if (local_info != null)
4099 target.local_info = clonectx.LookupVariable (local_info);
4104 /// This represents a reference to a parameter in the intermediate
4107 public class ParameterReference : VariableReference, IVariable {
4108 readonly ToplevelParameterInfo pi;
4109 readonly ToplevelBlock referenced;
4112 public bool is_ref, is_out;
4115 get { return is_out; }
4118 public override bool IsRef {
4119 get { return is_ref; }
4122 public string Name {
4123 get { return Parameter.Name; }
4126 public Parameter Parameter {
4127 get { return pi.Parameter; }
4130 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4133 this.referenced = referenced;
4135 eclass = ExprClass.Variable;
4138 public VariableInfo VariableInfo {
4139 get { return pi.VariableInfo; }
4142 public override Variable Variable {
4143 get { return variable != null ? variable : Parameter.Variable; }
4146 public bool VerifyFixed ()
4148 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4149 return Parameter.ModFlags == Parameter.Modifier.NONE;
4152 public bool IsAssigned (EmitContext ec, Location loc)
4154 // HACK: Variables are not captured in probing mode
4155 if (ec.IsInProbingMode)
4158 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
4161 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4165 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4167 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
4170 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
4174 public void SetAssigned (EmitContext ec)
4176 if (is_out && ec.DoFlowAnalysis)
4177 ec.CurrentBranching.SetAssigned (VariableInfo);
4180 public void SetFieldAssigned (EmitContext ec, string field_name)
4182 if (is_out && ec.DoFlowAnalysis)
4183 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
4186 protected bool DoResolveBase (EmitContext ec)
4188 Parameter par = Parameter;
4189 if (!par.Resolve (ec)) {
4193 type = par.ParameterType;
4194 Parameter.Modifier mod = par.ModFlags;
4195 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4196 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
4197 eclass = ExprClass.Variable;
4199 AnonymousContainer am = ec.CurrentAnonymousMethod;
4203 ToplevelBlock declared = pi.Block;
4204 if (is_ref && declared != referenced) {
4205 Report.Error (1628, Location,
4206 "Cannot use ref or out parameter `{0}' inside an " +
4207 "anonymous method block", par.Name);
4211 if (!am.IsIterator && declared == referenced)
4214 // Don't capture aruments when the probing is on
4215 if (!ec.IsInProbingMode) {
4216 ScopeInfo scope = declared.CreateScopeInfo ();
4217 variable = scope.AddParameter (par, pi.Index);
4218 type = variable.Type;
4223 public override int GetHashCode ()
4225 return Name.GetHashCode ();
4228 public override bool Equals (object obj)
4230 ParameterReference pr = obj as ParameterReference;
4234 return Name == pr.Name && referenced == pr.referenced;
4237 public override Expression CreateExpressionTree (EmitContext ec)
4239 return Parameter.ExpressionTreeVariableReference ();
4243 // Notice that for ref/out parameters, the type exposed is not the
4244 // same type exposed externally.
4247 // externally we expose "int&"
4248 // here we expose "int".
4250 // We record this in "is_ref". This means that the type system can treat
4251 // the type as it is expected, but when we generate the code, we generate
4252 // the alternate kind of code.
4254 public override Expression DoResolve (EmitContext ec)
4256 if (!DoResolveBase (ec))
4259 if (is_out && ec.DoFlowAnalysis &&
4260 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4266 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4268 if (!DoResolveBase (ec))
4271 // HACK: parameters are not captured when probing is on
4272 if (!ec.IsInProbingMode)
4278 static public void EmitLdArg (ILGenerator ig, int x)
4282 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4283 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4284 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4285 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4286 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4289 ig.Emit (OpCodes.Ldarg, x);
4292 public override string ToString ()
4294 return "ParameterReference[" + Name + "]";
4299 /// Used for arguments to New(), Invocation()
4301 public class Argument {
4302 public enum AType : byte {
4309 public static readonly Argument[] Empty = new Argument [0];
4311 public readonly AType ArgType;
4312 public Expression Expr;
4314 public Argument (Expression expr, AType type)
4317 this.ArgType = type;
4320 public Argument (Expression expr)
4323 this.ArgType = AType.Expression;
4328 if (ArgType == AType.Ref || ArgType == AType.Out)
4329 return TypeManager.GetReferenceType (Expr.Type);
4335 public Parameter.Modifier Modifier
4340 return Parameter.Modifier.OUT;
4343 return Parameter.Modifier.REF;
4346 return Parameter.Modifier.NONE;
4351 public string GetSignatureForError ()
4353 if (Expr.eclass == ExprClass.MethodGroup)
4354 return Expr.ExprClassName;
4356 return Expr.GetSignatureForError ();
4359 public bool ResolveMethodGroup (EmitContext ec)
4361 SimpleName sn = Expr as SimpleName;
4363 Expr = sn.GetMethodGroup ();
4365 // FIXME: csc doesn't report any error if you try to use `ref' or
4366 // `out' in a delegate creation expression.
4367 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4374 public bool Resolve (EmitContext ec, Location loc)
4376 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4377 // Verify that the argument is readable
4378 if (ArgType != AType.Out)
4379 Expr = Expr.Resolve (ec);
4381 // Verify that the argument is writeable
4382 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4383 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4385 return Expr != null;
4389 public void Emit (EmitContext ec)
4391 if (ArgType != AType.Ref && ArgType != AType.Out) {
4396 AddressOp mode = AddressOp.Store;
4397 if (ArgType == AType.Ref)
4398 mode |= AddressOp.Load;
4400 IMemoryLocation ml = (IMemoryLocation) Expr;
4401 ParameterReference pr = ml as ParameterReference;
4404 // ParameterReferences might already be references, so we want
4405 // to pass just the value
4407 if (pr != null && pr.IsRef)
4410 ml.AddressOf (ec, mode);
4413 public Argument Clone (CloneContext clonectx)
4415 return new Argument (Expr.Clone (clonectx), ArgType);
4420 /// Invocation of methods or delegates.
4422 public class Invocation : ExpressionStatement {
4423 protected ArrayList Arguments;
4424 protected Expression expr;
4425 protected MethodGroupExpr mg;
4426 bool arguments_resolved;
4429 // arguments is an ArrayList, but we do not want to typecast,
4430 // as it might be null.
4432 public Invocation (Expression expr, ArrayList arguments)
4434 SimpleName sn = expr as SimpleName;
4436 this.expr = sn.GetMethodGroup ();
4440 Arguments = arguments;
4442 loc = expr.Location;
4445 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4446 : this (expr, arguments)
4448 this.arguments_resolved = arguments_resolved;
4451 public override Expression CreateExpressionTree (EmitContext ec)
4456 // Special conversion for nested expression trees
4458 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4459 args = new ArrayList (1);
4460 args.Add (new Argument (this));
4461 return CreateExpressionFactoryCall ("Quote", args);
4464 args = new ArrayList (Arguments.Count + 3);
4466 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4468 args.Add (new Argument (new NullLiteral (loc).CreateExpressionTree (ec)));
4470 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4471 foreach (Argument a in Arguments) {
4472 Expression e = a.Expr.CreateExpressionTree (ec);
4474 args.Add (new Argument (e));
4477 return CreateExpressionFactoryCall ("Call", args);
4480 public override Expression DoResolve (EmitContext ec)
4482 // Don't resolve already resolved expression
4483 if (eclass != ExprClass.Invalid)
4486 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4487 if (expr_resolved == null)
4490 mg = expr_resolved as MethodGroupExpr;
4492 Type expr_type = expr_resolved.Type;
4494 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4495 return (new DelegateInvocation (
4496 expr_resolved, Arguments, loc)).Resolve (ec);
4499 MemberExpr me = expr_resolved as MemberExpr;
4501 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4505 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4507 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4508 expr_resolved.GetSignatureForError ());
4512 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4516 // Next, evaluate all the expressions in the argument list
4518 if (Arguments != null && !arguments_resolved) {
4519 for (int i = 0; i < Arguments.Count; ++i)
4521 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4526 mg = DoResolveOverload (ec);
4530 MethodInfo method = (MethodInfo)mg;
4531 if (method != null) {
4532 type = TypeManager.TypeToCoreType (method.ReturnType);
4534 // TODO: this is a copy of mg.ResolveMemberAccess method
4535 Expression iexpr = mg.InstanceExpression;
4536 if (method.IsStatic) {
4537 if (iexpr == null ||
4538 iexpr is This || iexpr is EmptyExpression ||
4539 mg.IdenticalTypeName) {
4540 mg.InstanceExpression = null;
4542 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4548 if (type.IsPointer){
4556 // Only base will allow this invocation to happen.
4558 if (mg.IsBase && method.IsAbstract){
4559 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4563 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4565 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4567 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4571 if (IsSpecialMethodInvocation (method)) {
4575 if (mg.InstanceExpression != null)
4576 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4578 eclass = ExprClass.Value;
4582 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4584 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4587 bool IsSpecialMethodInvocation (MethodBase method)
4589 if (!TypeManager.IsSpecialMethod (method))
4592 Report.SymbolRelatedToPreviousError (method);
4593 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4594 TypeManager.CSharpSignature (method, true));
4600 /// Emits a list of resolved Arguments that are in the arguments
4603 /// The MethodBase argument might be null if the
4604 /// emission of the arguments is known not to contain
4605 /// a `params' field (for example in constructors or other routines
4606 /// that keep their arguments in this structure)
4608 /// if `dup_args' is true, a copy of the arguments will be left
4609 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4610 /// which will be duplicated before any other args. Only EmitCall
4611 /// should be using this interface.
4613 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4615 if (arguments == null)
4618 int top = arguments.Count;
4619 LocalTemporary [] temps = null;
4621 if (dup_args && top != 0)
4622 temps = new LocalTemporary [top];
4624 int argument_index = 0;
4626 for (int i = 0; i < top; i++) {
4627 a = (Argument) arguments [argument_index++];
4630 ec.ig.Emit (OpCodes.Dup);
4631 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4636 if (this_arg != null)
4639 for (int i = 0; i < top; i ++) {
4640 temps [i].Emit (ec);
4641 temps [i].Release (ec);
4646 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4648 ParameterData pd = TypeManager.GetParameterData (mb);
4650 if (arguments == null)
4651 return new Type [0];
4653 Argument a = (Argument) arguments [pd.Count - 1];
4654 Arglist list = (Arglist) a.Expr;
4656 return list.ArgumentTypes;
4660 /// This checks the ConditionalAttribute on the method
4662 public static bool IsMethodExcluded (MethodBase method)
4664 if (method.IsConstructor)
4667 method = TypeManager.DropGenericMethodArguments (method);
4668 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4669 IMethodData md = TypeManager.GetMethod (method);
4671 return md.IsExcluded ();
4673 // For some methods (generated by delegate class) GetMethod returns null
4674 // because they are not included in builder_to_method table
4678 return AttributeTester.IsConditionalMethodExcluded (method);
4682 /// is_base tells whether we want to force the use of the `call'
4683 /// opcode instead of using callvirt. Call is required to call
4684 /// a specific method, while callvirt will always use the most
4685 /// recent method in the vtable.
4687 /// is_static tells whether this is an invocation on a static method
4689 /// instance_expr is an expression that represents the instance
4690 /// it must be non-null if is_static is false.
4692 /// method is the method to invoke.
4694 /// Arguments is the list of arguments to pass to the method or constructor.
4696 public static void EmitCall (EmitContext ec, bool is_base,
4697 Expression instance_expr,
4698 MethodBase method, ArrayList Arguments, Location loc)
4700 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4703 // `dup_args' leaves an extra copy of the arguments on the stack
4704 // `omit_args' does not leave any arguments at all.
4705 // So, basically, you could make one call with `dup_args' set to true,
4706 // and then another with `omit_args' set to true, and the two calls
4707 // would have the same set of arguments. However, each argument would
4708 // only have been evaluated once.
4709 public static void EmitCall (EmitContext ec, bool is_base,
4710 Expression instance_expr,
4711 MethodBase method, ArrayList Arguments, Location loc,
4712 bool dup_args, bool omit_args)
4714 ILGenerator ig = ec.ig;
4715 bool struct_call = false;
4716 bool this_call = false;
4717 LocalTemporary this_arg = null;
4719 Type decl_type = method.DeclaringType;
4721 if (!ec.IsInObsoleteScope) {
4723 // This checks ObsoleteAttribute on the method and on the declaring type
4725 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4727 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4729 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4731 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4735 if (IsMethodExcluded (method))
4738 bool is_static = method.IsStatic;
4740 if (instance_expr == EmptyExpression.Null) {
4741 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4745 this_call = instance_expr is This;
4746 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4750 // If this is ourselves, push "this"
4754 Type iexpr_type = instance_expr.Type;
4757 // Push the instance expression
4759 if (TypeManager.IsValueType (iexpr_type)) {
4761 // Special case: calls to a function declared in a
4762 // reference-type with a value-type argument need
4763 // to have their value boxed.
4764 if (decl_type.IsValueType ||
4765 TypeManager.IsGenericParameter (iexpr_type)) {
4767 // If the expression implements IMemoryLocation, then
4768 // we can optimize and use AddressOf on the
4771 // If not we have to use some temporary storage for
4773 if (instance_expr is IMemoryLocation) {
4774 ((IMemoryLocation)instance_expr).
4775 AddressOf (ec, AddressOp.LoadStore);
4777 LocalTemporary temp = new LocalTemporary (iexpr_type);
4778 instance_expr.Emit (ec);
4780 temp.AddressOf (ec, AddressOp.Load);
4783 // avoid the overhead of doing this all the time.
4785 t = TypeManager.GetReferenceType (iexpr_type);
4787 instance_expr.Emit (ec);
4788 ig.Emit (OpCodes.Box, instance_expr.Type);
4789 t = TypeManager.object_type;
4792 instance_expr.Emit (ec);
4793 t = instance_expr.Type;
4797 ig.Emit (OpCodes.Dup);
4798 if (Arguments != null && Arguments.Count != 0) {
4799 this_arg = new LocalTemporary (t);
4800 this_arg.Store (ec);
4807 EmitArguments (ec, Arguments, dup_args, this_arg);
4810 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4811 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4815 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4816 call_op = OpCodes.Call;
4818 call_op = OpCodes.Callvirt;
4820 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4821 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4822 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4829 // and DoFoo is not virtual, you can omit the callvirt,
4830 // because you don't need the null checking behavior.
4832 if (method is MethodInfo)
4833 ig.Emit (call_op, (MethodInfo) method);
4835 ig.Emit (call_op, (ConstructorInfo) method);
4838 public override void Emit (EmitContext ec)
4840 mg.EmitCall (ec, Arguments);
4843 public override void EmitStatement (EmitContext ec)
4848 // Pop the return value if there is one
4850 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4851 ec.ig.Emit (OpCodes.Pop);
4854 protected override void CloneTo (CloneContext clonectx, Expression t)
4856 Invocation target = (Invocation) t;
4858 if (Arguments != null) {
4859 target.Arguments = new ArrayList (Arguments.Count);
4860 foreach (Argument a in Arguments)
4861 target.Arguments.Add (a.Clone (clonectx));
4864 target.expr = expr.Clone (clonectx);
4868 public class InvocationOrCast : ExpressionStatement
4871 Expression argument;
4873 public InvocationOrCast (Expression expr, Expression argument)
4876 this.argument = argument;
4877 this.loc = expr.Location;
4880 public override Expression DoResolve (EmitContext ec)
4883 // First try to resolve it as a cast.
4885 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4886 if ((te != null) && (te.eclass == ExprClass.Type)) {
4887 Cast cast = new Cast (te, argument, loc);
4888 return cast.Resolve (ec);
4892 // This can either be a type or a delegate invocation.
4893 // Let's just resolve it and see what we'll get.
4895 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4900 // Ok, so it's a Cast.
4902 if (expr.eclass == ExprClass.Type) {
4903 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4904 return cast.Resolve (ec);
4908 // It's a delegate invocation.
4910 if (!TypeManager.IsDelegateType (expr.Type)) {
4911 Error (149, "Method name expected");
4915 ArrayList args = new ArrayList ();
4916 args.Add (new Argument (argument, Argument.AType.Expression));
4917 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4918 return invocation.Resolve (ec);
4921 public override ExpressionStatement ResolveStatement (EmitContext ec)
4924 // First try to resolve it as a cast.
4926 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4927 if ((te != null) && (te.eclass == ExprClass.Type)) {
4928 Error_InvalidExpressionStatement ();
4933 // This can either be a type or a delegate invocation.
4934 // Let's just resolve it and see what we'll get.
4936 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4937 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4938 Error_InvalidExpressionStatement ();
4943 // It's a delegate invocation.
4945 if (!TypeManager.IsDelegateType (expr.Type)) {
4946 Error (149, "Method name expected");
4950 ArrayList args = new ArrayList ();
4951 args.Add (new Argument (argument, Argument.AType.Expression));
4952 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4953 return invocation.ResolveStatement (ec);
4956 public override void Emit (EmitContext ec)
4958 throw new Exception ("Cannot happen");
4961 public override void EmitStatement (EmitContext ec)
4963 throw new Exception ("Cannot happen");
4966 protected override void CloneTo (CloneContext clonectx, Expression t)
4968 InvocationOrCast target = (InvocationOrCast) t;
4970 target.expr = expr.Clone (clonectx);
4971 target.argument = argument.Clone (clonectx);
4976 // This class is used to "disable" the code generation for the
4977 // temporary variable when initializing value types.
4979 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4980 public void AddressOf (EmitContext ec, AddressOp Mode)
4987 /// Implements the new expression
4989 public class New : ExpressionStatement, IMemoryLocation {
4990 ArrayList Arguments;
4993 // During bootstrap, it contains the RequestedType,
4994 // but if `type' is not null, it *might* contain a NewDelegate
4995 // (because of field multi-initialization)
4997 public Expression RequestedType;
4999 MethodGroupExpr method;
5002 // If set, the new expression is for a value_target, and
5003 // we will not leave anything on the stack.
5005 protected Expression value_target;
5006 protected bool value_target_set;
5007 bool is_type_parameter = false;
5009 public New (Expression requested_type, ArrayList arguments, Location l)
5011 RequestedType = requested_type;
5012 Arguments = arguments;
5016 public bool SetTargetVariable (Expression value)
5018 value_target = value;
5019 value_target_set = true;
5020 if (!(value_target is IMemoryLocation)){
5021 Error_UnexpectedKind (null, "variable", loc);
5028 // This function is used to disable the following code sequence for
5029 // value type initialization:
5031 // AddressOf (temporary)
5035 // Instead the provide will have provided us with the address on the
5036 // stack to store the results.
5038 static Expression MyEmptyExpression;
5040 public void DisableTemporaryValueType ()
5042 if (MyEmptyExpression == null)
5043 MyEmptyExpression = new EmptyAddressOf ();
5046 // To enable this, look into:
5047 // test-34 and test-89 and self bootstrapping.
5049 // For instance, we can avoid a copy by using `newobj'
5050 // instead of Call + Push-temp on value types.
5051 // value_target = MyEmptyExpression;
5056 /// Converts complex core type syntax like 'new int ()' to simple constant
5058 public static Constant Constantify (Type t)
5060 if (t == TypeManager.int32_type)
5061 return new IntConstant (0, Location.Null);
5062 if (t == TypeManager.uint32_type)
5063 return new UIntConstant (0, Location.Null);
5064 if (t == TypeManager.int64_type)
5065 return new LongConstant (0, Location.Null);
5066 if (t == TypeManager.uint64_type)
5067 return new ULongConstant (0, Location.Null);
5068 if (t == TypeManager.float_type)
5069 return new FloatConstant (0, Location.Null);
5070 if (t == TypeManager.double_type)
5071 return new DoubleConstant (0, Location.Null);
5072 if (t == TypeManager.short_type)
5073 return new ShortConstant (0, Location.Null);
5074 if (t == TypeManager.ushort_type)
5075 return new UShortConstant (0, Location.Null);
5076 if (t == TypeManager.sbyte_type)
5077 return new SByteConstant (0, Location.Null);
5078 if (t == TypeManager.byte_type)
5079 return new ByteConstant (0, Location.Null);
5080 if (t == TypeManager.char_type)
5081 return new CharConstant ('\0', Location.Null);
5082 if (t == TypeManager.bool_type)
5083 return new BoolConstant (false, Location.Null);
5084 if (t == TypeManager.decimal_type)
5085 return new DecimalConstant (0, Location.Null);
5086 if (TypeManager.IsEnumType (t))
5087 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5093 // Checks whether the type is an interface that has the
5094 // [ComImport, CoClass] attributes and must be treated
5097 public Expression CheckComImport (EmitContext ec)
5099 if (!type.IsInterface)
5103 // Turn the call into:
5104 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5106 Type real_class = AttributeTester.GetCoClassAttribute (type);
5107 if (real_class == null)
5110 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5111 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5112 return cast.Resolve (ec);
5115 public override Expression CreateExpressionTree (EmitContext ec)
5117 ArrayList args = Arguments == null ?
5118 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5120 args.Add (new Argument (method.CreateExpressionTree (ec)));
5121 if (Arguments != null) {
5123 foreach (Argument a in Arguments) {
5124 expr = a.Expr.CreateExpressionTree (ec);
5126 args.Add (new Argument (expr));
5130 return CreateExpressionFactoryCall ("New", args);
5133 public override Expression DoResolve (EmitContext ec)
5136 // The New DoResolve might be called twice when initializing field
5137 // expressions (see EmitFieldInitializers, the call to
5138 // GetInitializerExpression will perform a resolve on the expression,
5139 // and later the assign will trigger another resolution
5141 // This leads to bugs (#37014)
5144 if (RequestedType is NewDelegate)
5145 return RequestedType;
5149 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5155 if (type == TypeManager.void_type) {
5156 Error_VoidInvalidInTheContext (loc);
5160 if (type.IsPointer) {
5161 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5162 TypeManager.CSharpName (type));
5166 if (Arguments == null) {
5167 Expression c = Constantify (type);
5172 if (TypeManager.IsDelegateType (type)) {
5173 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5174 if (RequestedType != null)
5175 if (!(RequestedType is DelegateCreation))
5176 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5177 return RequestedType;
5181 if (type.IsGenericParameter) {
5182 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5184 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5185 Error (304, String.Format (
5186 "Cannot create an instance of the " +
5187 "variable type '{0}' because it " +
5188 "doesn't have the new() constraint",
5193 if ((Arguments != null) && (Arguments.Count != 0)) {
5194 Error (417, String.Format (
5195 "`{0}': cannot provide arguments " +
5196 "when creating an instance of a " +
5197 "variable type.", type));
5201 if (TypeManager.activator_create_instance == null) {
5202 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5203 if (activator_type != null) {
5204 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5205 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5209 is_type_parameter = true;
5210 eclass = ExprClass.Value;
5215 if (type.IsAbstract && type.IsSealed) {
5216 Report.SymbolRelatedToPreviousError (type);
5217 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5221 if (type.IsInterface || type.IsAbstract){
5222 if (!TypeManager.IsGenericType (type)) {
5223 RequestedType = CheckComImport (ec);
5224 if (RequestedType != null)
5225 return RequestedType;
5228 Report.SymbolRelatedToPreviousError (type);
5229 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5233 bool is_struct = type.IsValueType;
5234 eclass = ExprClass.Value;
5237 // SRE returns a match for .ctor () on structs (the object constructor),
5238 // so we have to manually ignore it.
5240 if (is_struct && Arguments == null)
5243 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5244 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5245 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5247 if (Arguments != null){
5248 foreach (Argument a in Arguments){
5249 if (!a.Resolve (ec, loc))
5257 method = ml as MethodGroupExpr;
5258 if (method == null) {
5259 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5263 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5270 bool DoEmitTypeParameter (EmitContext ec)
5273 ILGenerator ig = ec.ig;
5274 // IMemoryLocation ml;
5276 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5277 new Type [] { type });
5279 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5280 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5281 ig.Emit (OpCodes.Call, ci);
5285 // Allow DoEmit() to be called multiple times.
5286 // We need to create a new LocalTemporary each time since
5287 // you can't share LocalBuilders among ILGeneators.
5288 LocalTemporary temp = new LocalTemporary (type);
5290 Label label_activator = ig.DefineLabel ();
5291 Label label_end = ig.DefineLabel ();
5293 temp.AddressOf (ec, AddressOp.Store);
5294 ig.Emit (OpCodes.Initobj, type);
5297 ig.Emit (OpCodes.Box, type);
5298 ig.Emit (OpCodes.Brfalse, label_activator);
5300 temp.AddressOf (ec, AddressOp.Store);
5301 ig.Emit (OpCodes.Initobj, type);
5303 ig.Emit (OpCodes.Br, label_end);
5305 ig.MarkLabel (label_activator);
5307 ig.Emit (OpCodes.Call, ci);
5308 ig.MarkLabel (label_end);
5311 throw new InternalErrorException ();
5316 // This DoEmit can be invoked in two contexts:
5317 // * As a mechanism that will leave a value on the stack (new object)
5318 // * As one that wont (init struct)
5320 // You can control whether a value is required on the stack by passing
5321 // need_value_on_stack. The code *might* leave a value on the stack
5322 // so it must be popped manually
5324 // If we are dealing with a ValueType, we have a few
5325 // situations to deal with:
5327 // * The target is a ValueType, and we have been provided
5328 // the instance (this is easy, we are being assigned).
5330 // * The target of New is being passed as an argument,
5331 // to a boxing operation or a function that takes a
5334 // In this case, we need to create a temporary variable
5335 // that is the argument of New.
5337 // Returns whether a value is left on the stack
5339 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5341 bool is_value_type = TypeManager.IsValueType (type);
5342 ILGenerator ig = ec.ig;
5347 // Allow DoEmit() to be called multiple times.
5348 // We need to create a new LocalTemporary each time since
5349 // you can't share LocalBuilders among ILGeneators.
5350 if (!value_target_set)
5351 value_target = new LocalTemporary (type);
5353 ml = (IMemoryLocation) value_target;
5354 ml.AddressOf (ec, AddressOp.Store);
5358 method.EmitArguments (ec, Arguments);
5362 ig.Emit (OpCodes.Initobj, type);
5364 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5365 if (need_value_on_stack){
5366 value_target.Emit (ec);
5371 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5376 public override void Emit (EmitContext ec)
5378 if (is_type_parameter)
5379 DoEmitTypeParameter (ec);
5384 public override void EmitStatement (EmitContext ec)
5386 bool value_on_stack;
5388 if (is_type_parameter)
5389 value_on_stack = DoEmitTypeParameter (ec);
5391 value_on_stack = DoEmit (ec, false);
5394 ec.ig.Emit (OpCodes.Pop);
5398 public virtual bool HasInitializer {
5404 public void AddressOf (EmitContext ec, AddressOp Mode)
5406 if (is_type_parameter) {
5407 LocalTemporary temp = new LocalTemporary (type);
5408 DoEmitTypeParameter (ec);
5410 temp.AddressOf (ec, Mode);
5414 if (!type.IsValueType){
5416 // We throw an exception. So far, I believe we only need to support
5418 // foreach (int j in new StructType ())
5421 throw new Exception ("AddressOf should not be used for classes");
5424 if (!value_target_set)
5425 value_target = new LocalTemporary (type);
5426 IMemoryLocation ml = (IMemoryLocation) value_target;
5428 ml.AddressOf (ec, AddressOp.Store);
5429 if (method == null) {
5430 ec.ig.Emit (OpCodes.Initobj, type);
5432 method.EmitArguments (ec, Arguments);
5433 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5436 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5439 protected override void CloneTo (CloneContext clonectx, Expression t)
5441 New target = (New) t;
5443 target.RequestedType = RequestedType.Clone (clonectx);
5444 if (Arguments != null){
5445 target.Arguments = new ArrayList ();
5446 foreach (Argument a in Arguments){
5447 target.Arguments.Add (a.Clone (clonectx));
5454 /// 14.5.10.2: Represents an array creation expression.
5458 /// There are two possible scenarios here: one is an array creation
5459 /// expression that specifies the dimensions and optionally the
5460 /// initialization data and the other which does not need dimensions
5461 /// specified but where initialization data is mandatory.
5463 public class ArrayCreation : Expression {
5464 Expression requested_base_type;
5465 ArrayList initializers;
5468 // The list of Argument types.
5469 // This is used to construct the `newarray' or constructor signature
5471 protected ArrayList arguments;
5473 protected Type array_element_type;
5474 bool expect_initializers = false;
5475 int num_arguments = 0;
5476 protected int dimensions;
5477 protected readonly string rank;
5479 protected ArrayList array_data;
5483 // The number of constants in array initializers
5484 int const_initializers_count;
5485 bool only_constant_initializers;
5487 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5489 this.requested_base_type = requested_base_type;
5490 this.initializers = initializers;
5494 arguments = new ArrayList ();
5496 foreach (Expression e in exprs) {
5497 arguments.Add (new Argument (e, Argument.AType.Expression));
5502 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5504 this.requested_base_type = requested_base_type;
5505 this.initializers = initializers;
5509 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5511 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5513 //dimensions = tmp.Length - 1;
5514 expect_initializers = true;
5517 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5519 StringBuilder sb = new StringBuilder (rank);
5522 for (int i = 1; i < idx_count; i++)
5527 return new ComposedCast (base_type, sb.ToString (), loc);
5530 void Error_IncorrectArrayInitializer ()
5532 Error (178, "Invalid rank specifier: expected `,' or `]'");
5535 protected override void Error_NegativeArrayIndex (Location loc)
5537 Report.Error (248, loc, "Cannot create an array with a negative size");
5540 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5542 if (specified_dims) {
5543 Argument a = (Argument) arguments [idx];
5545 if (!a.Resolve (ec, loc))
5548 Constant c = a.Expr as Constant;
5550 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5554 Report.Error (150, a.Expr.Location, "A constant value is expected");
5558 int value = (int) c.GetValue ();
5560 if (value != probe.Count) {
5561 Error_IncorrectArrayInitializer ();
5565 bounds [idx] = value;
5568 int child_bounds = -1;
5569 only_constant_initializers = true;
5570 for (int i = 0; i < probe.Count; ++i) {
5571 object o = probe [i];
5572 if (o is ArrayList) {
5573 ArrayList sub_probe = o as ArrayList;
5574 int current_bounds = sub_probe.Count;
5576 if (child_bounds == -1)
5577 child_bounds = current_bounds;
5579 else if (child_bounds != current_bounds){
5580 Error_IncorrectArrayInitializer ();
5583 if (idx + 1 >= dimensions){
5584 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5588 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5592 if (child_bounds != -1){
5593 Error_IncorrectArrayInitializer ();
5597 Expression element = ResolveArrayElement (ec, (Expression) o);
5598 if (element == null)
5601 // Initializers with the default values can be ignored
5602 Constant c = element as Constant;
5604 if (c.IsDefaultInitializer (array_element_type)) {
5608 ++const_initializers_count;
5611 only_constant_initializers = false;
5614 array_data.Add (element);
5621 public override Expression CreateExpressionTree (EmitContext ec)
5623 if (dimensions != 1) {
5624 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5628 ArrayList args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5629 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5630 if (array_data != null) {
5631 foreach (Expression e in array_data)
5632 args.Add (new Argument (e.CreateExpressionTree (ec)));
5635 return CreateExpressionFactoryCall ("NewArrayInit", args);
5638 public void UpdateIndices ()
5641 for (ArrayList probe = initializers; probe != null;) {
5642 if (probe.Count > 0 && probe [0] is ArrayList) {
5643 Expression e = new IntConstant (probe.Count, Location.Null);
5644 arguments.Add (new Argument (e, Argument.AType.Expression));
5646 bounds [i++] = probe.Count;
5648 probe = (ArrayList) probe [0];
5651 Expression e = new IntConstant (probe.Count, Location.Null);
5652 arguments.Add (new Argument (e, Argument.AType.Expression));
5654 bounds [i++] = probe.Count;
5661 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5663 element = element.Resolve (ec);
5664 if (element == null)
5667 return Convert.ImplicitConversionRequired (
5668 ec, element, array_element_type, loc);
5671 protected bool ResolveInitializers (EmitContext ec)
5673 if (initializers == null) {
5674 return !expect_initializers;
5678 // We use this to store all the date values in the order in which we
5679 // will need to store them in the byte blob later
5681 array_data = new ArrayList ();
5682 bounds = new System.Collections.Specialized.HybridDictionary ();
5684 if (arguments != null)
5685 return CheckIndices (ec, initializers, 0, true);
5687 arguments = new ArrayList ();
5689 if (!CheckIndices (ec, initializers, 0, false))
5698 // Resolved the type of the array
5700 bool ResolveArrayType (EmitContext ec)
5702 if (requested_base_type == null) {
5703 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5707 StringBuilder array_qualifier = new StringBuilder (rank);
5710 // `In the first form allocates an array instace of the type that results
5711 // from deleting each of the individual expression from the expression list'
5713 if (num_arguments > 0) {
5714 array_qualifier.Append ("[");
5715 for (int i = num_arguments-1; i > 0; i--)
5716 array_qualifier.Append (",");
5717 array_qualifier.Append ("]");
5723 TypeExpr array_type_expr;
5724 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5725 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5726 if (array_type_expr == null)
5729 type = array_type_expr.Type;
5730 array_element_type = TypeManager.GetElementType (type);
5731 dimensions = type.GetArrayRank ();
5736 public override Expression DoResolve (EmitContext ec)
5741 if (!ResolveArrayType (ec))
5744 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5745 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5746 TypeManager.CSharpName (array_element_type));
5750 // First step is to validate the initializers and fill
5751 // in any missing bits
5753 if (!ResolveInitializers (ec))
5756 if (arguments.Count != dimensions) {
5757 Error_IncorrectArrayInitializer ();
5760 foreach (Argument a in arguments){
5761 if (!a.Resolve (ec, loc))
5764 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5767 eclass = ExprClass.Value;
5771 MethodInfo GetArrayMethod (int arguments)
5773 ModuleBuilder mb = CodeGen.Module.Builder;
5775 Type[] arg_types = new Type[arguments];
5776 for (int i = 0; i < arguments; i++)
5777 arg_types[i] = TypeManager.int32_type;
5779 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5783 Report.Error (-6, "New invocation: Can not find a constructor for " +
5784 "this argument list");
5791 byte [] MakeByteBlob ()
5796 int count = array_data.Count;
5798 if (TypeManager.IsEnumType (array_element_type))
5799 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
5801 factor = GetTypeSize (array_element_type);
5803 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5805 data = new byte [(count * factor + 3) & ~3];
5808 for (int i = 0; i < count; ++i) {
5809 object v = array_data [i];
5811 if (v is EnumConstant)
5812 v = ((EnumConstant) v).Child;
5814 if (v is Constant && !(v is StringConstant))
5815 v = ((Constant) v).GetValue ();
5821 if (array_element_type == TypeManager.int64_type){
5822 if (!(v is Expression)){
5823 long val = (long) v;
5825 for (int j = 0; j < factor; ++j) {
5826 data [idx + j] = (byte) (val & 0xFF);
5830 } else if (array_element_type == TypeManager.uint64_type){
5831 if (!(v is Expression)){
5832 ulong val = (ulong) v;
5834 for (int j = 0; j < factor; ++j) {
5835 data [idx + j] = (byte) (val & 0xFF);
5839 } else if (array_element_type == TypeManager.float_type) {
5840 if (!(v is Expression)){
5841 element = BitConverter.GetBytes ((float) v);
5843 for (int j = 0; j < factor; ++j)
5844 data [idx + j] = element [j];
5845 if (!BitConverter.IsLittleEndian)
5846 System.Array.Reverse (data, idx, 4);
5848 } else if (array_element_type == TypeManager.double_type) {
5849 if (!(v is Expression)){
5850 element = BitConverter.GetBytes ((double) v);
5852 for (int j = 0; j < factor; ++j)
5853 data [idx + j] = element [j];
5855 // FIXME: Handle the ARM float format.
5856 if (!BitConverter.IsLittleEndian)
5857 System.Array.Reverse (data, idx, 8);
5859 } else if (array_element_type == TypeManager.char_type){
5860 if (!(v is Expression)){
5861 int val = (int) ((char) v);
5863 data [idx] = (byte) (val & 0xff);
5864 data [idx+1] = (byte) (val >> 8);
5866 } else if (array_element_type == TypeManager.short_type){
5867 if (!(v is Expression)){
5868 int val = (int) ((short) v);
5870 data [idx] = (byte) (val & 0xff);
5871 data [idx+1] = (byte) (val >> 8);
5873 } else if (array_element_type == TypeManager.ushort_type){
5874 if (!(v is Expression)){
5875 int val = (int) ((ushort) v);
5877 data [idx] = (byte) (val & 0xff);
5878 data [idx+1] = (byte) (val >> 8);
5880 } else if (array_element_type == TypeManager.int32_type) {
5881 if (!(v is Expression)){
5884 data [idx] = (byte) (val & 0xff);
5885 data [idx+1] = (byte) ((val >> 8) & 0xff);
5886 data [idx+2] = (byte) ((val >> 16) & 0xff);
5887 data [idx+3] = (byte) (val >> 24);
5889 } else if (array_element_type == TypeManager.uint32_type) {
5890 if (!(v is Expression)){
5891 uint val = (uint) v;
5893 data [idx] = (byte) (val & 0xff);
5894 data [idx+1] = (byte) ((val >> 8) & 0xff);
5895 data [idx+2] = (byte) ((val >> 16) & 0xff);
5896 data [idx+3] = (byte) (val >> 24);
5898 } else if (array_element_type == TypeManager.sbyte_type) {
5899 if (!(v is Expression)){
5900 sbyte val = (sbyte) v;
5901 data [idx] = (byte) val;
5903 } else if (array_element_type == TypeManager.byte_type) {
5904 if (!(v is Expression)){
5905 byte val = (byte) v;
5906 data [idx] = (byte) val;
5908 } else if (array_element_type == TypeManager.bool_type) {
5909 if (!(v is Expression)){
5910 bool val = (bool) v;
5911 data [idx] = (byte) (val ? 1 : 0);
5913 } else if (array_element_type == TypeManager.decimal_type){
5914 if (!(v is Expression)){
5915 int [] bits = Decimal.GetBits ((decimal) v);
5918 // FIXME: For some reason, this doesn't work on the MS runtime.
5919 int [] nbits = new int [4];
5920 nbits [0] = bits [3];
5921 nbits [1] = bits [2];
5922 nbits [2] = bits [0];
5923 nbits [3] = bits [1];
5925 for (int j = 0; j < 4; j++){
5926 data [p++] = (byte) (nbits [j] & 0xff);
5927 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5928 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5929 data [p++] = (byte) (nbits [j] >> 24);
5933 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5942 // Emits the initializers for the array
5944 void EmitStaticInitializers (EmitContext ec)
5946 // FIXME: This should go to Resolve !
5947 if (TypeManager.void_initializearray_array_fieldhandle == null) {
5948 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
5949 TypeManager.runtime_helpers_type, "InitializeArray", loc,
5950 TypeManager.array_type, TypeManager.runtime_field_handle_type);
5951 if (TypeManager.void_initializearray_array_fieldhandle == null)
5956 // First, the static data
5959 ILGenerator ig = ec.ig;
5961 byte [] data = MakeByteBlob ();
5963 fb = RootContext.MakeStaticData (data);
5965 ig.Emit (OpCodes.Dup);
5966 ig.Emit (OpCodes.Ldtoken, fb);
5967 ig.Emit (OpCodes.Call,
5968 TypeManager.void_initializearray_array_fieldhandle);
5972 // Emits pieces of the array that can not be computed at compile
5973 // time (variables and string locations).
5975 // This always expect the top value on the stack to be the array
5977 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5979 ILGenerator ig = ec.ig;
5980 int dims = bounds.Count;
5981 int [] current_pos = new int [dims];
5983 MethodInfo set = null;
5986 Type [] args = new Type [dims + 1];
5988 for (int j = 0; j < dims; j++)
5989 args [j] = TypeManager.int32_type;
5990 args [dims] = array_element_type;
5992 set = CodeGen.Module.Builder.GetArrayMethod (
5994 CallingConventions.HasThis | CallingConventions.Standard,
5995 TypeManager.void_type, args);
5998 for (int i = 0; i < array_data.Count; i++){
6000 Expression e = (Expression)array_data [i];
6002 // Constant can be initialized via StaticInitializer
6003 if (e != null && !(!emitConstants && e is Constant)) {
6004 Type etype = e.Type;
6006 ig.Emit (OpCodes.Dup);
6008 for (int idx = 0; idx < dims; idx++)
6009 IntConstant.EmitInt (ig, current_pos [idx]);
6012 // If we are dealing with a struct, get the
6013 // address of it, so we can store it.
6015 if ((dims == 1) && etype.IsValueType &&
6016 (!TypeManager.IsBuiltinOrEnum (etype) ||
6017 etype == TypeManager.decimal_type)) {
6022 // Let new know that we are providing
6023 // the address where to store the results
6025 n.DisableTemporaryValueType ();
6028 ig.Emit (OpCodes.Ldelema, etype);
6034 bool is_stobj, has_type_arg;
6035 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6037 ig.Emit (OpCodes.Stobj, etype);
6038 else if (has_type_arg)
6039 ig.Emit (op, etype);
6043 ig.Emit (OpCodes.Call, set);
6050 for (int j = dims - 1; j >= 0; j--){
6052 if (current_pos [j] < (int) bounds [j])
6054 current_pos [j] = 0;
6059 public override void Emit (EmitContext ec)
6061 ILGenerator ig = ec.ig;
6063 foreach (Argument a in arguments)
6066 if (arguments.Count == 1)
6067 ig.Emit (OpCodes.Newarr, array_element_type);
6069 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6072 if (initializers == null)
6075 // Emit static initializer for arrays which have contain more than 4 items and
6076 // the static initializer will initialize at least 25% of array values.
6077 // NOTE: const_initializers_count does not contain default constant values.
6078 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6079 TypeManager.IsPrimitiveType (array_element_type)) {
6080 EmitStaticInitializers (ec);
6082 if (!only_constant_initializers)
6083 EmitDynamicInitializers (ec, false);
6085 EmitDynamicInitializers (ec, true);
6089 public override bool GetAttributableValue (Type value_type, out object value)
6091 if (arguments.Count != 1) {
6092 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6093 return base.GetAttributableValue (null, out value);
6096 if (array_data == null) {
6097 Constant c = (Constant)((Argument)arguments [0]).Expr;
6098 if (c.IsDefaultValue) {
6099 value = Array.CreateInstance (array_element_type, 0);
6102 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6103 return base.GetAttributableValue (null, out value);
6106 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6107 object element_value;
6108 for (int i = 0; i < ret.Length; ++i)
6110 Expression e = (Expression)array_data [i];
6112 // Is null when an initializer is optimized (value == predefined value)
6116 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6120 ret.SetValue (element_value, i);
6126 protected override void CloneTo (CloneContext clonectx, Expression t)
6128 ArrayCreation target = (ArrayCreation) t;
6130 if (requested_base_type != null)
6131 target.requested_base_type = requested_base_type.Clone (clonectx);
6133 if (arguments != null){
6134 target.arguments = new ArrayList (arguments.Count);
6135 foreach (Argument a in arguments)
6136 target.arguments.Add (a.Clone (clonectx));
6139 if (initializers != null){
6140 target.initializers = new ArrayList (initializers.Count);
6141 foreach (object initializer in initializers)
6142 if (initializer is ArrayList) {
6143 ArrayList this_al = (ArrayList)initializer;
6144 ArrayList al = new ArrayList (this_al.Count);
6145 target.initializers.Add (al);
6146 foreach (Expression e in this_al)
6147 al.Add (e.Clone (clonectx));
6149 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6156 // Represents an implicitly typed array epxression
6158 public class ImplicitlyTypedArrayCreation : ArrayCreation
6160 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6161 : base (null, rank, initializers, loc)
6163 if (RootContext.Version <= LanguageVersion.ISO_2)
6164 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6166 if (rank.Length > 2) {
6167 while (rank [++dimensions] == ',');
6173 public override Expression DoResolve (EmitContext ec)
6178 if (!ResolveInitializers (ec))
6181 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6182 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6183 arguments.Count != dimensions) {
6184 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6189 // At this point we found common base type for all initializer elements
6190 // but we have to be sure that all static initializer elements are of
6193 UnifyInitializerElement (ec);
6195 type = TypeManager.GetConstructedType (array_element_type, rank);
6196 eclass = ExprClass.Value;
6201 // Converts static initializer only
6203 void UnifyInitializerElement (EmitContext ec)
6205 for (int i = 0; i < array_data.Count; ++i) {
6206 Expression e = (Expression)array_data[i];
6208 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6212 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6214 element = element.Resolve (ec);
6215 if (element == null)
6218 if (array_element_type == null) {
6219 array_element_type = element.Type;
6223 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6227 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6228 array_element_type = element.Type;
6232 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6237 public sealed class CompilerGeneratedThis : This
6239 public static This Instance = new CompilerGeneratedThis ();
6241 private CompilerGeneratedThis ()
6242 : base (Location.Null)
6246 public override Expression DoResolve (EmitContext ec)
6248 eclass = ExprClass.Variable;
6249 type = ec.ContainerType;
6250 variable = new SimpleThis (type);
6256 /// Represents the `this' construct
6259 public class This : VariableReference, IVariable
6262 VariableInfo variable_info;
6263 protected Variable variable;
6266 public This (Block block, Location loc)
6272 public This (Location loc)
6277 public VariableInfo VariableInfo {
6278 get { return variable_info; }
6281 public bool VerifyFixed ()
6283 return !TypeManager.IsValueType (Type);
6286 public override bool IsRef {
6287 get { return is_struct; }
6290 public override Variable Variable {
6291 get { return variable; }
6294 public bool ResolveBase (EmitContext ec)
6296 eclass = ExprClass.Variable;
6298 if (ec.TypeContainer.CurrentType != null)
6299 type = ec.TypeContainer.CurrentType;
6301 type = ec.ContainerType;
6303 is_struct = ec.TypeContainer is Struct;
6306 Error (26, "Keyword `this' is not valid in a static property, " +
6307 "static method, or static field initializer");
6311 if (block != null) {
6312 if (block.Toplevel.ThisVariable != null)
6313 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6315 AnonymousContainer am = ec.CurrentAnonymousMethod;
6316 if (is_struct && (am != null) && !am.IsIterator) {
6317 Report.Error (1673, loc, "Anonymous methods inside structs " +
6318 "cannot access instance members of `this'. " +
6319 "Consider copying `this' to a local variable " +
6320 "outside the anonymous method and using the " +
6324 RootScopeInfo host = block.Toplevel.RootScope;
6325 if ((host != null) && !ec.IsConstructor &&
6326 (!is_struct || host.IsIterator)) {
6327 variable = host.CaptureThis ();
6328 type = variable.Type;
6333 if (variable == null)
6334 variable = new SimpleThis (type);
6340 // Called from Invocation to check if the invocation is correct
6342 public override void CheckMarshalByRefAccess (EmitContext ec)
6344 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6345 !variable_info.IsAssigned (ec)) {
6346 Error (188, "The `this' object cannot be used before all of its " +
6347 "fields are assigned to");
6348 variable_info.SetAssigned (ec);
6352 public override Expression CreateExpressionTree (EmitContext ec)
6354 ArrayList args = new ArrayList (2);
6355 args.Add (new Argument (this));
6356 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6357 return CreateExpressionFactoryCall ("Constant", args);
6360 public override Expression DoResolve (EmitContext ec)
6362 if (!ResolveBase (ec))
6366 if (ec.IsInFieldInitializer) {
6367 Error (27, "Keyword `this' is not available in the current context");
6374 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6376 if (!ResolveBase (ec))
6379 if (variable_info != null)
6380 variable_info.SetAssigned (ec);
6382 if (ec.TypeContainer is Class){
6383 Error (1604, "Cannot assign to 'this' because it is read-only");
6389 public override int GetHashCode()
6391 return block.GetHashCode ();
6394 public override bool Equals (object obj)
6396 This t = obj as This;
6400 return block == t.block;
6403 protected class SimpleThis : Variable
6407 public SimpleThis (Type type)
6412 public override Type Type {
6413 get { return type; }
6416 public override bool HasInstance {
6417 get { return false; }
6420 public override bool NeedsTemporary {
6421 get { return false; }
6424 public override void EmitInstance (EmitContext ec)
6429 public override void Emit (EmitContext ec)
6431 ec.ig.Emit (OpCodes.Ldarg_0);
6434 public override void EmitAssign (EmitContext ec)
6436 throw new InvalidOperationException ();
6439 public override void EmitAddressOf (EmitContext ec)
6441 ec.ig.Emit (OpCodes.Ldarg_0);
6445 protected override void CloneTo (CloneContext clonectx, Expression t)
6447 This target = (This) t;
6449 target.block = clonectx.LookupBlock (block);
6454 /// Represents the `__arglist' construct
6456 public class ArglistAccess : Expression
6458 public ArglistAccess (Location loc)
6463 public override Expression DoResolve (EmitContext ec)
6465 eclass = ExprClass.Variable;
6466 type = TypeManager.runtime_argument_handle_type;
6468 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6470 Error (190, "The __arglist construct is valid only within " +
6471 "a variable argument method");
6478 public override void Emit (EmitContext ec)
6480 ec.ig.Emit (OpCodes.Arglist);
6483 protected override void CloneTo (CloneContext clonectx, Expression target)
6490 /// Represents the `__arglist (....)' construct
6492 public class Arglist : Expression
6494 Argument[] Arguments;
6496 public Arglist (Location loc)
6497 : this (Argument.Empty, loc)
6501 public Arglist (Argument[] args, Location l)
6507 public Type[] ArgumentTypes {
6509 Type[] retval = new Type [Arguments.Length];
6510 for (int i = 0; i < Arguments.Length; i++)
6511 retval [i] = Arguments [i].Type;
6516 public override Expression CreateExpressionTree (EmitContext ec)
6518 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6522 public override Expression DoResolve (EmitContext ec)
6524 eclass = ExprClass.Variable;
6525 type = TypeManager.runtime_argument_handle_type;
6527 foreach (Argument arg in Arguments) {
6528 if (!arg.Resolve (ec, loc))
6535 public override void Emit (EmitContext ec)
6537 foreach (Argument arg in Arguments)
6541 protected override void CloneTo (CloneContext clonectx, Expression t)
6543 Arglist target = (Arglist) t;
6545 target.Arguments = new Argument [Arguments.Length];
6546 for (int i = 0; i < Arguments.Length; i++)
6547 target.Arguments [i] = Arguments [i].Clone (clonectx);
6552 // This produces the value that renders an instance, used by the iterators code
6554 public class ProxyInstance : Expression, IMemoryLocation {
6555 public override Expression DoResolve (EmitContext ec)
6557 eclass = ExprClass.Variable;
6558 type = ec.ContainerType;
6562 public override void Emit (EmitContext ec)
6564 ec.ig.Emit (OpCodes.Ldarg_0);
6568 public void AddressOf (EmitContext ec, AddressOp mode)
6570 ec.ig.Emit (OpCodes.Ldarg_0);
6575 /// Implements the typeof operator
6577 public class TypeOf : Expression {
6578 Expression QueriedType;
6579 protected Type typearg;
6581 public TypeOf (Expression queried_type, Location l)
6583 QueriedType = queried_type;
6587 public override Expression DoResolve (EmitContext ec)
6589 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6593 typearg = texpr.Type;
6595 if (typearg == TypeManager.void_type) {
6596 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6600 if (typearg.IsPointer && !ec.InUnsafe){
6605 type = TypeManager.type_type;
6607 return DoResolveBase ();
6610 protected Expression DoResolveBase ()
6612 if (TypeManager.system_type_get_type_from_handle == null) {
6613 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6614 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6617 // Even though what is returned is a type object, it's treated as a value by the compiler.
6618 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6619 eclass = ExprClass.Value;
6623 public override void Emit (EmitContext ec)
6625 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6626 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6629 public override bool GetAttributableValue (Type value_type, out object value)
6631 if (TypeManager.ContainsGenericParameters (typearg) &&
6632 !TypeManager.IsGenericTypeDefinition (typearg)) {
6633 Report.SymbolRelatedToPreviousError (typearg);
6634 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6635 TypeManager.CSharpName (typearg));
6640 if (value_type == TypeManager.object_type) {
6641 value = (object)typearg;
6648 public Type TypeArgument
6656 protected override void CloneTo (CloneContext clonectx, Expression t)
6658 TypeOf target = (TypeOf) t;
6660 target.QueriedType = QueriedType.Clone (clonectx);
6665 /// Implements the `typeof (void)' operator
6667 public class TypeOfVoid : TypeOf {
6668 public TypeOfVoid (Location l) : base (null, l)
6673 public override Expression DoResolve (EmitContext ec)
6675 type = TypeManager.type_type;
6676 typearg = TypeManager.void_type;
6678 return DoResolveBase ();
6682 internal class TypeOfMethod : Expression
6684 readonly MethodBase method;
6686 public TypeOfMethod (MethodBase method, Location loc)
6688 this.method = method;
6692 public override Expression DoResolve (EmitContext ec)
6694 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6695 MethodInfo mi = is_generic ?
6696 TypeManager.methodbase_get_type_from_handle_generic :
6697 TypeManager.methodbase_get_type_from_handle;
6700 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
6701 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
6703 if (t == null || handle_type == null)
6706 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
6708 new Type[] { handle_type, TypeManager.runtime_handle_type } :
6709 new Type[] { handle_type } );
6712 TypeManager.methodbase_get_type_from_handle_generic = mi;
6714 TypeManager.methodbase_get_type_from_handle = mi;
6717 type = typeof (MethodBase);
6718 eclass = ExprClass.Value;
6722 public override void Emit (EmitContext ec)
6724 if (method is MethodInfo)
6725 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo)method);
6727 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
6729 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6732 mi = TypeManager.methodbase_get_type_from_handle_generic;
6733 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
6735 mi = TypeManager.methodbase_get_type_from_handle;
6738 ec.ig.Emit (OpCodes.Call, mi);
6742 internal class TypeOfField : Expression
6744 readonly FieldInfo field;
6746 public TypeOfField (FieldInfo field, Location loc)
6752 public override Expression DoResolve (EmitContext ec)
6754 if (TypeManager.fieldinfo_get_field_from_handle == null) {
6755 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
6756 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
6758 if (t != null && handle_type != null)
6759 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
6760 "GetFieldFromHandle", loc, handle_type);
6763 type = typeof (FieldInfo);
6764 eclass = ExprClass.Value;
6768 public override void Emit (EmitContext ec)
6770 ec.ig.Emit (OpCodes.Ldtoken, field);
6771 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
6776 /// Implements the sizeof expression
6778 public class SizeOf : Expression {
6779 readonly Expression QueriedType;
6782 public SizeOf (Expression queried_type, Location l)
6784 this.QueriedType = queried_type;
6788 public override Expression DoResolve (EmitContext ec)
6790 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6795 if (texpr is TypeParameterExpr){
6796 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6801 type_queried = texpr.Type;
6802 if (TypeManager.IsEnumType (type_queried))
6803 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
6805 if (type_queried == TypeManager.void_type) {
6806 Expression.Error_VoidInvalidInTheContext (loc);
6810 int size_of = GetTypeSize (type_queried);
6812 return new IntConstant (size_of, loc);
6816 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)",
6817 TypeManager.CSharpName (type_queried));
6821 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6825 type = TypeManager.int32_type;
6826 eclass = ExprClass.Value;
6830 public override void Emit (EmitContext ec)
6832 int size = GetTypeSize (type_queried);
6835 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6837 IntConstant.EmitInt (ec.ig, size);
6840 protected override void CloneTo (CloneContext clonectx, Expression t)
6846 /// Implements the qualified-alias-member (::) expression.
6848 public class QualifiedAliasMember : Expression
6850 string alias, identifier;
6852 public QualifiedAliasMember (string alias, string identifier, Location l)
6855 this.identifier = identifier;
6859 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6861 if (alias == "global")
6862 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6864 int errors = Report.Errors;
6865 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6867 if (errors == Report.Errors)
6868 Report.Error (432, loc, "Alias `{0}' not found", alias);
6871 if (fne.eclass != ExprClass.Namespace) {
6873 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6876 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6879 public override Expression DoResolve (EmitContext ec)
6881 FullNamedExpression fne;
6882 if (alias == "global") {
6883 fne = RootNamespace.Global;
6885 int errors = Report.Errors;
6886 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6888 if (errors == Report.Errors)
6889 Report.Error (432, loc, "Alias `{0}' not found", alias);
6894 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6898 if (!(retval is FullNamedExpression)) {
6899 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6903 // We defer this check till the end to match the behaviour of CSC
6904 if (fne.eclass != ExprClass.Namespace) {
6905 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6911 public override void Emit (EmitContext ec)
6913 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6917 public override string ToString ()
6919 return alias + "::" + identifier;
6922 public override string GetSignatureForError ()
6927 protected override void CloneTo (CloneContext clonectx, Expression t)
6934 /// Implements the member access expression
6936 public class MemberAccess : Expression {
6937 public readonly string Identifier;
6939 readonly TypeArguments args;
6941 public MemberAccess (Expression expr, string id)
6942 : this (expr, id, expr.Location)
6946 public MemberAccess (Expression expr, string identifier, Location loc)
6949 Identifier = identifier;
6953 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6954 : this (expr, identifier, loc)
6959 protected string LookupIdentifier {
6960 get { return MemberName.MakeName (Identifier, args); }
6963 // TODO: this method has very poor performace for Enum fields and
6964 // probably for other constants as well
6965 Expression DoResolve (EmitContext ec, Expression right_side)
6968 throw new Exception ();
6971 // Resolve the expression with flow analysis turned off, we'll do the definite
6972 // assignment checks later. This is because we don't know yet what the expression
6973 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6974 // definite assignment check on the actual field and not on the whole struct.
6977 SimpleName original = expr as SimpleName;
6978 Expression expr_resolved = expr.Resolve (ec,
6979 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6980 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6982 if (expr_resolved == null)
6985 if (expr_resolved is Namespace) {
6986 Namespace ns = (Namespace) expr_resolved;
6987 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6989 if ((retval != null) && (args != null))
6990 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6994 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6998 Type expr_type = expr_resolved.Type;
6999 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
7000 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7003 if (expr_type == TypeManager.anonymous_method_type){
7004 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
7008 Constant c = expr_resolved as Constant;
7009 if (c != null && c.GetValue () == null) {
7010 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7011 "System.NullReferenceException");
7015 if (!args.Resolve (ec))
7019 Expression member_lookup;
7020 member_lookup = MemberLookup (
7021 ec.ContainerType, expr_type, expr_type, Identifier, loc);
7023 if ((member_lookup == null) && (args != null)) {
7024 member_lookup = MemberLookup (
7025 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7028 if (member_lookup == null) {
7029 ExprClass expr_eclass = expr_resolved.eclass;
7032 // Extension methods are not allowed on all expression types
7034 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7035 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7036 expr_eclass == ExprClass.EventAccess) {
7037 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier, loc);
7038 if (ex_method_lookup != null) {
7039 ex_method_lookup.ExtensionExpression = expr_resolved;
7042 ex_method_lookup.SetTypeArguments (args);
7045 return ex_method_lookup.DoResolve (ec);
7049 expr = expr_resolved;
7050 Error_MemberLookupFailed (
7051 ec.ContainerType, expr_type, expr_type, Identifier, null,
7052 AllMemberTypes, AllBindingFlags);
7056 TypeExpr texpr = member_lookup as TypeExpr;
7057 if (texpr != null) {
7058 if (!(expr_resolved is TypeExpr) &&
7059 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7060 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7061 Identifier, member_lookup.GetSignatureForError ());
7065 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7066 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7067 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7072 ConstructedType ct = expr_resolved as ConstructedType;
7075 // When looking up a nested type in a generic instance
7076 // via reflection, we always get a generic type definition
7077 // and not a generic instance - so we have to do this here.
7079 // See gtest-172-lib.cs and gtest-172.cs for an example.
7081 ct = new ConstructedType (
7082 member_lookup.Type, ct.TypeArguments, loc);
7084 return ct.ResolveAsTypeStep (ec, false);
7087 return member_lookup;
7090 MemberExpr me = (MemberExpr) member_lookup;
7091 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7096 me.SetTypeArguments (args);
7099 if (original != null && !TypeManager.IsValueType (expr_type)) {
7100 if (me.IsInstance) {
7101 LocalVariableReference var = expr_resolved as LocalVariableReference;
7102 if (var != null && !var.VerifyAssigned (ec))
7107 // The following DoResolve/DoResolveLValue will do the definite assignment
7110 if (right_side != null)
7111 return me.DoResolveLValue (ec, right_side);
7113 return me.DoResolve (ec);
7116 public override Expression DoResolve (EmitContext ec)
7118 return DoResolve (ec, null);
7121 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7123 return DoResolve (ec, right_side);
7126 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7128 return ResolveNamespaceOrType (ec, silent);
7131 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7133 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7135 if (new_expr == null)
7138 if (new_expr is Namespace) {
7139 Namespace ns = (Namespace) new_expr;
7140 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7142 if ((retval != null) && (args != null))
7143 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
7145 if (!silent && retval == null)
7146 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7150 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7151 if (tnew_expr == null)
7154 Type expr_type = tnew_expr.Type;
7156 if (expr_type.IsPointer){
7157 Error (23, "The `.' operator can not be applied to pointer operands (" +
7158 TypeManager.CSharpName (expr_type) + ")");
7162 Expression member_lookup = MemberLookup (
7163 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7164 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7165 if (member_lookup == null) {
7169 member_lookup = MemberLookup (
7170 rc.DeclContainer.TypeBuilder, expr_type, expr_type, SimpleName.RemoveGenericArity (LookupIdentifier),
7171 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7173 if (member_lookup != null) {
7174 tnew_expr = member_lookup.ResolveAsTypeTerminal (rc, false);
7175 if (tnew_expr == null)
7178 Namespace.Error_TypeArgumentsCannotBeUsed (tnew_expr.Type, loc);
7182 member_lookup = MemberLookup (
7183 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7184 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7186 if (member_lookup == null) {
7187 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7188 Identifier, new_expr.GetSignatureForError ());
7190 // TODO: Report.SymbolRelatedToPreviousError
7191 member_lookup.Error_UnexpectedKind (null, "type", loc);
7196 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7201 TypeArguments the_args = args;
7202 Type declaring_type = texpr.Type.DeclaringType;
7203 if (TypeManager.HasGenericArguments (declaring_type)) {
7204 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7205 expr_type = expr_type.BaseType;
7208 TypeArguments new_args = new TypeArguments (loc);
7209 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7210 new_args.Add (new TypeExpression (decl, loc));
7213 new_args.Add (args);
7215 the_args = new_args;
7218 if (the_args != null) {
7219 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7220 return ctype.ResolveAsTypeStep (rc, false);
7227 public override void Emit (EmitContext ec)
7229 throw new Exception ("Should not happen");
7232 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7234 if (RootContext.Version > LanguageVersion.ISO_2 &&
7235 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7236 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7237 "extension method `{1}' of type `{0}' could be found " +
7238 "(are you missing a using directive or an assembly reference?)",
7239 TypeManager.CSharpName (type), name);
7243 base.Error_TypeDoesNotContainDefinition (type, name);
7246 public override string ToString ()
7248 return expr + "." + MemberName.MakeName (Identifier, args);
7251 public override string GetSignatureForError ()
7253 return expr.GetSignatureForError () + "." + Identifier;
7256 protected override void CloneTo (CloneContext clonectx, Expression t)
7258 MemberAccess target = (MemberAccess) t;
7260 target.expr = expr.Clone (clonectx);
7265 /// Implements checked expressions
7267 public class CheckedExpr : Expression {
7269 public Expression Expr;
7271 public CheckedExpr (Expression e, Location l)
7277 public override Expression CreateExpressionTree (EmitContext ec)
7279 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7280 return Expr.CreateExpressionTree (ec);
7283 public override Expression DoResolve (EmitContext ec)
7285 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7286 Expr = Expr.Resolve (ec);
7291 if (Expr is Constant)
7294 eclass = Expr.eclass;
7299 public override void Emit (EmitContext ec)
7301 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7305 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7307 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7308 Expr.EmitBranchable (ec, target, on_true);
7311 protected override void CloneTo (CloneContext clonectx, Expression t)
7313 CheckedExpr target = (CheckedExpr) t;
7315 target.Expr = Expr.Clone (clonectx);
7320 /// Implements the unchecked expression
7322 public class UnCheckedExpr : Expression {
7324 public Expression Expr;
7326 public UnCheckedExpr (Expression e, Location l)
7332 public override Expression CreateExpressionTree (EmitContext ec)
7334 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7335 return Expr.CreateExpressionTree (ec);
7338 public override Expression DoResolve (EmitContext ec)
7340 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7341 Expr = Expr.Resolve (ec);
7346 if (Expr is Constant)
7349 eclass = Expr.eclass;
7354 public override void Emit (EmitContext ec)
7356 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7360 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7362 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7363 Expr.EmitBranchable (ec, target, on_true);
7366 protected override void CloneTo (CloneContext clonectx, Expression t)
7368 UnCheckedExpr target = (UnCheckedExpr) t;
7370 target.Expr = Expr.Clone (clonectx);
7375 /// An Element Access expression.
7377 /// During semantic analysis these are transformed into
7378 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7380 public class ElementAccess : Expression {
7381 public ArrayList Arguments;
7382 public Expression Expr;
7384 public ElementAccess (Expression e, ArrayList e_list)
7393 Arguments = new ArrayList ();
7394 foreach (Expression tmp in e_list)
7395 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7399 bool CommonResolve (EmitContext ec)
7401 Expr = Expr.Resolve (ec);
7403 if (Arguments == null)
7406 foreach (Argument a in Arguments){
7407 if (!a.Resolve (ec, loc))
7411 return Expr != null;
7414 public override Expression CreateExpressionTree (EmitContext ec)
7416 ArrayList args = new ArrayList (Arguments.Count + 1);
7417 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7418 foreach (Argument a in Arguments)
7419 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7421 return CreateExpressionFactoryCall ("ArrayIndex", args);
7424 Expression MakePointerAccess (EmitContext ec, Type t)
7426 if (t == TypeManager.void_ptr_type){
7427 Error (242, "The array index operation is not valid on void pointers");
7430 if (Arguments.Count != 1){
7431 Error (196, "A pointer must be indexed by only one value");
7436 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7439 return new Indirection (p, loc).Resolve (ec);
7442 public override Expression DoResolve (EmitContext ec)
7444 if (!CommonResolve (ec))
7448 // We perform some simple tests, and then to "split" the emit and store
7449 // code we create an instance of a different class, and return that.
7451 // I am experimenting with this pattern.
7455 if (t == TypeManager.array_type){
7456 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7461 return (new ArrayAccess (this, loc)).Resolve (ec);
7463 return MakePointerAccess (ec, t);
7465 FieldExpr fe = Expr as FieldExpr;
7467 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7469 return MakePointerAccess (ec, ff.ElementType);
7472 return (new IndexerAccess (this, loc)).Resolve (ec);
7475 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7477 if (!CommonResolve (ec))
7482 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7485 return MakePointerAccess (ec, type);
7487 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7488 Error_CannotModifyIntermediateExpressionValue (ec);
7490 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7493 public override void Emit (EmitContext ec)
7495 throw new Exception ("Should never be reached");
7498 public override string GetSignatureForError ()
7500 return Expr.GetSignatureForError ();
7503 protected override void CloneTo (CloneContext clonectx, Expression t)
7505 ElementAccess target = (ElementAccess) t;
7507 target.Expr = Expr.Clone (clonectx);
7508 target.Arguments = new ArrayList (Arguments.Count);
7509 foreach (Argument a in Arguments)
7510 target.Arguments.Add (a.Clone (clonectx));
7515 /// Implements array access
7517 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7519 // Points to our "data" repository
7523 LocalTemporary temp;
7524 LocalTemporary prepared_value;
7528 public ArrayAccess (ElementAccess ea_data, Location l)
7531 eclass = ExprClass.Variable;
7535 public override Expression CreateExpressionTree (EmitContext ec)
7537 return ea.CreateExpressionTree (ec);
7540 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7542 return DoResolve (ec);
7545 public override Expression DoResolve (EmitContext ec)
7548 ExprClass eclass = ea.Expr.eclass;
7550 // As long as the type is valid
7551 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7552 eclass == ExprClass.Value)) {
7553 ea.Expr.Error_UnexpectedKind ("variable or value");
7558 Type t = ea.Expr.Type;
7559 int rank = ea.Arguments.Count;
7560 if (t.GetArrayRank () != rank) {
7561 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7562 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7566 if (rank != 1 && TypeManager.int_getlength_int == null) {
7567 TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
7568 TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
7571 type = TypeManager.GetElementType (t);
7572 if (type.IsPointer && !ec.InUnsafe) {
7573 UnsafeError (ea.Location);
7577 foreach (Argument a in ea.Arguments) {
7578 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7581 eclass = ExprClass.Variable;
7587 /// Emits the right opcode to load an object of Type `t'
7588 /// from an array of T
7590 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7593 MethodInfo get = FetchGetMethod ();
7594 ig.Emit (OpCodes.Call, get);
7598 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7599 ig.Emit (OpCodes.Ldelem_U1);
7600 else if (type == TypeManager.sbyte_type)
7601 ig.Emit (OpCodes.Ldelem_I1);
7602 else if (type == TypeManager.short_type)
7603 ig.Emit (OpCodes.Ldelem_I2);
7604 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7605 ig.Emit (OpCodes.Ldelem_U2);
7606 else if (type == TypeManager.int32_type)
7607 ig.Emit (OpCodes.Ldelem_I4);
7608 else if (type == TypeManager.uint32_type)
7609 ig.Emit (OpCodes.Ldelem_U4);
7610 else if (type == TypeManager.uint64_type)
7611 ig.Emit (OpCodes.Ldelem_I8);
7612 else if (type == TypeManager.int64_type)
7613 ig.Emit (OpCodes.Ldelem_I8);
7614 else if (type == TypeManager.float_type)
7615 ig.Emit (OpCodes.Ldelem_R4);
7616 else if (type == TypeManager.double_type)
7617 ig.Emit (OpCodes.Ldelem_R8);
7618 else if (type == TypeManager.intptr_type)
7619 ig.Emit (OpCodes.Ldelem_I);
7620 else if (TypeManager.IsEnumType (type)){
7621 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7622 } else if (type.IsValueType){
7623 ig.Emit (OpCodes.Ldelema, type);
7624 ig.Emit (OpCodes.Ldobj, type);
7626 } else if (type.IsGenericParameter) {
7627 ig.Emit (OpCodes.Ldelem, type);
7629 } else if (type.IsPointer)
7630 ig.Emit (OpCodes.Ldelem_I);
7632 ig.Emit (OpCodes.Ldelem_Ref);
7635 protected override void Error_NegativeArrayIndex (Location loc)
7637 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7641 /// Returns the right opcode to store an object of Type `t'
7642 /// from an array of T.
7644 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7646 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7647 has_type_arg = false; is_stobj = false;
7648 t = TypeManager.TypeToCoreType (t);
7649 if (TypeManager.IsEnumType (t))
7650 t = TypeManager.GetEnumUnderlyingType (t);
7651 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7652 t == TypeManager.bool_type)
7653 return OpCodes.Stelem_I1;
7654 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7655 t == TypeManager.char_type)
7656 return OpCodes.Stelem_I2;
7657 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7658 return OpCodes.Stelem_I4;
7659 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7660 return OpCodes.Stelem_I8;
7661 else if (t == TypeManager.float_type)
7662 return OpCodes.Stelem_R4;
7663 else if (t == TypeManager.double_type)
7664 return OpCodes.Stelem_R8;
7665 else if (t == TypeManager.intptr_type) {
7666 has_type_arg = true;
7668 return OpCodes.Stobj;
7669 } else if (t.IsValueType) {
7670 has_type_arg = true;
7672 return OpCodes.Stobj;
7674 } else if (t.IsGenericParameter) {
7675 has_type_arg = true;
7676 return OpCodes.Stelem;
7679 } else if (t.IsPointer)
7680 return OpCodes.Stelem_I;
7682 return OpCodes.Stelem_Ref;
7685 MethodInfo FetchGetMethod ()
7687 ModuleBuilder mb = CodeGen.Module.Builder;
7688 int arg_count = ea.Arguments.Count;
7689 Type [] args = new Type [arg_count];
7692 for (int i = 0; i < arg_count; i++){
7693 //args [i++] = a.Type;
7694 args [i] = TypeManager.int32_type;
7697 get = mb.GetArrayMethod (
7698 ea.Expr.Type, "Get",
7699 CallingConventions.HasThis |
7700 CallingConventions.Standard,
7706 MethodInfo FetchAddressMethod ()
7708 ModuleBuilder mb = CodeGen.Module.Builder;
7709 int arg_count = ea.Arguments.Count;
7710 Type [] args = new Type [arg_count];
7714 ret_type = TypeManager.GetReferenceType (type);
7716 for (int i = 0; i < arg_count; i++){
7717 //args [i++] = a.Type;
7718 args [i] = TypeManager.int32_type;
7721 address = mb.GetArrayMethod (
7722 ea.Expr.Type, "Address",
7723 CallingConventions.HasThis |
7724 CallingConventions.Standard,
7731 // Load the array arguments into the stack.
7733 // If we have been requested to cache the values (cached_locations array
7734 // initialized), then load the arguments the first time and store them
7735 // in locals. otherwise load from local variables.
7737 // prepare_for_load is used in compound assignments to cache original index
7738 // values ( label[idx++] += s )
7740 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
7744 LocalTemporary[] indexes = null;
7745 if (prepare_for_load) {
7746 ec.ig.Emit (OpCodes.Dup);
7747 indexes = new LocalTemporary [ea.Arguments.Count];
7750 for (int i = 0; i < ea.Arguments.Count; ++i) {
7751 ((Argument)ea.Arguments [i]).Emit (ec);
7752 if (!prepare_for_load)
7755 // Keep original array index value on the stack
7756 ec.ig.Emit (OpCodes.Dup);
7758 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7759 indexes [i].Store (ec);
7765 public void Emit (EmitContext ec, bool leave_copy)
7767 int rank = ea.Expr.Type.GetArrayRank ();
7768 ILGenerator ig = ec.ig;
7770 if (prepared_value != null) {
7771 prepared_value.Emit (ec);
7772 } else if (prepared) {
7773 LoadFromPtr (ig, this.type);
7775 LoadArrayAndArguments (ec, false);
7776 EmitLoadOpcode (ig, type, rank);
7780 ig.Emit (OpCodes.Dup);
7781 temp = new LocalTemporary (this.type);
7786 public override void Emit (EmitContext ec)
7791 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7793 int rank = ea.Expr.Type.GetArrayRank ();
7794 ILGenerator ig = ec.ig;
7795 Type t = source.Type;
7796 prepared = prepare_for_load && !(source is StringConcat);
7799 AddressOf (ec, AddressOp.LoadStore);
7800 ec.ig.Emit (OpCodes.Dup);
7802 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7803 prepare_for_load && (source is StringConcat));
7805 if (original_indexes_values != null) {
7806 prepared_value = new LocalTemporary (type);
7807 EmitLoadOpcode (ig, type, rank);
7808 prepared_value.Store (ec);
7809 foreach (LocalTemporary lt in original_indexes_values) {
7817 bool is_stobj, has_type_arg;
7818 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7822 // The stobj opcode used by value types will need
7823 // an address on the stack, not really an array/array
7827 ig.Emit (OpCodes.Ldelema, t);
7832 ec.ig.Emit (OpCodes.Dup);
7833 temp = new LocalTemporary (this.type);
7838 StoreFromPtr (ig, t);
7840 ig.Emit (OpCodes.Stobj, t);
7841 else if (has_type_arg)
7848 ec.ig.Emit (OpCodes.Dup);
7849 temp = new LocalTemporary (this.type);
7854 StoreFromPtr (ig, t);
7856 int arg_count = ea.Arguments.Count;
7857 Type [] args = new Type [arg_count + 1];
7858 for (int i = 0; i < arg_count; i++) {
7859 //args [i++] = a.Type;
7860 args [i] = TypeManager.int32_type;
7862 args [arg_count] = type;
7864 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7865 ea.Expr.Type, "Set",
7866 CallingConventions.HasThis |
7867 CallingConventions.Standard,
7868 TypeManager.void_type, args);
7870 ig.Emit (OpCodes.Call, set);
7880 public void AddressOf (EmitContext ec, AddressOp mode)
7882 int rank = ea.Expr.Type.GetArrayRank ();
7883 ILGenerator ig = ec.ig;
7885 LoadArrayAndArguments (ec, false);
7888 ig.Emit (OpCodes.Ldelema, type);
7890 MethodInfo address = FetchAddressMethod ();
7891 ig.Emit (OpCodes.Call, address);
7895 public void EmitGetLength (EmitContext ec, int dim)
7897 int rank = ea.Expr.Type.GetArrayRank ();
7898 ILGenerator ig = ec.ig;
7902 ig.Emit (OpCodes.Ldlen);
7903 ig.Emit (OpCodes.Conv_I4);
7905 IntLiteral.EmitInt (ig, dim);
7906 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7912 /// Expressions that represent an indexer call.
7914 public class IndexerAccess : Expression, IAssignMethod
7916 class IndexerMethodGroupExpr : MethodGroupExpr
7918 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7921 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7924 public override string Name {
7930 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7933 // Here is the trick, decrease number of arguments by 1 when only
7934 // available property method is setter. This makes overload resolution
7935 // work correctly for indexers.
7938 if (method.Name [0] == 'g')
7939 return parameters.Count;
7941 return parameters.Count - 1;
7947 // Contains either property getter or setter
7948 public ArrayList Methods;
7949 public ArrayList Properties;
7955 void Append (Type caller_type, MemberInfo [] mi)
7960 foreach (PropertyInfo property in mi) {
7961 MethodInfo accessor = property.GetGetMethod (true);
7962 if (accessor == null)
7963 accessor = property.GetSetMethod (true);
7965 if (Methods == null) {
7966 Methods = new ArrayList ();
7967 Properties = new ArrayList ();
7970 Methods.Add (accessor);
7971 Properties.Add (property);
7975 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7977 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7979 return TypeManager.MemberLookup (
7980 caller_type, caller_type, lookup_type, MemberTypes.Property,
7981 BindingFlags.Public | BindingFlags.Instance |
7982 BindingFlags.DeclaredOnly, p_name, null);
7985 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7987 Indexers ix = new Indexers ();
7990 if (lookup_type.IsGenericParameter) {
7991 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7995 if (gc.HasClassConstraint)
7996 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7998 Type[] ifaces = gc.InterfaceConstraints;
7999 foreach (Type itype in ifaces)
8000 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8006 Type copy = lookup_type;
8007 while (copy != TypeManager.object_type && copy != null){
8008 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8009 copy = copy.BaseType;
8012 if (lookup_type.IsInterface) {
8013 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8014 if (ifaces != null) {
8015 foreach (Type itype in ifaces)
8016 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8031 // Points to our "data" repository
8033 MethodInfo get, set;
8034 bool is_base_indexer;
8036 LocalTemporary temp;
8037 LocalTemporary prepared_value;
8038 Expression set_expr;
8040 protected Type indexer_type;
8041 protected Type current_type;
8042 protected Expression instance_expr;
8043 protected ArrayList arguments;
8045 public IndexerAccess (ElementAccess ea, Location loc)
8046 : this (ea.Expr, false, loc)
8048 this.arguments = ea.Arguments;
8051 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8054 this.instance_expr = instance_expr;
8055 this.is_base_indexer = is_base_indexer;
8056 this.eclass = ExprClass.Value;
8060 static string GetAccessorName (AccessorType at)
8062 if (at == AccessorType.Set)
8065 if (at == AccessorType.Get)
8068 throw new NotImplementedException (at.ToString ());
8071 protected virtual bool CommonResolve (EmitContext ec)
8073 indexer_type = instance_expr.Type;
8074 current_type = ec.ContainerType;
8079 public override Expression DoResolve (EmitContext ec)
8081 return ResolveAccessor (ec, AccessorType.Get);
8084 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8086 if (right_side == EmptyExpression.OutAccess) {
8087 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8088 GetSignatureForError ());
8092 // if the indexer returns a value type, and we try to set a field in it
8093 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8094 Error_CannotModifyIntermediateExpressionValue (ec);
8097 Expression e = ResolveAccessor (ec, AccessorType.Set);
8101 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8105 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8107 if (!CommonResolve (ec))
8110 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8111 if (ilist.Methods == null) {
8112 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8113 TypeManager.CSharpName (indexer_type));
8117 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8118 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8122 MethodInfo mi = (MethodInfo) mg;
8123 PropertyInfo pi = null;
8124 for (int i = 0; i < ilist.Methods.Count; ++i) {
8125 if (ilist.Methods [i] == mi) {
8126 pi = (PropertyInfo) ilist.Properties [i];
8131 type = TypeManager.TypeToCoreType (pi.PropertyType);
8132 if (type.IsPointer && !ec.InUnsafe)
8135 MethodInfo accessor;
8136 if (accessorType == AccessorType.Get) {
8137 accessor = get = pi.GetGetMethod (true);
8139 accessor = set = pi.GetSetMethod (true);
8140 if (accessor == null && pi.GetGetMethod (true) != null) {
8141 Report.SymbolRelatedToPreviousError (pi);
8142 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8143 TypeManager.GetFullNameSignature (pi));
8148 if (accessor == null) {
8149 Report.SymbolRelatedToPreviousError (pi);
8150 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8151 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8156 // Only base will allow this invocation to happen.
8158 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8159 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8162 bool must_do_cs1540_check;
8163 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8165 set = pi.GetSetMethod (true);
8167 get = pi.GetGetMethod (true);
8169 if (set != null && get != null &&
8170 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8171 Report.SymbolRelatedToPreviousError (accessor);
8172 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8173 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8175 Report.SymbolRelatedToPreviousError (pi);
8176 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8180 instance_expr.CheckMarshalByRefAccess (ec);
8181 eclass = ExprClass.IndexerAccess;
8185 public void Emit (EmitContext ec, bool leave_copy)
8188 prepared_value.Emit (ec);
8190 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8191 arguments, loc, false, false);
8195 ec.ig.Emit (OpCodes.Dup);
8196 temp = new LocalTemporary (Type);
8202 // source is ignored, because we already have a copy of it from the
8203 // LValue resolution and we have already constructed a pre-cached
8204 // version of the arguments (ea.set_arguments);
8206 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8208 prepared = prepare_for_load;
8209 Expression value = set_expr;
8212 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8213 arguments, loc, true, false);
8215 prepared_value = new LocalTemporary (type);
8216 prepared_value.Store (ec);
8218 prepared_value.Release (ec);
8221 ec.ig.Emit (OpCodes.Dup);
8222 temp = new LocalTemporary (Type);
8225 } else if (leave_copy) {
8226 temp = new LocalTemporary (Type);
8232 arguments.Add (new Argument (value, Argument.AType.Expression));
8233 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8241 public override void Emit (EmitContext ec)
8246 public override string GetSignatureForError ()
8248 return TypeManager.CSharpSignature (get != null ? get : set, false);
8251 protected override void CloneTo (CloneContext clonectx, Expression t)
8253 IndexerAccess target = (IndexerAccess) t;
8255 if (arguments != null){
8256 target.arguments = new ArrayList ();
8257 foreach (Argument a in arguments)
8258 target.arguments.Add (a.Clone (clonectx));
8260 if (instance_expr != null)
8261 target.instance_expr = instance_expr.Clone (clonectx);
8266 /// The base operator for method names
8268 public class BaseAccess : Expression {
8269 public readonly string Identifier;
8272 public BaseAccess (string member, Location l)
8274 this.Identifier = member;
8278 public BaseAccess (string member, TypeArguments args, Location l)
8284 public override Expression DoResolve (EmitContext ec)
8286 Expression c = CommonResolve (ec);
8292 // MethodGroups use this opportunity to flag an error on lacking ()
8294 if (!(c is MethodGroupExpr))
8295 return c.Resolve (ec);
8299 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8301 Expression c = CommonResolve (ec);
8307 // MethodGroups use this opportunity to flag an error on lacking ()
8309 if (! (c is MethodGroupExpr))
8310 return c.DoResolveLValue (ec, right_side);
8315 Expression CommonResolve (EmitContext ec)
8317 Expression member_lookup;
8318 Type current_type = ec.ContainerType;
8319 Type base_type = current_type.BaseType;
8322 Error (1511, "Keyword `base' is not available in a static method");
8326 if (ec.IsInFieldInitializer){
8327 Error (1512, "Keyword `base' is not available in the current context");
8331 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8332 AllMemberTypes, AllBindingFlags, loc);
8333 if (member_lookup == null) {
8334 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8335 null, AllMemberTypes, AllBindingFlags);
8342 left = new TypeExpression (base_type, loc);
8344 left = ec.GetThis (loc);
8346 MemberExpr me = (MemberExpr) member_lookup;
8347 me = me.ResolveMemberAccess (ec, left, loc, null);
8354 me.SetTypeArguments (args);
8360 public override void Emit (EmitContext ec)
8362 throw new Exception ("Should never be called");
8365 protected override void CloneTo (CloneContext clonectx, Expression t)
8367 BaseAccess target = (BaseAccess) t;
8370 target.args = args.Clone ();
8375 /// The base indexer operator
8377 public class BaseIndexerAccess : IndexerAccess {
8378 public BaseIndexerAccess (ArrayList args, Location loc)
8379 : base (null, true, loc)
8381 arguments = new ArrayList ();
8382 foreach (Expression tmp in args)
8383 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8386 protected override bool CommonResolve (EmitContext ec)
8388 instance_expr = ec.GetThis (loc);
8390 current_type = ec.ContainerType.BaseType;
8391 indexer_type = current_type;
8393 foreach (Argument a in arguments){
8394 if (!a.Resolve (ec, loc))
8403 /// This class exists solely to pass the Type around and to be a dummy
8404 /// that can be passed to the conversion functions (this is used by
8405 /// foreach implementation to typecast the object return value from
8406 /// get_Current into the proper type. All code has been generated and
8407 /// we only care about the side effect conversions to be performed
8409 /// This is also now used as a placeholder where a no-action expression
8410 /// is needed (the `New' class).
8412 public class EmptyExpression : Expression {
8413 public static readonly EmptyExpression Null = new EmptyExpression ();
8415 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8416 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8417 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8419 static EmptyExpression temp = new EmptyExpression ();
8420 public static EmptyExpression Grab ()
8422 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8427 public static void Release (EmptyExpression e)
8432 // TODO: should be protected
8433 public EmptyExpression ()
8435 type = TypeManager.object_type;
8436 eclass = ExprClass.Value;
8437 loc = Location.Null;
8440 public EmptyExpression (Type t)
8443 eclass = ExprClass.Value;
8444 loc = Location.Null;
8447 public override Expression DoResolve (EmitContext ec)
8452 public override void Emit (EmitContext ec)
8454 // nothing, as we only exist to not do anything.
8458 // This is just because we might want to reuse this bad boy
8459 // instead of creating gazillions of EmptyExpressions.
8460 // (CanImplicitConversion uses it)
8462 public void SetType (Type t)
8469 // Empty statement expression
8471 public sealed class EmptyExpressionStatement : ExpressionStatement
8473 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8475 private EmptyExpressionStatement ()
8477 type = TypeManager.object_type;
8478 eclass = ExprClass.Value;
8479 loc = Location.Null;
8482 public override void EmitStatement (EmitContext ec)
8487 public override Expression DoResolve (EmitContext ec)
8492 public override void Emit (EmitContext ec)
8498 public class UserCast : Expression {
8502 public UserCast (MethodInfo method, Expression source, Location l)
8504 this.method = method;
8505 this.source = source;
8506 type = TypeManager.TypeToCoreType (method.ReturnType);
8507 eclass = ExprClass.Value;
8511 public Expression Source {
8517 public override Expression CreateExpressionTree (EmitContext ec)
8519 ArrayList args = new ArrayList (2);
8520 args.Add (new Argument (source.CreateExpressionTree (ec)));
8521 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8522 args.Add (new Argument (new Cast (new TypeExpression (typeof (MethodInfo), loc),
8523 new TypeOfMethod (method, loc))));
8524 return CreateExpressionFactoryCall ("Convert", args);
8527 public override Expression DoResolve (EmitContext ec)
8530 // We are born fully resolved
8535 public override void Emit (EmitContext ec)
8538 ec.ig.Emit (OpCodes.Call, method);
8543 // This class is used to "construct" the type during a typecast
8544 // operation. Since the Type.GetType class in .NET can parse
8545 // the type specification, we just use this to construct the type
8546 // one bit at a time.
8548 public class ComposedCast : TypeExpr {
8552 public ComposedCast (Expression left, string dim)
8553 : this (left, dim, left.Location)
8557 public ComposedCast (Expression left, string dim, Location l)
8564 public Expression RemoveNullable ()
8566 if (dim.EndsWith ("?")) {
8567 dim = dim.Substring (0, dim.Length - 1);
8568 if (dim.Length == 0)
8575 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8577 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8581 Type ltype = lexpr.Type;
8582 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8583 Error_VoidInvalidInTheContext (loc);
8588 if ((dim.Length > 0) && (dim [0] == '?')) {
8589 TypeExpr nullable = new Nullable.NullableType (left, loc);
8591 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8592 return nullable.ResolveAsTypeTerminal (ec, false);
8596 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8599 if (dim != "" && dim [0] == '[' &&
8600 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8601 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8606 type = TypeManager.GetConstructedType (ltype, dim);
8611 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8613 if (type.IsPointer && !ec.IsInUnsafeScope){
8618 eclass = ExprClass.Type;
8622 public override string Name {
8623 get { return left + dim; }
8626 public override string FullName {
8627 get { return type.FullName; }
8630 public override string GetSignatureForError ()
8632 return left.GetSignatureForError () + dim;
8635 protected override void CloneTo (CloneContext clonectx, Expression t)
8637 ComposedCast target = (ComposedCast) t;
8639 target.left = left.Clone (clonectx);
8643 public class FixedBufferPtr : Expression {
8646 public FixedBufferPtr (Expression array, Type array_type, Location l)
8651 type = TypeManager.GetPointerType (array_type);
8652 eclass = ExprClass.Value;
8655 public override void Emit(EmitContext ec)
8660 public override Expression DoResolve (EmitContext ec)
8663 // We are born fully resolved
8671 // This class is used to represent the address of an array, used
8672 // only by the Fixed statement, this generates "&a [0]" construct
8673 // for fixed (char *pa = a)
8675 public class ArrayPtr : FixedBufferPtr {
8678 public ArrayPtr (Expression array, Type array_type, Location l):
8679 base (array, array_type, l)
8681 this.array_type = array_type;
8684 public override void Emit (EmitContext ec)
8688 ILGenerator ig = ec.ig;
8689 IntLiteral.EmitInt (ig, 0);
8690 ig.Emit (OpCodes.Ldelema, array_type);
8695 // Encapsulates a conversion rules required for array indexes
8697 public class ArrayIndexCast : Expression
8701 public ArrayIndexCast (Expression expr)
8704 this.loc = expr.Location;
8707 public override Expression CreateExpressionTree (EmitContext ec)
8709 ArrayList args = new ArrayList (2);
8710 args.Add (new Argument (expr.CreateExpressionTree (ec)));
8711 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8712 return CreateExpressionFactoryCall ("ConvertChecked", args);
8715 public override Expression DoResolve (EmitContext ec)
8718 eclass = expr.eclass;
8722 public override void Emit (EmitContext ec)
8726 if (type == TypeManager.int32_type)
8729 if (type == TypeManager.uint32_type)
8730 ec.ig.Emit (OpCodes.Conv_U);
8731 else if (type == TypeManager.int64_type)
8732 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8733 else if (type == TypeManager.uint64_type)
8734 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8736 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8741 // Used by the fixed statement
8743 public class StringPtr : Expression {
8746 public StringPtr (LocalBuilder b, Location l)
8749 eclass = ExprClass.Value;
8750 type = TypeManager.char_ptr_type;
8754 public override Expression DoResolve (EmitContext ec)
8756 // This should never be invoked, we are born in fully
8757 // initialized state.
8762 public override void Emit (EmitContext ec)
8764 if (TypeManager.int_get_offset_to_string_data == null) {
8765 // TODO: Move to resolve !!
8766 TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
8767 TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
8770 ILGenerator ig = ec.ig;
8772 ig.Emit (OpCodes.Ldloc, b);
8773 ig.Emit (OpCodes.Conv_I);
8774 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8775 ig.Emit (OpCodes.Add);
8780 // Implements the `stackalloc' keyword
8782 public class StackAlloc : Expression {
8787 public StackAlloc (Expression type, Expression count, Location l)
8794 public override Expression DoResolve (EmitContext ec)
8796 count = count.Resolve (ec);
8800 if (count.Type != TypeManager.int32_type){
8801 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8806 Constant c = count as Constant;
8807 if (c != null && c.IsNegative) {
8808 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8812 if (ec.InCatch || ec.InFinally) {
8813 Error (255, "Cannot use stackalloc in finally or catch");
8817 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8823 if (!TypeManager.VerifyUnManaged (otype, loc))
8826 type = TypeManager.GetPointerType (otype);
8827 eclass = ExprClass.Value;
8832 public override void Emit (EmitContext ec)
8834 int size = GetTypeSize (otype);
8835 ILGenerator ig = ec.ig;
8838 ig.Emit (OpCodes.Sizeof, otype);
8840 IntConstant.EmitInt (ig, size);
8842 ig.Emit (OpCodes.Mul);
8843 ig.Emit (OpCodes.Localloc);
8846 protected override void CloneTo (CloneContext clonectx, Expression t)
8848 StackAlloc target = (StackAlloc) t;
8849 target.count = count.Clone (clonectx);
8850 target.t = t.Clone (clonectx);
8855 // An object initializer expression
8857 public class ElementInitializer : Expression
8859 Expression initializer;
8860 public readonly string Name;
8862 public ElementInitializer (string name, Expression initializer, Location loc)
8865 this.initializer = initializer;
8869 protected override void CloneTo (CloneContext clonectx, Expression t)
8871 if (initializer == null)
8874 ElementInitializer target = (ElementInitializer) t;
8875 target.initializer = initializer.Clone (clonectx);
8878 public override Expression DoResolve (EmitContext ec)
8880 if (initializer == null)
8881 return EmptyExpressionStatement.Instance;
8883 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8884 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8886 if (element_member == null)
8889 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8891 if (initializer is CollectionOrObjectInitializers) {
8892 Expression previous = ec.CurrentInitializerVariable;
8893 ec.CurrentInitializerVariable = element_member;
8894 initializer = initializer.Resolve (ec);
8895 ec.CurrentInitializerVariable = previous;
8899 Assign a = new Assign (element_member, initializer, loc);
8900 if (a.Resolve (ec) == null)
8904 // Ignore field initializers with default value
8906 Constant c = a.Source as Constant;
8907 if (c != null && c.IsDefaultInitializer (a.Type) && a.Target.eclass == ExprClass.Variable)
8908 return EmptyExpressionStatement.Instance;
8913 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8915 MemberInfo member = members [0];
8916 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8917 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8918 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8920 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8921 TypeManager.GetFullNameSignature (member));
8926 public override void Emit (EmitContext ec)
8928 throw new NotSupportedException ("Should not be reached");
8933 // A collection initializer expression
8935 public class CollectionElementInitializer : Invocation
8937 public class ElementInitializerArgument : Argument
8939 public ElementInitializerArgument (Expression e)
8945 public CollectionElementInitializer (Expression argument)
8946 : base (null, new ArrayList (1), true)
8948 Arguments.Add (argument);
8949 this.loc = argument.Location;
8952 public CollectionElementInitializer (ArrayList arguments, Location loc)
8953 : base (null, arguments, true)
8958 public override Expression CreateExpressionTree (EmitContext ec)
8960 ArrayList args = new ArrayList (2);
8961 args.Add (new Argument (mg.CreateExpressionTree (ec)));
8963 ArrayList expr_initializers = new ArrayList (Arguments.Count);
8964 foreach (Argument a in Arguments)
8965 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
8967 args.Add (new Argument (new ArrayCreation (
8968 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
8969 return CreateExpressionFactoryCall ("ElementInit", args);
8972 public override Expression DoResolve (EmitContext ec)
8974 if (eclass != ExprClass.Invalid)
8977 // TODO: We could call a constructor which takes element count argument,
8978 // for known types like List<T>, Dictionary<T, U>
8980 for (int i = 0; i < Arguments.Count; ++i) {
8981 Expression expr = ((Expression) Arguments [i]).Resolve (ec);
8985 Arguments [i] = new ElementInitializerArgument (expr);
8988 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
8990 return base.DoResolve (ec);
8995 // A block of object or collection initializers
8997 public class CollectionOrObjectInitializers : ExpressionStatement
8999 ArrayList initializers;
9001 public static readonly CollectionOrObjectInitializers Empty =
9002 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9004 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9006 this.initializers = initializers;
9010 public bool IsEmpty {
9012 return initializers.Count == 0;
9016 protected override void CloneTo (CloneContext clonectx, Expression target)
9018 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9020 t.initializers = new ArrayList (initializers.Count);
9021 foreach (Expression e in initializers)
9022 t.initializers.Add (e.Clone (clonectx));
9025 public override Expression CreateExpressionTree (EmitContext ec)
9027 ArrayList expr_initializers = new ArrayList (initializers.Count);
9028 foreach (Expression e in initializers) {
9029 Expression expr = e.CreateExpressionTree (ec);
9031 expr_initializers.Add (expr);
9034 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9037 public override Expression DoResolve (EmitContext ec)
9039 if (eclass != ExprClass.Invalid)
9042 bool is_elements_initialization = false;
9043 ArrayList element_names = null;
9044 for (int i = 0; i < initializers.Count; ++i) {
9045 Expression initializer = (Expression) initializers [i];
9046 ElementInitializer element_initializer = initializer as ElementInitializer;
9049 if (element_initializer != null) {
9050 is_elements_initialization = true;
9051 element_names = new ArrayList (initializers.Count);
9052 element_names.Add (element_initializer.Name);
9054 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9055 TypeManager.ienumerable_type)) {
9056 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9057 "object initializer because type `{1}' does not implement `{2}' interface",
9058 ec.CurrentInitializerVariable.GetSignatureForError (),
9059 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9060 TypeManager.CSharpName (TypeManager.ienumerable_type));
9065 if (is_elements_initialization == (element_initializer == null)) {
9066 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9067 is_elements_initialization ? "object initializer" : "collection initializer");
9071 if (is_elements_initialization) {
9072 if (element_names.Contains (element_initializer.Name)) {
9073 Report.Error (1912, element_initializer.Location,
9074 "An object initializer includes more than one member `{0}' initialization",
9075 element_initializer.Name);
9077 element_names.Add (element_initializer.Name);
9082 Expression e = initializer.Resolve (ec);
9083 if (e == EmptyExpressionStatement.Instance)
9084 initializers.RemoveAt (i--);
9086 initializers [i] = e;
9089 type = typeof (CollectionOrObjectInitializers);
9090 eclass = ExprClass.Variable;
9094 public override void Emit (EmitContext ec)
9099 public override void EmitStatement (EmitContext ec)
9101 foreach (ExpressionStatement e in initializers)
9102 e.EmitStatement (ec);
9107 // New expression with element/object initializers
9109 public class NewInitialize : New
9112 // This class serves as a proxy for variable initializer target instances.
9113 // A real variable is assigned later when we resolve left side of an
9116 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9118 NewInitialize new_instance;
9120 public InitializerTargetExpression (NewInitialize newInstance)
9122 this.type = newInstance.type;
9123 this.loc = newInstance.loc;
9124 this.eclass = newInstance.eclass;
9125 this.new_instance = newInstance;
9128 public override Expression DoResolve (EmitContext ec)
9133 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9138 public override void Emit (EmitContext ec)
9140 new_instance.value_target.Emit (ec);
9143 #region IMemoryLocation Members
9145 public void AddressOf (EmitContext ec, AddressOp mode)
9147 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9153 CollectionOrObjectInitializers initializers;
9155 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9156 : base (requested_type, arguments, l)
9158 this.initializers = initializers;
9161 protected override void CloneTo (CloneContext clonectx, Expression t)
9163 base.CloneTo (clonectx, t);
9165 NewInitialize target = (NewInitialize) t;
9166 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9169 public override Expression CreateExpressionTree (EmitContext ec)
9171 ArrayList args = new ArrayList (2);
9172 args.Add (new Argument (base.CreateExpressionTree (ec)));
9173 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9175 return CreateExpressionFactoryCall ("ListInit", args);
9178 public override Expression DoResolve (EmitContext ec)
9180 if (eclass != ExprClass.Invalid)
9183 Expression e = base.DoResolve (ec);
9187 // Empty initializer can be optimized to simple new
9188 if (initializers.IsEmpty)
9191 Expression previous = ec.CurrentInitializerVariable;
9192 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9193 initializers.Resolve (ec);
9194 ec.CurrentInitializerVariable = previous;
9198 public override void Emit (EmitContext ec)
9203 // If target is a value, let's use it
9205 VariableReference variable = value_target as VariableReference;
9206 if (variable != null) {
9208 StoreFromPtr (ec.ig, type);
9210 variable.Variable.EmitAssign (ec);
9212 if (value_target == null || value_target_set)
9213 value_target = new LocalTemporary (type);
9215 ((LocalTemporary) value_target).Store (ec);
9218 initializers.Emit (ec);
9220 if (variable == null)
9221 value_target.Emit (ec);
9224 public override void EmitStatement (EmitContext ec)
9226 if (initializers.IsEmpty) {
9227 base.EmitStatement (ec);
9233 if (value_target == null) {
9234 LocalTemporary variable = new LocalTemporary (type);
9235 variable.Store (ec);
9236 value_target = variable;
9239 initializers.EmitStatement (ec);
9242 public override bool HasInitializer {
9244 return !initializers.IsEmpty;
9249 public class AnonymousTypeDeclaration : Expression
9251 ArrayList parameters;
9252 readonly TypeContainer parent;
9253 static readonly ArrayList EmptyParameters = new ArrayList (0);
9255 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9257 this.parameters = parameters;
9258 this.parent = parent;
9262 protected override void CloneTo (CloneContext clonectx, Expression target)
9264 if (parameters == null)
9267 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9268 t.parameters = new ArrayList (parameters.Count);
9269 foreach (AnonymousTypeParameter atp in parameters)
9270 t.parameters.Add (atp.Clone (clonectx));
9273 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9275 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9279 type = AnonymousTypeClass.Create (parent, parameters, loc);
9284 type.DefineMembers ();
9288 RootContext.ToplevelTypes.AddAnonymousType (type);
9292 public override Expression DoResolve (EmitContext ec)
9294 AnonymousTypeClass anonymous_type;
9296 if (parameters == null) {
9297 anonymous_type = CreateAnonymousType (EmptyParameters);
9298 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9299 null, loc).Resolve (ec);
9303 ArrayList arguments = new ArrayList (parameters.Count);
9304 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9305 for (int i = 0; i < parameters.Count; ++i) {
9306 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9312 arguments.Add (new Argument (e));
9313 t_args [i] = new TypeExpression (e.Type, e.Location);
9319 anonymous_type = CreateAnonymousType (parameters);
9320 if (anonymous_type == null)
9323 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9324 new TypeArguments (loc, t_args), loc);
9326 return new New (te, arguments, loc).Resolve (ec);
9329 public override void Emit (EmitContext ec)
9331 throw new InternalErrorException ("Should not be reached");
9335 public class AnonymousTypeParameter : Expression
9337 public readonly string Name;
9338 Expression initializer;
9340 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9344 this.initializer = initializer;
9347 public AnonymousTypeParameter (Parameter parameter)
9349 this.Name = parameter.Name;
9350 this.loc = parameter.Location;
9351 this.initializer = new SimpleName (Name, loc);
9354 protected override void CloneTo (CloneContext clonectx, Expression target)
9356 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9357 t.initializer = initializer.Clone (clonectx);
9360 public override bool Equals (object o)
9362 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9363 return other != null && Name == other.Name;
9366 public override int GetHashCode ()
9368 return Name.GetHashCode ();
9371 public override Expression DoResolve (EmitContext ec)
9373 Expression e = initializer.Resolve (ec);
9378 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9379 type == TypeManager.anonymous_method_type || type.IsPointer) {
9380 Error_InvalidInitializer (e);
9387 protected virtual void Error_InvalidInitializer (Expression initializer)
9389 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9390 Name, initializer.GetSignatureForError ());
9393 public override void Emit (EmitContext ec)
9395 throw new InternalErrorException ("Should not be reached");