2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
20 /// This is just a helper class, it is generated by Unary, UnaryMutator
21 /// when an overloaded method has been found. It just emits the code for a
24 public class StaticCallExpr : ExpressionStatement {
28 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
34 eclass = ExprClass.Value;
38 public override Expression DoResolve (EmitContext ec)
41 // We are born fully resolved
46 public override void Emit (EmitContext ec)
49 Invocation.EmitArguments (ec, mi, args, false, null);
51 ec.ig.Emit (OpCodes.Call, mi);
55 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56 Expression e, Location loc)
61 args = new ArrayList (1);
62 Argument a = new Argument (e, Argument.AType.Expression);
64 // We need to resolve the arguments before sending them in !
65 if (!a.Resolve (ec, loc))
69 method = Invocation.OverloadResolve (
70 ec, (MethodGroupExpr) mg, args, false, loc);
75 return new StaticCallExpr ((MethodInfo) method, args, loc);
78 public override void EmitStatement (EmitContext ec)
81 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
82 ec.ig.Emit (OpCodes.Pop);
85 public MethodInfo Method {
90 public class ParenthesizedExpression : Expression
92 public Expression Expr;
94 public ParenthesizedExpression (Expression expr)
97 this.loc = expr.Location;
100 public override Expression DoResolve (EmitContext ec)
102 Expr = Expr.Resolve (ec);
106 public override void Emit (EmitContext ec)
108 throw new Exception ("Should not happen");
111 public override Location Location
114 return Expr.Location;
120 /// Unary expressions.
124 /// Unary implements unary expressions. It derives from
125 /// ExpressionStatement becuase the pre/post increment/decrement
126 /// operators can be used in a statement context.
128 public class Unary : Expression {
129 public enum Operator : byte {
130 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 Indirection, AddressOf, TOP
134 public Operator Oper;
135 public Expression Expr;
137 public Unary (Operator op, Expression expr, Location loc)
145 /// Returns a stringified representation of the Operator
147 static public string OperName (Operator oper)
150 case Operator.UnaryPlus:
152 case Operator.UnaryNegation:
154 case Operator.LogicalNot:
156 case Operator.OnesComplement:
158 case Operator.AddressOf:
160 case Operator.Indirection:
164 return oper.ToString ();
167 public static readonly string [] oper_names;
171 oper_names = new string [(int)Operator.TOP];
173 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
174 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
175 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
176 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
177 oper_names [(int) Operator.Indirection] = "op_Indirection";
178 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
181 void Error23 (Type t)
183 Report.Error (23, loc, "Operator `{0}' cannot be applied to operand of type `{1}'",
184 OperName (Oper), TypeManager.CSharpName (t));
188 /// The result has been already resolved:
190 /// FIXME: a minus constant -128 sbyte cant be turned into a
193 static Expression TryReduceNegative (Constant expr)
197 if (expr is IntConstant)
198 e = new IntConstant (-((IntConstant) expr).Value, expr.Location);
199 else if (expr is UIntConstant){
200 uint value = ((UIntConstant) expr).Value;
202 if (value < 2147483649)
203 return new IntConstant (-(int)value, expr.Location);
205 e = new LongConstant (-value, expr.Location);
207 else if (expr is LongConstant)
208 e = new LongConstant (-((LongConstant) expr).Value, expr.Location);
209 else if (expr is ULongConstant){
210 ulong value = ((ULongConstant) expr).Value;
212 if (value < 9223372036854775809)
213 return new LongConstant(-(long)value, expr.Location);
215 else if (expr is FloatConstant)
216 e = new FloatConstant (-((FloatConstant) expr).Value, expr.Location);
217 else if (expr is DoubleConstant)
218 e = new DoubleConstant (-((DoubleConstant) expr).Value, expr.Location);
219 else if (expr is DecimalConstant)
220 e = new DecimalConstant (-((DecimalConstant) expr).Value, expr.Location);
221 else if (expr is ShortConstant)
222 e = new IntConstant (-((ShortConstant) expr).Value, expr.Location);
223 else if (expr is UShortConstant)
224 e = new IntConstant (-((UShortConstant) expr).Value, expr.Location);
225 else if (expr is SByteConstant)
226 e = new IntConstant (-((SByteConstant) expr).Value, expr.Location);
227 else if (expr is ByteConstant)
228 e = new IntConstant (-((ByteConstant) expr).Value, expr.Location);
233 // This routine will attempt to simplify the unary expression when the
234 // argument is a constant. The result is returned in `result' and the
235 // function returns true or false depending on whether a reduction
236 // was performed or not
238 bool Reduce (EmitContext ec, Constant e, out Expression result)
240 Type expr_type = e.Type;
243 case Operator.UnaryPlus:
244 if (expr_type == TypeManager.bool_type){
253 case Operator.UnaryNegation:
254 result = TryReduceNegative (e);
255 return result != null;
257 case Operator.LogicalNot:
258 if (expr_type != TypeManager.bool_type) {
264 BoolConstant b = (BoolConstant) e;
265 result = new BoolConstant (!(b.Value), b.Location);
268 case Operator.OnesComplement:
269 if (!((expr_type == TypeManager.int32_type) ||
270 (expr_type == TypeManager.uint32_type) ||
271 (expr_type == TypeManager.int64_type) ||
272 (expr_type == TypeManager.uint64_type) ||
273 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
276 if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
277 result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
278 result = result.Resolve (ec);
279 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
280 result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
281 result = result.Resolve (ec);
282 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
283 result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
284 result = result.Resolve (ec);
285 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
286 result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
287 result = result.Resolve (ec);
290 if (result == null || !(result is Constant)){
296 expr_type = result.Type;
297 e = (Constant) result;
300 if (e is EnumConstant){
301 EnumConstant enum_constant = (EnumConstant) e;
304 if (Reduce (ec, enum_constant.Child, out reduced)){
305 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
313 if (expr_type == TypeManager.int32_type){
314 result = new IntConstant (~ ((IntConstant) e).Value, e.Location);
315 } else if (expr_type == TypeManager.uint32_type){
316 result = new UIntConstant (~ ((UIntConstant) e).Value, e.Location);
317 } else if (expr_type == TypeManager.int64_type){
318 result = new LongConstant (~ ((LongConstant) e).Value, e.Location);
319 } else if (expr_type == TypeManager.uint64_type){
320 result = new ULongConstant (~ ((ULongConstant) e).Value, e.Location);
328 case Operator.AddressOf:
332 case Operator.Indirection:
336 throw new Exception ("Can not constant fold: " + Oper.ToString());
339 Expression ResolveOperator (EmitContext ec)
342 // Step 1: Default operations on CLI native types.
345 // Attempt to use a constant folding operation.
346 if (Expr is Constant){
349 if (Reduce (ec, (Constant) Expr, out result))
354 // Step 2: Perform Operator Overload location
356 Type expr_type = Expr.Type;
360 op_name = oper_names [(int) Oper];
362 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
365 Expression e = StaticCallExpr.MakeSimpleCall (
366 ec, (MethodGroupExpr) mg, Expr, loc);
376 // Only perform numeric promotions on:
379 if (expr_type == null)
383 case Operator.LogicalNot:
384 if (expr_type != TypeManager.bool_type) {
385 Expr = ResolveBoolean (ec, Expr, loc);
392 type = TypeManager.bool_type;
395 case Operator.OnesComplement:
396 if (!((expr_type == TypeManager.int32_type) ||
397 (expr_type == TypeManager.uint32_type) ||
398 (expr_type == TypeManager.int64_type) ||
399 (expr_type == TypeManager.uint64_type) ||
400 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
403 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
406 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
409 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
412 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
425 case Operator.AddressOf:
431 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
435 IVariable variable = Expr as IVariable;
436 bool is_fixed = variable != null && variable.VerifyFixed ();
438 if (!ec.InFixedInitializer && !is_fixed) {
439 Error (212, "You can only take the address of unfixed expression inside " +
440 "of a fixed statement initializer");
444 if (ec.InFixedInitializer && is_fixed) {
445 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
449 LocalVariableReference lr = Expr as LocalVariableReference;
451 if (lr.local_info.IsCaptured){
452 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
455 lr.local_info.AddressTaken = true;
456 lr.local_info.Used = true;
459 // According to the specs, a variable is considered definitely assigned if you take
461 if ((variable != null) && (variable.VariableInfo != null))
462 variable.VariableInfo.SetAssigned (ec);
464 type = TypeManager.GetPointerType (Expr.Type);
467 case Operator.Indirection:
473 if (!expr_type.IsPointer){
474 Error (193, "The * or -> operator must be applied to a pointer");
479 // We create an Indirection expression, because
480 // it can implement the IMemoryLocation.
482 return new Indirection (Expr, loc);
484 case Operator.UnaryPlus:
486 // A plus in front of something is just a no-op, so return the child.
490 case Operator.UnaryNegation:
492 // Deals with -literals
493 // int operator- (int x)
494 // long operator- (long x)
495 // float operator- (float f)
496 // double operator- (double d)
497 // decimal operator- (decimal d)
499 Expression expr = null;
502 // transform - - expr into expr
505 Unary unary = (Unary) Expr;
507 if (unary.Oper == Operator.UnaryNegation)
512 // perform numeric promotions to int,
516 // The following is inneficient, because we call
517 // ImplicitConversion too many times.
519 // It is also not clear if we should convert to Float
520 // or Double initially.
522 if (expr_type == TypeManager.uint32_type){
524 // FIXME: handle exception to this rule that
525 // permits the int value -2147483648 (-2^31) to
526 // bt wrote as a decimal interger literal
528 type = TypeManager.int64_type;
529 Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
533 if (expr_type == TypeManager.uint64_type){
535 // FIXME: Handle exception of `long value'
536 // -92233720368547758087 (-2^63) to be wrote as
537 // decimal integer literal.
543 if (expr_type == TypeManager.float_type){
548 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
555 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
562 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
573 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
574 TypeManager.CSharpName (expr_type) + "'");
578 public override Expression DoResolve (EmitContext ec)
580 if (Oper == Operator.AddressOf) {
581 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
583 if (Expr == null || Expr.eclass != ExprClass.Variable){
584 Error (211, "Cannot take the address of the given expression");
589 Expr = Expr.Resolve (ec);
594 if (TypeManager.IsNullableType (Expr.Type))
595 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
597 eclass = ExprClass.Value;
598 return ResolveOperator (ec);
601 public override Expression DoResolveLValue (EmitContext ec, Expression right)
603 if (Oper == Operator.Indirection)
604 return DoResolve (ec);
609 public override void Emit (EmitContext ec)
611 ILGenerator ig = ec.ig;
614 case Operator.UnaryPlus:
615 throw new Exception ("This should be caught by Resolve");
617 case Operator.UnaryNegation:
619 ig.Emit (OpCodes.Ldc_I4_0);
620 if (type == TypeManager.int64_type)
621 ig.Emit (OpCodes.Conv_U8);
623 ig.Emit (OpCodes.Sub_Ovf);
626 ig.Emit (OpCodes.Neg);
631 case Operator.LogicalNot:
633 ig.Emit (OpCodes.Ldc_I4_0);
634 ig.Emit (OpCodes.Ceq);
637 case Operator.OnesComplement:
639 ig.Emit (OpCodes.Not);
642 case Operator.AddressOf:
643 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
647 throw new Exception ("This should not happen: Operator = "
652 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
654 if (Oper == Operator.LogicalNot)
655 Expr.EmitBranchable (ec, target, !onTrue);
657 base.EmitBranchable (ec, target, onTrue);
660 public override string ToString ()
662 return "Unary (" + Oper + ", " + Expr + ")";
668 // Unary operators are turned into Indirection expressions
669 // after semantic analysis (this is so we can take the address
670 // of an indirection).
672 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
674 LocalTemporary temporary;
677 public Indirection (Expression expr, Location l)
680 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
681 eclass = ExprClass.Variable;
685 public override void Emit (EmitContext ec)
690 LoadFromPtr (ec.ig, Type);
693 public void Emit (EmitContext ec, bool leave_copy)
697 ec.ig.Emit (OpCodes.Dup);
698 temporary = new LocalTemporary (ec, expr.Type);
699 temporary.Store (ec);
703 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
705 prepared = prepare_for_load;
709 if (prepare_for_load)
710 ec.ig.Emit (OpCodes.Dup);
714 ec.ig.Emit (OpCodes.Dup);
715 temporary = new LocalTemporary (ec, expr.Type);
716 temporary.Store (ec);
719 StoreFromPtr (ec.ig, type);
721 if (temporary != null)
725 public void AddressOf (EmitContext ec, AddressOp Mode)
730 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
732 return DoResolve (ec);
735 public override Expression DoResolve (EmitContext ec)
738 // Born fully resolved
743 public override string ToString ()
745 return "*(" + expr + ")";
748 #region IVariable Members
750 public VariableInfo VariableInfo {
756 public bool VerifyFixed ()
758 // A pointer-indirection is always fixed.
766 /// Unary Mutator expressions (pre and post ++ and --)
770 /// UnaryMutator implements ++ and -- expressions. It derives from
771 /// ExpressionStatement becuase the pre/post increment/decrement
772 /// operators can be used in a statement context.
774 /// FIXME: Idea, we could split this up in two classes, one simpler
775 /// for the common case, and one with the extra fields for more complex
776 /// classes (indexers require temporary access; overloaded require method)
779 public class UnaryMutator : ExpressionStatement {
781 public enum Mode : byte {
788 PreDecrement = IsDecrement,
789 PostIncrement = IsPost,
790 PostDecrement = IsPost | IsDecrement
794 bool is_expr = false;
795 bool recurse = false;
800 // This is expensive for the simplest case.
802 StaticCallExpr method;
804 public UnaryMutator (Mode m, Expression e, Location l)
811 static string OperName (Mode mode)
813 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
818 /// Returns whether an object of type `t' can be incremented
819 /// or decremented with add/sub (ie, basically whether we can
820 /// use pre-post incr-decr operations on it, but it is not a
821 /// System.Decimal, which we require operator overloading to catch)
823 static bool IsIncrementableNumber (Type t)
825 return (t == TypeManager.sbyte_type) ||
826 (t == TypeManager.byte_type) ||
827 (t == TypeManager.short_type) ||
828 (t == TypeManager.ushort_type) ||
829 (t == TypeManager.int32_type) ||
830 (t == TypeManager.uint32_type) ||
831 (t == TypeManager.int64_type) ||
832 (t == TypeManager.uint64_type) ||
833 (t == TypeManager.char_type) ||
834 (t.IsSubclassOf (TypeManager.enum_type)) ||
835 (t == TypeManager.float_type) ||
836 (t == TypeManager.double_type) ||
837 (t.IsPointer && t != TypeManager.void_ptr_type);
840 Expression ResolveOperator (EmitContext ec)
842 Type expr_type = expr.Type;
845 // Step 1: Perform Operator Overload location
850 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
851 op_name = "op_Increment";
853 op_name = "op_Decrement";
855 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
858 method = StaticCallExpr.MakeSimpleCall (
859 ec, (MethodGroupExpr) mg, expr, loc);
862 } else if (!IsIncrementableNumber (expr_type)) {
863 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
864 TypeManager.CSharpName (expr_type) + "'");
869 // The operand of the prefix/postfix increment decrement operators
870 // should be an expression that is classified as a variable,
871 // a property access or an indexer access
874 if (expr.eclass == ExprClass.Variable){
875 LocalVariableReference var = expr as LocalVariableReference;
876 if ((var != null) && var.IsReadOnly) {
877 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
880 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
881 expr = expr.ResolveLValue (ec, this, Location);
885 expr.Error_UnexpectedKind (ec, "variable, indexer or property access", loc);
892 public override Expression DoResolve (EmitContext ec)
894 expr = expr.Resolve (ec);
899 eclass = ExprClass.Value;
901 if (TypeManager.IsNullableType (expr.Type))
902 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
904 return ResolveOperator (ec);
907 static int PtrTypeSize (Type t)
909 return GetTypeSize (TypeManager.GetElementType (t));
913 // Loads the proper "1" into the stack based on the type, then it emits the
914 // opcode for the operation requested
916 void LoadOneAndEmitOp (EmitContext ec, Type t)
919 // Measure if getting the typecode and using that is more/less efficient
920 // that comparing types. t.GetTypeCode() is an internal call.
922 ILGenerator ig = ec.ig;
924 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
925 LongConstant.EmitLong (ig, 1);
926 else if (t == TypeManager.double_type)
927 ig.Emit (OpCodes.Ldc_R8, 1.0);
928 else if (t == TypeManager.float_type)
929 ig.Emit (OpCodes.Ldc_R4, 1.0F);
930 else if (t.IsPointer){
931 int n = PtrTypeSize (t);
934 ig.Emit (OpCodes.Sizeof, t);
936 IntConstant.EmitInt (ig, n);
938 ig.Emit (OpCodes.Ldc_I4_1);
941 // Now emit the operation
944 if (t == TypeManager.int32_type ||
945 t == TypeManager.int64_type){
946 if ((mode & Mode.IsDecrement) != 0)
947 ig.Emit (OpCodes.Sub_Ovf);
949 ig.Emit (OpCodes.Add_Ovf);
950 } else if (t == TypeManager.uint32_type ||
951 t == TypeManager.uint64_type){
952 if ((mode & Mode.IsDecrement) != 0)
953 ig.Emit (OpCodes.Sub_Ovf_Un);
955 ig.Emit (OpCodes.Add_Ovf_Un);
957 if ((mode & Mode.IsDecrement) != 0)
958 ig.Emit (OpCodes.Sub_Ovf);
960 ig.Emit (OpCodes.Add_Ovf);
963 if ((mode & Mode.IsDecrement) != 0)
964 ig.Emit (OpCodes.Sub);
966 ig.Emit (OpCodes.Add);
969 if (t == TypeManager.sbyte_type){
971 ig.Emit (OpCodes.Conv_Ovf_I1);
973 ig.Emit (OpCodes.Conv_I1);
974 } else if (t == TypeManager.byte_type){
976 ig.Emit (OpCodes.Conv_Ovf_U1);
978 ig.Emit (OpCodes.Conv_U1);
979 } else if (t == TypeManager.short_type){
981 ig.Emit (OpCodes.Conv_Ovf_I2);
983 ig.Emit (OpCodes.Conv_I2);
984 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
986 ig.Emit (OpCodes.Conv_Ovf_U2);
988 ig.Emit (OpCodes.Conv_U2);
993 void EmitCode (EmitContext ec, bool is_expr)
996 this.is_expr = is_expr;
997 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1000 public override void Emit (EmitContext ec)
1003 // We use recurse to allow ourselfs to be the source
1004 // of an assignment. This little hack prevents us from
1005 // having to allocate another expression
1008 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1010 LoadOneAndEmitOp (ec, expr.Type);
1012 ec.ig.Emit (OpCodes.Call, method.Method);
1017 EmitCode (ec, true);
1020 public override void EmitStatement (EmitContext ec)
1022 EmitCode (ec, false);
1027 /// Base class for the `Is' and `As' classes.
1031 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1034 public abstract class Probe : Expression {
1035 public Expression ProbeType;
1036 protected Expression expr;
1037 protected TypeExpr probe_type_expr;
1039 public Probe (Expression expr, Expression probe_type, Location l)
1041 ProbeType = probe_type;
1046 public Expression Expr {
1052 public override Expression DoResolve (EmitContext ec)
1054 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec);
1055 if (probe_type_expr == null)
1057 Type probe_type = probe_type_expr.ResolveType (ec);
1059 expr = expr.Resolve (ec);
1063 if (expr.Type.IsPointer) {
1064 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1072 /// Implementation of the `is' operator.
1074 public class Is : Probe {
1075 public Is (Expression expr, Expression probe_type, Location l)
1076 : base (expr, probe_type, l)
1081 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1086 public override void Emit (EmitContext ec)
1088 ILGenerator ig = ec.ig;
1093 case Action.AlwaysFalse:
1094 ig.Emit (OpCodes.Pop);
1095 IntConstant.EmitInt (ig, 0);
1097 case Action.AlwaysTrue:
1098 ig.Emit (OpCodes.Pop);
1099 IntConstant.EmitInt (ig, 1);
1101 case Action.LeaveOnStack:
1102 // the `e != null' rule.
1103 ig.Emit (OpCodes.Ldnull);
1104 ig.Emit (OpCodes.Ceq);
1105 ig.Emit (OpCodes.Ldc_I4_0);
1106 ig.Emit (OpCodes.Ceq);
1109 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1110 ig.Emit (OpCodes.Ldnull);
1111 ig.Emit (OpCodes.Cgt_Un);
1114 throw new Exception ("never reached");
1117 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1119 ILGenerator ig = ec.ig;
1122 case Action.AlwaysFalse:
1124 ig.Emit (OpCodes.Br, target);
1127 case Action.AlwaysTrue:
1129 ig.Emit (OpCodes.Br, target);
1132 case Action.LeaveOnStack:
1133 // the `e != null' rule.
1135 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1139 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1140 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1143 throw new Exception ("never reached");
1146 public override Expression DoResolve (EmitContext ec)
1148 Expression e = base.DoResolve (ec);
1150 if ((e == null) || (expr == null))
1153 Type etype = expr.Type;
1154 bool warning_always_matches = false;
1155 bool warning_never_matches = false;
1157 type = TypeManager.bool_type;
1158 eclass = ExprClass.Value;
1161 // First case, if at compile time, there is an implicit conversion
1162 // then e != null (objects) or true (value types)
1164 Type probe_type = probe_type_expr.Type;
1165 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1166 if (e != null && !(e is NullCast)){
1168 if (etype.IsValueType)
1169 action = Action.AlwaysTrue;
1171 action = Action.LeaveOnStack;
1173 warning_always_matches = true;
1174 } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1175 if (etype.IsGenericParameter)
1176 expr = new BoxedCast (expr, etype);
1179 // Second case: explicit reference convresion
1181 if (expr is NullLiteral)
1182 action = Action.AlwaysFalse;
1184 action = Action.Probe;
1186 action = Action.AlwaysFalse;
1187 warning_never_matches = true;
1190 if (warning_always_matches)
1191 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1192 else if (warning_never_matches){
1193 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1194 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1202 /// Implementation of the `as' operator.
1204 public class As : Probe {
1205 public As (Expression expr, Expression probe_type, Location l)
1206 : base (expr, probe_type, l)
1210 bool do_isinst = false;
1211 Expression resolved_type;
1213 public override void Emit (EmitContext ec)
1215 ILGenerator ig = ec.ig;
1220 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1223 static void Error_CannotConvertType (Type source, Type target, Location loc)
1225 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1226 TypeManager.CSharpName (source),
1227 TypeManager.CSharpName (target));
1230 public override Expression DoResolve (EmitContext ec)
1232 if (resolved_type == null) {
1233 resolved_type = base.DoResolve (ec);
1235 if (resolved_type == null)
1239 type = probe_type_expr.Type;
1240 eclass = ExprClass.Value;
1241 Type etype = expr.Type;
1243 if (type.IsValueType) {
1244 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1245 TypeManager.CSharpName (type) + "' is a value type)");
1251 // If the type is a type parameter, ensure
1252 // that it is constrained by a class
1254 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1256 Constraints constraints = tpe.TypeParameter.Constraints;
1259 if (constraints == null)
1262 if (!constraints.HasClassConstraint)
1263 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1267 Report.Error (413, loc,
1268 "The as operator requires that the `{0}' type parameter be constrained by a class",
1274 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1281 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1282 if (etype.IsGenericParameter)
1283 expr = new BoxedCast (expr, etype);
1289 Error_CannotConvertType (etype, type, loc);
1295 /// This represents a typecast in the source language.
1297 /// FIXME: Cast expressions have an unusual set of parsing
1298 /// rules, we need to figure those out.
1300 public class Cast : Expression {
1301 Expression target_type;
1304 public Cast (Expression cast_type, Expression expr)
1305 : this (cast_type, expr, cast_type.Location)
1309 public Cast (Expression cast_type, Expression expr, Location loc)
1311 this.target_type = cast_type;
1316 public Expression TargetType {
1322 public Expression Expr {
1331 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1333 if (!ec.ConstantCheckState)
1336 if ((value < min) || (value > max)) {
1337 Error (221, "Constant value `" + value + "' cannot be converted " +
1338 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1339 "syntax to override)");
1346 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1348 if (!ec.ConstantCheckState)
1352 Error (221, "Constant value `" + value + "' cannot be converted " +
1353 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1354 "syntax to override)");
1361 bool CheckUnsigned (EmitContext ec, long value, Type type)
1363 if (!ec.ConstantCheckState)
1367 Error (221, "Constant value `" + value + "' cannot be converted " +
1368 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1369 "syntax to override)");
1376 // TODO: move to constant
1378 /// Attempts to do a compile-time folding of a constant cast.
1380 Expression TryReduce (EmitContext ec, Type target_type)
1382 if (expr.Type == target_type)
1385 if (TypeManager.IsEnumType (target_type) && TypeManager.EnumToUnderlying (target_type) == expr.Type)
1386 return new EnumConstant ((Constant)expr, target_type);
1388 Expression real_expr = expr;
1389 if (real_expr is EnumConstant)
1390 real_expr = ((EnumConstant) real_expr).Child;
1392 if (real_expr is ByteConstant){
1393 byte v = ((ByteConstant) real_expr).Value;
1395 if (target_type == TypeManager.sbyte_type) {
1396 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1398 return new SByteConstant ((sbyte) v, real_expr.Location);
1400 if (target_type == TypeManager.short_type)
1401 return new ShortConstant ((short) v, real_expr.Location);
1402 if (target_type == TypeManager.ushort_type)
1403 return new UShortConstant ((ushort) v, real_expr.Location);
1404 if (target_type == TypeManager.int32_type)
1405 return new IntConstant ((int) v, real_expr.Location);
1406 if (target_type == TypeManager.uint32_type)
1407 return new UIntConstant ((uint) v, real_expr.Location);
1408 if (target_type == TypeManager.int64_type)
1409 return new LongConstant ((long) v, real_expr.Location);
1410 if (target_type == TypeManager.uint64_type)
1411 return new ULongConstant ((ulong) v, real_expr.Location);
1412 if (target_type == TypeManager.float_type)
1413 return new FloatConstant ((float) v, real_expr.Location);
1414 if (target_type == TypeManager.double_type)
1415 return new DoubleConstant ((double) v, real_expr.Location);
1416 if (target_type == TypeManager.char_type)
1417 return new CharConstant ((char) v, real_expr.Location);
1418 if (target_type == TypeManager.decimal_type)
1419 return new DecimalConstant ((decimal) v, real_expr.Location);
1421 if (real_expr is SByteConstant){
1422 sbyte v = ((SByteConstant) real_expr).Value;
1424 if (target_type == TypeManager.byte_type) {
1425 if (!CheckUnsigned (ec, v, target_type))
1427 return new ByteConstant ((byte) v, real_expr.Location);
1429 if (target_type == TypeManager.short_type)
1430 return new ShortConstant ((short) v, real_expr.Location);
1431 if (target_type == TypeManager.ushort_type) {
1432 if (!CheckUnsigned (ec, v, target_type))
1434 return new UShortConstant ((ushort) v, real_expr.Location);
1435 } if (target_type == TypeManager.int32_type)
1436 return new IntConstant ((int) v, real_expr.Location);
1437 if (target_type == TypeManager.uint32_type) {
1438 if (!CheckUnsigned (ec, v, target_type))
1440 return new UIntConstant ((uint) v, real_expr.Location);
1441 } if (target_type == TypeManager.int64_type)
1442 return new LongConstant ((long) v, real_expr.Location);
1443 if (target_type == TypeManager.uint64_type) {
1444 if (!CheckUnsigned (ec, v, target_type))
1446 return new ULongConstant ((ulong) v, real_expr.Location);
1448 if (target_type == TypeManager.float_type)
1449 return new FloatConstant ((float) v, real_expr.Location);
1450 if (target_type == TypeManager.double_type)
1451 return new DoubleConstant ((double) v, real_expr.Location);
1452 if (target_type == TypeManager.char_type) {
1453 if (!CheckUnsigned (ec, v, target_type))
1455 return new CharConstant ((char) v, real_expr.Location);
1457 if (target_type == TypeManager.decimal_type)
1458 return new DecimalConstant ((decimal) v, real_expr.Location);
1460 if (real_expr is ShortConstant){
1461 short v = ((ShortConstant) real_expr).Value;
1463 if (target_type == TypeManager.byte_type) {
1464 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1466 return new ByteConstant ((byte) v, real_expr.Location);
1468 if (target_type == TypeManager.sbyte_type) {
1469 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1471 return new SByteConstant ((sbyte) v, real_expr.Location);
1473 if (target_type == TypeManager.ushort_type) {
1474 if (!CheckUnsigned (ec, v, target_type))
1476 return new UShortConstant ((ushort) v, real_expr.Location);
1478 if (target_type == TypeManager.int32_type)
1479 return new IntConstant ((int) v, real_expr.Location);
1480 if (target_type == TypeManager.uint32_type) {
1481 if (!CheckUnsigned (ec, v, target_type))
1483 return new UIntConstant ((uint) v, real_expr.Location);
1485 if (target_type == TypeManager.int64_type)
1486 return new LongConstant ((long) v, real_expr.Location);
1487 if (target_type == TypeManager.uint64_type) {
1488 if (!CheckUnsigned (ec, v, target_type))
1490 return new ULongConstant ((ulong) v, real_expr.Location);
1492 if (target_type == TypeManager.float_type)
1493 return new FloatConstant ((float) v, real_expr.Location);
1494 if (target_type == TypeManager.double_type)
1495 return new DoubleConstant ((double) v, real_expr.Location);
1496 if (target_type == TypeManager.char_type) {
1497 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1499 return new CharConstant ((char) v, real_expr.Location);
1501 if (target_type == TypeManager.decimal_type)
1502 return new DecimalConstant ((decimal) v, real_expr.Location);
1504 if (real_expr is UShortConstant){
1505 ushort v = ((UShortConstant) real_expr).Value;
1507 if (target_type == TypeManager.byte_type) {
1508 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1510 return new ByteConstant ((byte) v, real_expr.Location);
1512 if (target_type == TypeManager.sbyte_type) {
1513 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1515 return new SByteConstant ((sbyte) v, real_expr.Location);
1517 if (target_type == TypeManager.short_type) {
1518 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1520 return new ShortConstant ((short) v, real_expr.Location);
1522 if (target_type == TypeManager.int32_type)
1523 return new IntConstant ((int) v, real_expr.Location);
1524 if (target_type == TypeManager.uint32_type)
1525 return new UIntConstant ((uint) v, real_expr.Location);
1526 if (target_type == TypeManager.int64_type)
1527 return new LongConstant ((long) v, real_expr.Location);
1528 if (target_type == TypeManager.uint64_type)
1529 return new ULongConstant ((ulong) v, real_expr.Location);
1530 if (target_type == TypeManager.float_type)
1531 return new FloatConstant ((float) v, real_expr.Location);
1532 if (target_type == TypeManager.double_type)
1533 return new DoubleConstant ((double) v, real_expr.Location);
1534 if (target_type == TypeManager.char_type) {
1535 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1537 return new CharConstant ((char) v, real_expr.Location);
1539 if (target_type == TypeManager.decimal_type)
1540 return new DecimalConstant ((decimal) v, real_expr.Location);
1542 if (real_expr is IntConstant){
1543 int v = ((IntConstant) real_expr).Value;
1545 if (target_type == TypeManager.byte_type) {
1546 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1548 return new ByteConstant ((byte) v, real_expr.Location);
1550 if (target_type == TypeManager.sbyte_type) {
1551 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1553 return new SByteConstant ((sbyte) v, real_expr.Location);
1555 if (target_type == TypeManager.short_type) {
1556 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1558 return new ShortConstant ((short) v, real_expr.Location);
1560 if (target_type == TypeManager.ushort_type) {
1561 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1563 return new UShortConstant ((ushort) v, real_expr.Location);
1565 if (target_type == TypeManager.uint32_type) {
1566 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1568 return new UIntConstant ((uint) v, real_expr.Location);
1570 if (target_type == TypeManager.int64_type)
1571 return new LongConstant ((long) v, real_expr.Location);
1572 if (target_type == TypeManager.uint64_type) {
1573 if (!CheckUnsigned (ec, v, target_type))
1575 return new ULongConstant ((ulong) v, real_expr.Location);
1577 if (target_type == TypeManager.float_type)
1578 return new FloatConstant ((float) v, real_expr.Location);
1579 if (target_type == TypeManager.double_type)
1580 return new DoubleConstant ((double) v, real_expr.Location);
1581 if (target_type == TypeManager.char_type) {
1582 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1584 return new CharConstant ((char) v, real_expr.Location);
1586 if (target_type == TypeManager.decimal_type)
1587 return new DecimalConstant ((decimal) v, real_expr.Location);
1589 if (real_expr is UIntConstant){
1590 uint v = ((UIntConstant) real_expr).Value;
1592 if (target_type == TypeManager.byte_type) {
1593 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1595 return new ByteConstant ((byte) v, real_expr.Location);
1597 if (target_type == TypeManager.sbyte_type) {
1598 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1600 return new SByteConstant ((sbyte) v, real_expr.Location);
1602 if (target_type == TypeManager.short_type) {
1603 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1605 return new ShortConstant ((short) v, real_expr.Location);
1607 if (target_type == TypeManager.ushort_type) {
1608 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1610 return new UShortConstant ((ushort) v, real_expr.Location);
1612 if (target_type == TypeManager.int32_type) {
1613 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1615 return new IntConstant ((int) v, real_expr.Location);
1617 if (target_type == TypeManager.int64_type)
1618 return new LongConstant ((long) v, real_expr.Location);
1619 if (target_type == TypeManager.uint64_type)
1620 return new ULongConstant ((ulong) v, real_expr.Location);
1621 if (target_type == TypeManager.float_type)
1622 return new FloatConstant ((float) v, real_expr.Location);
1623 if (target_type == TypeManager.double_type)
1624 return new DoubleConstant ((double) v, real_expr.Location);
1625 if (target_type == TypeManager.char_type) {
1626 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1628 return new CharConstant ((char) v, real_expr.Location);
1630 if (target_type == TypeManager.decimal_type)
1631 return new DecimalConstant ((decimal) v, real_expr.Location);
1633 if (real_expr is LongConstant){
1634 long v = ((LongConstant) real_expr).Value;
1636 if (target_type == TypeManager.byte_type) {
1637 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1639 return new ByteConstant ((byte) v, real_expr.Location);
1641 if (target_type == TypeManager.sbyte_type) {
1642 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1644 return new SByteConstant ((sbyte) v, real_expr.Location);
1646 if (target_type == TypeManager.short_type) {
1647 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1649 return new ShortConstant ((short) v, real_expr.Location);
1651 if (target_type == TypeManager.ushort_type) {
1652 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1654 return new UShortConstant ((ushort) v, real_expr.Location);
1656 if (target_type == TypeManager.int32_type) {
1657 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1659 return new IntConstant ((int) v, real_expr.Location);
1661 if (target_type == TypeManager.uint32_type) {
1662 if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1664 return new UIntConstant ((uint) v, real_expr.Location);
1666 if (target_type == TypeManager.uint64_type) {
1667 if (!CheckUnsigned (ec, v, target_type))
1669 return new ULongConstant ((ulong) v, real_expr.Location);
1671 if (target_type == TypeManager.float_type)
1672 return new FloatConstant ((float) v, real_expr.Location);
1673 if (target_type == TypeManager.double_type)
1674 return new DoubleConstant ((double) v, real_expr.Location);
1675 if (target_type == TypeManager.char_type) {
1676 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1678 return new CharConstant ((char) v, real_expr.Location);
1680 if (target_type == TypeManager.decimal_type)
1681 return new DecimalConstant ((decimal) v, real_expr.Location);
1683 if (real_expr is ULongConstant){
1684 ulong v = ((ULongConstant) real_expr).Value;
1686 if (target_type == TypeManager.byte_type) {
1687 if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1689 return new ByteConstant ((byte) v, real_expr.Location);
1691 if (target_type == TypeManager.sbyte_type) {
1692 if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1694 return new SByteConstant ((sbyte) v, real_expr.Location);
1696 if (target_type == TypeManager.short_type) {
1697 if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1699 return new ShortConstant ((short) v, real_expr.Location);
1701 if (target_type == TypeManager.ushort_type) {
1702 if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1704 return new UShortConstant ((ushort) v, real_expr.Location);
1706 if (target_type == TypeManager.int32_type) {
1707 if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1709 return new IntConstant ((int) v, real_expr.Location);
1711 if (target_type == TypeManager.uint32_type) {
1712 if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1714 return new UIntConstant ((uint) v, real_expr.Location);
1716 if (target_type == TypeManager.int64_type) {
1717 if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1719 return new LongConstant ((long) v, real_expr.Location);
1721 if (target_type == TypeManager.float_type)
1722 return new FloatConstant ((float) v, real_expr.Location);
1723 if (target_type == TypeManager.double_type)
1724 return new DoubleConstant ((double) v, real_expr.Location);
1725 if (target_type == TypeManager.char_type) {
1726 if (!CheckRange (ec, v, target_type, Char.MaxValue))
1728 return new CharConstant ((char) v, real_expr.Location);
1730 if (target_type == TypeManager.decimal_type)
1731 return new DecimalConstant ((decimal) v, real_expr.Location);
1733 if (real_expr is FloatConstant){
1734 float v = ((FloatConstant) real_expr).Value;
1736 if (target_type == TypeManager.byte_type)
1737 return new ByteConstant ((byte) v, real_expr.Location);
1738 if (target_type == TypeManager.sbyte_type)
1739 return new SByteConstant ((sbyte) v, real_expr.Location);
1740 if (target_type == TypeManager.short_type)
1741 return new ShortConstant ((short) v, real_expr.Location);
1742 if (target_type == TypeManager.ushort_type)
1743 return new UShortConstant ((ushort) v, real_expr.Location);
1744 if (target_type == TypeManager.int32_type)
1745 return new IntConstant ((int) v, real_expr.Location);
1746 if (target_type == TypeManager.uint32_type)
1747 return new UIntConstant ((uint) v, real_expr.Location);
1748 if (target_type == TypeManager.int64_type)
1749 return new LongConstant ((long) v, real_expr.Location);
1750 if (target_type == TypeManager.uint64_type)
1751 return new ULongConstant ((ulong) v, real_expr.Location);
1752 if (target_type == TypeManager.double_type)
1753 return new DoubleConstant ((double) v, real_expr.Location);
1754 if (target_type == TypeManager.char_type)
1755 return new CharConstant ((char) v, real_expr.Location);
1756 if (target_type == TypeManager.decimal_type)
1757 return new DecimalConstant ((decimal) v, real_expr.Location);
1759 if (real_expr is DoubleConstant){
1760 double v = ((DoubleConstant) real_expr).Value;
1762 if (target_type == TypeManager.byte_type){
1763 return new ByteConstant ((byte) v, real_expr.Location);
1764 } if (target_type == TypeManager.sbyte_type)
1765 return new SByteConstant ((sbyte) v, real_expr.Location);
1766 if (target_type == TypeManager.short_type)
1767 return new ShortConstant ((short) v, real_expr.Location);
1768 if (target_type == TypeManager.ushort_type)
1769 return new UShortConstant ((ushort) v, real_expr.Location);
1770 if (target_type == TypeManager.int32_type)
1771 return new IntConstant ((int) v, real_expr.Location);
1772 if (target_type == TypeManager.uint32_type)
1773 return new UIntConstant ((uint) v, real_expr.Location);
1774 if (target_type == TypeManager.int64_type)
1775 return new LongConstant ((long) v, real_expr.Location);
1776 if (target_type == TypeManager.uint64_type)
1777 return new ULongConstant ((ulong) v, real_expr.Location);
1778 if (target_type == TypeManager.float_type)
1779 return new FloatConstant ((float) v, real_expr.Location);
1780 if (target_type == TypeManager.char_type)
1781 return new CharConstant ((char) v, real_expr.Location);
1782 if (target_type == TypeManager.decimal_type)
1783 return new DecimalConstant ((decimal) v, real_expr.Location);
1786 if (real_expr is CharConstant){
1787 char v = ((CharConstant) real_expr).Value;
1789 if (target_type == TypeManager.byte_type) {
1790 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1792 return new ByteConstant ((byte) v, real_expr.Location);
1794 if (target_type == TypeManager.sbyte_type) {
1795 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1797 return new SByteConstant ((sbyte) v, real_expr.Location);
1799 if (target_type == TypeManager.short_type) {
1800 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1802 return new ShortConstant ((short) v, real_expr.Location);
1804 if (target_type == TypeManager.int32_type)
1805 return new IntConstant ((int) v, real_expr.Location);
1806 if (target_type == TypeManager.uint32_type)
1807 return new UIntConstant ((uint) v, real_expr.Location);
1808 if (target_type == TypeManager.int64_type)
1809 return new LongConstant ((long) v, real_expr.Location);
1810 if (target_type == TypeManager.uint64_type)
1811 return new ULongConstant ((ulong) v, real_expr.Location);
1812 if (target_type == TypeManager.float_type)
1813 return new FloatConstant ((float) v, real_expr.Location);
1814 if (target_type == TypeManager.double_type)
1815 return new DoubleConstant ((double) v, real_expr.Location);
1816 if (target_type == TypeManager.char_type) {
1817 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1819 return new CharConstant ((char) v, real_expr.Location);
1821 if (target_type == TypeManager.decimal_type)
1822 return new DecimalConstant ((decimal) v, real_expr.Location);
1828 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1830 expr = expr.DoResolveLValue (ec, right_side);
1834 return ResolveRest (ec);
1837 public override Expression DoResolve (EmitContext ec)
1839 expr = expr.Resolve (ec);
1843 return ResolveRest (ec);
1846 Expression ResolveRest (EmitContext ec)
1848 TypeExpr target = target_type.ResolveAsTypeTerminal (ec);
1852 type = target.ResolveType (ec);
1854 if (type.IsAbstract && type.IsSealed) {
1855 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1859 eclass = ExprClass.Value;
1861 if (expr is Constant){
1862 Expression e = TryReduce (ec, type);
1868 if (type.IsPointer && !ec.InUnsafe) {
1872 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1876 public override void Emit (EmitContext ec)
1879 // This one will never happen
1881 throw new Exception ("Should not happen");
1886 /// Binary operators
1888 public class Binary : Expression {
1889 public enum Operator : byte {
1890 Multiply, Division, Modulus,
1891 Addition, Subtraction,
1892 LeftShift, RightShift,
1893 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1894 Equality, Inequality,
1904 Expression left, right;
1906 // This must be kept in sync with Operator!!!
1907 public static readonly string [] oper_names;
1911 oper_names = new string [(int) Operator.TOP];
1913 oper_names [(int) Operator.Multiply] = "op_Multiply";
1914 oper_names [(int) Operator.Division] = "op_Division";
1915 oper_names [(int) Operator.Modulus] = "op_Modulus";
1916 oper_names [(int) Operator.Addition] = "op_Addition";
1917 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1918 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1919 oper_names [(int) Operator.RightShift] = "op_RightShift";
1920 oper_names [(int) Operator.LessThan] = "op_LessThan";
1921 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1922 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1923 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1924 oper_names [(int) Operator.Equality] = "op_Equality";
1925 oper_names [(int) Operator.Inequality] = "op_Inequality";
1926 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1927 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1928 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1929 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1930 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1933 public Binary (Operator oper, Expression left, Expression right)
1938 this.loc = left.Location;
1941 public Operator Oper {
1950 public Expression Left {
1959 public Expression Right {
1970 /// Returns a stringified representation of the Operator
1972 static string OperName (Operator oper)
1975 case Operator.Multiply:
1977 case Operator.Division:
1979 case Operator.Modulus:
1981 case Operator.Addition:
1983 case Operator.Subtraction:
1985 case Operator.LeftShift:
1987 case Operator.RightShift:
1989 case Operator.LessThan:
1991 case Operator.GreaterThan:
1993 case Operator.LessThanOrEqual:
1995 case Operator.GreaterThanOrEqual:
1997 case Operator.Equality:
1999 case Operator.Inequality:
2001 case Operator.BitwiseAnd:
2003 case Operator.BitwiseOr:
2005 case Operator.ExclusiveOr:
2007 case Operator.LogicalOr:
2009 case Operator.LogicalAnd:
2013 return oper.ToString ();
2016 public override string ToString ()
2018 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
2019 right.ToString () + ")";
2022 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
2024 if (expr.Type == target_type)
2027 return Convert.ImplicitConversion (ec, expr, target_type, loc);
2030 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
2033 34, loc, "Operator `" + OperName (oper)
2034 + "' is ambiguous on operands of type `"
2035 + TypeManager.CSharpName (l) + "' "
2036 + "and `" + TypeManager.CSharpName (r)
2040 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
2042 if ((l == t) || (r == t))
2045 if (!check_user_conversions)
2048 if (Convert.ImplicitUserConversionExists (ec, l, t))
2050 else if (Convert.ImplicitUserConversionExists (ec, r, t))
2057 // Note that handling the case l == Decimal || r == Decimal
2058 // is taken care of by the Step 1 Operator Overload resolution.
2060 // If `check_user_conv' is true, we also check whether a user-defined conversion
2061 // exists. Note that we only need to do this if both arguments are of a user-defined
2062 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
2063 // so we don't explicitly check for performance reasons.
2065 bool DoNumericPromotions (EmitContext ec, Type l, Type r, Expression lexpr, Expression rexpr, bool check_user_conv)
2067 if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
2069 // If either operand is of type double, the other operand is
2070 // conveted to type double.
2072 if (r != TypeManager.double_type)
2073 right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
2074 if (l != TypeManager.double_type)
2075 left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
2077 type = TypeManager.double_type;
2078 } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
2080 // if either operand is of type float, the other operand is
2081 // converted to type float.
2083 if (r != TypeManager.double_type)
2084 right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
2085 if (l != TypeManager.double_type)
2086 left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
2087 type = TypeManager.float_type;
2088 } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2092 // If either operand is of type ulong, the other operand is
2093 // converted to type ulong. or an error ocurrs if the other
2094 // operand is of type sbyte, short, int or long
2096 if (l == TypeManager.uint64_type){
2097 if (r != TypeManager.uint64_type){
2098 if (right is IntConstant){
2099 IntConstant ic = (IntConstant) right;
2101 e = Convert.TryImplicitIntConversion (l, ic);
2104 } else if (right is LongConstant){
2105 long ll = ((LongConstant) right).Value;
2108 right = new ULongConstant ((ulong) ll, right.Location);
2110 e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2117 if (left is IntConstant){
2118 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2121 } else if (left is LongConstant){
2122 long ll = ((LongConstant) left).Value;
2125 left = new ULongConstant ((ulong) ll, right.Location);
2127 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2134 if ((other == TypeManager.sbyte_type) ||
2135 (other == TypeManager.short_type) ||
2136 (other == TypeManager.int32_type) ||
2137 (other == TypeManager.int64_type))
2138 Error_OperatorAmbiguous (loc, oper, l, r);
2140 left = ForceConversion (ec, left, TypeManager.uint64_type);
2141 right = ForceConversion (ec, right, TypeManager.uint64_type);
2143 type = TypeManager.uint64_type;
2144 } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2146 // If either operand is of type long, the other operand is converted
2149 if (l != TypeManager.int64_type)
2150 left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2151 if (r != TypeManager.int64_type)
2152 right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2154 type = TypeManager.int64_type;
2155 } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2157 // If either operand is of type uint, and the other
2158 // operand is of type sbyte, short or int, othe operands are
2159 // converted to type long (unless we have an int constant).
2163 if (l == TypeManager.uint32_type){
2164 if (right is IntConstant){
2165 IntConstant ic = (IntConstant) right;
2169 right = new UIntConstant ((uint) val, ic.Location);
2176 } else if (r == TypeManager.uint32_type){
2177 if (left is IntConstant){
2178 IntConstant ic = (IntConstant) left;
2182 left = new UIntConstant ((uint) val, ic.Location);
2191 if ((other == TypeManager.sbyte_type) ||
2192 (other == TypeManager.short_type) ||
2193 (other == TypeManager.int32_type)){
2194 left = ForceConversion (ec, left, TypeManager.int64_type);
2195 right = ForceConversion (ec, right, TypeManager.int64_type);
2196 type = TypeManager.int64_type;
2199 // if either operand is of type uint, the other
2200 // operand is converd to type uint
2202 left = ForceConversion (ec, left, TypeManager.uint32_type);
2203 right = ForceConversion (ec, right, TypeManager.uint32_type);
2204 type = TypeManager.uint32_type;
2206 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2207 if (l != TypeManager.decimal_type)
2208 left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2210 if (r != TypeManager.decimal_type)
2211 right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2212 type = TypeManager.decimal_type;
2214 left = ForceConversion (ec, left, TypeManager.int32_type);
2215 right = ForceConversion (ec, right, TypeManager.int32_type);
2218 Convert.ImplicitConversionExists (ec, lexpr, TypeManager.string_type) &&
2219 Convert.ImplicitConversionExists (ec, rexpr, TypeManager.string_type);
2220 if (strConv && left != null && right != null)
2221 Error_OperatorAmbiguous (loc, oper, l, r);
2223 type = TypeManager.int32_type;
2226 return (left != null) && (right != null);
2229 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2231 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
2234 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
2236 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2240 void Error_OperatorCannotBeApplied ()
2242 Error_OperatorCannotBeApplied (Location, OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2245 static bool is_unsigned (Type t)
2247 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2248 t == TypeManager.short_type || t == TypeManager.byte_type);
2251 static bool is_user_defined (Type t)
2253 if (t.IsSubclassOf (TypeManager.value_type) &&
2254 (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2260 Expression Make32or64 (EmitContext ec, Expression e)
2264 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2265 t == TypeManager.int64_type || t == TypeManager.uint64_type)
2267 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
2270 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
2273 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
2276 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
2282 Expression CheckShiftArguments (EmitContext ec)
2286 e = ForceConversion (ec, right, TypeManager.int32_type);
2288 Error_OperatorCannotBeApplied ();
2293 if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2294 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2295 ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2296 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2300 if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
2301 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (31, loc));
2302 right = right.DoResolve (ec);
2304 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (63, loc));
2305 right = right.DoResolve (ec);
2310 Error_OperatorCannotBeApplied ();
2315 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2316 // i.e., not invoke op_Equality.
2318 static bool EqualsNullIsReferenceEquals (Type t)
2320 return t == TypeManager.object_type || t == TypeManager.string_type ||
2321 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
2324 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
2326 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
2327 "Possible unintended reference comparison; to get a value comparison, " +
2328 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
2331 Expression ResolveOperator (EmitContext ec)
2334 Type r = right.Type;
2336 if (oper == Operator.Equality || oper == Operator.Inequality){
2337 if (l.IsGenericParameter && (right is NullLiteral)) {
2338 if (l.BaseType == TypeManager.value_type) {
2339 Error_OperatorCannotBeApplied ();
2343 left = new BoxedCast (left, TypeManager.object_type);
2344 Type = TypeManager.bool_type;
2348 if (r.IsGenericParameter && (left is NullLiteral)) {
2349 if (r.BaseType == TypeManager.value_type) {
2350 Error_OperatorCannotBeApplied ();
2354 right = new BoxedCast (right, TypeManager.object_type);
2355 Type = TypeManager.bool_type;
2360 // Optimize out call to op_Equality in a few cases.
2362 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
2363 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
2364 Type = TypeManager.bool_type;
2370 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
2371 Type = TypeManager.bool_type;
2378 // Do not perform operator overload resolution when both sides are
2381 Expression left_operators = null, right_operators = null;
2382 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){
2384 // Step 1: Perform Operator Overload location
2386 string op = oper_names [(int) oper];
2388 MethodGroupExpr union;
2389 left_operators = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2391 right_operators = MemberLookup (
2392 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2393 union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
2395 union = (MethodGroupExpr) left_operators;
2397 if (union != null) {
2398 ArrayList args = new ArrayList (2);
2399 args.Add (new Argument (left, Argument.AType.Expression));
2400 args.Add (new Argument (right, Argument.AType.Expression));
2402 MethodBase method = Invocation.OverloadResolve (
2403 ec, union, args, true, Location.Null);
2405 if (method != null) {
2406 MethodInfo mi = (MethodInfo) method;
2408 return new BinaryMethod (mi.ReturnType, method, args);
2414 // Step 0: String concatenation (because overloading will get this wrong)
2416 if (oper == Operator.Addition){
2418 // If any of the arguments is a string, cast to string
2421 // Simple constant folding
2422 if (left is StringConstant && right is StringConstant)
2423 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
2425 if (l == TypeManager.string_type || r == TypeManager.string_type) {
2427 if (r == TypeManager.void_type || l == TypeManager.void_type) {
2428 Error_OperatorCannotBeApplied ();
2432 // try to fold it in on the left
2433 if (left is StringConcat) {
2436 // We have to test here for not-null, since we can be doubly-resolved
2437 // take care of not appending twice
2440 type = TypeManager.string_type;
2441 ((StringConcat) left).Append (ec, right);
2442 return left.Resolve (ec);
2448 // Otherwise, start a new concat expression
2449 return new StringConcat (ec, loc, left, right).Resolve (ec);
2453 // Transform a + ( - b) into a - b
2455 if (right is Unary){
2456 Unary right_unary = (Unary) right;
2458 if (right_unary.Oper == Unary.Operator.UnaryNegation){
2459 oper = Operator.Subtraction;
2460 right = right_unary.Expr;
2466 if (oper == Operator.Equality || oper == Operator.Inequality){
2467 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2468 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2469 Error_OperatorCannotBeApplied ();
2473 type = TypeManager.bool_type;
2477 if (l.IsPointer || r.IsPointer) {
2478 if (l.IsPointer && r.IsPointer) {
2479 type = TypeManager.bool_type;
2483 if (l.IsPointer && r == TypeManager.null_type) {
2484 right = new EmptyCast (NullPointer.Null, l);
2485 type = TypeManager.bool_type;
2489 if (r.IsPointer && l == TypeManager.null_type) {
2490 left = new EmptyCast (NullPointer.Null, r);
2491 type = TypeManager.bool_type;
2496 if (l.IsGenericParameter && r.IsGenericParameter) {
2497 GenericConstraints l_gc, r_gc;
2499 l_gc = TypeManager.GetTypeParameterConstraints (l);
2500 r_gc = TypeManager.GetTypeParameterConstraints (r);
2502 if ((l_gc == null) || (r_gc == null) ||
2503 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
2504 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
2505 Error_OperatorCannotBeApplied ();
2512 // operator != (object a, object b)
2513 // operator == (object a, object b)
2515 // For this to be used, both arguments have to be reference-types.
2516 // Read the rationale on the spec (14.9.6)
2518 if (!(l.IsValueType || r.IsValueType)){
2519 type = TypeManager.bool_type;
2525 // Also, a standard conversion must exist from either one
2527 bool left_to_right =
2528 Convert.ImplicitStandardConversionExists (ec, left, r);
2529 bool right_to_left = !left_to_right &&
2530 Convert.ImplicitStandardConversionExists (ec, right, l);
2532 if (!left_to_right && !right_to_left) {
2533 Error_OperatorCannotBeApplied ();
2537 if (left_to_right && left_operators != null &&
2538 RootContext.WarningLevel >= 2) {
2539 ArrayList args = new ArrayList (2);
2540 args.Add (new Argument (left, Argument.AType.Expression));
2541 args.Add (new Argument (left, Argument.AType.Expression));
2542 MethodBase method = Invocation.OverloadResolve (
2543 ec, (MethodGroupExpr) left_operators, args, true, Location.Null);
2545 Warning_UnintendedReferenceComparison (loc, "right", l);
2548 if (right_to_left && right_operators != null &&
2549 RootContext.WarningLevel >= 2) {
2550 ArrayList args = new ArrayList (2);
2551 args.Add (new Argument (right, Argument.AType.Expression));
2552 args.Add (new Argument (right, Argument.AType.Expression));
2553 MethodBase method = Invocation.OverloadResolve (
2554 ec, (MethodGroupExpr) right_operators, args, true, Location.Null);
2556 Warning_UnintendedReferenceComparison (loc, "left", r);
2560 // We are going to have to convert to an object to compare
2562 if (l != TypeManager.object_type)
2563 left = new EmptyCast (left, TypeManager.object_type);
2564 if (r != TypeManager.object_type)
2565 right = new EmptyCast (right, TypeManager.object_type);
2568 // FIXME: CSC here catches errors cs254 and cs252
2574 // One of them is a valuetype, but the other one is not.
2576 if (!l.IsValueType || !r.IsValueType) {
2577 Error_OperatorCannotBeApplied ();
2582 // Only perform numeric promotions on:
2583 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2585 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2586 if (TypeManager.IsDelegateType (l)){
2587 if (((right.eclass == ExprClass.MethodGroup) ||
2588 (r == TypeManager.anonymous_method_type))){
2589 if ((RootContext.Version != LanguageVersion.ISO_1)){
2590 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2598 if (TypeManager.IsDelegateType (r)){
2600 ArrayList args = new ArrayList (2);
2602 args = new ArrayList (2);
2603 args.Add (new Argument (left, Argument.AType.Expression));
2604 args.Add (new Argument (right, Argument.AType.Expression));
2606 if (oper == Operator.Addition)
2607 method = TypeManager.delegate_combine_delegate_delegate;
2609 method = TypeManager.delegate_remove_delegate_delegate;
2611 if (!TypeManager.IsEqual (l, r)) {
2612 Error_OperatorCannotBeApplied ();
2616 return new BinaryDelegate (l, method, args);
2621 // Pointer arithmetic:
2623 // T* operator + (T* x, int y);
2624 // T* operator + (T* x, uint y);
2625 // T* operator + (T* x, long y);
2626 // T* operator + (T* x, ulong y);
2628 // T* operator + (int y, T* x);
2629 // T* operator + (uint y, T *x);
2630 // T* operator + (long y, T *x);
2631 // T* operator + (ulong y, T *x);
2633 // T* operator - (T* x, int y);
2634 // T* operator - (T* x, uint y);
2635 // T* operator - (T* x, long y);
2636 // T* operator - (T* x, ulong y);
2638 // long operator - (T* x, T *y)
2641 if (r.IsPointer && oper == Operator.Subtraction){
2643 return new PointerArithmetic (
2644 false, left, right, TypeManager.int64_type,
2647 Expression t = Make32or64 (ec, right);
2649 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2651 } else if (r.IsPointer && oper == Operator.Addition){
2652 Expression t = Make32or64 (ec, left);
2654 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2659 // Enumeration operators
2661 bool lie = TypeManager.IsEnumType (l);
2662 bool rie = TypeManager.IsEnumType (r);
2666 // U operator - (E e, E f)
2668 if (oper == Operator.Subtraction){
2670 type = TypeManager.EnumToUnderlying (l);
2673 Error_OperatorCannotBeApplied ();
2679 // operator + (E e, U x)
2680 // operator - (E e, U x)
2682 if (oper == Operator.Addition || oper == Operator.Subtraction){
2683 Type enum_type = lie ? l : r;
2684 Type other_type = lie ? r : l;
2685 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2687 if (underlying_type != other_type){
2688 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2698 Error_OperatorCannotBeApplied ();
2707 temp = Convert.ImplicitConversion (ec, right, l, loc);
2711 Error_OperatorCannotBeApplied ();
2715 temp = Convert.ImplicitConversion (ec, left, r, loc);
2720 Error_OperatorCannotBeApplied ();
2725 if (oper == Operator.Equality || oper == Operator.Inequality ||
2726 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2727 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2728 if (left.Type != right.Type){
2729 Error_OperatorCannotBeApplied ();
2732 type = TypeManager.bool_type;
2736 if (oper == Operator.BitwiseAnd ||
2737 oper == Operator.BitwiseOr ||
2738 oper == Operator.ExclusiveOr){
2739 if (left.Type != right.Type){
2740 Error_OperatorCannotBeApplied ();
2746 Error_OperatorCannotBeApplied ();
2750 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2751 return CheckShiftArguments (ec);
2753 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2754 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2755 type = TypeManager.bool_type;
2760 Error_OperatorCannotBeApplied ();
2764 Expression e = new ConditionalLogicalOperator (
2765 oper == Operator.LogicalAnd, left, right, l, loc);
2766 return e.Resolve (ec);
2770 // operator & (bool x, bool y)
2771 // operator | (bool x, bool y)
2772 // operator ^ (bool x, bool y)
2774 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2775 if (oper == Operator.BitwiseAnd ||
2776 oper == Operator.BitwiseOr ||
2777 oper == Operator.ExclusiveOr){
2784 // Pointer comparison
2786 if (l.IsPointer && r.IsPointer){
2787 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2788 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2789 type = TypeManager.bool_type;
2795 // This will leave left or right set to null if there is an error
2797 bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2798 DoNumericPromotions (ec, l, r, left, right, check_user_conv);
2799 if (left == null || right == null){
2800 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2805 // reload our cached types if required
2810 if (oper == Operator.BitwiseAnd ||
2811 oper == Operator.BitwiseOr ||
2812 oper == Operator.ExclusiveOr){
2814 if (((l == TypeManager.int32_type) ||
2815 (l == TypeManager.uint32_type) ||
2816 (l == TypeManager.short_type) ||
2817 (l == TypeManager.ushort_type) ||
2818 (l == TypeManager.int64_type) ||
2819 (l == TypeManager.uint64_type))){
2822 Error_OperatorCannotBeApplied ();
2826 Error_OperatorCannotBeApplied ();
2831 if (oper == Operator.Equality ||
2832 oper == Operator.Inequality ||
2833 oper == Operator.LessThanOrEqual ||
2834 oper == Operator.LessThan ||
2835 oper == Operator.GreaterThanOrEqual ||
2836 oper == Operator.GreaterThan){
2837 type = TypeManager.bool_type;
2843 public override Expression DoResolve (EmitContext ec)
2845 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2846 left = ((ParenthesizedExpression) left).Expr;
2847 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2851 if (left.eclass == ExprClass.Type) {
2852 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2856 left = left.Resolve (ec);
2861 Constant lc = left as Constant;
2862 if (lc != null && lc.Type == TypeManager.bool_type &&
2863 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2864 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2866 // TODO: make a sense to resolve unreachable expression as we do for statement
2867 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2871 right = right.Resolve (ec);
2875 eclass = ExprClass.Value;
2877 Constant rc = right as Constant;
2879 if (oper == Operator.BitwiseAnd) {
2880 if (rc != null && rc.IsZeroInteger) {
2881 return lc is EnumConstant ?
2882 new EnumConstant (rc, lc.Type):
2886 if (lc != null && lc.IsZeroInteger) {
2887 return rc is EnumConstant ?
2888 new EnumConstant (lc, rc.Type):
2892 else if (oper == Operator.BitwiseOr) {
2893 if (lc is EnumConstant &&
2894 rc != null && rc.IsZeroInteger)
2896 if (rc is EnumConstant &&
2897 lc != null && lc.IsZeroInteger)
2901 if (rc != null && lc != null){
2902 int prev_e = Report.Errors;
2903 Expression e = ConstantFold.BinaryFold (
2904 ec, oper, lc, rc, loc);
2905 if (e != null || Report.Errors != prev_e)
2909 if (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type))
2910 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2912 // Check CS0652 warning here (before resolving operator).
2913 if (oper == Operator.Equality ||
2914 oper == Operator.Inequality ||
2915 oper == Operator.LessThanOrEqual ||
2916 oper == Operator.LessThan ||
2917 oper == Operator.GreaterThanOrEqual ||
2918 oper == Operator.GreaterThan){
2919 CheckUselessComparison (left as Constant, right.Type);
2920 CheckUselessComparison (right as Constant, left.Type);
2923 return ResolveOperator (ec);
2926 private void CheckUselessComparison (Constant c, Type type)
2928 if (c == null || !IsTypeIntegral (type)
2929 || c is StringConstant
2930 || c is BoolConstant
2931 || c is CharConstant
2932 || c is FloatConstant
2933 || c is DoubleConstant
2934 || c is DecimalConstant
2940 if (c is ULongConstant) {
2941 ulong uvalue = ((ULongConstant) c).Value;
2942 if (uvalue > long.MaxValue) {
2943 if (type == TypeManager.byte_type ||
2944 type == TypeManager.sbyte_type ||
2945 type == TypeManager.short_type ||
2946 type == TypeManager.ushort_type ||
2947 type == TypeManager.int32_type ||
2948 type == TypeManager.uint32_type ||
2949 type == TypeManager.int64_type)
2950 WarnUselessComparison (type);
2953 value = (long) uvalue;
2955 else if (c is ByteConstant)
2956 value = ((ByteConstant) c).Value;
2957 else if (c is SByteConstant)
2958 value = ((SByteConstant) c).Value;
2959 else if (c is ShortConstant)
2960 value = ((ShortConstant) c).Value;
2961 else if (c is UShortConstant)
2962 value = ((UShortConstant) c).Value;
2963 else if (c is IntConstant)
2964 value = ((IntConstant) c).Value;
2965 else if (c is UIntConstant)
2966 value = ((UIntConstant) c).Value;
2967 else if (c is LongConstant)
2968 value = ((LongConstant) c).Value;
2971 if (IsValueOutOfRange (value, type))
2972 WarnUselessComparison (type);
2977 private bool IsValueOutOfRange (long value, Type type)
2979 if (IsTypeUnsigned (type) && value < 0)
2981 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2982 type == TypeManager.byte_type && value >= 0x100 ||
2983 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2984 type == TypeManager.ushort_type && value >= 0x10000 ||
2985 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2986 type == TypeManager.uint32_type && value >= 0x100000000;
2989 private static bool IsTypeIntegral (Type type)
2991 return type == TypeManager.uint64_type ||
2992 type == TypeManager.int64_type ||
2993 type == TypeManager.uint32_type ||
2994 type == TypeManager.int32_type ||
2995 type == TypeManager.ushort_type ||
2996 type == TypeManager.short_type ||
2997 type == TypeManager.sbyte_type ||
2998 type == TypeManager.byte_type;
3001 private static bool IsTypeUnsigned (Type type)
3003 return type == TypeManager.uint64_type ||
3004 type == TypeManager.uint32_type ||
3005 type == TypeManager.ushort_type ||
3006 type == TypeManager.byte_type;
3009 private void WarnUselessComparison (Type type)
3011 Report.Warning (652, 2, loc, "Comparison to integral constant is useless; the constant is outside the range of type `{0}'",
3012 TypeManager.CSharpName (type));
3016 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3017 /// context of a conditional bool expression. This function will return
3018 /// false if it is was possible to use EmitBranchable, or true if it was.
3020 /// The expression's code is generated, and we will generate a branch to `target'
3021 /// if the resulting expression value is equal to isTrue
3023 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
3025 ILGenerator ig = ec.ig;
3028 // This is more complicated than it looks, but its just to avoid
3029 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3030 // but on top of that we want for == and != to use a special path
3031 // if we are comparing against null
3033 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3034 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
3037 // put the constant on the rhs, for simplicity
3039 if (left is Constant) {
3040 Expression swap = right;
3045 if (((Constant) right).IsZeroInteger) {
3048 ig.Emit (OpCodes.Brtrue, target);
3050 ig.Emit (OpCodes.Brfalse, target);
3053 } else if (right is BoolConstant){
3055 if (my_on_true != ((BoolConstant) right).Value)
3056 ig.Emit (OpCodes.Brtrue, target);
3058 ig.Emit (OpCodes.Brfalse, target);
3063 } else if (oper == Operator.LogicalAnd) {
3066 Label tests_end = ig.DefineLabel ();
3068 left.EmitBranchable (ec, tests_end, false);
3069 right.EmitBranchable (ec, target, true);
3070 ig.MarkLabel (tests_end);
3072 left.EmitBranchable (ec, target, false);
3073 right.EmitBranchable (ec, target, false);
3078 } else if (oper == Operator.LogicalOr){
3080 left.EmitBranchable (ec, target, true);
3081 right.EmitBranchable (ec, target, true);
3084 Label tests_end = ig.DefineLabel ();
3085 left.EmitBranchable (ec, tests_end, true);
3086 right.EmitBranchable (ec, target, false);
3087 ig.MarkLabel (tests_end);
3092 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3093 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3094 oper == Operator.Equality || oper == Operator.Inequality)) {
3095 base.EmitBranchable (ec, target, onTrue);
3103 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
3106 case Operator.Equality:
3108 ig.Emit (OpCodes.Beq, target);
3110 ig.Emit (OpCodes.Bne_Un, target);
3113 case Operator.Inequality:
3115 ig.Emit (OpCodes.Bne_Un, target);
3117 ig.Emit (OpCodes.Beq, target);
3120 case Operator.LessThan:
3123 ig.Emit (OpCodes.Blt_Un, target);
3125 ig.Emit (OpCodes.Blt, target);
3128 ig.Emit (OpCodes.Bge_Un, target);
3130 ig.Emit (OpCodes.Bge, target);
3133 case Operator.GreaterThan:
3136 ig.Emit (OpCodes.Bgt_Un, target);
3138 ig.Emit (OpCodes.Bgt, target);
3141 ig.Emit (OpCodes.Ble_Un, target);
3143 ig.Emit (OpCodes.Ble, target);
3146 case Operator.LessThanOrEqual:
3149 ig.Emit (OpCodes.Ble_Un, target);
3151 ig.Emit (OpCodes.Ble, target);
3154 ig.Emit (OpCodes.Bgt_Un, target);
3156 ig.Emit (OpCodes.Bgt, target);
3160 case Operator.GreaterThanOrEqual:
3163 ig.Emit (OpCodes.Bge_Un, target);
3165 ig.Emit (OpCodes.Bge, target);
3168 ig.Emit (OpCodes.Blt_Un, target);
3170 ig.Emit (OpCodes.Blt, target);
3173 Console.WriteLine (oper);
3174 throw new Exception ("what is THAT");
3178 public override void Emit (EmitContext ec)
3180 ILGenerator ig = ec.ig;
3185 // Handle short-circuit operators differently
3188 if (oper == Operator.LogicalAnd) {
3189 Label load_zero = ig.DefineLabel ();
3190 Label end = ig.DefineLabel ();
3192 left.EmitBranchable (ec, load_zero, false);
3194 ig.Emit (OpCodes.Br, end);
3196 ig.MarkLabel (load_zero);
3197 ig.Emit (OpCodes.Ldc_I4_0);
3200 } else if (oper == Operator.LogicalOr) {
3201 Label load_one = ig.DefineLabel ();
3202 Label end = ig.DefineLabel ();
3204 left.EmitBranchable (ec, load_one, true);
3206 ig.Emit (OpCodes.Br, end);
3208 ig.MarkLabel (load_one);
3209 ig.Emit (OpCodes.Ldc_I4_1);
3217 bool isUnsigned = is_unsigned (left.Type);
3220 case Operator.Multiply:
3222 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3223 opcode = OpCodes.Mul_Ovf;
3224 else if (isUnsigned)
3225 opcode = OpCodes.Mul_Ovf_Un;
3227 opcode = OpCodes.Mul;
3229 opcode = OpCodes.Mul;
3233 case Operator.Division:
3235 opcode = OpCodes.Div_Un;
3237 opcode = OpCodes.Div;
3240 case Operator.Modulus:
3242 opcode = OpCodes.Rem_Un;
3244 opcode = OpCodes.Rem;
3247 case Operator.Addition:
3249 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3250 opcode = OpCodes.Add_Ovf;
3251 else if (isUnsigned)
3252 opcode = OpCodes.Add_Ovf_Un;
3254 opcode = OpCodes.Add;
3256 opcode = OpCodes.Add;
3259 case Operator.Subtraction:
3261 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3262 opcode = OpCodes.Sub_Ovf;
3263 else if (isUnsigned)
3264 opcode = OpCodes.Sub_Ovf_Un;
3266 opcode = OpCodes.Sub;
3268 opcode = OpCodes.Sub;
3271 case Operator.RightShift:
3273 opcode = OpCodes.Shr_Un;
3275 opcode = OpCodes.Shr;
3278 case Operator.LeftShift:
3279 opcode = OpCodes.Shl;
3282 case Operator.Equality:
3283 opcode = OpCodes.Ceq;
3286 case Operator.Inequality:
3287 ig.Emit (OpCodes.Ceq);
3288 ig.Emit (OpCodes.Ldc_I4_0);
3290 opcode = OpCodes.Ceq;
3293 case Operator.LessThan:
3295 opcode = OpCodes.Clt_Un;
3297 opcode = OpCodes.Clt;
3300 case Operator.GreaterThan:
3302 opcode = OpCodes.Cgt_Un;
3304 opcode = OpCodes.Cgt;
3307 case Operator.LessThanOrEqual:
3308 Type lt = left.Type;
3310 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3311 ig.Emit (OpCodes.Cgt_Un);
3313 ig.Emit (OpCodes.Cgt);
3314 ig.Emit (OpCodes.Ldc_I4_0);
3316 opcode = OpCodes.Ceq;
3319 case Operator.GreaterThanOrEqual:
3320 Type le = left.Type;
3322 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3323 ig.Emit (OpCodes.Clt_Un);
3325 ig.Emit (OpCodes.Clt);
3327 ig.Emit (OpCodes.Ldc_I4_0);
3329 opcode = OpCodes.Ceq;
3332 case Operator.BitwiseOr:
3333 opcode = OpCodes.Or;
3336 case Operator.BitwiseAnd:
3337 opcode = OpCodes.And;
3340 case Operator.ExclusiveOr:
3341 opcode = OpCodes.Xor;
3345 throw new Exception ("This should not happen: Operator = "
3346 + oper.ToString ());
3354 // Object created by Binary when the binary operator uses an method instead of being
3355 // a binary operation that maps to a CIL binary operation.
3357 public class BinaryMethod : Expression {
3358 public MethodBase method;
3359 public ArrayList Arguments;
3361 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3366 eclass = ExprClass.Value;
3369 public override Expression DoResolve (EmitContext ec)
3374 public override void Emit (EmitContext ec)
3376 ILGenerator ig = ec.ig;
3378 if (Arguments != null)
3379 Invocation.EmitArguments (ec, method, Arguments, false, null);
3381 if (method is MethodInfo)
3382 ig.Emit (OpCodes.Call, (MethodInfo) method);
3384 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3389 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3390 // b, c, d... may be strings or objects.
3392 public class StringConcat : Expression {
3394 bool invalid = false;
3395 bool emit_conv_done = false;
3397 // Are we also concating objects?
3399 bool is_strings_only = true;
3401 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3404 type = TypeManager.string_type;
3405 eclass = ExprClass.Value;
3407 operands = new ArrayList (2);
3412 public override Expression DoResolve (EmitContext ec)
3420 public void Append (EmitContext ec, Expression operand)
3425 if (operand is StringConstant && operands.Count != 0) {
3426 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3427 if (last_operand != null) {
3428 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
3434 // Conversion to object
3436 if (operand.Type != TypeManager.string_type) {
3437 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3440 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3446 operands.Add (operand);
3449 public override void Emit (EmitContext ec)
3451 MethodInfo concat_method = null;
3454 // Do conversion to arguments; check for strings only
3457 // This can get called multiple times, so we have to deal with that.
3458 if (!emit_conv_done) {
3459 emit_conv_done = true;
3460 for (int i = 0; i < operands.Count; i ++) {
3461 Expression e = (Expression) operands [i];
3462 is_strings_only &= e.Type == TypeManager.string_type;
3465 for (int i = 0; i < operands.Count; i ++) {
3466 Expression e = (Expression) operands [i];
3468 if (! is_strings_only && e.Type == TypeManager.string_type) {
3469 // need to make sure this is an object, because the EmitParams
3470 // method might look at the type of this expression, see it is a
3471 // string and emit a string [] when we want an object [];
3473 e = new EmptyCast (e, TypeManager.object_type);
3475 operands [i] = new Argument (e, Argument.AType.Expression);
3480 // Find the right method
3482 switch (operands.Count) {
3485 // This should not be possible, because simple constant folding
3486 // is taken care of in the Binary code.
3488 throw new Exception ("how did you get here?");
3491 concat_method = is_strings_only ?
3492 TypeManager.string_concat_string_string :
3493 TypeManager.string_concat_object_object ;
3496 concat_method = is_strings_only ?
3497 TypeManager.string_concat_string_string_string :
3498 TypeManager.string_concat_object_object_object ;
3502 // There is not a 4 param overlaod for object (the one that there is
3503 // is actually a varargs methods, and is only in corlib because it was
3504 // introduced there before.).
3506 if (!is_strings_only)
3509 concat_method = TypeManager.string_concat_string_string_string_string;
3512 concat_method = is_strings_only ?
3513 TypeManager.string_concat_string_dot_dot_dot :
3514 TypeManager.string_concat_object_dot_dot_dot ;
3518 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3519 ec.ig.Emit (OpCodes.Call, concat_method);
3524 // Object created with +/= on delegates
3526 public class BinaryDelegate : Expression {
3530 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3535 eclass = ExprClass.Value;
3538 public override Expression DoResolve (EmitContext ec)
3543 public override void Emit (EmitContext ec)
3545 ILGenerator ig = ec.ig;
3547 Invocation.EmitArguments (ec, method, args, false, null);
3549 ig.Emit (OpCodes.Call, (MethodInfo) method);
3550 ig.Emit (OpCodes.Castclass, type);
3553 public Expression Right {
3555 Argument arg = (Argument) args [1];
3560 public bool IsAddition {
3562 return method == TypeManager.delegate_combine_delegate_delegate;
3568 // User-defined conditional logical operator
3569 public class ConditionalLogicalOperator : Expression {
3570 Expression left, right;
3573 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3576 eclass = ExprClass.Value;
3580 this.is_and = is_and;
3583 protected void Error19 ()
3585 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3588 protected void Error218 ()
3590 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3591 "declarations of operator true and operator false");
3594 Expression op_true, op_false, op;
3595 LocalTemporary left_temp;
3597 public override Expression DoResolve (EmitContext ec)
3600 Expression operator_group;
3602 operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3603 if (operator_group == null) {
3608 left_temp = new LocalTemporary (ec, type);
3610 ArrayList arguments = new ArrayList ();
3611 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3612 arguments.Add (new Argument (right, Argument.AType.Expression));
3613 method = Invocation.OverloadResolve (
3614 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3616 if (method == null) {
3621 if (method.ReturnType != type) {
3622 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3623 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3627 op = new StaticCallExpr (method, arguments, loc);
3629 op_true = GetOperatorTrue (ec, left_temp, loc);
3630 op_false = GetOperatorFalse (ec, left_temp, loc);
3631 if ((op_true == null) || (op_false == null)) {
3639 public override void Emit (EmitContext ec)
3641 ILGenerator ig = ec.ig;
3642 Label false_target = ig.DefineLabel ();
3643 Label end_target = ig.DefineLabel ();
3646 left_temp.Store (ec);
3648 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3649 left_temp.Emit (ec);
3650 ig.Emit (OpCodes.Br, end_target);
3651 ig.MarkLabel (false_target);
3653 ig.MarkLabel (end_target);
3657 public class PointerArithmetic : Expression {
3658 Expression left, right;
3662 // We assume that `l' is always a pointer
3664 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3670 is_add = is_addition;
3673 public override Expression DoResolve (EmitContext ec)
3675 eclass = ExprClass.Variable;
3677 if (left.Type == TypeManager.void_ptr_type) {
3678 Error (242, "The operation in question is undefined on void pointers");
3685 public override void Emit (EmitContext ec)
3687 Type op_type = left.Type;
3688 ILGenerator ig = ec.ig;
3690 // It must be either array or fixed buffer
3691 Type element = TypeManager.HasElementType (op_type) ?
3692 element = TypeManager.GetElementType (op_type) :
3693 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3695 int size = GetTypeSize (element);
3696 Type rtype = right.Type;
3698 if (rtype.IsPointer){
3700 // handle (pointer - pointer)
3704 ig.Emit (OpCodes.Sub);
3708 ig.Emit (OpCodes.Sizeof, element);
3710 IntLiteral.EmitInt (ig, size);
3711 ig.Emit (OpCodes.Div);
3713 ig.Emit (OpCodes.Conv_I8);
3716 // handle + and - on (pointer op int)
3719 ig.Emit (OpCodes.Conv_I);
3721 Constant right_const = right as Constant;
3722 if (right_const != null && size != 0) {
3723 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3731 ig.Emit (OpCodes.Sizeof, element);
3733 IntLiteral.EmitInt (ig, size);
3734 if (rtype == TypeManager.int64_type)
3735 ig.Emit (OpCodes.Conv_I8);
3736 else if (rtype == TypeManager.uint64_type)
3737 ig.Emit (OpCodes.Conv_U8);
3738 ig.Emit (OpCodes.Mul);
3742 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3743 ig.Emit (OpCodes.Conv_I);
3746 ig.Emit (OpCodes.Add);
3748 ig.Emit (OpCodes.Sub);
3754 /// Implements the ternary conditional operator (?:)
3756 public class Conditional : Expression {
3757 Expression expr, trueExpr, falseExpr;
3759 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3762 this.trueExpr = trueExpr;
3763 this.falseExpr = falseExpr;
3764 this.loc = expr.Location;
3767 public Expression Expr {
3773 public Expression TrueExpr {
3779 public Expression FalseExpr {
3785 public override Expression DoResolve (EmitContext ec)
3787 expr = expr.Resolve (ec);
3792 if (TypeManager.IsNullableType (expr.Type))
3793 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3795 if (expr.Type != TypeManager.bool_type){
3796 expr = Expression.ResolveBoolean (
3803 Assign ass = expr as Assign;
3804 if (ass != null && ass.Source is Constant) {
3805 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3808 trueExpr = trueExpr.Resolve (ec);
3809 falseExpr = falseExpr.Resolve (ec);
3811 if (trueExpr == null || falseExpr == null)
3814 eclass = ExprClass.Value;
3815 if (trueExpr.Type == falseExpr.Type)
3816 type = trueExpr.Type;
3819 Type true_type = trueExpr.Type;
3820 Type false_type = falseExpr.Type;
3823 // First, if an implicit conversion exists from trueExpr
3824 // to falseExpr, then the result type is of type falseExpr.Type
3826 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3829 // Check if both can convert implicitl to each other's type
3831 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3833 "Can not compute type of conditional expression " +
3834 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3835 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3836 "' convert implicitly to each other");
3841 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3845 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3846 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3851 // Dead code optimalization
3852 if (expr is BoolConstant){
3853 BoolConstant bc = (BoolConstant) expr;
3855 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3856 return bc.Value ? trueExpr : falseExpr;
3862 public override void Emit (EmitContext ec)
3864 ILGenerator ig = ec.ig;
3865 Label false_target = ig.DefineLabel ();
3866 Label end_target = ig.DefineLabel ();
3868 expr.EmitBranchable (ec, false_target, false);
3870 ig.Emit (OpCodes.Br, end_target);
3871 ig.MarkLabel (false_target);
3872 falseExpr.Emit (ec);
3873 ig.MarkLabel (end_target);
3881 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3882 public readonly string Name;
3883 public readonly Block Block;
3884 public LocalInfo local_info;
3887 LocalTemporary temp;
3889 public LocalVariableReference (Block block, string name, Location l)
3894 eclass = ExprClass.Variable;
3898 // Setting `is_readonly' to false will allow you to create a writable
3899 // reference to a read-only variable. This is used by foreach and using.
3901 public LocalVariableReference (Block block, string name, Location l,
3902 LocalInfo local_info, bool is_readonly)
3903 : this (block, name, l)
3905 this.local_info = local_info;
3906 this.is_readonly = is_readonly;
3909 public VariableInfo VariableInfo {
3911 return local_info.VariableInfo;
3915 public bool IsReadOnly {
3921 public bool VerifyAssigned (EmitContext ec)
3923 VariableInfo variable_info = local_info.VariableInfo;
3924 return variable_info == null || variable_info.IsAssigned (ec, loc);
3927 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3929 if (local_info == null) {
3930 local_info = Block.GetLocalInfo (Name);
3933 if (lvalue_right_side == EmptyExpression.Null)
3934 local_info.Used = true;
3936 is_readonly = local_info.ReadOnly;
3939 type = local_info.VariableType;
3941 VariableInfo variable_info = local_info.VariableInfo;
3942 if (lvalue_right_side != null){
3944 if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.Null)
3945 Report.Error (1657, loc, "Cannot pass `{0}' as a ref or out argument because it is a `{1}'",
3946 Name, local_info.GetReadOnlyContext ());
3948 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
3949 Name, local_info.GetReadOnlyContext ());
3953 if (variable_info != null)
3954 variable_info.SetAssigned (ec);
3957 Expression e = Block.GetConstantExpression (Name);
3959 local_info.Used = true;
3960 eclass = ExprClass.Value;
3961 return e.Resolve (ec);
3964 if (!VerifyAssigned (ec))
3967 if (lvalue_right_side == null)
3968 local_info.Used = true;
3970 if (ec.CurrentAnonymousMethod != null){
3972 // If we are referencing a variable from the external block
3973 // flag it for capturing
3975 if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) ||
3976 ec.CurrentAnonymousMethod.IsIterator)
3978 if (local_info.AddressTaken){
3979 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3982 ec.CaptureVariable (local_info);
3989 public override Expression DoResolve (EmitContext ec)
3991 return DoResolveBase (ec, null);
3994 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3996 return DoResolveBase (ec, right_side);
3999 public bool VerifyFixed ()
4001 // A local Variable is always fixed.
4005 public override int GetHashCode()
4007 return Name.GetHashCode ();
4010 public override bool Equals (object obj)
4012 LocalVariableReference lvr = obj as LocalVariableReference;
4016 return Name == lvr.Name && Block == lvr.Block;
4019 public override void Emit (EmitContext ec)
4021 ILGenerator ig = ec.ig;
4023 if (local_info.FieldBuilder == null){
4025 // A local variable on the local CLR stack
4027 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
4030 // A local variable captured by anonymous methods.
4033 ec.EmitCapturedVariableInstance (local_info);
4035 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
4039 public void Emit (EmitContext ec, bool leave_copy)
4043 ec.ig.Emit (OpCodes.Dup);
4044 if (local_info.FieldBuilder != null){
4045 temp = new LocalTemporary (ec, Type);
4051 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4053 ILGenerator ig = ec.ig;
4054 prepared = prepare_for_load;
4056 if (local_info.FieldBuilder == null){
4058 // A local variable on the local CLR stack
4060 if (local_info.LocalBuilder == null)
4061 throw new Exception ("This should not happen: both Field and Local are null");
4065 ec.ig.Emit (OpCodes.Dup);
4066 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
4069 // A local variable captured by anonymous methods or itereators.
4071 ec.EmitCapturedVariableInstance (local_info);
4073 if (prepare_for_load)
4074 ig.Emit (OpCodes.Dup);
4077 ig.Emit (OpCodes.Dup);
4078 temp = new LocalTemporary (ec, Type);
4081 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
4087 public void AddressOf (EmitContext ec, AddressOp mode)
4089 ILGenerator ig = ec.ig;
4091 if (local_info.FieldBuilder == null){
4093 // A local variable on the local CLR stack
4095 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
4098 // A local variable captured by anonymous methods or iterators
4100 ec.EmitCapturedVariableInstance (local_info);
4101 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
4105 public override string ToString ()
4107 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4112 /// This represents a reference to a parameter in the intermediate
4115 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
4121 public Parameter.Modifier mod;
4122 public bool is_ref, is_out, prepared;
4136 LocalTemporary temp;
4138 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
4145 eclass = ExprClass.Variable;
4148 public ParameterReference (InternalParameters pars, Block block, int idx, Location loc)
4149 : this (pars.Parameters, block, idx, pars.ParameterName (idx), loc)
4152 public VariableInfo VariableInfo {
4156 public bool VerifyFixed ()
4158 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4159 return mod == Parameter.Modifier.NONE;
4162 public bool IsAssigned (EmitContext ec, Location loc)
4164 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
4167 Report.Error (269, loc,
4168 "Use of unassigned out parameter `{0}'", name);
4172 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4174 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
4177 Report.Error (170, loc,
4178 "Use of possibly unassigned field `" + field_name + "'");
4182 public void SetAssigned (EmitContext ec)
4184 if (is_out && ec.DoFlowAnalysis)
4185 ec.CurrentBranching.SetAssigned (vi);
4188 public void SetFieldAssigned (EmitContext ec, string field_name)
4190 if (is_out && ec.DoFlowAnalysis)
4191 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
4194 protected void DoResolveBase (EmitContext ec)
4196 type = pars.GetParameterInfo (ec, idx, out mod);
4197 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4198 is_out = (mod & Parameter.Modifier.OUT) != 0;
4199 eclass = ExprClass.Variable;
4202 vi = block.ParameterMap [idx];
4204 if (ec.CurrentAnonymousMethod != null){
4206 Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block",
4212 // If we are referencing the parameter from the external block
4213 // flag it for capturing
4215 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
4216 if (!block.Toplevel.IsLocalParameter (name)){
4217 ec.CaptureParameter (name, type, idx);
4222 public override int GetHashCode()
4224 return name.GetHashCode ();
4227 public override bool Equals (object obj)
4229 ParameterReference pr = obj as ParameterReference;
4233 return name == pr.name && block == pr.block;
4237 // Notice that for ref/out parameters, the type exposed is not the
4238 // same type exposed externally.
4241 // externally we expose "int&"
4242 // here we expose "int".
4244 // We record this in "is_ref". This means that the type system can treat
4245 // the type as it is expected, but when we generate the code, we generate
4246 // the alternate kind of code.
4248 public override Expression DoResolve (EmitContext ec)
4252 if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4258 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4267 static public void EmitLdArg (ILGenerator ig, int x)
4271 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4272 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4273 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4274 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4275 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4278 ig.Emit (OpCodes.Ldarg, x);
4282 // This method is used by parameters that are references, that are
4283 // being passed as references: we only want to pass the pointer (that
4284 // is already stored in the parameter, not the address of the pointer,
4285 // and not the value of the variable).
4287 public void EmitLoad (EmitContext ec)
4289 ILGenerator ig = ec.ig;
4292 if (!ec.MethodIsStatic)
4295 EmitLdArg (ig, arg_idx);
4298 // FIXME: Review for anonymous methods
4302 public override void Emit (EmitContext ec)
4307 public void Emit (EmitContext ec, bool leave_copy)
4309 ILGenerator ig = ec.ig;
4312 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4314 throw new InternalErrorException ();
4316 ec.EmitParameter (name);
4320 if (!ec.MethodIsStatic)
4323 EmitLdArg (ig, arg_idx);
4327 ec.ig.Emit (OpCodes.Dup);
4330 // If we are a reference, we loaded on the stack a pointer
4331 // Now lets load the real value
4333 LoadFromPtr (ig, type);
4337 ec.ig.Emit (OpCodes.Dup);
4340 temp = new LocalTemporary (ec, type);
4346 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4348 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4349 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
4353 ILGenerator ig = ec.ig;
4356 prepared = prepare_for_load;
4358 if (!ec.MethodIsStatic)
4361 if (is_ref && !prepared)
4362 EmitLdArg (ig, arg_idx);
4367 ec.ig.Emit (OpCodes.Dup);
4371 temp = new LocalTemporary (ec, type);
4375 StoreFromPtr (ig, type);
4381 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
4383 ig.Emit (OpCodes.Starg, arg_idx);
4387 public void AddressOf (EmitContext ec, AddressOp mode)
4389 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4390 ec.EmitAddressOfParameter (name);
4396 if (!ec.MethodIsStatic)
4401 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4403 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4406 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4408 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4415 /// Used for arguments to New(), Invocation()
4417 public class Argument {
4418 public enum AType : byte {
4425 public readonly AType ArgType;
4426 public Expression Expr;
4428 public Argument (Expression expr, AType type)
4431 this.ArgType = type;
4434 public Argument (Expression expr)
4437 this.ArgType = AType.Expression;
4442 if (ArgType == AType.Ref || ArgType == AType.Out)
4443 return TypeManager.GetReferenceType (Expr.Type);
4449 public Parameter.Modifier Modifier
4454 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4457 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4460 return Parameter.Modifier.NONE;
4465 public static string FullDesc (Argument a)
4467 if (a.ArgType == AType.ArgList)
4470 return (a.ArgType == AType.Ref ? "ref " :
4471 (a.ArgType == AType.Out ? "out " : "")) +
4472 TypeManager.CSharpName (a.Expr.Type);
4475 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4477 SimpleName sn = Expr as SimpleName;
4479 Expr = sn.GetMethodGroup ();
4481 // FIXME: csc doesn't report any error if you try to use `ref' or
4482 // `out' in a delegate creation expression.
4483 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4490 void Error_LValueRequired (Location loc)
4492 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
4495 public bool Resolve (EmitContext ec, Location loc)
4497 bool old_do_flow_analysis = ec.DoFlowAnalysis;
4498 ec.DoFlowAnalysis = true;
4500 if (ArgType == AType.Ref) {
4501 ec.InRefOutArgumentResolving = true;
4502 Expr = Expr.Resolve (ec);
4503 ec.InRefOutArgumentResolving = false;
4505 ec.DoFlowAnalysis = old_do_flow_analysis;
4509 Expr = Expr.DoResolveLValue (ec, Expr);
4511 Error_LValueRequired (loc);
4512 } else if (ArgType == AType.Out) {
4513 ec.InRefOutArgumentResolving = true;
4514 Expr = Expr.DoResolveLValue (ec, EmptyExpression.Null);
4515 ec.InRefOutArgumentResolving = false;
4518 Error_LValueRequired (loc);
4521 Expr = Expr.Resolve (ec);
4523 ec.DoFlowAnalysis = old_do_flow_analysis;
4528 if (ArgType == AType.Expression)
4532 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4533 // This is only allowed for `this'
4535 FieldExpr fe = Expr as FieldExpr;
4536 if (fe != null && !fe.IsStatic){
4537 Expression instance = fe.InstanceExpression;
4539 if (instance.GetType () != typeof (This)){
4540 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4541 Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type);
4542 Report.Warning (197, 1, loc,
4543 "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
4544 fe.GetSignatureForError ());
4551 if (Expr.eclass != ExprClass.Variable){
4553 // We just probe to match the CSC output
4555 if (Expr.eclass == ExprClass.PropertyAccess ||
4556 Expr.eclass == ExprClass.IndexerAccess){
4557 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4558 Expr.GetSignatureForError ());
4560 Error_LValueRequired (loc);
4568 public void Emit (EmitContext ec)
4571 // Ref and Out parameters need to have their addresses taken.
4573 // ParameterReferences might already be references, so we want
4574 // to pass just the value
4576 if (ArgType == AType.Ref || ArgType == AType.Out){
4577 AddressOp mode = AddressOp.Store;
4579 if (ArgType == AType.Ref)
4580 mode |= AddressOp.Load;
4582 if (Expr is ParameterReference){
4583 ParameterReference pr = (ParameterReference) Expr;
4589 pr.AddressOf (ec, mode);
4592 if (Expr is IMemoryLocation)
4593 ((IMemoryLocation) Expr).AddressOf (ec, mode);
4595 Error_LValueRequired (Expr.Location);
4605 /// Invocation of methods or delegates.
4607 public class Invocation : ExpressionStatement {
4608 public readonly ArrayList Arguments;
4611 MethodBase method = null;
4614 // arguments is an ArrayList, but we do not want to typecast,
4615 // as it might be null.
4617 // FIXME: only allow expr to be a method invocation or a
4618 // delegate invocation (7.5.5)
4620 public Invocation (Expression expr, ArrayList arguments)
4623 Arguments = arguments;
4624 loc = expr.Location;
4627 public Expression Expr {
4634 /// Determines "better conversion" as specified in 14.4.2.3
4636 /// Returns : p if a->p is better,
4637 /// q if a->q is better,
4638 /// null if neither is better
4640 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4642 Type argument_type = TypeManager.TypeToCoreType (a.Type);
4643 Expression argument_expr = a.Expr;
4645 // p = TypeManager.TypeToCoreType (p);
4646 // q = TypeManager.TypeToCoreType (q);
4648 if (argument_type == null)
4649 throw new Exception ("Expression of type " + a.Expr +
4650 " does not resolve its type");
4652 if (p == null || q == null)
4653 throw new InternalErrorException ("BetterConversion Got a null conversion");
4658 if (argument_expr is NullLiteral) {
4660 // If the argument is null and one of the types to compare is 'object' and
4661 // the other is a reference type, we prefer the other.
4663 // This follows from the usual rules:
4664 // * There is an implicit conversion from 'null' to type 'object'
4665 // * There is an implicit conversion from 'null' to any reference type
4666 // * There is an implicit conversion from any reference type to type 'object'
4667 // * There is no implicit conversion from type 'object' to other reference types
4668 // => Conversion of 'null' to a reference type is better than conversion to 'object'
4670 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
4671 // null type. I think it used to be 'object' and thus needed a special
4672 // case to avoid the immediately following two checks.
4674 if (!p.IsValueType && q == TypeManager.object_type)
4676 if (!q.IsValueType && p == TypeManager.object_type)
4680 if (argument_type == p)
4683 if (argument_type == q)
4686 Expression p_tmp = new EmptyExpression (p);
4687 Expression q_tmp = new EmptyExpression (q);
4689 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4690 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4692 if (p_to_q && !q_to_p)
4695 if (q_to_p && !p_to_q)
4698 if (p == TypeManager.sbyte_type)
4699 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4700 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4702 if (q == TypeManager.sbyte_type)
4703 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4704 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4707 if (p == TypeManager.short_type)
4708 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4709 q == TypeManager.uint64_type)
4712 if (q == TypeManager.short_type)
4713 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4714 p == TypeManager.uint64_type)
4717 if (p == TypeManager.int32_type)
4718 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4721 if (q == TypeManager.int32_type)
4722 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4725 if (p == TypeManager.int64_type)
4726 if (q == TypeManager.uint64_type)
4728 if (q == TypeManager.int64_type)
4729 if (p == TypeManager.uint64_type)
4736 /// Determines "Better function" between candidate
4737 /// and the current best match
4740 /// Returns a boolean indicating :
4741 /// false if candidate ain't better
4742 /// true if candidate is better than the current best match
4744 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4745 MethodBase candidate, bool candidate_params,
4746 MethodBase best, bool best_params, Location loc)
4748 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4749 ParameterData best_pd = TypeManager.GetParameterData (best);
4751 bool better_at_least_one = false;
4753 for (int j = 0; j < argument_count; ++j) {
4754 Argument a = (Argument) args [j];
4756 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4757 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4759 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4760 if (candidate_params)
4761 ct = TypeManager.GetElementType (ct);
4763 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4765 bt = TypeManager.GetElementType (bt);
4771 Type better = BetterConversion (ec, a, ct, bt, loc);
4772 // for each argument, the conversion to 'ct' should be no worse than
4773 // the conversion to 'bt'.
4777 // for at least one argument, the conversion to 'ct' should be better than
4778 // the conversion to 'bt'.
4780 better_at_least_one = true;
4783 if (better_at_least_one)
4790 // If two methods have equal parameter types, but
4791 // only one of them is generic, the non-generic one wins.
4793 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
4795 else if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
4799 // Note that this is not just an optimization. This handles the case
4800 // This handles the case
4802 // Add (float f1, float f2, float f3);
4803 // Add (params decimal [] foo);
4805 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4806 // first candidate would've chosen as better.
4809 // This handles the following cases:
4811 // Trim () is better than Trim (params char[] chars)
4812 // Concat (string s1, string s2, string s3) is better than
4813 // Concat (string s1, params string [] srest)
4815 return !candidate_params && best_params;
4818 static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4820 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4823 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4824 ParameterData base_pd = TypeManager.GetParameterData (base_method);
4826 if (cand_pd.Count != base_pd.Count)
4829 for (int j = 0; j < cand_pd.Count; ++j) {
4830 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4831 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4832 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4833 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4835 if (cm != bm || ct != bt)
4842 public static string FullMethodDesc (MethodBase mb)
4848 if (mb is MethodInfo) {
4849 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4853 sb = new StringBuilder ();
4855 sb.Append (TypeManager.CSharpSignature (mb));
4856 return sb.ToString ();
4859 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4861 MemberInfo [] miset;
4862 MethodGroupExpr union;
4867 return (MethodGroupExpr) mg2;
4870 return (MethodGroupExpr) mg1;
4873 MethodGroupExpr left_set = null, right_set = null;
4874 int length1 = 0, length2 = 0;
4876 left_set = (MethodGroupExpr) mg1;
4877 length1 = left_set.Methods.Length;
4879 right_set = (MethodGroupExpr) mg2;
4880 length2 = right_set.Methods.Length;
4882 ArrayList common = new ArrayList ();
4884 foreach (MethodBase r in right_set.Methods){
4885 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4889 miset = new MemberInfo [length1 + length2 - common.Count];
4890 left_set.Methods.CopyTo (miset, 0);
4894 foreach (MethodBase r in right_set.Methods) {
4895 if (!common.Contains (r))
4899 union = new MethodGroupExpr (miset, loc);
4904 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4905 ArrayList arguments, int arg_count,
4906 ref MethodBase candidate)
4908 return IsParamsMethodApplicable (
4909 ec, me, arguments, arg_count, false, ref candidate) ||
4910 IsParamsMethodApplicable (
4911 ec, me, arguments, arg_count, true, ref candidate);
4916 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4917 ArrayList arguments, int arg_count,
4918 bool do_varargs, ref MethodBase candidate)
4920 if (!me.HasTypeArguments &&
4921 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4924 return IsParamsMethodApplicable (
4925 ec, arguments, arg_count, candidate, do_varargs);
4929 /// Determines if the candidate method, if a params method, is applicable
4930 /// in its expanded form to the given set of arguments
4932 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4933 int arg_count, MethodBase candidate,
4936 ParameterData pd = TypeManager.GetParameterData (candidate);
4938 int pd_count = pd.Count;
4943 int count = pd_count - 1;
4945 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4947 if (pd_count != arg_count)
4950 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4954 if (count > arg_count)
4957 if (pd_count == 1 && arg_count == 0)
4961 // If we have come this far, the case which
4962 // remains is when the number of parameters is
4963 // less than or equal to the argument count.
4965 for (int i = 0; i < count; ++i) {
4967 Argument a = (Argument) arguments [i];
4969 Parameter.Modifier a_mod = a.Modifier &
4970 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4971 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4972 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4974 if (a_mod == p_mod) {
4976 if (a_mod == Parameter.Modifier.NONE)
4977 if (!Convert.ImplicitConversionExists (ec,
4979 pd.ParameterType (i)))
4982 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4983 Type pt = pd.ParameterType (i);
4986 pt = TypeManager.GetReferenceType (pt);
4997 Argument a = (Argument) arguments [count];
4998 if (!(a.Expr is Arglist))
5004 Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
5006 for (int i = pd_count - 1; i < arg_count; i++) {
5007 Argument a = (Argument) arguments [i];
5009 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
5016 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
5017 ArrayList arguments, int arg_count,
5018 ref MethodBase candidate)
5020 if (!me.HasTypeArguments &&
5021 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
5024 return IsApplicable (ec, arguments, arg_count, candidate);
5028 /// Determines if the candidate method is applicable (section 14.4.2.1)
5029 /// to the given set of arguments
5031 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
5032 MethodBase candidate)
5034 ParameterData pd = TypeManager.GetParameterData (candidate);
5036 if (arg_count != pd.Count)
5039 for (int i = arg_count; i > 0; ) {
5042 Argument a = (Argument) arguments [i];
5044 Parameter.Modifier a_mod = a.Modifier &
5045 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5046 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
5047 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5049 if (a_mod == p_mod ||
5050 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
5051 if (a_mod == Parameter.Modifier.NONE) {
5052 if (!TypeManager.IsEqual (a.Type, pd.ParameterType (i)) && !Convert.ImplicitConversionExists (ec,
5054 pd.ParameterType (i)))
5058 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
5059 Type pt = pd.ParameterType (i);
5062 pt = TypeManager.GetReferenceType (pt);
5074 static private bool IsAncestralType (Type first_type, Type second_type)
5076 return first_type != second_type &&
5077 (second_type.IsSubclassOf (first_type) ||
5078 TypeManager.ImplementsInterface (second_type, first_type));
5082 /// Find the Applicable Function Members (7.4.2.1)
5084 /// me: Method Group expression with the members to select.
5085 /// it might contain constructors or methods (or anything
5086 /// that maps to a method).
5088 /// Arguments: ArrayList containing resolved Argument objects.
5090 /// loc: The location if we want an error to be reported, or a Null
5091 /// location for "probing" purposes.
5093 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
5094 /// that is the best match of me on Arguments.
5097 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
5098 ArrayList Arguments, bool may_fail,
5101 MethodBase method = null;
5102 bool method_params = false;
5103 Type applicable_type = null;
5105 ArrayList candidates = new ArrayList (2);
5106 ArrayList candidate_overrides = null;
5109 // Used to keep a map between the candidate
5110 // and whether it is being considered in its
5111 // normal or expanded form
5113 // false is normal form, true is expanded form
5115 Hashtable candidate_to_form = null;
5117 if (Arguments != null)
5118 arg_count = Arguments.Count;
5120 if ((me.Name == "Invoke") &&
5121 TypeManager.IsDelegateType (me.DeclaringType)) {
5122 Error_InvokeOnDelegate (loc);
5126 MethodBase[] methods = me.Methods;
5129 // First we construct the set of applicable methods
5131 bool is_sorted = true;
5132 for (int i = 0; i < methods.Length; i++){
5133 Type decl_type = methods [i].DeclaringType;
5136 // If we have already found an applicable method
5137 // we eliminate all base types (Section 14.5.5.1)
5139 if ((applicable_type != null) &&
5140 IsAncestralType (decl_type, applicable_type))
5144 // Methods marked 'override' don't take part in 'applicable_type'
5145 // computation, nor in the actual overload resolution.
5146 // However, they still need to be emitted instead of a base virtual method.
5147 // We avoid doing the 'applicable' test here, since it'll anyway be applied
5148 // to the base virtual function, and IsOverride is much faster than IsApplicable.
5150 if (!me.IsBase && TypeManager.IsOverride (methods [i])) {
5151 if (candidate_overrides == null)
5152 candidate_overrides = new ArrayList ();
5153 candidate_overrides.Add (methods [i]);
5158 // Check if candidate is applicable (section 14.4.2.1)
5159 // Is candidate applicable in normal form?
5161 bool is_applicable = IsApplicable (
5162 ec, me, Arguments, arg_count, ref methods [i]);
5164 if (!is_applicable &&
5165 (IsParamsMethodApplicable (
5166 ec, me, Arguments, arg_count, ref methods [i]))) {
5167 MethodBase candidate = methods [i];
5168 if (candidate_to_form == null)
5169 candidate_to_form = new PtrHashtable ();
5170 candidate_to_form [candidate] = candidate;
5171 // Candidate is applicable in expanded form
5172 is_applicable = true;
5178 candidates.Add (methods [i]);
5180 if (applicable_type == null)
5181 applicable_type = decl_type;
5182 else if (applicable_type != decl_type) {
5184 if (IsAncestralType (applicable_type, decl_type))
5185 applicable_type = decl_type;
5189 int candidate_top = candidates.Count;
5191 if (applicable_type == null) {
5193 // Okay so we have failed to find anything so we
5194 // return by providing info about the closest match
5196 int errors = Report.Errors;
5197 for (int i = 0; i < methods.Length; ++i) {
5198 MethodBase c = (MethodBase) methods [i];
5199 ParameterData pd = TypeManager.GetParameterData (c);
5201 if (pd.Count != arg_count)
5204 if (!TypeManager.InferTypeArguments (ec, Arguments, ref c))
5207 VerifyArgumentsCompat (ec, Arguments, arg_count,
5208 c, false, null, may_fail, loc);
5210 if (!may_fail && errors == Report.Errors)
5211 throw new InternalErrorException (
5212 "VerifyArgumentsCompat and IsApplicable do not agree; " +
5213 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
5218 if (!may_fail && errors == Report.Errors) {
5219 string report_name = me.Name;
5220 if (report_name == ".ctor")
5221 report_name = me.DeclaringType.ToString ();
5223 for (int i = 0; i < methods.Length; ++i) {
5224 MethodBase c = methods [i];
5225 ParameterData pd = TypeManager.GetParameterData (c);
5227 if (pd.Count != arg_count)
5230 if (TypeManager.InferTypeArguments (ec, Arguments, ref c))
5234 411, loc, "The type arguments for " +
5235 "method `{0}' cannot be infered from " +
5236 "the usage. Try specifying the type " +
5237 "arguments explicitly.", report_name);
5241 Error_WrongNumArguments (loc, report_name, arg_count);
5249 // At this point, applicable_type is _one_ of the most derived types
5250 // in the set of types containing the methods in this MethodGroup.
5251 // Filter the candidates so that they only contain methods from the
5252 // most derived types.
5255 int finalized = 0; // Number of finalized candidates
5258 // Invariant: applicable_type is a most derived type
5260 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
5261 // eliminating all it's base types. At the same time, we'll also move
5262 // every unrelated type to the end of the array, and pick the next
5263 // 'applicable_type'.
5265 Type next_applicable_type = null;
5266 int j = finalized; // where to put the next finalized candidate
5267 int k = finalized; // where to put the next undiscarded candidate
5268 for (int i = finalized; i < candidate_top; ++i) {
5269 MethodBase candidate = (MethodBase) candidates [i];
5270 Type decl_type = candidate.DeclaringType;
5272 if (decl_type == applicable_type) {
5273 candidates [k++] = candidates [j];
5274 candidates [j++] = candidates [i];
5278 if (IsAncestralType (decl_type, applicable_type))
5281 if (next_applicable_type != null &&
5282 IsAncestralType (decl_type, next_applicable_type))
5285 candidates [k++] = candidates [i];
5287 if (next_applicable_type == null ||
5288 IsAncestralType (next_applicable_type, decl_type))
5289 next_applicable_type = decl_type;
5292 applicable_type = next_applicable_type;
5295 } while (applicable_type != null);
5299 // Now we actually find the best method
5302 method = (MethodBase) candidates [0];
5303 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
5304 for (int ix = 1; ix < candidate_top; ix++){
5305 MethodBase candidate = (MethodBase) candidates [ix];
5307 if (candidate == method)
5310 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5312 if (BetterFunction (ec, Arguments, arg_count,
5313 candidate, cand_params,
5314 method, method_params, loc)) {
5316 method_params = cand_params;
5320 // Now check that there are no ambiguities i.e the selected method
5321 // should be better than all the others
5323 MethodBase ambiguous = null;
5324 for (int ix = 0; ix < candidate_top; ix++){
5325 MethodBase candidate = (MethodBase) candidates [ix];
5327 if (candidate == method)
5330 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5331 if (!BetterFunction (ec, Arguments, arg_count,
5332 method, method_params,
5333 candidate, cand_params,
5335 Report.SymbolRelatedToPreviousError (candidate);
5336 ambiguous = candidate;
5340 if (ambiguous != null) {
5341 Report.SymbolRelatedToPreviousError (method);
5342 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5343 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
5348 // If the method is a virtual function, pick an override closer to the LHS type.
5350 if (!me.IsBase && method.IsVirtual) {
5351 if (TypeManager.IsOverride (method))
5352 throw new InternalErrorException (
5353 "Should not happen. An 'override' method took part in overload resolution: " + method);
5355 if (candidate_overrides != null)
5356 foreach (MethodBase candidate in candidate_overrides) {
5357 if (IsOverride (candidate, method))
5363 // And now check if the arguments are all
5364 // compatible, perform conversions if
5365 // necessary etc. and return if everything is
5368 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
5369 method_params, null, may_fail, loc))
5372 if (method != null) {
5373 MethodBase the_method = method;
5374 if (the_method.Mono_IsInflatedMethod)
5375 the_method = the_method.GetGenericMethodDefinition ();
5376 IMethodData data = TypeManager.GetMethod (the_method);
5378 data.SetMemberIsUsed ();
5383 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
5385 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5389 static void Error_InvokeOnDelegate (Location loc)
5391 Report.Error (1533, loc,
5392 "Invoke cannot be called directly on a delegate");
5395 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
5396 Type delegate_type, Argument a, ParameterData expected_par)
5398 if (delegate_type == null)
5399 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5400 TypeManager.CSharpSignature (method));
5402 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5403 TypeManager.CSharpName (delegate_type));
5405 string par_desc = expected_par.ParameterDesc (idx);
5407 if (a.Modifier != expected_par.ParameterModifier (idx)) {
5408 if ((expected_par.ParameterModifier (idx) & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
5409 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
5410 idx + 1, Parameter.GetModifierSignature (a.Modifier));
5412 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
5413 idx + 1, Parameter.GetModifierSignature (expected_par.ParameterModifier (idx)));
5417 Report.Error (1503, loc,
5418 String.Format ("Argument {0}: Cannot convert from `{1}' to `{2}'",
5419 idx + 1, Argument.FullDesc (a), par_desc));
5422 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
5423 int arg_count, MethodBase method,
5424 bool chose_params_expanded,
5425 Type delegate_type, bool may_fail,
5428 ParameterData pd = TypeManager.GetParameterData (method);
5429 int pd_count = pd.Count;
5431 for (int j = 0; j < arg_count; j++) {
5432 Argument a = (Argument) Arguments [j];
5433 Expression a_expr = a.Expr;
5434 Type parameter_type = pd.ParameterType (j);
5435 Parameter.Modifier pm = pd.ParameterModifier (j);
5437 if (pm == Parameter.Modifier.PARAMS){
5438 if ((pm & ~Parameter.Modifier.PARAMS) != a.Modifier) {
5440 Error_InvalidArguments (
5441 loc, j, method, delegate_type,
5446 if (chose_params_expanded)
5447 parameter_type = TypeManager.GetElementType (parameter_type);
5448 } else if (pm == Parameter.Modifier.ARGLIST){
5454 if (pd.ParameterModifier (j) != a.Modifier){
5456 Error_InvalidArguments (
5457 loc, j, method, delegate_type,
5466 if (!TypeManager.IsEqual (a.Type, parameter_type)){
5469 conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5473 Error_InvalidArguments (loc, j, method, delegate_type, a, pd);
5478 // Update the argument with the implicit conversion
5484 if (parameter_type.IsPointer){
5491 Parameter.Modifier a_mod = a.Modifier &
5492 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5493 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5494 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5496 if (a_mod != p_mod &&
5497 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5499 Invocation.Error_InvalidArguments (loc, j, method, null, a, pd);
5509 public override Expression DoResolve (EmitContext ec)
5512 // First, resolve the expression that is used to
5513 // trigger the invocation
5515 SimpleName sn = expr as SimpleName;
5517 expr = sn.GetMethodGroup ();
5519 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5523 if (!(expr is MethodGroupExpr)) {
5524 Type expr_type = expr.Type;
5526 if (expr_type != null){
5527 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5529 return (new DelegateInvocation (
5530 this.expr, Arguments, loc)).Resolve (ec);
5534 if (!(expr is MethodGroupExpr)){
5535 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5540 // Next, evaluate all the expressions in the argument list
5542 if (Arguments != null){
5543 foreach (Argument a in Arguments){
5544 if (!a.Resolve (ec, loc))
5549 MethodGroupExpr mg = (MethodGroupExpr) expr;
5550 method = OverloadResolve (ec, mg, Arguments, false, loc);
5555 MethodInfo mi = method as MethodInfo;
5557 type = TypeManager.TypeToCoreType (mi.ReturnType);
5558 Expression iexpr = mg.InstanceExpression;
5560 if (iexpr == null ||
5561 iexpr is This || iexpr is EmptyExpression ||
5562 mg.IdenticalTypeName) {
5563 mg.InstanceExpression = null;
5565 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
5569 if (iexpr == null || iexpr is EmptyExpression) {
5570 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
5576 if (type.IsPointer){
5584 // Only base will allow this invocation to happen.
5586 if (mg.IsBase && method.IsAbstract){
5587 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
5591 if (Arguments == null && method.Name == "Finalize") {
5593 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5595 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5599 if ((method.Attributes & MethodAttributes.SpecialName) != 0 && IsSpecialMethodInvocation (method)) {
5603 if (mg.InstanceExpression != null)
5604 mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
5606 eclass = ExprClass.Value;
5610 bool IsSpecialMethodInvocation (MethodBase method)
5612 IMethodData md = TypeManager.GetMethod (method);
5614 if (!(md is AbstractPropertyEventMethod) && !(md is Operator))
5617 if (!TypeManager.IsSpecialMethod (method))
5620 int args = TypeManager.GetParameterData (method).Count;
5621 if (method.Name.StartsWith ("get_") && args > 0)
5623 else if (method.Name.StartsWith ("set_") && args > 2)
5626 // TODO: check operators and events as well ?
5629 Report.SymbolRelatedToPreviousError (method);
5630 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5631 TypeManager.CSharpSignature (method, true));
5637 // Emits the list of arguments as an array
5639 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5641 ILGenerator ig = ec.ig;
5642 int count = arguments.Count - idx;
5643 Argument a = (Argument) arguments [idx];
5644 Type t = a.Expr.Type;
5646 IntConstant.EmitInt (ig, count);
5647 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5649 int top = arguments.Count;
5650 for (int j = idx; j < top; j++){
5651 a = (Argument) arguments [j];
5653 ig.Emit (OpCodes.Dup);
5654 IntConstant.EmitInt (ig, j - idx);
5656 bool is_stobj, has_type_arg;
5657 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5659 ig.Emit (OpCodes.Ldelema, t);
5671 /// Emits a list of resolved Arguments that are in the arguments
5674 /// The MethodBase argument might be null if the
5675 /// emission of the arguments is known not to contain
5676 /// a `params' field (for example in constructors or other routines
5677 /// that keep their arguments in this structure)
5679 /// if `dup_args' is true, a copy of the arguments will be left
5680 /// on the stack. If `dup_args' is true, you can specify `this_arg'
5681 /// which will be duplicated before any other args. Only EmitCall
5682 /// should be using this interface.
5684 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5688 pd = TypeManager.GetParameterData (mb);
5692 LocalTemporary [] temps = null;
5695 temps = new LocalTemporary [arguments.Count];
5698 // If we are calling a params method with no arguments, special case it
5700 if (arguments == null){
5701 if (pd != null && pd.Count > 0 &&
5702 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5703 ILGenerator ig = ec.ig;
5705 IntConstant.EmitInt (ig, 0);
5706 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5712 int top = arguments.Count;
5714 for (int i = 0; i < top; i++){
5715 Argument a = (Argument) arguments [i];
5718 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5720 // Special case if we are passing the same data as the
5721 // params argument, do not put it in an array.
5723 if (pd.ParameterType (i) == a.Type)
5726 EmitParams (ec, i, arguments);
5733 ec.ig.Emit (OpCodes.Dup);
5734 (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5739 if (this_arg != null)
5742 for (int i = 0; i < top; i ++)
5743 temps [i].Emit (ec);
5746 if (pd != null && pd.Count > top &&
5747 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5748 ILGenerator ig = ec.ig;
5750 IntConstant.EmitInt (ig, 0);
5751 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5755 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5756 ArrayList arguments)
5758 ParameterData pd = TypeManager.GetParameterData (mb);
5760 if (arguments == null)
5761 return new Type [0];
5763 Argument a = (Argument) arguments [pd.Count - 1];
5764 Arglist list = (Arglist) a.Expr;
5766 return list.ArgumentTypes;
5770 /// This checks the ConditionalAttribute on the method
5772 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5774 if (method.IsConstructor)
5777 IMethodData md = TypeManager.GetMethod (method);
5779 return md.IsExcluded (ec);
5781 // For some methods (generated by delegate class) GetMethod returns null
5782 // because they are not included in builder_to_method table
5783 if (method.DeclaringType is TypeBuilder)
5786 return AttributeTester.IsConditionalMethodExcluded (method);
5790 /// is_base tells whether we want to force the use of the `call'
5791 /// opcode instead of using callvirt. Call is required to call
5792 /// a specific method, while callvirt will always use the most
5793 /// recent method in the vtable.
5795 /// is_static tells whether this is an invocation on a static method
5797 /// instance_expr is an expression that represents the instance
5798 /// it must be non-null if is_static is false.
5800 /// method is the method to invoke.
5802 /// Arguments is the list of arguments to pass to the method or constructor.
5804 public static void EmitCall (EmitContext ec, bool is_base,
5805 bool is_static, Expression instance_expr,
5806 MethodBase method, ArrayList Arguments, Location loc)
5808 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5811 // `dup_args' leaves an extra copy of the arguments on the stack
5812 // `omit_args' does not leave any arguments at all.
5813 // So, basically, you could make one call with `dup_args' set to true,
5814 // and then another with `omit_args' set to true, and the two calls
5815 // would have the same set of arguments. However, each argument would
5816 // only have been evaluated once.
5817 public static void EmitCall (EmitContext ec, bool is_base,
5818 bool is_static, Expression instance_expr,
5819 MethodBase method, ArrayList Arguments, Location loc,
5820 bool dup_args, bool omit_args)
5822 ILGenerator ig = ec.ig;
5823 bool struct_call = false;
5824 bool this_call = false;
5825 LocalTemporary this_arg = null;
5827 Type decl_type = method.DeclaringType;
5829 if (!RootContext.StdLib) {
5830 // Replace any calls to the system's System.Array type with calls to
5831 // the newly created one.
5832 if (method == TypeManager.system_int_array_get_length)
5833 method = TypeManager.int_array_get_length;
5834 else if (method == TypeManager.system_int_array_get_rank)
5835 method = TypeManager.int_array_get_rank;
5836 else if (method == TypeManager.system_object_array_clone)
5837 method = TypeManager.object_array_clone;
5838 else if (method == TypeManager.system_int_array_get_length_int)
5839 method = TypeManager.int_array_get_length_int;
5840 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5841 method = TypeManager.int_array_get_lower_bound_int;
5842 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5843 method = TypeManager.int_array_get_upper_bound_int;
5844 else if (method == TypeManager.system_void_array_copyto_array_int)
5845 method = TypeManager.void_array_copyto_array_int;
5848 if (ec.TestObsoleteMethodUsage) {
5850 // This checks ObsoleteAttribute on the method and on the declaring type
5852 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5854 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5856 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5858 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5862 if (IsMethodExcluded (method, ec))
5866 if (instance_expr == EmptyExpression.Null) {
5867 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5871 this_call = instance_expr is This;
5872 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5876 // If this is ourselves, push "this"
5880 Type iexpr_type = instance_expr.Type;
5883 // Push the instance expression
5885 if (TypeManager.IsValueType (iexpr_type)) {
5887 // Special case: calls to a function declared in a
5888 // reference-type with a value-type argument need
5889 // to have their value boxed.
5890 if (decl_type.IsValueType ||
5891 iexpr_type.IsGenericParameter) {
5893 // If the expression implements IMemoryLocation, then
5894 // we can optimize and use AddressOf on the
5897 // If not we have to use some temporary storage for
5899 if (instance_expr is IMemoryLocation) {
5900 ((IMemoryLocation)instance_expr).
5901 AddressOf (ec, AddressOp.LoadStore);
5903 LocalTemporary temp = new LocalTemporary (ec, iexpr_type);
5904 instance_expr.Emit (ec);
5906 temp.AddressOf (ec, AddressOp.Load);
5909 // avoid the overhead of doing this all the time.
5911 t = TypeManager.GetReferenceType (iexpr_type);
5913 instance_expr.Emit (ec);
5914 ig.Emit (OpCodes.Box, instance_expr.Type);
5915 t = TypeManager.object_type;
5918 instance_expr.Emit (ec);
5919 t = instance_expr.Type;
5923 this_arg = new LocalTemporary (ec, t);
5924 ig.Emit (OpCodes.Dup);
5925 this_arg.Store (ec);
5931 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5933 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5934 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5937 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5938 call_op = OpCodes.Call;
5940 call_op = OpCodes.Callvirt;
5942 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5943 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5944 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5951 // and DoFoo is not virtual, you can omit the callvirt,
5952 // because you don't need the null checking behavior.
5954 if (method is MethodInfo)
5955 ig.Emit (call_op, (MethodInfo) method);
5957 ig.Emit (call_op, (ConstructorInfo) method);
5960 public override void Emit (EmitContext ec)
5962 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5964 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5967 public override void EmitStatement (EmitContext ec)
5972 // Pop the return value if there is one
5974 if (method is MethodInfo){
5975 Type ret = ((MethodInfo)method).ReturnType;
5976 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5977 ec.ig.Emit (OpCodes.Pop);
5982 public class InvocationOrCast : ExpressionStatement
5985 Expression argument;
5987 public InvocationOrCast (Expression expr, Expression argument)
5990 this.argument = argument;
5991 this.loc = expr.Location;
5994 public override Expression DoResolve (EmitContext ec)
5997 // First try to resolve it as a cast.
5999 TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr;
6000 if ((te != null) && (te.eclass == ExprClass.Type)) {
6001 Cast cast = new Cast (te, argument, loc);
6002 return cast.Resolve (ec);
6006 // This can either be a type or a delegate invocation.
6007 // Let's just resolve it and see what we'll get.
6009 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
6014 // Ok, so it's a Cast.
6016 if (expr.eclass == ExprClass.Type) {
6017 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
6018 return cast.Resolve (ec);
6022 // It's a delegate invocation.
6024 if (!TypeManager.IsDelegateType (expr.Type)) {
6025 Error (149, "Method name expected");
6029 ArrayList args = new ArrayList ();
6030 args.Add (new Argument (argument, Argument.AType.Expression));
6031 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
6032 return invocation.Resolve (ec);
6037 Error (201, "Only assignment, call, increment, decrement and new object " +
6038 "expressions can be used as a statement");
6041 public override ExpressionStatement ResolveStatement (EmitContext ec)
6044 // First try to resolve it as a cast.
6046 TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr;
6047 if ((te != null) && (te.eclass == ExprClass.Type)) {
6053 // This can either be a type or a delegate invocation.
6054 // Let's just resolve it and see what we'll get.
6056 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
6057 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
6063 // It's a delegate invocation.
6065 if (!TypeManager.IsDelegateType (expr.Type)) {
6066 Error (149, "Method name expected");
6070 ArrayList args = new ArrayList ();
6071 args.Add (new Argument (argument, Argument.AType.Expression));
6072 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
6073 return invocation.ResolveStatement (ec);
6076 public override void Emit (EmitContext ec)
6078 throw new Exception ("Cannot happen");
6081 public override void EmitStatement (EmitContext ec)
6083 throw new Exception ("Cannot happen");
6088 // This class is used to "disable" the code generation for the
6089 // temporary variable when initializing value types.
6091 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
6092 public void AddressOf (EmitContext ec, AddressOp Mode)
6099 /// Implements the new expression
6101 public class New : ExpressionStatement, IMemoryLocation {
6102 public readonly ArrayList Arguments;
6105 // During bootstrap, it contains the RequestedType,
6106 // but if `type' is not null, it *might* contain a NewDelegate
6107 // (because of field multi-initialization)
6109 public Expression RequestedType;
6111 MethodBase method = null;
6114 // If set, the new expression is for a value_target, and
6115 // we will not leave anything on the stack.
6117 Expression value_target;
6118 bool value_target_set = false;
6119 bool is_type_parameter = false;
6121 public New (Expression requested_type, ArrayList arguments, Location l)
6123 RequestedType = requested_type;
6124 Arguments = arguments;
6128 public bool SetValueTypeVariable (Expression value)
6130 value_target = value;
6131 value_target_set = true;
6132 if (!(value_target is IMemoryLocation)){
6133 Error_UnexpectedKind (null, "variable", loc);
6140 // This function is used to disable the following code sequence for
6141 // value type initialization:
6143 // AddressOf (temporary)
6147 // Instead the provide will have provided us with the address on the
6148 // stack to store the results.
6150 static Expression MyEmptyExpression;
6152 public void DisableTemporaryValueType ()
6154 if (MyEmptyExpression == null)
6155 MyEmptyExpression = new EmptyAddressOf ();
6158 // To enable this, look into:
6159 // test-34 and test-89 and self bootstrapping.
6161 // For instance, we can avoid a copy by using `newobj'
6162 // instead of Call + Push-temp on value types.
6163 // value_target = MyEmptyExpression;
6168 /// Converts complex core type syntax like 'new int ()' to simple constant
6170 public static Constant Constantify (Type t)
6172 if (t == TypeManager.int32_type)
6173 return new IntConstant (0, Location.Null);
6174 if (t == TypeManager.uint32_type)
6175 return new UIntConstant (0, Location.Null);
6176 if (t == TypeManager.int64_type)
6177 return new LongConstant (0, Location.Null);
6178 if (t == TypeManager.uint64_type)
6179 return new ULongConstant (0, Location.Null);
6180 if (t == TypeManager.float_type)
6181 return new FloatConstant (0, Location.Null);
6182 if (t == TypeManager.double_type)
6183 return new DoubleConstant (0, Location.Null);
6184 if (t == TypeManager.short_type)
6185 return new ShortConstant (0, Location.Null);
6186 if (t == TypeManager.ushort_type)
6187 return new UShortConstant (0, Location.Null);
6188 if (t == TypeManager.sbyte_type)
6189 return new SByteConstant (0, Location.Null);
6190 if (t == TypeManager.byte_type)
6191 return new ByteConstant (0, Location.Null);
6192 if (t == TypeManager.char_type)
6193 return new CharConstant ('\0', Location.Null);
6194 if (t == TypeManager.bool_type)
6195 return new BoolConstant (false, Location.Null);
6196 if (t == TypeManager.decimal_type)
6197 return new DecimalConstant (0, Location.Null);
6202 public override Expression DoResolve (EmitContext ec)
6205 // The New DoResolve might be called twice when initializing field
6206 // expressions (see EmitFieldInitializers, the call to
6207 // GetInitializerExpression will perform a resolve on the expression,
6208 // and later the assign will trigger another resolution
6210 // This leads to bugs (#37014)
6213 if (RequestedType is NewDelegate)
6214 return RequestedType;
6218 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec);
6222 type = texpr.ResolveType (ec);
6224 if (Arguments == null) {
6225 Expression c = Constantify (type);
6230 if (TypeManager.IsDelegateType (type)) {
6231 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
6232 if (RequestedType != null)
6233 if (!(RequestedType is DelegateCreation))
6234 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
6235 return RequestedType;
6238 if (type.IsGenericParameter) {
6239 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
6241 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
6242 Error (304, String.Format (
6243 "Cannot create an instance of the " +
6244 "variable type '{0}' because it " +
6245 "doesn't have the new() constraint",
6250 if ((Arguments != null) && (Arguments.Count != 0)) {
6251 Error (417, String.Format (
6252 "`{0}': cannot provide arguments " +
6253 "when creating an instance of a " +
6254 "variable type.", type));
6258 is_type_parameter = true;
6259 eclass = ExprClass.Value;
6263 if (type.IsAbstract && type.IsSealed) {
6264 Report.SymbolRelatedToPreviousError (type);
6265 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
6269 if (type.IsInterface || type.IsAbstract){
6270 Report.SymbolRelatedToPreviousError (type);
6271 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
6275 bool is_struct = type.IsValueType;
6276 eclass = ExprClass.Value;
6279 // SRE returns a match for .ctor () on structs (the object constructor),
6280 // so we have to manually ignore it.
6282 if (is_struct && Arguments == null)
6285 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
6286 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
6291 MethodGroupExpr mg = ml as MethodGroupExpr;
6294 ml.Error_UnexpectedKind (ec, "method group", loc);
6298 if (Arguments != null){
6299 foreach (Argument a in Arguments){
6300 if (!a.Resolve (ec, loc))
6305 method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
6306 if (method == null) {
6307 if (almostMatchedMembers.Count != 0)
6308 MemberLookupFailed (ec, type, type, ".ctor", null, true, loc);
6315 bool DoEmitTypeParameter (EmitContext ec)
6317 ILGenerator ig = ec.ig;
6319 ig.Emit (OpCodes.Ldtoken, type);
6320 ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6321 ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
6322 ig.Emit (OpCodes.Unbox_Any, type);
6328 // This DoEmit can be invoked in two contexts:
6329 // * As a mechanism that will leave a value on the stack (new object)
6330 // * As one that wont (init struct)
6332 // You can control whether a value is required on the stack by passing
6333 // need_value_on_stack. The code *might* leave a value on the stack
6334 // so it must be popped manually
6336 // If we are dealing with a ValueType, we have a few
6337 // situations to deal with:
6339 // * The target is a ValueType, and we have been provided
6340 // the instance (this is easy, we are being assigned).
6342 // * The target of New is being passed as an argument,
6343 // to a boxing operation or a function that takes a
6346 // In this case, we need to create a temporary variable
6347 // that is the argument of New.
6349 // Returns whether a value is left on the stack
6351 bool DoEmit (EmitContext ec, bool need_value_on_stack)
6353 bool is_value_type = TypeManager.IsValueType (type);
6354 ILGenerator ig = ec.ig;
6359 // Allow DoEmit() to be called multiple times.
6360 // We need to create a new LocalTemporary each time since
6361 // you can't share LocalBuilders among ILGeneators.
6362 if (!value_target_set)
6363 value_target = new LocalTemporary (ec, type);
6365 ml = (IMemoryLocation) value_target;
6366 ml.AddressOf (ec, AddressOp.Store);
6370 Invocation.EmitArguments (ec, method, Arguments, false, null);
6374 ig.Emit (OpCodes.Initobj, type);
6376 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6377 if (need_value_on_stack){
6378 value_target.Emit (ec);
6383 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6388 public override void Emit (EmitContext ec)
6390 if (is_type_parameter)
6391 DoEmitTypeParameter (ec);
6396 public override void EmitStatement (EmitContext ec)
6398 if (is_type_parameter)
6399 throw new InvalidOperationException ();
6401 if (DoEmit (ec, false))
6402 ec.ig.Emit (OpCodes.Pop);
6405 public void AddressOf (EmitContext ec, AddressOp Mode)
6407 if (is_type_parameter)
6408 throw new InvalidOperationException ();
6410 if (!type.IsValueType){
6412 // We throw an exception. So far, I believe we only need to support
6414 // foreach (int j in new StructType ())
6417 throw new Exception ("AddressOf should not be used for classes");
6420 if (!value_target_set)
6421 value_target = new LocalTemporary (ec, type);
6423 IMemoryLocation ml = (IMemoryLocation) value_target;
6424 ml.AddressOf (ec, AddressOp.Store);
6426 Invocation.EmitArguments (ec, method, Arguments, false, null);
6429 ec.ig.Emit (OpCodes.Initobj, type);
6431 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6433 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6438 /// 14.5.10.2: Represents an array creation expression.
6442 /// There are two possible scenarios here: one is an array creation
6443 /// expression that specifies the dimensions and optionally the
6444 /// initialization data and the other which does not need dimensions
6445 /// specified but where initialization data is mandatory.
6447 public class ArrayCreation : Expression {
6448 Expression requested_base_type;
6449 ArrayList initializers;
6452 // The list of Argument types.
6453 // This is used to construct the `newarray' or constructor signature
6455 ArrayList arguments;
6458 // Method used to create the array object.
6460 MethodBase new_method = null;
6462 Type array_element_type;
6463 Type underlying_type;
6464 bool is_one_dimensional = false;
6465 bool is_builtin_type = false;
6466 bool expect_initializers = false;
6467 int num_arguments = 0;
6471 ArrayList array_data;
6476 // The number of array initializers that we can handle
6477 // via the InitializeArray method - through EmitStaticInitializers
6479 int num_automatic_initializers;
6481 const int max_automatic_initializers = 6;
6483 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6485 this.requested_base_type = requested_base_type;
6486 this.initializers = initializers;
6490 arguments = new ArrayList ();
6492 foreach (Expression e in exprs) {
6493 arguments.Add (new Argument (e, Argument.AType.Expression));
6498 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6500 this.requested_base_type = requested_base_type;
6501 this.initializers = initializers;
6505 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6507 //string tmp = rank.Substring (rank.LastIndexOf ('['));
6509 //dimensions = tmp.Length - 1;
6510 expect_initializers = true;
6513 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6515 StringBuilder sb = new StringBuilder (rank);
6518 for (int i = 1; i < idx_count; i++)
6523 return new ComposedCast (base_type, sb.ToString (), loc);
6526 void Error_IncorrectArrayInitializer ()
6528 Error (178, "Invalid rank specifier: expected `,' or `]'");
6531 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6533 if (specified_dims) {
6534 Argument a = (Argument) arguments [idx];
6536 if (!a.Resolve (ec, loc))
6539 if (!(a.Expr is Constant)) {
6540 Error (150, "A constant value is expected");
6544 int value = (int) ((Constant) a.Expr).GetValue ();
6546 if (value != probe.Count) {
6547 Error_IncorrectArrayInitializer ();
6551 bounds [idx] = value;
6554 int child_bounds = -1;
6555 for (int i = 0; i < probe.Count; ++i) {
6556 object o = probe [i];
6557 if (o is ArrayList) {
6558 ArrayList sub_probe = o as ArrayList;
6559 int current_bounds = sub_probe.Count;
6561 if (child_bounds == -1)
6562 child_bounds = current_bounds;
6564 else if (child_bounds != current_bounds){
6565 Error_IncorrectArrayInitializer ();
6568 if (specified_dims && (idx + 1 >= arguments.Count)){
6569 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6573 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6577 if (child_bounds != -1){
6578 Error_IncorrectArrayInitializer ();
6582 Expression tmp = (Expression) o;
6583 tmp = tmp.Resolve (ec);
6588 // Console.WriteLine ("I got: " + tmp);
6589 // Handle initialization from vars, fields etc.
6591 Expression conv = Convert.ImplicitConversionRequired (
6592 ec, tmp, underlying_type, loc);
6597 if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6598 // These are subclasses of Constant that can appear as elements of an
6599 // array that cannot be statically initialized (with num_automatic_initializers
6600 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6601 array_data.Add (conv);
6602 } else if (conv is Constant) {
6603 // These are the types of Constant that can appear in arrays that can be
6604 // statically allocated.
6605 array_data.Add (conv);
6606 num_automatic_initializers++;
6608 array_data.Add (conv);
6615 public void UpdateIndices (EmitContext ec)
6618 for (ArrayList probe = initializers; probe != null;) {
6619 if (probe.Count > 0 && probe [0] is ArrayList) {
6620 Expression e = new IntConstant (probe.Count, Location.Null);
6621 arguments.Add (new Argument (e, Argument.AType.Expression));
6623 bounds [i++] = probe.Count;
6625 probe = (ArrayList) probe [0];
6628 Expression e = new IntConstant (probe.Count, Location.Null);
6629 arguments.Add (new Argument (e, Argument.AType.Expression));
6631 bounds [i++] = probe.Count;
6638 public bool ValidateInitializers (EmitContext ec, Type array_type)
6640 if (initializers == null) {
6641 if (expect_initializers)
6647 if (underlying_type == null)
6651 // We use this to store all the date values in the order in which we
6652 // will need to store them in the byte blob later
6654 array_data = new ArrayList ();
6655 bounds = new Hashtable ();
6659 if (arguments != null) {
6660 ret = CheckIndices (ec, initializers, 0, true);
6663 arguments = new ArrayList ();
6665 ret = CheckIndices (ec, initializers, 0, false);
6672 if (arguments.Count != dimensions) {
6673 Error_IncorrectArrayInitializer ();
6682 // Creates the type of the array
6684 bool LookupType (EmitContext ec)
6686 StringBuilder array_qualifier = new StringBuilder (rank);
6689 // `In the first form allocates an array instace of the type that results
6690 // from deleting each of the individual expression from the expression list'
6692 if (num_arguments > 0) {
6693 array_qualifier.Append ("[");
6694 for (int i = num_arguments-1; i > 0; i--)
6695 array_qualifier.Append (",");
6696 array_qualifier.Append ("]");
6702 TypeExpr array_type_expr;
6703 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString ());
6704 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec);
6705 if (array_type_expr == null)
6708 type = array_type_expr.ResolveType (ec);
6710 if (!type.IsArray) {
6711 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6714 underlying_type = TypeManager.GetElementType (type);
6715 dimensions = type.GetArrayRank ();
6720 public override Expression DoResolve (EmitContext ec)
6724 if (!LookupType (ec))
6728 // First step is to validate the initializers and fill
6729 // in any missing bits
6731 if (!ValidateInitializers (ec, type))
6734 if (arguments == null)
6737 arg_count = arguments.Count;
6738 foreach (Argument a in arguments){
6739 if (!a.Resolve (ec, loc))
6742 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6743 if (real_arg == null)
6750 array_element_type = TypeManager.GetElementType (type);
6752 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6753 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6757 if (arg_count == 1) {
6758 is_one_dimensional = true;
6759 eclass = ExprClass.Value;
6763 is_builtin_type = TypeManager.IsBuiltinType (type);
6765 if (is_builtin_type) {
6768 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6769 AllBindingFlags, loc);
6771 if (!(ml is MethodGroupExpr)) {
6772 ml.Error_UnexpectedKind (ec, "method group", loc);
6777 Error (-6, "New invocation: Can not find a constructor for " +
6778 "this argument list");
6782 new_method = Invocation.OverloadResolve (
6783 ec, (MethodGroupExpr) ml, arguments, false, loc);
6785 if (new_method == null) {
6786 Error (-6, "New invocation: Can not find a constructor for " +
6787 "this argument list");
6791 eclass = ExprClass.Value;
6794 ModuleBuilder mb = CodeGen.Module.Builder;
6795 ArrayList args = new ArrayList ();
6797 if (arguments != null) {
6798 for (int i = 0; i < arg_count; i++)
6799 args.Add (TypeManager.int32_type);
6802 Type [] arg_types = null;
6805 arg_types = new Type [args.Count];
6807 args.CopyTo (arg_types, 0);
6809 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6812 if (new_method == null) {
6813 Error (-6, "New invocation: Can not find a constructor for " +
6814 "this argument list");
6818 eclass = ExprClass.Value;
6823 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6828 int count = array_data.Count;
6830 if (underlying_type.IsEnum)
6831 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6833 factor = GetTypeSize (underlying_type);
6835 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6837 data = new byte [(count * factor + 4) & ~3];
6840 for (int i = 0; i < count; ++i) {
6841 object v = array_data [i];
6843 if (v is EnumConstant)
6844 v = ((EnumConstant) v).Child;
6846 if (v is Constant && !(v is StringConstant))
6847 v = ((Constant) v).GetValue ();
6853 if (underlying_type == TypeManager.int64_type){
6854 if (!(v is Expression)){
6855 long val = (long) v;
6857 for (int j = 0; j < factor; ++j) {
6858 data [idx + j] = (byte) (val & 0xFF);
6862 } else if (underlying_type == TypeManager.uint64_type){
6863 if (!(v is Expression)){
6864 ulong val = (ulong) v;
6866 for (int j = 0; j < factor; ++j) {
6867 data [idx + j] = (byte) (val & 0xFF);
6871 } else if (underlying_type == TypeManager.float_type) {
6872 if (!(v is Expression)){
6873 element = BitConverter.GetBytes ((float) v);
6875 for (int j = 0; j < factor; ++j)
6876 data [idx + j] = element [j];
6878 } else if (underlying_type == TypeManager.double_type) {
6879 if (!(v is Expression)){
6880 element = BitConverter.GetBytes ((double) v);
6882 for (int j = 0; j < factor; ++j)
6883 data [idx + j] = element [j];
6885 } else if (underlying_type == TypeManager.char_type){
6886 if (!(v is Expression)){
6887 int val = (int) ((char) v);
6889 data [idx] = (byte) (val & 0xff);
6890 data [idx+1] = (byte) (val >> 8);
6892 } else if (underlying_type == TypeManager.short_type){
6893 if (!(v is Expression)){
6894 int val = (int) ((short) v);
6896 data [idx] = (byte) (val & 0xff);
6897 data [idx+1] = (byte) (val >> 8);
6899 } else if (underlying_type == TypeManager.ushort_type){
6900 if (!(v is Expression)){
6901 int val = (int) ((ushort) v);
6903 data [idx] = (byte) (val & 0xff);
6904 data [idx+1] = (byte) (val >> 8);
6906 } else if (underlying_type == TypeManager.int32_type) {
6907 if (!(v is Expression)){
6910 data [idx] = (byte) (val & 0xff);
6911 data [idx+1] = (byte) ((val >> 8) & 0xff);
6912 data [idx+2] = (byte) ((val >> 16) & 0xff);
6913 data [idx+3] = (byte) (val >> 24);
6915 } else if (underlying_type == TypeManager.uint32_type) {
6916 if (!(v is Expression)){
6917 uint val = (uint) v;
6919 data [idx] = (byte) (val & 0xff);
6920 data [idx+1] = (byte) ((val >> 8) & 0xff);
6921 data [idx+2] = (byte) ((val >> 16) & 0xff);
6922 data [idx+3] = (byte) (val >> 24);
6924 } else if (underlying_type == TypeManager.sbyte_type) {
6925 if (!(v is Expression)){
6926 sbyte val = (sbyte) v;
6927 data [idx] = (byte) val;
6929 } else if (underlying_type == TypeManager.byte_type) {
6930 if (!(v is Expression)){
6931 byte val = (byte) v;
6932 data [idx] = (byte) val;
6934 } else if (underlying_type == TypeManager.bool_type) {
6935 if (!(v is Expression)){
6936 bool val = (bool) v;
6937 data [idx] = (byte) (val ? 1 : 0);
6939 } else if (underlying_type == TypeManager.decimal_type){
6940 if (!(v is Expression)){
6941 int [] bits = Decimal.GetBits ((decimal) v);
6944 // FIXME: For some reason, this doesn't work on the MS runtime.
6945 int [] nbits = new int [4];
6946 nbits [0] = bits [3];
6947 nbits [1] = bits [2];
6948 nbits [2] = bits [0];
6949 nbits [3] = bits [1];
6951 for (int j = 0; j < 4; j++){
6952 data [p++] = (byte) (nbits [j] & 0xff);
6953 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6954 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6955 data [p++] = (byte) (nbits [j] >> 24);
6959 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6968 // Emits the initializers for the array
6970 void EmitStaticInitializers (EmitContext ec)
6973 // First, the static data
6976 ILGenerator ig = ec.ig;
6978 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6980 fb = RootContext.MakeStaticData (data);
6982 ig.Emit (OpCodes.Dup);
6983 ig.Emit (OpCodes.Ldtoken, fb);
6984 ig.Emit (OpCodes.Call,
6985 TypeManager.void_initializearray_array_fieldhandle);
6989 // Emits pieces of the array that can not be computed at compile
6990 // time (variables and string locations).
6992 // This always expect the top value on the stack to be the array
6994 void EmitDynamicInitializers (EmitContext ec)
6996 ILGenerator ig = ec.ig;
6997 int dims = bounds.Count;
6998 int [] current_pos = new int [dims];
6999 int top = array_data.Count;
7001 MethodInfo set = null;
7005 ModuleBuilder mb = null;
7006 mb = CodeGen.Module.Builder;
7007 args = new Type [dims + 1];
7010 for (j = 0; j < dims; j++)
7011 args [j] = TypeManager.int32_type;
7013 args [j] = array_element_type;
7015 set = mb.GetArrayMethod (
7017 CallingConventions.HasThis | CallingConventions.Standard,
7018 TypeManager.void_type, args);
7021 for (int i = 0; i < top; i++){
7023 Expression e = null;
7025 if (array_data [i] is Expression)
7026 e = (Expression) array_data [i];
7030 // Basically we do this for string literals and
7031 // other non-literal expressions
7033 if (e is EnumConstant){
7034 e = ((EnumConstant) e).Child;
7037 if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
7038 num_automatic_initializers <= max_automatic_initializers) {
7039 Type etype = e.Type;
7041 ig.Emit (OpCodes.Dup);
7043 for (int idx = 0; idx < dims; idx++)
7044 IntConstant.EmitInt (ig, current_pos [idx]);
7047 // If we are dealing with a struct, get the
7048 // address of it, so we can store it.
7051 TypeManager.IsValueType (etype) &&
7052 (!TypeManager.IsBuiltinOrEnum (etype) ||
7053 etype == TypeManager.decimal_type)) {
7058 // Let new know that we are providing
7059 // the address where to store the results
7061 n.DisableTemporaryValueType ();
7064 ig.Emit (OpCodes.Ldelema, etype);
7070 bool is_stobj, has_type_arg;
7071 OpCode op = ArrayAccess.GetStoreOpcode (
7072 etype, out is_stobj,
7075 ig.Emit (OpCodes.Stobj, etype);
7076 else if (has_type_arg)
7077 ig.Emit (op, etype);
7081 ig.Emit (OpCodes.Call, set);
7088 for (int j = dims - 1; j >= 0; j--){
7090 if (current_pos [j] < (int) bounds [j])
7092 current_pos [j] = 0;
7097 void EmitArrayArguments (EmitContext ec)
7099 ILGenerator ig = ec.ig;
7101 foreach (Argument a in arguments) {
7102 Type atype = a.Type;
7105 if (atype == TypeManager.uint64_type)
7106 ig.Emit (OpCodes.Conv_Ovf_U4);
7107 else if (atype == TypeManager.int64_type)
7108 ig.Emit (OpCodes.Conv_Ovf_I4);
7112 public override void Emit (EmitContext ec)
7114 ILGenerator ig = ec.ig;
7116 EmitArrayArguments (ec);
7117 if (is_one_dimensional)
7118 ig.Emit (OpCodes.Newarr, array_element_type);
7120 if (is_builtin_type)
7121 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
7123 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
7126 if (initializers != null){
7128 // FIXME: Set this variable correctly.
7130 bool dynamic_initializers = true;
7132 // This will never be true for array types that cannot be statically
7133 // initialized. num_automatic_initializers will always be zero. See
7135 if (num_automatic_initializers > max_automatic_initializers)
7136 EmitStaticInitializers (ec);
7138 if (dynamic_initializers)
7139 EmitDynamicInitializers (ec);
7143 public object EncodeAsAttribute ()
7145 if (!is_one_dimensional){
7146 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
7150 if (array_data == null){
7151 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
7155 object [] ret = new object [array_data.Count];
7157 foreach (Expression e in array_data){
7160 if (e is NullLiteral)
7163 if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
7173 /// Represents the `this' construct
7175 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
7178 VariableInfo variable_info;
7180 public This (Block block, Location loc)
7186 public This (Location loc)
7191 public VariableInfo VariableInfo {
7192 get { return variable_info; }
7195 public bool VerifyFixed ()
7197 return !TypeManager.IsValueType (Type);
7200 public bool ResolveBase (EmitContext ec)
7202 eclass = ExprClass.Variable;
7204 if (ec.TypeContainer.CurrentType != null)
7205 type = ec.TypeContainer.CurrentType;
7207 type = ec.ContainerType;
7210 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
7214 if (block != null && block.Toplevel.ThisVariable != null)
7215 variable_info = block.Toplevel.ThisVariable.VariableInfo;
7217 if (ec.CurrentAnonymousMethod != null)
7223 public override Expression DoResolve (EmitContext ec)
7225 if (!ResolveBase (ec))
7228 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && !variable_info.IsAssigned (ec)) {
7229 Error (188, "The `this' object cannot be used before all of its fields are assigned to");
7230 variable_info.SetAssigned (ec);
7234 if (ec.IsFieldInitializer) {
7235 Error (27, "Keyword `this' is not available in the current context");
7242 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
7244 if (!ResolveBase (ec))
7247 if (variable_info != null)
7248 variable_info.SetAssigned (ec);
7250 if (ec.TypeContainer is Class){
7251 Error (1604, "Cannot assign to 'this' because it is read-only");
7258 public void Emit (EmitContext ec, bool leave_copy)
7262 ec.ig.Emit (OpCodes.Dup);
7265 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7267 ILGenerator ig = ec.ig;
7269 if (ec.TypeContainer is Struct){
7273 ec.ig.Emit (OpCodes.Dup);
7274 ig.Emit (OpCodes.Stobj, type);
7276 throw new Exception ("how did you get here");
7280 public override void Emit (EmitContext ec)
7282 ILGenerator ig = ec.ig;
7285 if (ec.TypeContainer is Struct)
7286 ig.Emit (OpCodes.Ldobj, type);
7289 public override int GetHashCode()
7291 return block.GetHashCode ();
7294 public override bool Equals (object obj)
7296 This t = obj as This;
7300 return block == t.block;
7303 public void AddressOf (EmitContext ec, AddressOp mode)
7308 // FIGURE OUT WHY LDARG_S does not work
7310 // consider: struct X { int val; int P { set { val = value; }}}
7312 // Yes, this looks very bad. Look at `NOTAS' for
7314 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
7319 /// Represents the `__arglist' construct
7321 public class ArglistAccess : Expression
7323 public ArglistAccess (Location loc)
7328 public bool ResolveBase (EmitContext ec)
7330 eclass = ExprClass.Variable;
7331 type = TypeManager.runtime_argument_handle_type;
7335 public override Expression DoResolve (EmitContext ec)
7337 if (!ResolveBase (ec))
7340 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) {
7341 Error (190, "The __arglist construct is valid only within " +
7342 "a variable argument method.");
7349 public override void Emit (EmitContext ec)
7351 ec.ig.Emit (OpCodes.Arglist);
7356 /// Represents the `__arglist (....)' construct
7358 public class Arglist : Expression
7360 public readonly Argument[] Arguments;
7362 public Arglist (Argument[] args, Location l)
7368 public Type[] ArgumentTypes {
7370 Type[] retval = new Type [Arguments.Length];
7371 for (int i = 0; i < Arguments.Length; i++)
7372 retval [i] = Arguments [i].Type;
7377 public override Expression DoResolve (EmitContext ec)
7379 eclass = ExprClass.Variable;
7380 type = TypeManager.runtime_argument_handle_type;
7382 foreach (Argument arg in Arguments) {
7383 if (!arg.Resolve (ec, loc))
7390 public override void Emit (EmitContext ec)
7392 foreach (Argument arg in Arguments)
7398 // This produces the value that renders an instance, used by the iterators code
7400 public class ProxyInstance : Expression, IMemoryLocation {
7401 public override Expression DoResolve (EmitContext ec)
7403 eclass = ExprClass.Variable;
7404 type = ec.ContainerType;
7408 public override void Emit (EmitContext ec)
7410 ec.ig.Emit (OpCodes.Ldarg_0);
7414 public void AddressOf (EmitContext ec, AddressOp mode)
7416 ec.ig.Emit (OpCodes.Ldarg_0);
7421 /// Implements the typeof operator
7423 public class TypeOf : Expression {
7424 public Expression QueriedType;
7425 protected Type typearg;
7427 public TypeOf (Expression queried_type, Location l)
7429 QueriedType = queried_type;
7433 public override Expression DoResolve (EmitContext ec)
7435 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec);
7439 typearg = texpr.ResolveType (ec);
7441 if (typearg == TypeManager.void_type) {
7442 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7446 if (typearg.IsPointer && !ec.InUnsafe){
7451 type = TypeManager.type_type;
7452 // Even though what is returned is a type object, it's treated as a value by the compiler.
7453 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7454 eclass = ExprClass.Value;
7458 public override void Emit (EmitContext ec)
7460 ec.ig.Emit (OpCodes.Ldtoken, typearg);
7461 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7464 public Type TypeArg {
7465 get { return typearg; }
7470 /// Implements the `typeof (void)' operator
7472 public class TypeOfVoid : TypeOf {
7473 public TypeOfVoid (Location l) : base (null, l)
7478 public override Expression DoResolve (EmitContext ec)
7480 type = TypeManager.type_type;
7481 typearg = TypeManager.void_type;
7482 // See description in TypeOf.
7483 eclass = ExprClass.Value;
7489 /// Implements the sizeof expression
7491 public class SizeOf : Expression {
7492 public Expression QueriedType;
7495 public SizeOf (Expression queried_type, Location l)
7497 this.QueriedType = queried_type;
7501 public override Expression DoResolve (EmitContext ec)
7503 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec);
7507 if (texpr is TypeParameterExpr){
7508 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
7512 type_queried = texpr.ResolveType (ec);
7514 int size_of = GetTypeSize (type_queried);
7516 return new IntConstant (size_of, loc);
7520 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)",
7521 TypeManager.CSharpName (type_queried));
7525 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7529 type = TypeManager.int32_type;
7530 eclass = ExprClass.Value;
7534 public override void Emit (EmitContext ec)
7536 int size = GetTypeSize (type_queried);
7539 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7541 IntConstant.EmitInt (ec.ig, size);
7546 /// Implements the qualified-alias-member (::) expression.
7548 public class QualifiedAliasMember : Expression
7550 string alias, identifier;
7552 public QualifiedAliasMember (string alias, string identifier, Location l)
7555 this.identifier = identifier;
7559 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
7561 if (alias == "global")
7562 return new MemberAccess (Namespace.Root, identifier, loc).ResolveAsTypeStep (ec, silent);
7564 int errors = Report.Errors;
7565 FullNamedExpression fne = ec.DeclSpace.NamespaceEntry.LookupAlias (alias);
7567 if (errors == Report.Errors)
7568 Report.Error (432, loc, "Alias `{0}' not found", alias);
7571 if (fne.eclass != ExprClass.Namespace) {
7573 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7576 return new MemberAccess (fne, identifier, loc).ResolveAsTypeStep (ec, silent);
7579 public override Expression DoResolve (EmitContext ec)
7581 FullNamedExpression fne;
7582 if (alias == "global") {
7583 fne = Namespace.Root;
7585 int errors = Report.Errors;
7586 fne = ec.DeclSpace.NamespaceEntry.LookupAlias (alias);
7588 if (errors == Report.Errors)
7589 Report.Error (432, loc, "Alias `{0}' not found", alias);
7594 Expression retval = new MemberAccess (fne, identifier, loc).DoResolve (ec);
7598 if (!(retval is FullNamedExpression)) {
7599 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
7603 // We defer this check till the end to match the behaviour of CSC
7604 if (fne.eclass != ExprClass.Namespace) {
7605 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7611 public override void Emit (EmitContext ec)
7613 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
7617 public override string ToString ()
7619 return alias + "::" + identifier;
7622 public override string GetSignatureForError ()
7629 /// Implements the member access expression
7631 public class MemberAccess : Expression {
7632 public readonly string Identifier;
7636 // TODO: Location can be removed
7637 public MemberAccess (Expression expr, string id, Location l)
7641 loc = expr.Location;
7644 public MemberAccess (Expression expr, string id, TypeArguments args,
7646 : this (expr, id, l)
7651 public Expression Expr {
7652 get { return expr; }
7655 // TODO: this method has very poor performace for Enum fields and
7656 // probably for other constants as well
7657 Expression DoResolve (EmitContext ec, Expression right_side)
7660 throw new Exception ();
7663 // Resolve the expression with flow analysis turned off, we'll do the definite
7664 // assignment checks later. This is because we don't know yet what the expression
7665 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7666 // definite assignment check on the actual field and not on the whole struct.
7669 SimpleName original = expr as SimpleName;
7670 Expression new_expr = expr.Resolve (ec,
7671 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7672 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7674 if (new_expr == null)
7677 if (new_expr is Namespace) {
7678 Namespace ns = (Namespace) new_expr;
7679 string lookup_id = MemberName.MakeName (Identifier, args);
7680 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc);
7681 if ((retval != null) && (args != null))
7682 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec);
7684 Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
7685 Identifier, ns.FullName);
7689 Type expr_type = new_expr.Type;
7690 if (expr_type.IsPointer){
7691 Error (23, "The `.' operator can not be applied to pointer operands (" +
7692 TypeManager.CSharpName (expr_type) + ")");
7696 Expression member_lookup;
7697 member_lookup = MemberLookup (
7698 ec, expr_type, expr_type, Identifier, loc);
7699 if ((member_lookup == null) && (args != null)) {
7700 string lookup_id = MemberName.MakeName (Identifier, args);
7701 member_lookup = MemberLookup (
7702 ec, expr_type, expr_type, lookup_id, loc);
7704 if (member_lookup == null) {
7705 MemberLookupFailed (
7706 ec, expr_type, expr_type, Identifier, null, true, loc);
7710 if (member_lookup is TypeExpr) {
7711 if (!(new_expr is TypeExpr) &&
7712 (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
7713 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7714 Identifier, member_lookup.GetSignatureForError ());
7718 ConstructedType ct = new_expr as ConstructedType;
7721 // When looking up a nested type in a generic instance
7722 // via reflection, we always get a generic type definition
7723 // and not a generic instance - so we have to do this here.
7725 // See gtest-172-lib.cs and gtest-172.cs for an example.
7727 ct = new ConstructedType (
7728 member_lookup.Type, ct.TypeArguments, loc);
7730 return ct.ResolveAsTypeStep (ec);
7733 return member_lookup;
7736 MemberExpr me = (MemberExpr) member_lookup;
7737 member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
7738 if (member_lookup == null)
7742 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7744 throw new InternalErrorException ();
7746 return mg.ResolveGeneric (ec, args);
7749 if (original != null && !TypeManager.IsValueType (expr_type)) {
7750 me = member_lookup as MemberExpr;
7751 if (me != null && me.IsInstance) {
7752 LocalVariableReference var = new_expr as LocalVariableReference;
7753 if (var != null && !var.VerifyAssigned (ec))
7758 // The following DoResolve/DoResolveLValue will do the definite assignment
7761 if (right_side != null)
7762 return member_lookup.DoResolveLValue (ec, right_side);
7764 return member_lookup.DoResolve (ec);
7767 public override Expression DoResolve (EmitContext ec)
7769 return DoResolve (ec, null);
7772 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7774 return DoResolve (ec, right_side);
7777 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
7779 return ResolveNamespaceOrType (ec, silent);
7782 public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent)
7784 FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec, silent);
7786 if (new_expr == null) {
7787 Report.Error (234, "No such name or typespace {0}", expr);
7791 string lookup_id = MemberName.MakeName (Identifier, args);
7793 if (new_expr is Namespace) {
7794 Namespace ns = (Namespace) new_expr;
7795 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, lookup_id, loc);
7796 if ((retval != null) && (args != null))
7797 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec);
7798 if (!silent && retval == null)
7799 Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
7800 Identifier, ns.FullName);
7804 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (ec);
7805 if (tnew_expr == null)
7808 Type expr_type = tnew_expr.ResolveType (ec);
7810 if (expr_type.IsPointer){
7811 Error (23, "The `.' operator can not be applied to pointer operands (" +
7812 TypeManager.CSharpName (expr_type) + ")");
7816 Expression member_lookup = MemberLookup (
7817 ec, ec.ContainerType, expr_type, expr_type, lookup_id,
7818 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7819 if (member_lookup == null) {
7820 int errors = Report.Errors;
7821 MemberLookupFailed (ec, expr_type, expr_type, lookup_id, null, false, loc);
7823 if (!silent && errors == Report.Errors) {
7824 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7825 Identifier, new_expr.GetSignatureForError ());
7830 if (!(member_lookup is TypeExpr)) {
7831 new_expr.Error_UnexpectedKind (ec, "type", loc);
7835 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (ec);
7839 TypeArguments the_args = args;
7840 if (TypeManager.HasGenericArguments (expr_type)) {
7841 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7843 TypeArguments new_args = new TypeArguments (loc);
7844 foreach (Type decl in decl_args)
7845 new_args.Add (new TypeExpression (decl, loc));
7848 new_args.Add (args);
7850 the_args = new_args;
7853 if (the_args != null) {
7854 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7855 return ctype.ResolveAsTypeStep (ec);
7861 public override void Emit (EmitContext ec)
7863 throw new Exception ("Should not happen");
7866 public override string ToString ()
7868 return expr + "." + MemberName.MakeName (Identifier, args);
7871 public override string GetSignatureForError ()
7873 return expr.GetSignatureForError () + "." + Identifier;
7878 /// Implements checked expressions
7880 public class CheckedExpr : Expression {
7882 public Expression Expr;
7884 public CheckedExpr (Expression e, Location l)
7890 public override Expression DoResolve (EmitContext ec)
7892 bool last_check = ec.CheckState;
7893 bool last_const_check = ec.ConstantCheckState;
7895 ec.CheckState = true;
7896 ec.ConstantCheckState = true;
7897 Expr = Expr.Resolve (ec);
7898 ec.CheckState = last_check;
7899 ec.ConstantCheckState = last_const_check;
7904 if (Expr is Constant)
7907 eclass = Expr.eclass;
7912 public override void Emit (EmitContext ec)
7914 bool last_check = ec.CheckState;
7915 bool last_const_check = ec.ConstantCheckState;
7917 ec.CheckState = true;
7918 ec.ConstantCheckState = true;
7920 ec.CheckState = last_check;
7921 ec.ConstantCheckState = last_const_check;
7927 /// Implements the unchecked expression
7929 public class UnCheckedExpr : Expression {
7931 public Expression Expr;
7933 public UnCheckedExpr (Expression e, Location l)
7939 public override Expression DoResolve (EmitContext ec)
7941 bool last_check = ec.CheckState;
7942 bool last_const_check = ec.ConstantCheckState;
7944 ec.CheckState = false;
7945 ec.ConstantCheckState = false;
7946 Expr = Expr.Resolve (ec);
7947 ec.CheckState = last_check;
7948 ec.ConstantCheckState = last_const_check;
7953 if (Expr is Constant)
7956 eclass = Expr.eclass;
7961 public override void Emit (EmitContext ec)
7963 bool last_check = ec.CheckState;
7964 bool last_const_check = ec.ConstantCheckState;
7966 ec.CheckState = false;
7967 ec.ConstantCheckState = false;
7969 ec.CheckState = last_check;
7970 ec.ConstantCheckState = last_const_check;
7976 /// An Element Access expression.
7978 /// During semantic analysis these are transformed into
7979 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7981 public class ElementAccess : Expression {
7982 public ArrayList Arguments;
7983 public Expression Expr;
7985 public ElementAccess (Expression e, ArrayList e_list)
7994 Arguments = new ArrayList ();
7995 foreach (Expression tmp in e_list)
7996 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
8000 bool CommonResolve (EmitContext ec)
8002 Expr = Expr.Resolve (ec);
8007 if (Arguments == null)
8010 foreach (Argument a in Arguments){
8011 if (!a.Resolve (ec, loc))
8018 Expression MakePointerAccess (EmitContext ec, Type t)
8020 if (t == TypeManager.void_ptr_type){
8021 Error (242, "The array index operation is not valid on void pointers");
8024 if (Arguments.Count != 1){
8025 Error (196, "A pointer must be indexed by only one value");
8030 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
8033 return new Indirection (p, loc).Resolve (ec);
8036 public override Expression DoResolve (EmitContext ec)
8038 if (!CommonResolve (ec))
8042 // We perform some simple tests, and then to "split" the emit and store
8043 // code we create an instance of a different class, and return that.
8045 // I am experimenting with this pattern.
8049 if (t == TypeManager.array_type){
8050 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
8055 return (new ArrayAccess (this, loc)).Resolve (ec);
8057 return MakePointerAccess (ec, Expr.Type);
8059 FieldExpr fe = Expr as FieldExpr;
8061 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
8063 return MakePointerAccess (ec, ff.ElementType);
8066 return (new IndexerAccess (this, loc)).Resolve (ec);
8069 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8071 if (!CommonResolve (ec))
8076 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
8079 return MakePointerAccess (ec, Expr.Type);
8081 FieldExpr fe = Expr as FieldExpr;
8083 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
8085 if (!(fe.InstanceExpression is LocalVariableReference) &&
8086 !(fe.InstanceExpression is This)) {
8087 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
8090 // TODO: not sure whether it is correct
8091 // if (!ec.InFixedInitializer) {
8092 // Error (1666, "You cannot use fixed sized buffers contained in unfixed expressions. Try using the fixed statement");
8095 return MakePointerAccess (ec, ff.ElementType);
8098 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
8101 public override void Emit (EmitContext ec)
8103 throw new Exception ("Should never be reached");
8108 /// Implements array access
8110 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
8112 // Points to our "data" repository
8116 LocalTemporary temp;
8119 public ArrayAccess (ElementAccess ea_data, Location l)
8122 eclass = ExprClass.Variable;
8126 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8128 return DoResolve (ec);
8131 public override Expression DoResolve (EmitContext ec)
8134 ExprClass eclass = ea.Expr.eclass;
8136 // As long as the type is valid
8137 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
8138 eclass == ExprClass.Value)) {
8139 ea.Expr.Error_UnexpectedKind ("variable or value");
8144 Type t = ea.Expr.Type;
8145 if (t.GetArrayRank () != ea.Arguments.Count){
8146 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
8147 ea.Arguments.Count, t.GetArrayRank ());
8151 type = TypeManager.GetElementType (t);
8152 if (type.IsPointer && !ec.InUnsafe){
8153 UnsafeError (ea.Location);
8157 foreach (Argument a in ea.Arguments){
8158 Type argtype = a.Type;
8160 if (argtype == TypeManager.int32_type ||
8161 argtype == TypeManager.uint32_type ||
8162 argtype == TypeManager.int64_type ||
8163 argtype == TypeManager.uint64_type) {
8164 Constant c = a.Expr as Constant;
8165 if (c != null && c.IsNegative) {
8166 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
8172 // Mhm. This is strage, because the Argument.Type is not the same as
8173 // Argument.Expr.Type: the value changes depending on the ref/out setting.
8175 // Wonder if I will run into trouble for this.
8177 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
8182 eclass = ExprClass.Variable;
8188 /// Emits the right opcode to load an object of Type `t'
8189 /// from an array of T
8191 static public void EmitLoadOpcode (ILGenerator ig, Type type)
8193 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8194 ig.Emit (OpCodes.Ldelem_U1);
8195 else if (type == TypeManager.sbyte_type)
8196 ig.Emit (OpCodes.Ldelem_I1);
8197 else if (type == TypeManager.short_type)
8198 ig.Emit (OpCodes.Ldelem_I2);
8199 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8200 ig.Emit (OpCodes.Ldelem_U2);
8201 else if (type == TypeManager.int32_type)
8202 ig.Emit (OpCodes.Ldelem_I4);
8203 else if (type == TypeManager.uint32_type)
8204 ig.Emit (OpCodes.Ldelem_U4);
8205 else if (type == TypeManager.uint64_type)
8206 ig.Emit (OpCodes.Ldelem_I8);
8207 else if (type == TypeManager.int64_type)
8208 ig.Emit (OpCodes.Ldelem_I8);
8209 else if (type == TypeManager.float_type)
8210 ig.Emit (OpCodes.Ldelem_R4);
8211 else if (type == TypeManager.double_type)
8212 ig.Emit (OpCodes.Ldelem_R8);
8213 else if (type == TypeManager.intptr_type)
8214 ig.Emit (OpCodes.Ldelem_I);
8215 else if (TypeManager.IsEnumType (type)){
8216 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
8217 } else if (type.IsValueType){
8218 ig.Emit (OpCodes.Ldelema, type);
8219 ig.Emit (OpCodes.Ldobj, type);
8220 } else if (type.IsGenericParameter)
8221 ig.Emit (OpCodes.Ldelem_Any, type);
8222 else if (type.IsPointer)
8223 ig.Emit (OpCodes.Ldelem_I);
8225 ig.Emit (OpCodes.Ldelem_Ref);
8229 /// Returns the right opcode to store an object of Type `t'
8230 /// from an array of T.
8232 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8234 //Console.WriteLine (new System.Diagnostics.StackTrace ());
8235 has_type_arg = false; is_stobj = false;
8236 t = TypeManager.TypeToCoreType (t);
8237 if (TypeManager.IsEnumType (t))
8238 t = TypeManager.EnumToUnderlying (t);
8239 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8240 t == TypeManager.bool_type)
8241 return OpCodes.Stelem_I1;
8242 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8243 t == TypeManager.char_type)
8244 return OpCodes.Stelem_I2;
8245 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8246 return OpCodes.Stelem_I4;
8247 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8248 return OpCodes.Stelem_I8;
8249 else if (t == TypeManager.float_type)
8250 return OpCodes.Stelem_R4;
8251 else if (t == TypeManager.double_type)
8252 return OpCodes.Stelem_R8;
8253 else if (t == TypeManager.intptr_type) {
8254 has_type_arg = true;
8256 return OpCodes.Stobj;
8257 } else if (t.IsValueType) {
8258 has_type_arg = true;
8260 return OpCodes.Stobj;
8261 } else if (t.IsGenericParameter) {
8262 has_type_arg = true;
8263 return OpCodes.Stelem_Any;
8264 } else if (t.IsPointer)
8265 return OpCodes.Stelem_I;
8267 return OpCodes.Stelem_Ref;
8270 MethodInfo FetchGetMethod ()
8272 ModuleBuilder mb = CodeGen.Module.Builder;
8273 int arg_count = ea.Arguments.Count;
8274 Type [] args = new Type [arg_count];
8277 for (int i = 0; i < arg_count; i++){
8278 //args [i++] = a.Type;
8279 args [i] = TypeManager.int32_type;
8282 get = mb.GetArrayMethod (
8283 ea.Expr.Type, "Get",
8284 CallingConventions.HasThis |
8285 CallingConventions.Standard,
8291 MethodInfo FetchAddressMethod ()
8293 ModuleBuilder mb = CodeGen.Module.Builder;
8294 int arg_count = ea.Arguments.Count;
8295 Type [] args = new Type [arg_count];
8299 ret_type = TypeManager.GetReferenceType (type);
8301 for (int i = 0; i < arg_count; i++){
8302 //args [i++] = a.Type;
8303 args [i] = TypeManager.int32_type;
8306 address = mb.GetArrayMethod (
8307 ea.Expr.Type, "Address",
8308 CallingConventions.HasThis |
8309 CallingConventions.Standard,
8316 // Load the array arguments into the stack.
8318 // If we have been requested to cache the values (cached_locations array
8319 // initialized), then load the arguments the first time and store them
8320 // in locals. otherwise load from local variables.
8322 void LoadArrayAndArguments (EmitContext ec)
8324 ILGenerator ig = ec.ig;
8327 foreach (Argument a in ea.Arguments){
8328 Type argtype = a.Expr.Type;
8332 if (argtype == TypeManager.int64_type)
8333 ig.Emit (OpCodes.Conv_Ovf_I);
8334 else if (argtype == TypeManager.uint64_type)
8335 ig.Emit (OpCodes.Conv_Ovf_I_Un);
8339 public void Emit (EmitContext ec, bool leave_copy)
8341 int rank = ea.Expr.Type.GetArrayRank ();
8342 ILGenerator ig = ec.ig;
8345 LoadArrayAndArguments (ec);
8348 EmitLoadOpcode (ig, type);
8352 method = FetchGetMethod ();
8353 ig.Emit (OpCodes.Call, method);
8356 LoadFromPtr (ec.ig, this.type);
8359 ec.ig.Emit (OpCodes.Dup);
8360 temp = new LocalTemporary (ec, this.type);
8365 public override void Emit (EmitContext ec)
8370 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8372 int rank = ea.Expr.Type.GetArrayRank ();
8373 ILGenerator ig = ec.ig;
8374 Type t = source.Type;
8375 prepared = prepare_for_load;
8377 if (prepare_for_load) {
8378 AddressOf (ec, AddressOp.LoadStore);
8379 ec.ig.Emit (OpCodes.Dup);
8382 ec.ig.Emit (OpCodes.Dup);
8383 temp = new LocalTemporary (ec, this.type);
8386 StoreFromPtr (ec.ig, t);
8394 LoadArrayAndArguments (ec);
8397 bool is_stobj, has_type_arg;
8398 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8401 // The stobj opcode used by value types will need
8402 // an address on the stack, not really an array/array
8406 ig.Emit (OpCodes.Ldelema, t);
8410 ec.ig.Emit (OpCodes.Dup);
8411 temp = new LocalTemporary (ec, this.type);
8416 ig.Emit (OpCodes.Stobj, t);
8417 else if (has_type_arg)
8422 ModuleBuilder mb = CodeGen.Module.Builder;
8423 int arg_count = ea.Arguments.Count;
8424 Type [] args = new Type [arg_count + 1];
8429 ec.ig.Emit (OpCodes.Dup);
8430 temp = new LocalTemporary (ec, this.type);
8434 for (int i = 0; i < arg_count; i++){
8435 //args [i++] = a.Type;
8436 args [i] = TypeManager.int32_type;
8439 args [arg_count] = type;
8441 set = mb.GetArrayMethod (
8442 ea.Expr.Type, "Set",
8443 CallingConventions.HasThis |
8444 CallingConventions.Standard,
8445 TypeManager.void_type, args);
8447 ig.Emit (OpCodes.Call, set);
8454 public void AddressOf (EmitContext ec, AddressOp mode)
8456 int rank = ea.Expr.Type.GetArrayRank ();
8457 ILGenerator ig = ec.ig;
8459 LoadArrayAndArguments (ec);
8462 ig.Emit (OpCodes.Ldelema, type);
8464 MethodInfo address = FetchAddressMethod ();
8465 ig.Emit (OpCodes.Call, address);
8469 public void EmitGetLength (EmitContext ec, int dim)
8471 int rank = ea.Expr.Type.GetArrayRank ();
8472 ILGenerator ig = ec.ig;
8476 ig.Emit (OpCodes.Ldlen);
8477 ig.Emit (OpCodes.Conv_I4);
8479 IntLiteral.EmitInt (ig, dim);
8480 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8486 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
8487 public readonly ArrayList Properties;
8488 static Indexers empty;
8490 public struct Indexer {
8491 public readonly PropertyInfo PropertyInfo;
8492 public readonly MethodInfo Getter, Setter;
8494 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
8496 this.PropertyInfo = property_info;
8504 empty = new Indexers (null);
8507 Indexers (ArrayList array)
8512 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
8517 foreach (PropertyInfo property in mi){
8518 MethodInfo get, set;
8520 get = property.GetGetMethod (true);
8521 set = property.GetSetMethod (true);
8522 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
8524 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
8526 if (get != null || set != null) {
8528 ix = new Indexers (new ArrayList ());
8529 ix.Properties.Add (new Indexer (property, get, set));
8534 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8536 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8538 return TypeManager.MemberLookup (
8539 caller_type, caller_type, lookup_type, MemberTypes.Property,
8540 BindingFlags.Public | BindingFlags.Instance |
8541 BindingFlags.DeclaredOnly, p_name, null);
8544 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
8546 Indexers ix = empty;
8548 Type copy = lookup_type;
8549 while (copy != TypeManager.object_type && copy != null){
8550 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8551 copy = copy.BaseType;
8554 if (lookup_type.IsInterface) {
8555 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8556 if (ifaces != null) {
8557 foreach (Type itype in ifaces)
8558 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8567 /// Expressions that represent an indexer call.
8569 public class IndexerAccess : Expression, IAssignMethod {
8571 // Points to our "data" repository
8573 MethodInfo get, set;
8574 ArrayList set_arguments;
8575 bool is_base_indexer;
8577 protected Type indexer_type;
8578 protected Type current_type;
8579 protected Expression instance_expr;
8580 protected ArrayList arguments;
8582 public IndexerAccess (ElementAccess ea, Location loc)
8583 : this (ea.Expr, false, loc)
8585 this.arguments = ea.Arguments;
8588 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8591 this.instance_expr = instance_expr;
8592 this.is_base_indexer = is_base_indexer;
8593 this.eclass = ExprClass.Value;
8597 protected virtual bool CommonResolve (EmitContext ec)
8599 indexer_type = instance_expr.Type;
8600 current_type = ec.ContainerType;
8605 public override Expression DoResolve (EmitContext ec)
8607 ArrayList AllGetters = new ArrayList();
8608 if (!CommonResolve (ec))
8612 // Step 1: Query for all `Item' *properties*. Notice
8613 // that the actual methods are pointed from here.
8615 // This is a group of properties, piles of them.
8617 bool found_any = false, found_any_getters = false;
8618 Type lookup_type = indexer_type;
8620 Indexers ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8621 if (ilist.Properties != null) {
8623 foreach (Indexers.Indexer ix in ilist.Properties) {
8624 if (ix.Getter != null)
8625 AllGetters.Add (ix.Getter);
8629 if (AllGetters.Count > 0) {
8630 found_any_getters = true;
8631 get = (MethodInfo) Invocation.OverloadResolve (
8632 ec, new MethodGroupExpr (AllGetters, loc),
8633 arguments, false, loc);
8637 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8638 TypeManager.CSharpName (indexer_type));
8642 if (!found_any_getters) {
8643 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
8649 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8654 // Only base will allow this invocation to happen.
8656 if (get.IsAbstract && this is BaseIndexerAccess){
8657 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
8661 type = get.ReturnType;
8662 if (type.IsPointer && !ec.InUnsafe){
8667 instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8669 eclass = ExprClass.IndexerAccess;
8673 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8675 ArrayList AllSetters = new ArrayList();
8676 if (!CommonResolve (ec))
8679 bool found_any = false, found_any_setters = false;
8681 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8682 if (ilist.Properties != null) {
8684 foreach (Indexers.Indexer ix in ilist.Properties) {
8685 if (ix.Setter != null)
8686 AllSetters.Add (ix.Setter);
8689 if (AllSetters.Count > 0) {
8690 found_any_setters = true;
8691 set_arguments = (ArrayList) arguments.Clone ();
8692 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8693 set = (MethodInfo) Invocation.OverloadResolve (
8694 ec, new MethodGroupExpr (AllSetters, loc),
8695 set_arguments, false, loc);
8699 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8700 TypeManager.CSharpName (indexer_type));
8704 if (!found_any_setters) {
8705 Error (154, "indexer can not be used in this context, because " +
8706 "it lacks a `set' accessor");
8711 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8716 // Only base will allow this invocation to happen.
8718 if (set.IsAbstract && this is BaseIndexerAccess){
8719 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
8724 // Now look for the actual match in the list of indexers to set our "return" type
8726 type = TypeManager.void_type; // default value
8727 foreach (Indexers.Indexer ix in ilist.Properties){
8728 if (ix.Setter == set){
8729 type = ix.PropertyInfo.PropertyType;
8734 instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8736 eclass = ExprClass.IndexerAccess;
8740 bool prepared = false;
8741 LocalTemporary temp;
8743 public void Emit (EmitContext ec, bool leave_copy)
8745 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8747 ec.ig.Emit (OpCodes.Dup);
8748 temp = new LocalTemporary (ec, Type);
8754 // source is ignored, because we already have a copy of it from the
8755 // LValue resolution and we have already constructed a pre-cached
8756 // version of the arguments (ea.set_arguments);
8758 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8760 prepared = prepare_for_load;
8761 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8766 ec.ig.Emit (OpCodes.Dup);
8767 temp = new LocalTemporary (ec, Type);
8770 } else if (leave_copy) {
8771 temp = new LocalTemporary (ec, Type);
8777 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8784 public override void Emit (EmitContext ec)
8791 /// The base operator for method names
8793 public class BaseAccess : Expression {
8796 public BaseAccess (string member, Location l)
8798 this.member = member;
8802 public override Expression DoResolve (EmitContext ec)
8804 Expression c = CommonResolve (ec);
8810 // MethodGroups use this opportunity to flag an error on lacking ()
8812 if (!(c is MethodGroupExpr))
8813 return c.Resolve (ec);
8817 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8819 Expression c = CommonResolve (ec);
8825 // MethodGroups use this opportunity to flag an error on lacking ()
8827 if (! (c is MethodGroupExpr))
8828 return c.DoResolveLValue (ec, right_side);
8833 Expression CommonResolve (EmitContext ec)
8835 Expression member_lookup;
8836 Type current_type = ec.ContainerType;
8837 Type base_type = current_type.BaseType;
8840 Error (1511, "Keyword `base' is not available in a static method");
8844 if (ec.IsFieldInitializer){
8845 Error (1512, "Keyword `base' is not available in the current context");
8849 member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
8850 member, AllMemberTypes, AllBindingFlags,
8852 if (member_lookup == null) {
8853 MemberLookupFailed (ec, base_type, base_type, member, null, true, loc);
8860 left = new TypeExpression (base_type, loc);
8862 left = ec.GetThis (loc);
8864 MemberExpr me = (MemberExpr) member_lookup;
8866 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8868 if (e is PropertyExpr) {
8869 PropertyExpr pe = (PropertyExpr) e;
8874 if (e is MethodGroupExpr)
8875 ((MethodGroupExpr) e).IsBase = true;
8880 public override void Emit (EmitContext ec)
8882 throw new Exception ("Should never be called");
8887 /// The base indexer operator
8889 public class BaseIndexerAccess : IndexerAccess {
8890 public BaseIndexerAccess (ArrayList args, Location loc)
8891 : base (null, true, loc)
8893 arguments = new ArrayList ();
8894 foreach (Expression tmp in args)
8895 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8898 protected override bool CommonResolve (EmitContext ec)
8900 instance_expr = ec.GetThis (loc);
8902 current_type = ec.ContainerType.BaseType;
8903 indexer_type = current_type;
8905 foreach (Argument a in arguments){
8906 if (!a.Resolve (ec, loc))
8915 /// This class exists solely to pass the Type around and to be a dummy
8916 /// that can be passed to the conversion functions (this is used by
8917 /// foreach implementation to typecast the object return value from
8918 /// get_Current into the proper type. All code has been generated and
8919 /// we only care about the side effect conversions to be performed
8921 /// This is also now used as a placeholder where a no-action expression
8922 /// is needed (the `New' class).
8924 public class EmptyExpression : Expression {
8925 public static readonly EmptyExpression Null = new EmptyExpression ();
8927 static EmptyExpression temp = new EmptyExpression ();
8928 public static EmptyExpression Grab ()
8931 throw new InternalErrorException ("Nested Grab");
8932 EmptyExpression retval = temp;
8937 public static void Release (EmptyExpression e)
8940 throw new InternalErrorException ("Already released");
8944 // TODO: should be protected
8945 public EmptyExpression ()
8947 type = TypeManager.object_type;
8948 eclass = ExprClass.Value;
8949 loc = Location.Null;
8952 public EmptyExpression (Type t)
8955 eclass = ExprClass.Value;
8956 loc = Location.Null;
8959 public override Expression DoResolve (EmitContext ec)
8964 public override void Emit (EmitContext ec)
8966 // nothing, as we only exist to not do anything.
8970 // This is just because we might want to reuse this bad boy
8971 // instead of creating gazillions of EmptyExpressions.
8972 // (CanImplicitConversion uses it)
8974 public void SetType (Type t)
8980 public class UserCast : Expression {
8984 public UserCast (MethodInfo method, Expression source, Location l)
8986 this.method = method;
8987 this.source = source;
8988 type = method.ReturnType;
8989 eclass = ExprClass.Value;
8993 public Expression Source {
8999 public override Expression DoResolve (EmitContext ec)
9002 // We are born fully resolved
9007 public override void Emit (EmitContext ec)
9009 ILGenerator ig = ec.ig;
9013 if (method is MethodInfo)
9014 ig.Emit (OpCodes.Call, (MethodInfo) method);
9016 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
9022 // This class is used to "construct" the type during a typecast
9023 // operation. Since the Type.GetType class in .NET can parse
9024 // the type specification, we just use this to construct the type
9025 // one bit at a time.
9027 public class ComposedCast : TypeExpr {
9031 public ComposedCast (Expression left, string dim)
9032 : this (left, dim, left.Location)
9036 public ComposedCast (Expression left, string dim, Location l)
9043 public Expression RemoveNullable ()
9045 if (dim.EndsWith ("?")) {
9046 dim = dim.Substring (0, dim.Length - 1);
9054 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
9056 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec);
9060 bool old = ec.TestObsoleteMethodUsage;
9061 ec.TestObsoleteMethodUsage = true;
9062 Type ltype = lexpr.ResolveType (ec);
9063 ec.TestObsoleteMethodUsage = old;
9065 if ((ltype == TypeManager.void_type) && (dim != "*")) {
9066 Report.Error (1547, Location,
9067 "Keyword 'void' cannot be used in this context");
9071 if ((dim.Length > 0) && (dim [0] == '?')) {
9072 TypeExpr nullable = new NullableType (left, loc);
9074 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
9075 return nullable.ResolveAsTypeTerminal (ec);
9078 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc)) {
9083 type = TypeManager.GetConstructedType (ltype, dim);
9088 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9091 if (!ec.InUnsafe && type.IsPointer){
9096 if (type.IsArray && (type.GetElementType () == TypeManager.arg_iterator_type ||
9097 type.GetElementType () == TypeManager.typed_reference_type)) {
9098 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (type.GetElementType ()));
9102 eclass = ExprClass.Type;
9106 public override string Name {
9112 public override string FullName {
9114 return type.FullName;
9119 public class FixedBufferPtr: Expression {
9122 public FixedBufferPtr (Expression array, Type array_type, Location l)
9127 type = TypeManager.GetPointerType (array_type);
9128 eclass = ExprClass.Value;
9131 public override void Emit(EmitContext ec)
9136 public override Expression DoResolve (EmitContext ec)
9139 // We are born fully resolved
9147 // This class is used to represent the address of an array, used
9148 // only by the Fixed statement, this generates "&a [0]" construct
9149 // for fixed (char *pa = a)
9151 public class ArrayPtr : FixedBufferPtr {
9154 public ArrayPtr (Expression array, Type array_type, Location l):
9155 base (array, array_type, l)
9157 this.array_type = array_type;
9160 public override void Emit (EmitContext ec)
9164 ILGenerator ig = ec.ig;
9165 IntLiteral.EmitInt (ig, 0);
9166 ig.Emit (OpCodes.Ldelema, array_type);
9171 // Used by the fixed statement
9173 public class StringPtr : Expression {
9176 public StringPtr (LocalBuilder b, Location l)
9179 eclass = ExprClass.Value;
9180 type = TypeManager.char_ptr_type;
9184 public override Expression DoResolve (EmitContext ec)
9186 // This should never be invoked, we are born in fully
9187 // initialized state.
9192 public override void Emit (EmitContext ec)
9194 ILGenerator ig = ec.ig;
9196 ig.Emit (OpCodes.Ldloc, b);
9197 ig.Emit (OpCodes.Conv_I);
9198 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
9199 ig.Emit (OpCodes.Add);
9204 // Implements the `stackalloc' keyword
9206 public class StackAlloc : Expression {
9211 public StackAlloc (Expression type, Expression count, Location l)
9218 public override Expression DoResolve (EmitContext ec)
9220 count = count.Resolve (ec);
9224 if (count.Type != TypeManager.int32_type){
9225 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9230 Constant c = count as Constant;
9231 if (c != null && c.IsNegative) {
9232 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9236 if (ec.InCatch || ec.InFinally) {
9237 Error (255, "Cannot use stackalloc in finally or catch");
9241 TypeExpr texpr = t.ResolveAsTypeTerminal (ec);
9245 otype = texpr.ResolveType (ec);
9247 if (!TypeManager.VerifyUnManaged (otype, loc))
9250 type = TypeManager.GetPointerType (otype);
9251 eclass = ExprClass.Value;
9256 public override void Emit (EmitContext ec)
9258 int size = GetTypeSize (otype);
9259 ILGenerator ig = ec.ig;
9262 ig.Emit (OpCodes.Sizeof, otype);
9264 IntConstant.EmitInt (ig, size);
9266 ig.Emit (OpCodes.Mul);
9267 ig.Emit (OpCodes.Localloc);