2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, 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);
51 ec.ig.Emit (OpCodes.Call, mi);
55 static public Expression 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 (ec, (MethodGroupExpr) mg, args, loc);
74 return new StaticCallExpr ((MethodInfo) method, args, loc);
77 public override void EmitStatement (EmitContext ec)
80 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
81 ec.ig.Emit (OpCodes.Pop);
86 /// Unary expressions.
90 /// Unary implements unary expressions. It derives from
91 /// ExpressionStatement becuase the pre/post increment/decrement
92 /// operators can be used in a statement context.
94 public class Unary : Expression {
95 public enum Operator : byte {
96 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
97 Indirection, AddressOf, TOP
100 public Operator Oper;
101 public Expression Expr;
103 public Unary (Operator op, Expression expr, Location loc)
111 /// Returns a stringified representation of the Operator
113 static public string OperName (Operator oper)
116 case Operator.UnaryPlus:
118 case Operator.UnaryNegation:
120 case Operator.LogicalNot:
122 case Operator.OnesComplement:
124 case Operator.AddressOf:
126 case Operator.Indirection:
130 return oper.ToString ();
133 public static readonly string [] oper_names;
137 oper_names = new string [(int)Operator.TOP];
139 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
140 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
141 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
142 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
143 oper_names [(int) Operator.Indirection] = "op_Indirection";
144 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
147 void Error23 (Type t)
150 23, "Operator " + OperName (Oper) +
151 " cannot be applied to operand of type `" +
152 TypeManager.CSharpName (t) + "'");
156 /// The result has been already resolved:
158 /// FIXME: a minus constant -128 sbyte cant be turned into a
161 static Expression TryReduceNegative (Constant expr)
165 if (expr is IntConstant)
166 e = new IntConstant (-((IntConstant) expr).Value);
167 else if (expr is UIntConstant){
168 uint value = ((UIntConstant) expr).Value;
170 if (value < 2147483649)
171 return new IntConstant (-(int)value);
173 e = new LongConstant (-value);
175 else if (expr is LongConstant)
176 e = new LongConstant (-((LongConstant) expr).Value);
177 else if (expr is ULongConstant){
178 ulong value = ((ULongConstant) expr).Value;
180 if (value < 9223372036854775809)
181 return new LongConstant(-(long)value);
183 else if (expr is FloatConstant)
184 e = new FloatConstant (-((FloatConstant) expr).Value);
185 else if (expr is DoubleConstant)
186 e = new DoubleConstant (-((DoubleConstant) expr).Value);
187 else if (expr is DecimalConstant)
188 e = new DecimalConstant (-((DecimalConstant) expr).Value);
189 else if (expr is ShortConstant)
190 e = new IntConstant (-((ShortConstant) expr).Value);
191 else if (expr is UShortConstant)
192 e = new IntConstant (-((UShortConstant) expr).Value);
197 // This routine will attempt to simplify the unary expression when the
198 // argument is a constant. The result is returned in `result' and the
199 // function returns true or false depending on whether a reduction
200 // was performed or not
202 bool Reduce (EmitContext ec, Constant e, out Expression result)
204 Type expr_type = e.Type;
207 case Operator.UnaryPlus:
211 case Operator.UnaryNegation:
212 result = TryReduceNegative (e);
215 case Operator.LogicalNot:
216 if (expr_type != TypeManager.bool_type) {
222 BoolConstant b = (BoolConstant) e;
223 result = new BoolConstant (!(b.Value));
226 case Operator.OnesComplement:
227 if (!((expr_type == TypeManager.int32_type) ||
228 (expr_type == TypeManager.uint32_type) ||
229 (expr_type == TypeManager.int64_type) ||
230 (expr_type == TypeManager.uint64_type) ||
231 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
234 if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
235 result = new Cast (new TypeExpr (TypeManager.int32_type, loc), e, loc);
236 result = result.Resolve (ec);
237 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
238 result = new Cast (new TypeExpr (TypeManager.uint32_type, loc), e, loc);
239 result = result.Resolve (ec);
240 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
241 result = new Cast (new TypeExpr (TypeManager.int64_type, loc), e, loc);
242 result = result.Resolve (ec);
243 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
244 result = new Cast (new TypeExpr (TypeManager.uint64_type, loc), e, loc);
245 result = result.Resolve (ec);
248 if (result == null || !(result is Constant)){
254 expr_type = result.Type;
255 e = (Constant) result;
258 if (e is EnumConstant){
259 EnumConstant enum_constant = (EnumConstant) e;
262 if (Reduce (ec, enum_constant.Child, out reduced)){
263 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
271 if (expr_type == TypeManager.int32_type){
272 result = new IntConstant (~ ((IntConstant) e).Value);
273 } else if (expr_type == TypeManager.uint32_type){
274 result = new UIntConstant (~ ((UIntConstant) e).Value);
275 } else if (expr_type == TypeManager.int64_type){
276 result = new LongConstant (~ ((LongConstant) e).Value);
277 } else if (expr_type == TypeManager.uint64_type){
278 result = new ULongConstant (~ ((ULongConstant) e).Value);
286 case Operator.AddressOf:
290 case Operator.Indirection:
294 throw new Exception ("Can not constant fold: " + Oper.ToString());
297 Expression ResolveOperator (EmitContext ec)
299 Type expr_type = Expr.Type;
302 // Step 1: Perform Operator Overload location
307 op_name = oper_names [(int) Oper];
309 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
312 Expression e = StaticCallExpr.MakeSimpleCall (
313 ec, (MethodGroupExpr) mg, Expr, loc);
323 // Only perform numeric promotions on:
326 if (expr_type == null)
330 // Step 2: Default operations on CLI native types.
333 // Attempt to use a constant folding operation.
334 if (Expr is Constant){
337 if (Reduce (ec, (Constant) Expr, out result))
342 case Operator.LogicalNot:
343 if (expr_type != TypeManager.bool_type) {
344 Expr = ResolveBoolean (ec, Expr, loc);
351 type = TypeManager.bool_type;
354 case Operator.OnesComplement:
355 if (!((expr_type == TypeManager.int32_type) ||
356 (expr_type == TypeManager.uint32_type) ||
357 (expr_type == TypeManager.int64_type) ||
358 (expr_type == TypeManager.uint64_type) ||
359 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
362 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
364 type = TypeManager.int32_type;
367 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
369 type = TypeManager.uint32_type;
372 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
374 type = TypeManager.int64_type;
377 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
379 type = TypeManager.uint64_type;
388 case Operator.AddressOf:
389 if (Expr.eclass != ExprClass.Variable){
390 Error (211, "Cannot take the address of non-variables");
399 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
403 type = TypeManager.GetPointerType (Expr.Type);
406 case Operator.Indirection:
412 if (!expr_type.IsPointer){
413 Error (193, "The * or -> operator can only be applied to pointers");
418 // We create an Indirection expression, because
419 // it can implement the IMemoryLocation.
421 return new Indirection (Expr, loc);
423 case Operator.UnaryPlus:
425 // A plus in front of something is just a no-op, so return the child.
429 case Operator.UnaryNegation:
431 // Deals with -literals
432 // int operator- (int x)
433 // long operator- (long x)
434 // float operator- (float f)
435 // double operator- (double d)
436 // decimal operator- (decimal d)
438 Expression expr = null;
441 // transform - - expr into expr
444 Unary unary = (Unary) Expr;
446 if (unary.Oper == Operator.UnaryNegation)
451 // perform numeric promotions to int,
455 // The following is inneficient, because we call
456 // ImplicitConversion too many times.
458 // It is also not clear if we should convert to Float
459 // or Double initially.
461 if (expr_type == TypeManager.uint32_type){
463 // FIXME: handle exception to this rule that
464 // permits the int value -2147483648 (-2^31) to
465 // bt wrote as a decimal interger literal
467 type = TypeManager.int64_type;
468 Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
472 if (expr_type == TypeManager.uint64_type){
474 // FIXME: Handle exception of `long value'
475 // -92233720368547758087 (-2^63) to be wrote as
476 // decimal integer literal.
482 if (expr_type == TypeManager.float_type){
487 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
494 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
501 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
512 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
513 TypeManager.CSharpName (expr_type) + "'");
517 public override Expression DoResolve (EmitContext ec)
519 if (Oper == Operator.AddressOf)
520 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
522 Expr = Expr.Resolve (ec);
527 eclass = ExprClass.Value;
528 return ResolveOperator (ec);
531 public override void Emit (EmitContext ec)
533 ILGenerator ig = ec.ig;
534 Type expr_type = Expr.Type;
537 case Operator.UnaryPlus:
538 throw new Exception ("This should be caught by Resolve");
540 case Operator.UnaryNegation:
542 ig.Emit (OpCodes.Neg);
545 case Operator.LogicalNot:
547 ig.Emit (OpCodes.Ldc_I4_0);
548 ig.Emit (OpCodes.Ceq);
551 case Operator.OnesComplement:
553 ig.Emit (OpCodes.Not);
556 case Operator.AddressOf:
557 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
561 throw new Exception ("This should not happen: Operator = "
567 /// This will emit the child expression for `ec' avoiding the logical
568 /// not. The parent will take care of changing brfalse/brtrue
570 public void EmitLogicalNot (EmitContext ec)
572 if (Oper != Operator.LogicalNot)
573 throw new Exception ("EmitLogicalNot can only be called with !expr");
578 public override string ToString ()
580 return "Unary (" + Oper + ", " + Expr + ")";
586 // Unary operators are turned into Indirection expressions
587 // after semantic analysis (this is so we can take the address
588 // of an indirection).
590 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
592 LocalTemporary temporary;
595 public Indirection (Expression expr, Location l)
598 this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
599 eclass = ExprClass.Variable;
603 void LoadExprValue (EmitContext ec)
607 public override void Emit (EmitContext ec)
609 ILGenerator ig = ec.ig;
611 if (temporary != null){
617 ec.ig.Emit (OpCodes.Dup);
618 temporary.Store (ec);
619 have_temporary = true;
623 LoadFromPtr (ig, Type);
626 public void EmitAssign (EmitContext ec, Expression source)
628 if (temporary != null){
633 ec.ig.Emit (OpCodes.Dup);
634 temporary.Store (ec);
635 have_temporary = true;
641 StoreFromPtr (ec.ig, type);
644 public void AddressOf (EmitContext ec, AddressOp Mode)
646 if (temporary != null){
652 ec.ig.Emit (OpCodes.Dup);
653 temporary.Store (ec);
654 have_temporary = true;
659 public override Expression DoResolve (EmitContext ec)
662 // Born fully resolved
667 public new void CacheTemporaries (EmitContext ec)
669 temporary = new LocalTemporary (ec, type);
672 public override string ToString ()
674 return "*(" + expr + ")";
679 /// Unary Mutator expressions (pre and post ++ and --)
683 /// UnaryMutator implements ++ and -- expressions. It derives from
684 /// ExpressionStatement becuase the pre/post increment/decrement
685 /// operators can be used in a statement context.
687 /// FIXME: Idea, we could split this up in two classes, one simpler
688 /// for the common case, and one with the extra fields for more complex
689 /// classes (indexers require temporary access; overloaded require method)
692 public class UnaryMutator : ExpressionStatement {
694 public enum Mode : byte {
701 PreDecrement = IsDecrement,
702 PostIncrement = IsPost,
703 PostDecrement = IsPost | IsDecrement
708 LocalTemporary temp_storage;
711 // This is expensive for the simplest case.
715 public UnaryMutator (Mode m, Expression e, Location l)
722 static string OperName (Mode mode)
724 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
728 void Error23 (Type t)
731 23, "Operator " + OperName (mode) +
732 " cannot be applied to operand of type `" +
733 TypeManager.CSharpName (t) + "'");
737 /// Returns whether an object of type `t' can be incremented
738 /// or decremented with add/sub (ie, basically whether we can
739 /// use pre-post incr-decr operations on it, but it is not a
740 /// System.Decimal, which we require operator overloading to catch)
742 static bool IsIncrementableNumber (Type t)
744 return (t == TypeManager.sbyte_type) ||
745 (t == TypeManager.byte_type) ||
746 (t == TypeManager.short_type) ||
747 (t == TypeManager.ushort_type) ||
748 (t == TypeManager.int32_type) ||
749 (t == TypeManager.uint32_type) ||
750 (t == TypeManager.int64_type) ||
751 (t == TypeManager.uint64_type) ||
752 (t == TypeManager.char_type) ||
753 (t.IsSubclassOf (TypeManager.enum_type)) ||
754 (t == TypeManager.float_type) ||
755 (t == TypeManager.double_type) ||
756 (t.IsPointer && t != TypeManager.void_ptr_type);
759 Expression ResolveOperator (EmitContext ec)
761 Type expr_type = expr.Type;
764 // Step 1: Perform Operator Overload location
769 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
770 op_name = "op_Increment";
772 op_name = "op_Decrement";
774 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
776 if (mg == null && expr_type.BaseType != null)
777 mg = MemberLookup (ec, expr_type.BaseType, op_name,
778 MemberTypes.Method, AllBindingFlags, loc);
781 method = StaticCallExpr.MakeSimpleCall (
782 ec, (MethodGroupExpr) mg, expr, loc);
789 // The operand of the prefix/postfix increment decrement operators
790 // should be an expression that is classified as a variable,
791 // a property access or an indexer access
794 if (expr.eclass == ExprClass.Variable){
795 if (IsIncrementableNumber (expr_type) ||
796 expr_type == TypeManager.decimal_type){
799 } else if (expr.eclass == ExprClass.IndexerAccess){
800 IndexerAccess ia = (IndexerAccess) expr;
802 temp_storage = new LocalTemporary (ec, expr.Type);
804 expr = ia.ResolveLValue (ec, temp_storage);
809 } else if (expr.eclass == ExprClass.PropertyAccess){
810 PropertyExpr pe = (PropertyExpr) expr;
812 if (pe.VerifyAssignable ())
817 expr.Error_UnexpectedKind ("variable, indexer or property access");
821 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
822 TypeManager.CSharpName (expr_type) + "'");
826 public override Expression DoResolve (EmitContext ec)
828 expr = expr.Resolve (ec);
833 eclass = ExprClass.Value;
834 return ResolveOperator (ec);
837 static int PtrTypeSize (Type t)
839 return GetTypeSize (t.GetElementType ());
843 // Loads the proper "1" into the stack based on the type, then it emits the
844 // opcode for the operation requested
846 void LoadOneAndEmitOp (EmitContext ec, Type t)
849 // Measure if getting the typecode and using that is more/less efficient
850 // that comparing types. t.GetTypeCode() is an internal call.
852 ILGenerator ig = ec.ig;
854 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
855 LongConstant.EmitLong (ig, 1);
856 else if (t == TypeManager.double_type)
857 ig.Emit (OpCodes.Ldc_R8, 1.0);
858 else if (t == TypeManager.float_type)
859 ig.Emit (OpCodes.Ldc_R4, 1.0F);
860 else if (t.IsPointer){
861 int n = PtrTypeSize (t);
864 ig.Emit (OpCodes.Sizeof, t);
866 IntConstant.EmitInt (ig, n);
868 ig.Emit (OpCodes.Ldc_I4_1);
871 // Now emit the operation
874 if (t == TypeManager.int32_type ||
875 t == TypeManager.int64_type){
876 if ((mode & Mode.IsDecrement) != 0)
877 ig.Emit (OpCodes.Sub_Ovf);
879 ig.Emit (OpCodes.Add_Ovf);
880 } else if (t == TypeManager.uint32_type ||
881 t == TypeManager.uint64_type){
882 if ((mode & Mode.IsDecrement) != 0)
883 ig.Emit (OpCodes.Sub_Ovf_Un);
885 ig.Emit (OpCodes.Add_Ovf_Un);
887 if ((mode & Mode.IsDecrement) != 0)
888 ig.Emit (OpCodes.Sub_Ovf);
890 ig.Emit (OpCodes.Add_Ovf);
893 if ((mode & Mode.IsDecrement) != 0)
894 ig.Emit (OpCodes.Sub);
896 ig.Emit (OpCodes.Add);
899 if (t == TypeManager.sbyte_type){
901 ig.Emit (OpCodes.Conv_Ovf_I1);
903 ig.Emit (OpCodes.Conv_I1);
904 } else if (t == TypeManager.byte_type){
906 ig.Emit (OpCodes.Conv_Ovf_U1);
908 ig.Emit (OpCodes.Conv_U1);
909 } else if (t == TypeManager.short_type){
911 ig.Emit (OpCodes.Conv_Ovf_I2);
913 ig.Emit (OpCodes.Conv_I2);
914 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
916 ig.Emit (OpCodes.Conv_Ovf_U2);
918 ig.Emit (OpCodes.Conv_U2);
923 static EmptyExpression empty_expr;
925 void EmitCode (EmitContext ec, bool is_expr)
927 ILGenerator ig = ec.ig;
928 IAssignMethod ia = (IAssignMethod) expr;
929 Type expr_type = expr.Type;
931 ia.CacheTemporaries (ec);
933 if (temp_storage == null){
935 // Temporary improvement: if we are dealing with something that does
936 // not require complicated instance setup, avoid using a temporary
938 // For now: only localvariables when not remapped
941 if (method == null &&
942 (expr is LocalVariableReference && ec.RemapToProxy == false) ||
943 (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){
944 if (empty_expr == null)
945 empty_expr = new EmptyExpression ();
948 case Mode.PreIncrement:
949 case Mode.PreDecrement:
952 LoadOneAndEmitOp (ec, expr_type);
954 ig.Emit (OpCodes.Dup);
955 ia.EmitAssign (ec, empty_expr);
958 case Mode.PostIncrement:
959 case Mode.PostDecrement:
962 ig.Emit (OpCodes.Dup);
964 LoadOneAndEmitOp (ec, expr_type);
965 ia.EmitAssign (ec, empty_expr);
970 temp_storage = new LocalTemporary (ec, expr_type);
974 case Mode.PreIncrement:
975 case Mode.PreDecrement:
979 LoadOneAndEmitOp (ec, expr_type);
983 temp_storage.Store (ec);
984 ia.EmitAssign (ec, temp_storage);
986 temp_storage.Emit (ec);
989 case Mode.PostIncrement:
990 case Mode.PostDecrement:
998 ig.Emit (OpCodes.Dup);
1000 LoadOneAndEmitOp (ec, expr_type);
1005 temp_storage.Store (ec);
1006 ia.EmitAssign (ec, temp_storage);
1011 public override void Emit (EmitContext ec)
1013 EmitCode (ec, true);
1017 public override void EmitStatement (EmitContext ec)
1019 EmitCode (ec, false);
1025 /// Base class for the `Is' and `As' classes.
1029 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1032 public abstract class Probe : Expression {
1033 public readonly Expression ProbeType;
1034 protected Expression expr;
1035 protected Type probe_type;
1037 public Probe (Expression expr, Expression probe_type, Location l)
1039 ProbeType = probe_type;
1044 public Expression Expr {
1050 public override Expression DoResolve (EmitContext ec)
1052 probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1054 if (probe_type == null)
1057 expr = expr.Resolve (ec);
1064 /// Implementation of the `is' operator.
1066 public class Is : Probe {
1067 public Is (Expression expr, Expression probe_type, Location l)
1068 : base (expr, probe_type, l)
1073 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1078 public override void Emit (EmitContext ec)
1080 ILGenerator ig = ec.ig;
1085 case Action.AlwaysFalse:
1086 ig.Emit (OpCodes.Pop);
1087 IntConstant.EmitInt (ig, 0);
1089 case Action.AlwaysTrue:
1090 ig.Emit (OpCodes.Pop);
1091 IntConstant.EmitInt (ig, 1);
1093 case Action.LeaveOnStack:
1094 // the `e != null' rule.
1095 ig.Emit (OpCodes.Ldnull);
1096 ig.Emit (OpCodes.Ceq);
1097 ig.Emit (OpCodes.Ldc_I4_0);
1098 ig.Emit (OpCodes.Ceq);
1101 ig.Emit (OpCodes.Isinst, probe_type);
1102 ig.Emit (OpCodes.Ldnull);
1103 ig.Emit (OpCodes.Cgt_Un);
1106 throw new Exception ("never reached");
1109 public override Expression DoResolve (EmitContext ec)
1111 Expression e = base.DoResolve (ec);
1113 if ((e == null) || (expr == null))
1116 Type etype = expr.Type;
1117 bool warning_always_matches = false;
1118 bool warning_never_matches = false;
1120 type = TypeManager.bool_type;
1121 eclass = ExprClass.Value;
1124 // First case, if at compile time, there is an implicit conversion
1125 // then e != null (objects) or true (value types)
1127 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1130 if (etype.IsValueType)
1131 action = Action.AlwaysTrue;
1133 action = Action.LeaveOnStack;
1135 warning_always_matches = true;
1136 } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1138 // Second case: explicit reference convresion
1140 if (expr is NullLiteral)
1141 action = Action.AlwaysFalse;
1143 action = Action.Probe;
1145 action = Action.AlwaysFalse;
1146 warning_never_matches = true;
1149 if (RootContext.WarningLevel >= 1){
1150 if (warning_always_matches)
1151 Warning (183, "The expression is always of type `" +
1152 TypeManager.CSharpName (probe_type) + "'");
1153 else if (warning_never_matches){
1154 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1156 "The expression is never of type `" +
1157 TypeManager.CSharpName (probe_type) + "'");
1166 /// Implementation of the `as' operator.
1168 public class As : Probe {
1169 public As (Expression expr, Expression probe_type, Location l)
1170 : base (expr, probe_type, l)
1174 bool do_isinst = false;
1176 public override void Emit (EmitContext ec)
1178 ILGenerator ig = ec.ig;
1183 ig.Emit (OpCodes.Isinst, probe_type);
1186 static void Error_CannotConvertType (Type source, Type target, Location loc)
1189 39, loc, "as operator can not convert from `" +
1190 TypeManager.CSharpName (source) + "' to `" +
1191 TypeManager.CSharpName (target) + "'");
1194 public override Expression DoResolve (EmitContext ec)
1196 Expression e = base.DoResolve (ec);
1202 eclass = ExprClass.Value;
1203 Type etype = expr.Type;
1205 if (TypeManager.IsValueType (probe_type)){
1206 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1207 TypeManager.CSharpName (probe_type) + " is a value type");
1212 e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
1219 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1224 Error_CannotConvertType (etype, probe_type, loc);
1230 /// This represents a typecast in the source language.
1232 /// FIXME: Cast expressions have an unusual set of parsing
1233 /// rules, we need to figure those out.
1235 public class Cast : Expression {
1236 Expression target_type;
1239 public Cast (Expression cast_type, Expression expr, Location loc)
1241 this.target_type = cast_type;
1246 public Expression TargetType {
1252 public Expression Expr {
1261 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1263 if (!ec.ConstantCheckState)
1266 if ((value < min) || (value > max)) {
1267 Error (221, "Constant value `" + value + "' cannot be converted " +
1268 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1269 "syntax to override)");
1276 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1278 if (!ec.ConstantCheckState)
1282 Error (221, "Constant value `" + value + "' cannot be converted " +
1283 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1284 "syntax to override)");
1291 bool CheckUnsigned (EmitContext ec, long value, Type type)
1293 if (!ec.ConstantCheckState)
1297 Error (221, "Constant value `" + value + "' cannot be converted " +
1298 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1299 "syntax to override)");
1307 /// Attempts to do a compile-time folding of a constant cast.
1309 Expression TryReduce (EmitContext ec, Type target_type)
1311 Expression real_expr = expr;
1312 if (real_expr is EnumConstant)
1313 real_expr = ((EnumConstant) real_expr).Child;
1315 if (real_expr is ByteConstant){
1316 byte v = ((ByteConstant) real_expr).Value;
1318 if (target_type == TypeManager.sbyte_type) {
1319 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1321 return new SByteConstant ((sbyte) v);
1323 if (target_type == TypeManager.short_type)
1324 return new ShortConstant ((short) v);
1325 if (target_type == TypeManager.ushort_type)
1326 return new UShortConstant ((ushort) v);
1327 if (target_type == TypeManager.int32_type)
1328 return new IntConstant ((int) v);
1329 if (target_type == TypeManager.uint32_type)
1330 return new UIntConstant ((uint) v);
1331 if (target_type == TypeManager.int64_type)
1332 return new LongConstant ((long) v);
1333 if (target_type == TypeManager.uint64_type)
1334 return new ULongConstant ((ulong) v);
1335 if (target_type == TypeManager.float_type)
1336 return new FloatConstant ((float) v);
1337 if (target_type == TypeManager.double_type)
1338 return new DoubleConstant ((double) v);
1339 if (target_type == TypeManager.char_type)
1340 return new CharConstant ((char) v);
1341 if (target_type == TypeManager.decimal_type)
1342 return new DecimalConstant ((decimal) v);
1344 if (real_expr is SByteConstant){
1345 sbyte v = ((SByteConstant) real_expr).Value;
1347 if (target_type == TypeManager.byte_type) {
1348 if (!CheckUnsigned (ec, v, target_type))
1350 return new ByteConstant ((byte) v);
1352 if (target_type == TypeManager.short_type)
1353 return new ShortConstant ((short) v);
1354 if (target_type == TypeManager.ushort_type) {
1355 if (!CheckUnsigned (ec, v, target_type))
1357 return new UShortConstant ((ushort) v);
1358 } if (target_type == TypeManager.int32_type)
1359 return new IntConstant ((int) v);
1360 if (target_type == TypeManager.uint32_type) {
1361 if (!CheckUnsigned (ec, v, target_type))
1363 return new UIntConstant ((uint) v);
1364 } if (target_type == TypeManager.int64_type)
1365 return new LongConstant ((long) v);
1366 if (target_type == TypeManager.uint64_type) {
1367 if (!CheckUnsigned (ec, v, target_type))
1369 return new ULongConstant ((ulong) v);
1371 if (target_type == TypeManager.float_type)
1372 return new FloatConstant ((float) v);
1373 if (target_type == TypeManager.double_type)
1374 return new DoubleConstant ((double) v);
1375 if (target_type == TypeManager.char_type) {
1376 if (!CheckUnsigned (ec, v, target_type))
1378 return new CharConstant ((char) v);
1380 if (target_type == TypeManager.decimal_type)
1381 return new DecimalConstant ((decimal) v);
1383 if (real_expr is ShortConstant){
1384 short v = ((ShortConstant) real_expr).Value;
1386 if (target_type == TypeManager.byte_type) {
1387 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1389 return new ByteConstant ((byte) v);
1391 if (target_type == TypeManager.sbyte_type) {
1392 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1394 return new SByteConstant ((sbyte) v);
1396 if (target_type == TypeManager.ushort_type) {
1397 if (!CheckUnsigned (ec, v, target_type))
1399 return new UShortConstant ((ushort) v);
1401 if (target_type == TypeManager.int32_type)
1402 return new IntConstant ((int) v);
1403 if (target_type == TypeManager.uint32_type) {
1404 if (!CheckUnsigned (ec, v, target_type))
1406 return new UIntConstant ((uint) v);
1408 if (target_type == TypeManager.int64_type)
1409 return new LongConstant ((long) v);
1410 if (target_type == TypeManager.uint64_type) {
1411 if (!CheckUnsigned (ec, v, target_type))
1413 return new ULongConstant ((ulong) v);
1415 if (target_type == TypeManager.float_type)
1416 return new FloatConstant ((float) v);
1417 if (target_type == TypeManager.double_type)
1418 return new DoubleConstant ((double) v);
1419 if (target_type == TypeManager.char_type) {
1420 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1422 return new CharConstant ((char) v);
1424 if (target_type == TypeManager.decimal_type)
1425 return new DecimalConstant ((decimal) v);
1427 if (real_expr is UShortConstant){
1428 ushort v = ((UShortConstant) real_expr).Value;
1430 if (target_type == TypeManager.byte_type) {
1431 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1433 return new ByteConstant ((byte) v);
1435 if (target_type == TypeManager.sbyte_type) {
1436 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1438 return new SByteConstant ((sbyte) v);
1440 if (target_type == TypeManager.short_type) {
1441 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1443 return new ShortConstant ((short) v);
1445 if (target_type == TypeManager.int32_type)
1446 return new IntConstant ((int) v);
1447 if (target_type == TypeManager.uint32_type)
1448 return new UIntConstant ((uint) v);
1449 if (target_type == TypeManager.int64_type)
1450 return new LongConstant ((long) v);
1451 if (target_type == TypeManager.uint64_type)
1452 return new ULongConstant ((ulong) v);
1453 if (target_type == TypeManager.float_type)
1454 return new FloatConstant ((float) v);
1455 if (target_type == TypeManager.double_type)
1456 return new DoubleConstant ((double) v);
1457 if (target_type == TypeManager.char_type) {
1458 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1460 return new CharConstant ((char) v);
1462 if (target_type == TypeManager.decimal_type)
1463 return new DecimalConstant ((decimal) v);
1465 if (real_expr is IntConstant){
1466 int v = ((IntConstant) real_expr).Value;
1468 if (target_type == TypeManager.byte_type) {
1469 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1471 return new ByteConstant ((byte) v);
1473 if (target_type == TypeManager.sbyte_type) {
1474 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1476 return new SByteConstant ((sbyte) v);
1478 if (target_type == TypeManager.short_type) {
1479 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1481 return new ShortConstant ((short) v);
1483 if (target_type == TypeManager.ushort_type) {
1484 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1486 return new UShortConstant ((ushort) v);
1488 if (target_type == TypeManager.uint32_type) {
1489 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1491 return new UIntConstant ((uint) v);
1493 if (target_type == TypeManager.int64_type)
1494 return new LongConstant ((long) v);
1495 if (target_type == TypeManager.uint64_type) {
1496 if (!CheckUnsigned (ec, v, target_type))
1498 return new ULongConstant ((ulong) v);
1500 if (target_type == TypeManager.float_type)
1501 return new FloatConstant ((float) v);
1502 if (target_type == TypeManager.double_type)
1503 return new DoubleConstant ((double) v);
1504 if (target_type == TypeManager.char_type) {
1505 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1507 return new CharConstant ((char) v);
1509 if (target_type == TypeManager.decimal_type)
1510 return new DecimalConstant ((decimal) v);
1512 if (real_expr is UIntConstant){
1513 uint v = ((UIntConstant) real_expr).Value;
1515 if (target_type == TypeManager.byte_type) {
1516 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1518 return new ByteConstant ((byte) v);
1520 if (target_type == TypeManager.sbyte_type) {
1521 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1523 return new SByteConstant ((sbyte) v);
1525 if (target_type == TypeManager.short_type) {
1526 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1528 return new ShortConstant ((short) v);
1530 if (target_type == TypeManager.ushort_type) {
1531 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1533 return new UShortConstant ((ushort) v);
1535 if (target_type == TypeManager.int32_type) {
1536 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1538 return new IntConstant ((int) v);
1540 if (target_type == TypeManager.int64_type)
1541 return new LongConstant ((long) v);
1542 if (target_type == TypeManager.uint64_type)
1543 return new ULongConstant ((ulong) v);
1544 if (target_type == TypeManager.float_type)
1545 return new FloatConstant ((float) v);
1546 if (target_type == TypeManager.double_type)
1547 return new DoubleConstant ((double) v);
1548 if (target_type == TypeManager.char_type) {
1549 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1551 return new CharConstant ((char) v);
1553 if (target_type == TypeManager.decimal_type)
1554 return new DecimalConstant ((decimal) v);
1556 if (real_expr is LongConstant){
1557 long v = ((LongConstant) real_expr).Value;
1559 if (target_type == TypeManager.byte_type) {
1560 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1562 return new ByteConstant ((byte) v);
1564 if (target_type == TypeManager.sbyte_type) {
1565 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1567 return new SByteConstant ((sbyte) v);
1569 if (target_type == TypeManager.short_type) {
1570 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1572 return new ShortConstant ((short) v);
1574 if (target_type == TypeManager.ushort_type) {
1575 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1577 return new UShortConstant ((ushort) v);
1579 if (target_type == TypeManager.int32_type) {
1580 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1582 return new IntConstant ((int) v);
1584 if (target_type == TypeManager.uint32_type) {
1585 if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1587 return new UIntConstant ((uint) v);
1589 if (target_type == TypeManager.uint64_type) {
1590 if (!CheckUnsigned (ec, v, target_type))
1592 return new ULongConstant ((ulong) v);
1594 if (target_type == TypeManager.float_type)
1595 return new FloatConstant ((float) v);
1596 if (target_type == TypeManager.double_type)
1597 return new DoubleConstant ((double) v);
1598 if (target_type == TypeManager.char_type) {
1599 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1601 return new CharConstant ((char) v);
1603 if (target_type == TypeManager.decimal_type)
1604 return new DecimalConstant ((decimal) v);
1606 if (real_expr is ULongConstant){
1607 ulong v = ((ULongConstant) real_expr).Value;
1609 if (target_type == TypeManager.byte_type) {
1610 if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1612 return new ByteConstant ((byte) v);
1614 if (target_type == TypeManager.sbyte_type) {
1615 if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1617 return new SByteConstant ((sbyte) v);
1619 if (target_type == TypeManager.short_type) {
1620 if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1622 return new ShortConstant ((short) v);
1624 if (target_type == TypeManager.ushort_type) {
1625 if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1627 return new UShortConstant ((ushort) v);
1629 if (target_type == TypeManager.int32_type) {
1630 if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1632 return new IntConstant ((int) v);
1634 if (target_type == TypeManager.uint32_type) {
1635 if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1637 return new UIntConstant ((uint) v);
1639 if (target_type == TypeManager.int64_type) {
1640 if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1642 return new LongConstant ((long) v);
1644 if (target_type == TypeManager.float_type)
1645 return new FloatConstant ((float) v);
1646 if (target_type == TypeManager.double_type)
1647 return new DoubleConstant ((double) v);
1648 if (target_type == TypeManager.char_type) {
1649 if (!CheckRange (ec, v, target_type, Char.MaxValue))
1651 return new CharConstant ((char) v);
1653 if (target_type == TypeManager.decimal_type)
1654 return new DecimalConstant ((decimal) v);
1656 if (real_expr is FloatConstant){
1657 float v = ((FloatConstant) real_expr).Value;
1659 if (target_type == TypeManager.byte_type)
1660 return new ByteConstant ((byte) v);
1661 if (target_type == TypeManager.sbyte_type)
1662 return new SByteConstant ((sbyte) v);
1663 if (target_type == TypeManager.short_type)
1664 return new ShortConstant ((short) v);
1665 if (target_type == TypeManager.ushort_type)
1666 return new UShortConstant ((ushort) v);
1667 if (target_type == TypeManager.int32_type)
1668 return new IntConstant ((int) v);
1669 if (target_type == TypeManager.uint32_type)
1670 return new UIntConstant ((uint) v);
1671 if (target_type == TypeManager.int64_type)
1672 return new LongConstant ((long) v);
1673 if (target_type == TypeManager.uint64_type)
1674 return new ULongConstant ((ulong) v);
1675 if (target_type == TypeManager.double_type)
1676 return new DoubleConstant ((double) v);
1677 if (target_type == TypeManager.char_type)
1678 return new CharConstant ((char) v);
1679 if (target_type == TypeManager.decimal_type)
1680 return new DecimalConstant ((decimal) v);
1682 if (real_expr is DoubleConstant){
1683 double v = ((DoubleConstant) real_expr).Value;
1685 if (target_type == TypeManager.byte_type)
1686 return new ByteConstant ((byte) v);
1687 if (target_type == TypeManager.sbyte_type)
1688 return new SByteConstant ((sbyte) v);
1689 if (target_type == TypeManager.short_type)
1690 return new ShortConstant ((short) v);
1691 if (target_type == TypeManager.ushort_type)
1692 return new UShortConstant ((ushort) v);
1693 if (target_type == TypeManager.int32_type)
1694 return new IntConstant ((int) v);
1695 if (target_type == TypeManager.uint32_type)
1696 return new UIntConstant ((uint) v);
1697 if (target_type == TypeManager.int64_type)
1698 return new LongConstant ((long) v);
1699 if (target_type == TypeManager.uint64_type)
1700 return new ULongConstant ((ulong) v);
1701 if (target_type == TypeManager.float_type)
1702 return new FloatConstant ((float) v);
1703 if (target_type == TypeManager.char_type)
1704 return new CharConstant ((char) v);
1705 if (target_type == TypeManager.decimal_type)
1706 return new DecimalConstant ((decimal) v);
1709 if (real_expr is CharConstant){
1710 char v = ((CharConstant) real_expr).Value;
1712 if (target_type == TypeManager.byte_type) {
1713 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1715 return new ByteConstant ((byte) v);
1717 if (target_type == TypeManager.sbyte_type) {
1718 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1720 return new SByteConstant ((sbyte) v);
1722 if (target_type == TypeManager.short_type) {
1723 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1725 return new ShortConstant ((short) v);
1727 if (target_type == TypeManager.int32_type)
1728 return new IntConstant ((int) v);
1729 if (target_type == TypeManager.uint32_type)
1730 return new UIntConstant ((uint) v);
1731 if (target_type == TypeManager.int64_type)
1732 return new LongConstant ((long) v);
1733 if (target_type == TypeManager.uint64_type)
1734 return new ULongConstant ((ulong) v);
1735 if (target_type == TypeManager.float_type)
1736 return new FloatConstant ((float) v);
1737 if (target_type == TypeManager.double_type)
1738 return new DoubleConstant ((double) v);
1739 if (target_type == TypeManager.char_type) {
1740 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1742 return new CharConstant ((char) v);
1744 if (target_type == TypeManager.decimal_type)
1745 return new DecimalConstant ((decimal) v);
1751 public override Expression DoResolve (EmitContext ec)
1753 expr = expr.Resolve (ec);
1757 int errors = Report.Errors;
1759 type = ec.DeclSpace.ResolveType (target_type, false, Location);
1764 eclass = ExprClass.Value;
1766 if (expr is Constant){
1767 Expression e = TryReduce (ec, type);
1773 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1777 public override void Emit (EmitContext ec)
1780 // This one will never happen
1782 throw new Exception ("Should not happen");
1787 /// Binary operators
1789 public class Binary : Expression {
1790 public enum Operator : byte {
1791 Multiply, Division, Modulus,
1792 Addition, Subtraction,
1793 LeftShift, RightShift,
1794 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1795 Equality, Inequality,
1805 Expression left, right;
1808 // After resolution, method might contain the operator overload
1811 protected MethodBase method;
1812 ArrayList Arguments;
1814 bool DelegateOperation;
1816 // This must be kept in sync with Operator!!!
1817 public static readonly string [] oper_names;
1821 oper_names = new string [(int) Operator.TOP];
1823 oper_names [(int) Operator.Multiply] = "op_Multiply";
1824 oper_names [(int) Operator.Division] = "op_Division";
1825 oper_names [(int) Operator.Modulus] = "op_Modulus";
1826 oper_names [(int) Operator.Addition] = "op_Addition";
1827 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1828 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1829 oper_names [(int) Operator.RightShift] = "op_RightShift";
1830 oper_names [(int) Operator.LessThan] = "op_LessThan";
1831 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1832 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1833 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1834 oper_names [(int) Operator.Equality] = "op_Equality";
1835 oper_names [(int) Operator.Inequality] = "op_Inequality";
1836 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1837 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1838 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1839 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1840 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1843 public Binary (Operator oper, Expression left, Expression right, Location loc)
1851 public Operator Oper {
1860 public Expression Left {
1869 public Expression Right {
1880 /// Returns a stringified representation of the Operator
1882 static string OperName (Operator oper)
1885 case Operator.Multiply:
1887 case Operator.Division:
1889 case Operator.Modulus:
1891 case Operator.Addition:
1893 case Operator.Subtraction:
1895 case Operator.LeftShift:
1897 case Operator.RightShift:
1899 case Operator.LessThan:
1901 case Operator.GreaterThan:
1903 case Operator.LessThanOrEqual:
1905 case Operator.GreaterThanOrEqual:
1907 case Operator.Equality:
1909 case Operator.Inequality:
1911 case Operator.BitwiseAnd:
1913 case Operator.BitwiseOr:
1915 case Operator.ExclusiveOr:
1917 case Operator.LogicalOr:
1919 case Operator.LogicalAnd:
1923 return oper.ToString ();
1926 public override string ToString ()
1928 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1929 right.ToString () + ")";
1932 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1934 if (expr.Type == target_type)
1937 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1940 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1943 34, loc, "Operator `" + OperName (oper)
1944 + "' is ambiguous on operands of type `"
1945 + TypeManager.CSharpName (l) + "' "
1946 + "and `" + TypeManager.CSharpName (r)
1950 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
1952 if ((l == t) || (r == t))
1955 if (!check_user_conversions)
1958 if (Convert.ImplicitUserConversionExists (ec, l, t))
1960 else if (Convert.ImplicitUserConversionExists (ec, r, t))
1967 // Note that handling the case l == Decimal || r == Decimal
1968 // is taken care of by the Step 1 Operator Overload resolution.
1970 // If `check_user_conv' is true, we also check whether a user-defined conversion
1971 // exists. Note that we only need to do this if both arguments are of a user-defined
1972 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
1973 // so we don't explicitly check for performance reasons.
1975 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
1977 if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
1979 // If either operand is of type double, the other operand is
1980 // conveted to type double.
1982 if (r != TypeManager.double_type)
1983 right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
1984 if (l != TypeManager.double_type)
1985 left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
1987 type = TypeManager.double_type;
1988 } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
1990 // if either operand is of type float, the other operand is
1991 // converted to type float.
1993 if (r != TypeManager.double_type)
1994 right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
1995 if (l != TypeManager.double_type)
1996 left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
1997 type = TypeManager.float_type;
1998 } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2002 // If either operand is of type ulong, the other operand is
2003 // converted to type ulong. or an error ocurrs if the other
2004 // operand is of type sbyte, short, int or long
2006 if (l == TypeManager.uint64_type){
2007 if (r != TypeManager.uint64_type){
2008 if (right is IntConstant){
2009 IntConstant ic = (IntConstant) right;
2011 e = Convert.TryImplicitIntConversion (l, ic);
2014 } else if (right is LongConstant){
2015 long ll = ((LongConstant) right).Value;
2018 right = new ULongConstant ((ulong) ll);
2020 e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2027 if (left is IntConstant){
2028 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2031 } else if (left is LongConstant){
2032 long ll = ((LongConstant) left).Value;
2035 left = new ULongConstant ((ulong) ll);
2037 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2044 if ((other == TypeManager.sbyte_type) ||
2045 (other == TypeManager.short_type) ||
2046 (other == TypeManager.int32_type) ||
2047 (other == TypeManager.int64_type))
2048 Error_OperatorAmbiguous (loc, oper, l, r);
2049 type = TypeManager.uint64_type;
2050 } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2052 // If either operand is of type long, the other operand is converted
2055 if (l != TypeManager.int64_type)
2056 left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2057 if (r != TypeManager.int64_type)
2058 right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2060 type = TypeManager.int64_type;
2061 } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2063 // If either operand is of type uint, and the other
2064 // operand is of type sbyte, short or int, othe operands are
2065 // converted to type long.
2069 if (l == TypeManager.uint32_type){
2070 if (right is IntConstant){
2071 IntConstant ic = (IntConstant) right;
2075 right = new UIntConstant ((uint) val);
2082 else if (r == TypeManager.uint32_type){
2083 if (left is IntConstant){
2084 IntConstant ic = (IntConstant) left;
2088 left = new UIntConstant ((uint) val);
2097 if ((other == TypeManager.sbyte_type) ||
2098 (other == TypeManager.short_type) ||
2099 (other == TypeManager.int32_type)){
2100 left = ForceConversion (ec, left, TypeManager.int64_type);
2101 right = ForceConversion (ec, right, TypeManager.int64_type);
2102 type = TypeManager.int64_type;
2105 // if either operand is of type uint, the other
2106 // operand is converd to type uint
2108 left = ForceConversion (ec, left, TypeManager.uint32_type);
2109 right = ForceConversion (ec, right, TypeManager.uint32_type);
2110 type = TypeManager.uint32_type;
2112 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2113 if (l != TypeManager.decimal_type)
2114 left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2116 if (r != TypeManager.decimal_type)
2117 right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2118 type = TypeManager.decimal_type;
2120 left = ForceConversion (ec, left, TypeManager.int32_type);
2121 right = ForceConversion (ec, right, TypeManager.int32_type);
2123 type = TypeManager.int32_type;
2126 return (left != null) && (right != null);
2129 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2131 Report.Error (19, loc,
2132 "Operator " + name + " cannot be applied to operands of type `" +
2133 TypeManager.CSharpName (l) + "' and `" +
2134 TypeManager.CSharpName (r) + "'");
2137 void Error_OperatorCannotBeApplied ()
2139 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2142 static bool is_32_or_64 (Type t)
2144 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2145 t == TypeManager.int64_type || t == TypeManager.uint64_type);
2148 static bool is_unsigned (Type t)
2150 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2151 t == TypeManager.short_type || t == TypeManager.byte_type);
2154 static bool is_user_defined (Type t)
2156 if (t.IsSubclassOf (TypeManager.value_type) &&
2157 (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2163 Expression CheckShiftArguments (EmitContext ec)
2167 Type r = right.Type;
2169 e = ForceConversion (ec, right, TypeManager.int32_type);
2171 Error_OperatorCannotBeApplied ();
2176 if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2177 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2178 ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2179 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2185 Error_OperatorCannotBeApplied ();
2189 Expression ResolveOperator (EmitContext ec)
2192 Type r = right.Type;
2194 bool overload_failed = false;
2197 // Special cases: string comapred to null
2199 if (oper == Operator.Equality || oper == Operator.Inequality){
2200 if ((l == TypeManager.string_type && (right is NullLiteral)) ||
2201 (r == TypeManager.string_type && (left is NullLiteral))){
2202 Type = TypeManager.bool_type;
2209 // Do not perform operator overload resolution when both sides are
2212 if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
2214 // Step 1: Perform Operator Overload location
2216 Expression left_expr, right_expr;
2218 string op = oper_names [(int) oper];
2220 MethodGroupExpr union;
2221 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2223 right_expr = MemberLookup (
2224 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2225 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2227 union = (MethodGroupExpr) left_expr;
2229 if (union != null) {
2230 Arguments = new ArrayList ();
2231 Arguments.Add (new Argument (left, Argument.AType.Expression));
2232 Arguments.Add (new Argument (right, Argument.AType.Expression));
2234 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
2235 if (method != null) {
2236 MethodInfo mi = (MethodInfo) method;
2238 type = mi.ReturnType;
2241 overload_failed = true;
2247 // Step 2: Default operations on CLI native types.
2251 // Step 0: String concatenation (because overloading will get this wrong)
2253 if (oper == Operator.Addition){
2255 // If any of the arguments is a string, cast to string
2258 if (l == TypeManager.string_type){
2260 if (r == TypeManager.void_type) {
2261 Error_OperatorCannotBeApplied ();
2265 if (r == TypeManager.string_type){
2266 if (left is Constant && right is Constant){
2267 StringConstant ls = (StringConstant) left;
2268 StringConstant rs = (StringConstant) right;
2270 return new StringConstant (
2271 ls.Value + rs.Value);
2274 if (left is Binary){
2275 Binary b = (Binary) left;
2278 // Call String.Concat (string, string, string) or
2279 // String.Concat (string, string, string, string)
2282 if (b.oper == Operator.Addition &&
2283 (b.method == TypeManager.string_concat_string_string ||
2284 b.method == TypeManager.string_concat_string_string_string)){
2285 ArrayList bargs = b.Arguments;
2286 int count = bargs.Count;
2290 Arguments.Add (new Argument (right, Argument.AType.Expression));
2291 type = TypeManager.string_type;
2292 method = TypeManager.string_concat_string_string_string;
2295 } else if (count == 3){
2297 Arguments.Add (new Argument (right, Argument.AType.Expression));
2298 type = TypeManager.string_type;
2299 method = TypeManager.string_concat_string_string_string_string;
2306 method = TypeManager.string_concat_string_string;
2309 method = TypeManager.string_concat_object_object;
2310 right = Convert.ImplicitConversion (
2311 ec, right, TypeManager.object_type, loc);
2313 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2317 type = TypeManager.string_type;
2319 Arguments = new ArrayList ();
2320 Arguments.Add (new Argument (left, Argument.AType.Expression));
2321 Arguments.Add (new Argument (right, Argument.AType.Expression));
2325 } else if (r == TypeManager.string_type){
2328 if (l == TypeManager.void_type) {
2329 Error_OperatorCannotBeApplied ();
2333 method = TypeManager.string_concat_object_object;
2334 left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc);
2336 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2339 Arguments = new ArrayList ();
2340 Arguments.Add (new Argument (left, Argument.AType.Expression));
2341 Arguments.Add (new Argument (right, Argument.AType.Expression));
2343 type = TypeManager.string_type;
2349 // Transform a + ( - b) into a - b
2351 if (right is Unary){
2352 Unary right_unary = (Unary) right;
2354 if (right_unary.Oper == Unary.Operator.UnaryNegation){
2355 oper = Operator.Subtraction;
2356 right = right_unary.Expr;
2362 if (oper == Operator.Equality || oper == Operator.Inequality){
2363 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2364 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2365 Error_OperatorCannotBeApplied ();
2369 type = TypeManager.bool_type;
2374 // operator != (object a, object b)
2375 // operator == (object a, object b)
2377 // For this to be used, both arguments have to be reference-types.
2378 // Read the rationale on the spec (14.9.6)
2380 // Also, if at compile time we know that the classes do not inherit
2381 // one from the other, then we catch the error there.
2383 if (!(l.IsValueType || r.IsValueType)){
2384 type = TypeManager.bool_type;
2389 if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2393 // Also, a standard conversion must exist from either one
2395 if (!(Convert.ImplicitStandardConversionExists (left, r) ||
2396 Convert.ImplicitStandardConversionExists (right, l))){
2397 Error_OperatorCannotBeApplied ();
2401 // We are going to have to convert to an object to compare
2403 if (l != TypeManager.object_type)
2404 left = new EmptyCast (left, TypeManager.object_type);
2405 if (r != TypeManager.object_type)
2406 right = new EmptyCast (right, TypeManager.object_type);
2409 // FIXME: CSC here catches errors cs254 and cs252
2415 // One of them is a valuetype, but the other one is not.
2417 if (!l.IsValueType || !r.IsValueType) {
2418 Error_OperatorCannotBeApplied ();
2423 // Only perform numeric promotions on:
2424 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2426 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2427 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2428 r.IsSubclassOf (TypeManager.delegate_type)) {
2430 Arguments = new ArrayList ();
2431 Arguments.Add (new Argument (left, Argument.AType.Expression));
2432 Arguments.Add (new Argument (right, Argument.AType.Expression));
2434 if (oper == Operator.Addition)
2435 method = TypeManager.delegate_combine_delegate_delegate;
2437 method = TypeManager.delegate_remove_delegate_delegate;
2440 Error_OperatorCannotBeApplied ();
2444 DelegateOperation = true;
2450 // Pointer arithmetic:
2452 // T* operator + (T* x, int y);
2453 // T* operator + (T* x, uint y);
2454 // T* operator + (T* x, long y);
2455 // T* operator + (T* x, ulong y);
2457 // T* operator + (int y, T* x);
2458 // T* operator + (uint y, T *x);
2459 // T* operator + (long y, T *x);
2460 // T* operator + (ulong y, T *x);
2462 // T* operator - (T* x, int y);
2463 // T* operator - (T* x, uint y);
2464 // T* operator - (T* x, long y);
2465 // T* operator - (T* x, ulong y);
2467 // long operator - (T* x, T *y)
2470 if (r.IsPointer && oper == Operator.Subtraction){
2472 return new PointerArithmetic (
2473 false, left, right, TypeManager.int64_type,
2475 } else if (is_32_or_64 (r))
2476 return new PointerArithmetic (
2477 oper == Operator.Addition, left, right, l, loc);
2478 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2479 return new PointerArithmetic (
2480 true, right, left, r, loc);
2484 // Enumeration operators
2486 bool lie = TypeManager.IsEnumType (l);
2487 bool rie = TypeManager.IsEnumType (r);
2491 // U operator - (E e, E f)
2492 if (lie && rie && oper == Operator.Subtraction){
2494 type = TypeManager.EnumToUnderlying (l);
2497 Error_OperatorCannotBeApplied ();
2502 // operator + (E e, U x)
2503 // operator - (E e, U x)
2505 if (oper == Operator.Addition || oper == Operator.Subtraction){
2506 Type enum_type = lie ? l : r;
2507 Type other_type = lie ? r : l;
2508 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2511 if (underlying_type != other_type){
2512 Error_OperatorCannotBeApplied ();
2521 temp = Convert.ImplicitConversion (ec, right, l, loc);
2525 Error_OperatorCannotBeApplied ();
2529 temp = Convert.ImplicitConversion (ec, left, r, loc);
2534 Error_OperatorCannotBeApplied ();
2539 if (oper == Operator.Equality || oper == Operator.Inequality ||
2540 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2541 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2542 if (left.Type != right.Type){
2543 Error_OperatorCannotBeApplied ();
2546 type = TypeManager.bool_type;
2550 if (oper == Operator.BitwiseAnd ||
2551 oper == Operator.BitwiseOr ||
2552 oper == Operator.ExclusiveOr){
2556 Error_OperatorCannotBeApplied ();
2560 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2561 return CheckShiftArguments (ec);
2563 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2564 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
2565 Error_OperatorCannotBeApplied ();
2569 type = TypeManager.bool_type;
2574 // operator & (bool x, bool y)
2575 // operator | (bool x, bool y)
2576 // operator ^ (bool x, bool y)
2578 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2579 if (oper == Operator.BitwiseAnd ||
2580 oper == Operator.BitwiseOr ||
2581 oper == Operator.ExclusiveOr){
2588 // Pointer comparison
2590 if (l.IsPointer && r.IsPointer){
2591 if (oper == Operator.Equality || oper == Operator.Inequality ||
2592 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2593 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2594 type = TypeManager.bool_type;
2600 // We are dealing with numbers
2602 if (overload_failed){
2603 Error_OperatorCannotBeApplied ();
2608 // This will leave left or right set to null if there is an error
2610 bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2611 DoNumericPromotions (ec, l, r, check_user_conv);
2612 if (left == null || right == null){
2613 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2618 // reload our cached types if required
2623 if (oper == Operator.BitwiseAnd ||
2624 oper == Operator.BitwiseOr ||
2625 oper == Operator.ExclusiveOr){
2627 if (!((l == TypeManager.int32_type) ||
2628 (l == TypeManager.uint32_type) ||
2629 (l == TypeManager.short_type) ||
2630 (l == TypeManager.ushort_type) ||
2631 (l == TypeManager.int64_type) ||
2632 (l == TypeManager.uint64_type)))
2635 Error_OperatorCannotBeApplied ();
2640 if (oper == Operator.Equality ||
2641 oper == Operator.Inequality ||
2642 oper == Operator.LessThanOrEqual ||
2643 oper == Operator.LessThan ||
2644 oper == Operator.GreaterThanOrEqual ||
2645 oper == Operator.GreaterThan){
2646 type = TypeManager.bool_type;
2652 public override Expression DoResolve (EmitContext ec)
2654 left = left.Resolve (ec);
2655 right = right.Resolve (ec);
2657 if (left == null || right == null)
2660 eclass = ExprClass.Value;
2662 Constant rc = right as Constant;
2663 Constant lc = left as Constant;
2665 if (rc != null & lc != null){
2666 Expression e = ConstantFold.BinaryFold (
2667 ec, oper, lc, rc, loc);
2672 return ResolveOperator (ec);
2676 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2677 /// context of a conditional bool expression. This function will return
2678 /// false if it is was possible to use EmitBranchable, or true if it was.
2680 /// The expression's code is generated, and we will generate a branch to `target'
2681 /// if the resulting expression value is equal to isTrue
2683 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2688 ILGenerator ig = ec.ig;
2691 // This is more complicated than it looks, but its just to avoid
2692 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2693 // but on top of that we want for == and != to use a special path
2694 // if we are comparing against null
2696 if (oper == Operator.Equality || oper == Operator.Inequality){
2697 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2699 if (left is NullLiteral){
2702 ig.Emit (OpCodes.Brtrue, target);
2704 ig.Emit (OpCodes.Brfalse, target);
2706 } else if (right is NullLiteral){
2709 ig.Emit (OpCodes.Brtrue, target);
2711 ig.Emit (OpCodes.Brfalse, target);
2713 } else if (left is BoolConstant){
2715 if (my_on_true != ((BoolConstant) left).Value)
2716 ig.Emit (OpCodes.Brtrue, target);
2718 ig.Emit (OpCodes.Brfalse, target);
2720 } else if (right is BoolConstant){
2722 if (my_on_true != ((BoolConstant) right).Value)
2723 ig.Emit (OpCodes.Brtrue, target);
2725 ig.Emit (OpCodes.Brfalse, target);
2729 } else if (oper == Operator.LogicalAnd){
2730 if (left is Binary){
2731 Binary left_binary = (Binary) left;
2734 Label tests_end = ig.DefineLabel ();
2736 if (left_binary.EmitBranchable (ec, tests_end, false)){
2737 if (right is Binary){
2738 Binary right_binary = (Binary) right;
2740 if (right_binary.EmitBranchable (ec, target, true)){
2741 ig.MarkLabel (tests_end);
2746 ig.Emit (OpCodes.Brtrue, target);
2747 ig.MarkLabel (tests_end);
2751 if (left_binary.EmitBranchable (ec, target, false)){
2752 if (right is Binary){
2753 Binary right_binary = (Binary) right;
2755 if (right_binary.EmitBranchable (ec, target, false))
2760 ig.Emit (OpCodes.Brtrue, target);
2762 ig.Emit (OpCodes.Brfalse, target);
2767 // Give up, and let the regular Emit work, but we could
2768 // also optimize the left-non-Branchable, but-right-Branchable
2772 } else if (oper == Operator.LogicalOr){
2773 if (left is Binary){
2774 Binary left_binary = (Binary) left;
2777 if (left_binary.EmitBranchable (ec, target, true)){
2778 if (right is Binary){
2779 Binary right_binary = (Binary) right;
2781 if (right_binary.EmitBranchable (ec, target, true))
2785 ig.Emit (OpCodes.Brtrue, target);
2790 // Give up, and let the regular Emit work, but we could
2791 // also optimize the left-non-Branchable, but-right-Branchable
2794 Label tests_end = ig.DefineLabel ();
2796 if (left_binary.EmitBranchable (ec, tests_end, true)){
2797 if (right is Binary){
2798 Binary right_binary = (Binary) right;
2800 if (right_binary.EmitBranchable (ec, target, false)){
2801 ig.MarkLabel (tests_end);
2806 ig.Emit (OpCodes.Brfalse, target);
2807 ig.MarkLabel (tests_end);
2814 } else if (!(oper == Operator.LessThan ||
2815 oper == Operator.GreaterThan ||
2816 oper == Operator.LessThanOrEqual ||
2817 oper == Operator.GreaterThanOrEqual))
2824 bool isUnsigned = is_unsigned (t);
2827 case Operator.Equality:
2829 ig.Emit (OpCodes.Beq, target);
2831 ig.Emit (OpCodes.Bne_Un, target);
2834 case Operator.Inequality:
2836 ig.Emit (OpCodes.Bne_Un, target);
2838 ig.Emit (OpCodes.Beq, target);
2841 case Operator.LessThan:
2844 ig.Emit (OpCodes.Blt_Un, target);
2846 ig.Emit (OpCodes.Blt, target);
2849 ig.Emit (OpCodes.Bge_Un, target);
2851 ig.Emit (OpCodes.Bge, target);
2854 case Operator.GreaterThan:
2857 ig.Emit (OpCodes.Bgt_Un, target);
2859 ig.Emit (OpCodes.Bgt, target);
2862 ig.Emit (OpCodes.Ble_Un, target);
2864 ig.Emit (OpCodes.Ble, target);
2867 case Operator.LessThanOrEqual:
2868 if (t == TypeManager.double_type || t == TypeManager.float_type)
2873 ig.Emit (OpCodes.Ble_Un, target);
2875 ig.Emit (OpCodes.Ble, target);
2878 ig.Emit (OpCodes.Bgt_Un, target);
2880 ig.Emit (OpCodes.Bgt, target);
2884 case Operator.GreaterThanOrEqual:
2885 if (t == TypeManager.double_type || t == TypeManager.float_type)
2889 ig.Emit (OpCodes.Bge_Un, target);
2891 ig.Emit (OpCodes.Bge, target);
2894 ig.Emit (OpCodes.Blt_Un, target);
2896 ig.Emit (OpCodes.Blt, target);
2906 public override void Emit (EmitContext ec)
2908 ILGenerator ig = ec.ig;
2910 Type r = right.Type;
2913 if (method != null) {
2915 // Note that operators are static anyway
2917 if (Arguments != null)
2918 Invocation.EmitArguments (ec, method, Arguments);
2920 if (method is MethodInfo)
2921 ig.Emit (OpCodes.Call, (MethodInfo) method);
2923 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2925 if (DelegateOperation)
2926 ig.Emit (OpCodes.Castclass, type);
2932 // Handle short-circuit operators differently
2935 if (oper == Operator.LogicalAnd){
2936 Label load_zero = ig.DefineLabel ();
2937 Label end = ig.DefineLabel ();
2938 bool process = true;
2940 if (left is Binary){
2941 Binary left_binary = (Binary) left;
2943 if (left_binary.EmitBranchable (ec, load_zero, false)){
2945 ig.Emit (OpCodes.Br, end);
2952 ig.Emit (OpCodes.Brfalse, load_zero);
2954 ig.Emit (OpCodes.Br, end);
2956 ig.MarkLabel (load_zero);
2957 ig.Emit (OpCodes.Ldc_I4_0);
2960 } else if (oper == Operator.LogicalOr){
2961 Label load_one = ig.DefineLabel ();
2962 Label end = ig.DefineLabel ();
2963 bool process = true;
2965 if (left is Binary){
2966 Binary left_binary = (Binary) left;
2968 if (left_binary.EmitBranchable (ec, load_one, true)){
2970 ig.Emit (OpCodes.Br, end);
2977 ig.Emit (OpCodes.Brtrue, load_one);
2979 ig.Emit (OpCodes.Br, end);
2981 ig.MarkLabel (load_one);
2982 ig.Emit (OpCodes.Ldc_I4_1);
2990 bool isUnsigned = is_unsigned (left.Type);
2993 case Operator.Multiply:
2995 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2996 opcode = OpCodes.Mul_Ovf;
2997 else if (isUnsigned)
2998 opcode = OpCodes.Mul_Ovf_Un;
3000 opcode = OpCodes.Mul;
3002 opcode = OpCodes.Mul;
3006 case Operator.Division:
3008 opcode = OpCodes.Div_Un;
3010 opcode = OpCodes.Div;
3013 case Operator.Modulus:
3015 opcode = OpCodes.Rem_Un;
3017 opcode = OpCodes.Rem;
3020 case Operator.Addition:
3022 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3023 opcode = OpCodes.Add_Ovf;
3024 else if (isUnsigned)
3025 opcode = OpCodes.Add_Ovf_Un;
3027 opcode = OpCodes.Add;
3029 opcode = OpCodes.Add;
3032 case Operator.Subtraction:
3034 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3035 opcode = OpCodes.Sub_Ovf;
3036 else if (isUnsigned)
3037 opcode = OpCodes.Sub_Ovf_Un;
3039 opcode = OpCodes.Sub;
3041 opcode = OpCodes.Sub;
3044 case Operator.RightShift:
3046 opcode = OpCodes.Shr_Un;
3048 opcode = OpCodes.Shr;
3051 case Operator.LeftShift:
3052 opcode = OpCodes.Shl;
3055 case Operator.Equality:
3056 opcode = OpCodes.Ceq;
3059 case Operator.Inequality:
3060 ig.Emit (OpCodes.Ceq);
3061 ig.Emit (OpCodes.Ldc_I4_0);
3063 opcode = OpCodes.Ceq;
3066 case Operator.LessThan:
3068 opcode = OpCodes.Clt_Un;
3070 opcode = OpCodes.Clt;
3073 case Operator.GreaterThan:
3075 opcode = OpCodes.Cgt_Un;
3077 opcode = OpCodes.Cgt;
3080 case Operator.LessThanOrEqual:
3081 Type lt = left.Type;
3083 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3084 ig.Emit (OpCodes.Cgt_Un);
3086 ig.Emit (OpCodes.Cgt);
3087 ig.Emit (OpCodes.Ldc_I4_0);
3089 opcode = OpCodes.Ceq;
3092 case Operator.GreaterThanOrEqual:
3093 Type le = left.Type;
3095 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3096 ig.Emit (OpCodes.Clt_Un);
3098 ig.Emit (OpCodes.Clt);
3100 ig.Emit (OpCodes.Ldc_I4_1);
3102 opcode = OpCodes.Sub;
3105 case Operator.BitwiseOr:
3106 opcode = OpCodes.Or;
3109 case Operator.BitwiseAnd:
3110 opcode = OpCodes.And;
3113 case Operator.ExclusiveOr:
3114 opcode = OpCodes.Xor;
3118 throw new Exception ("This should not happen: Operator = "
3119 + oper.ToString ());
3125 public bool IsBuiltinOperator {
3127 return method == null;
3132 public class PointerArithmetic : Expression {
3133 Expression left, right;
3137 // We assume that `l' is always a pointer
3139 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3142 eclass = ExprClass.Variable;
3146 is_add = is_addition;
3149 public override Expression DoResolve (EmitContext ec)
3152 // We are born fully resolved
3157 public override void Emit (EmitContext ec)
3159 Type op_type = left.Type;
3160 ILGenerator ig = ec.ig;
3161 int size = GetTypeSize (op_type.GetElementType ());
3162 Type rtype = right.Type;
3164 if (rtype.IsPointer){
3166 // handle (pointer - pointer)
3170 ig.Emit (OpCodes.Sub);
3174 ig.Emit (OpCodes.Sizeof, op_type);
3176 IntLiteral.EmitInt (ig, size);
3177 ig.Emit (OpCodes.Div);
3179 ig.Emit (OpCodes.Conv_I8);
3182 // handle + and - on (pointer op int)
3185 ig.Emit (OpCodes.Conv_I);
3189 ig.Emit (OpCodes.Sizeof, op_type);
3191 IntLiteral.EmitInt (ig, size);
3192 if (rtype == TypeManager.int64_type)
3193 ig.Emit (OpCodes.Conv_I8);
3194 else if (rtype == TypeManager.uint64_type)
3195 ig.Emit (OpCodes.Conv_U8);
3196 ig.Emit (OpCodes.Mul);
3197 ig.Emit (OpCodes.Conv_I);
3200 ig.Emit (OpCodes.Add);
3202 ig.Emit (OpCodes.Sub);
3208 /// Implements the ternary conditional operator (?:)
3210 public class Conditional : Expression {
3211 Expression expr, trueExpr, falseExpr;
3213 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3216 this.trueExpr = trueExpr;
3217 this.falseExpr = falseExpr;
3221 public Expression Expr {
3227 public Expression TrueExpr {
3233 public Expression FalseExpr {
3239 public override Expression DoResolve (EmitContext ec)
3241 expr = expr.Resolve (ec);
3246 if (expr.Type != TypeManager.bool_type){
3247 expr = Expression.ResolveBoolean (
3254 trueExpr = trueExpr.Resolve (ec);
3255 falseExpr = falseExpr.Resolve (ec);
3257 if (trueExpr == null || falseExpr == null)
3260 eclass = ExprClass.Value;
3261 if (trueExpr.Type == falseExpr.Type)
3262 type = trueExpr.Type;
3265 Type true_type = trueExpr.Type;
3266 Type false_type = falseExpr.Type;
3268 if (trueExpr is NullLiteral){
3271 } else if (falseExpr is NullLiteral){
3277 // First, if an implicit conversion exists from trueExpr
3278 // to falseExpr, then the result type is of type falseExpr.Type
3280 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3283 // Check if both can convert implicitl to each other's type
3285 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3287 "Can not compute type of conditional expression " +
3288 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3289 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3290 "' convert implicitly to each other");
3295 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3299 Error (173, "The type of the conditional expression can " +
3300 "not be computed because there is no implicit conversion" +
3301 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3302 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3307 if (expr is BoolConstant){
3308 BoolConstant bc = (BoolConstant) expr;
3319 public override void Emit (EmitContext ec)
3321 ILGenerator ig = ec.ig;
3322 Label false_target = ig.DefineLabel ();
3323 Label end_target = ig.DefineLabel ();
3325 Statement.EmitBoolExpression (ec, expr, false_target, false);
3327 ig.Emit (OpCodes.Br, end_target);
3328 ig.MarkLabel (false_target);
3329 falseExpr.Emit (ec);
3330 ig.MarkLabel (end_target);
3338 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3339 public readonly string Name;
3340 public readonly Block Block;
3341 LocalInfo local_info;
3342 VariableInfo variable_info;
3345 public LocalVariableReference (Block block, string name, Location l)
3350 eclass = ExprClass.Variable;
3353 // Setting `is_readonly' to false will allow you to create a writable
3354 // reference to a read-only variable. This is used by foreach and using.
3355 public LocalVariableReference (Block block, string name, Location l,
3356 LocalInfo local_info, bool is_readonly)
3357 : this (block, name, l)
3359 this.local_info = local_info;
3360 this.is_readonly = is_readonly;
3363 public VariableInfo VariableInfo {
3364 get { return variable_info; }
3367 public bool IsReadOnly {
3373 protected void DoResolveBase (EmitContext ec)
3375 if (local_info == null) {
3376 local_info = Block.GetLocalInfo (Name);
3377 is_readonly = local_info.ReadOnly;
3380 variable_info = Block.GetVariableInfo (local_info);
3381 type = local_info.VariableType;
3384 public override Expression DoResolve (EmitContext ec)
3388 Expression e = Block.GetConstantExpression (Name);
3390 local_info.Used = true;
3391 eclass = ExprClass.Value;
3395 if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3401 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3405 if (variable_info != null)
3406 variable_info.SetAssigned (ec);
3408 Expression e = DoResolve (ec);
3414 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3421 public override void Emit (EmitContext ec)
3423 ILGenerator ig = ec.ig;
3425 if (local_info.LocalBuilder == null){
3427 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3429 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3431 local_info.Used = true;
3434 public void EmitAssign (EmitContext ec, Expression source)
3436 ILGenerator ig = ec.ig;
3438 local_info.Assigned = true;
3440 if (local_info.LocalBuilder == null){
3443 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3446 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3450 public void AddressOf (EmitContext ec, AddressOp mode)
3452 if (local_info.LocalBuilder == null){
3454 ec.ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3456 ec.ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3461 /// This represents a reference to a parameter in the intermediate
3464 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3470 public Parameter.Modifier mod;
3471 public bool is_ref, is_out;
3473 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3480 eclass = ExprClass.Variable;
3483 public VariableInfo VariableInfo {
3487 public bool IsAssigned (EmitContext ec, Location loc)
3489 if (!ec.DoFlowAnalysis || !is_out ||
3490 ec.CurrentBranching.IsAssigned (vi))
3493 Report.Error (165, loc,
3494 "Use of unassigned parameter `" + name + "'");
3498 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3500 if (!ec.DoFlowAnalysis || !is_out ||
3501 ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3504 Report.Error (170, loc,
3505 "Use of possibly unassigned field `" + field_name + "'");
3509 public void SetAssigned (EmitContext ec)
3511 if (is_out && ec.DoFlowAnalysis)
3512 ec.CurrentBranching.SetAssigned (vi);
3515 public void SetFieldAssigned (EmitContext ec, string field_name)
3517 if (is_out && ec.DoFlowAnalysis)
3518 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3521 protected void DoResolveBase (EmitContext ec)
3523 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3524 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3525 is_out = (mod & Parameter.Modifier.OUT) != 0;
3526 eclass = ExprClass.Variable;
3529 vi = block.ParameterMap [idx];
3533 // Notice that for ref/out parameters, the type exposed is not the
3534 // same type exposed externally.
3537 // externally we expose "int&"
3538 // here we expose "int".
3540 // We record this in "is_ref". This means that the type system can treat
3541 // the type as it is expected, but when we generate the code, we generate
3542 // the alternate kind of code.
3544 public override Expression DoResolve (EmitContext ec)
3548 if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3554 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3563 static public void EmitLdArg (ILGenerator ig, int x)
3567 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3568 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3569 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3570 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3571 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3574 ig.Emit (OpCodes.Ldarg, x);
3578 // This method is used by parameters that are references, that are
3579 // being passed as references: we only want to pass the pointer (that
3580 // is already stored in the parameter, not the address of the pointer,
3581 // and not the value of the variable).
3583 public void EmitLoad (EmitContext ec)
3585 ILGenerator ig = ec.ig;
3591 EmitLdArg (ig, arg_idx);
3594 public override void Emit (EmitContext ec)
3596 ILGenerator ig = ec.ig;
3598 if (ec.RemapToProxy){
3599 ig.Emit (OpCodes.Ldarg_0);
3600 ec.EmitArgument (idx);
3609 EmitLdArg (ig, arg_idx);
3615 // If we are a reference, we loaded on the stack a pointer
3616 // Now lets load the real value
3618 LoadFromPtr (ig, type);
3621 public void EmitAssign (EmitContext ec, Expression source)
3623 ILGenerator ig = ec.ig;
3625 if (ec.RemapToProxy){
3626 ig.Emit (OpCodes.Ldarg_0);
3628 ec.EmitStoreArgument (idx);
3638 EmitLdArg (ig, arg_idx);
3643 StoreFromPtr (ig, type);
3646 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3648 ig.Emit (OpCodes.Starg, arg_idx);
3652 public void AddressOf (EmitContext ec, AddressOp mode)
3654 if (ec.RemapToProxy){
3655 Report.Error (-1, "Report this: Taking the address of a remapped parameter not supported");
3666 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3668 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3671 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3673 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3680 /// Used for arguments to New(), Invocation()
3682 public class Argument {
3683 public enum AType : byte {
3689 public readonly AType ArgType;
3690 public Expression Expr;
3692 public Argument (Expression expr, AType type)
3695 this.ArgType = type;
3700 if (ArgType == AType.Ref || ArgType == AType.Out)
3701 return TypeManager.GetReferenceType (Expr.Type);
3707 public Parameter.Modifier GetParameterModifier ()
3711 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
3714 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
3717 return Parameter.Modifier.NONE;
3721 public static string FullDesc (Argument a)
3723 return (a.ArgType == AType.Ref ? "ref " :
3724 (a.ArgType == AType.Out ? "out " : "")) +
3725 TypeManager.CSharpName (a.Expr.Type);
3728 public bool ResolveMethodGroup (EmitContext ec, Location loc)
3730 // FIXME: csc doesn't report any error if you try to use `ref' or
3731 // `out' in a delegate creation expression.
3732 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3739 public bool Resolve (EmitContext ec, Location loc)
3741 if (ArgType == AType.Ref) {
3742 Expr = Expr.Resolve (ec);
3746 Expr = Expr.ResolveLValue (ec, Expr);
3747 } else if (ArgType == AType.Out)
3748 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
3750 Expr = Expr.Resolve (ec);
3755 if (ArgType == AType.Expression)
3758 if (Expr.eclass != ExprClass.Variable){
3760 // We just probe to match the CSC output
3762 if (Expr.eclass == ExprClass.PropertyAccess ||
3763 Expr.eclass == ExprClass.IndexerAccess){
3766 "A property or indexer can not be passed as an out or ref " +
3771 "An lvalue is required as an argument to out or ref");
3779 public void Emit (EmitContext ec)
3782 // Ref and Out parameters need to have their addresses taken.
3784 // ParameterReferences might already be references, so we want
3785 // to pass just the value
3787 if (ArgType == AType.Ref || ArgType == AType.Out){
3788 AddressOp mode = AddressOp.Store;
3790 if (ArgType == AType.Ref)
3791 mode |= AddressOp.Load;
3793 if (Expr is ParameterReference){
3794 ParameterReference pr = (ParameterReference) Expr;
3800 pr.AddressOf (ec, mode);
3803 ((IMemoryLocation)Expr).AddressOf (ec, mode);
3810 /// Invocation of methods or delegates.
3812 public class Invocation : ExpressionStatement {
3813 public readonly ArrayList Arguments;
3816 MethodBase method = null;
3819 static Hashtable method_parameter_cache;
3821 static Invocation ()
3823 method_parameter_cache = new PtrHashtable ();
3827 // arguments is an ArrayList, but we do not want to typecast,
3828 // as it might be null.
3830 // FIXME: only allow expr to be a method invocation or a
3831 // delegate invocation (7.5.5)
3833 public Invocation (Expression expr, ArrayList arguments, Location l)
3836 Arguments = arguments;
3840 public Expression Expr {
3847 /// Returns the Parameters (a ParameterData interface) for the
3850 public static ParameterData GetParameterData (MethodBase mb)
3852 object pd = method_parameter_cache [mb];
3856 return (ParameterData) pd;
3859 ip = TypeManager.LookupParametersByBuilder (mb);
3861 method_parameter_cache [mb] = ip;
3863 return (ParameterData) ip;
3865 ParameterInfo [] pi = mb.GetParameters ();
3866 ReflectionParameters rp = new ReflectionParameters (pi);
3867 method_parameter_cache [mb] = rp;
3869 return (ParameterData) rp;
3874 /// Determines "better conversion" as specified in 7.4.2.3
3875 /// Returns : 1 if a->p is better
3876 /// 0 if a->q or neither is better
3878 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
3880 Type argument_type = a.Type;
3881 Expression argument_expr = a.Expr;
3883 if (argument_type == null)
3884 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3887 // This is a special case since csc behaves this way. I can't find
3888 // it anywhere in the spec but oh well ...
3890 if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
3892 else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
3898 if (argument_type == p)
3901 if (argument_type == q)
3905 // Now probe whether an implicit constant expression conversion
3908 // An implicit constant expression conversion permits the following
3911 // * A constant-expression of type `int' can be converted to type
3912 // sbyte, byute, short, ushort, uint, ulong provided the value of
3913 // of the expression is withing the range of the destination type.
3915 // * A constant-expression of type long can be converted to type
3916 // ulong, provided the value of the constant expression is not negative
3918 // FIXME: Note that this assumes that constant folding has
3919 // taken place. We dont do constant folding yet.
3922 if (argument_expr is IntConstant){
3923 IntConstant ei = (IntConstant) argument_expr;
3924 int value = ei.Value;
3926 if (p == TypeManager.sbyte_type){
3927 if (value >= SByte.MinValue && value <= SByte.MaxValue)
3929 } else if (p == TypeManager.byte_type){
3930 if (q == TypeManager.sbyte_type &&
3931 value >= SByte.MinValue && value <= SByte.MaxValue)
3933 else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3935 } else if (p == TypeManager.short_type){
3936 if (value >= Int16.MinValue && value <= Int16.MaxValue)
3938 } else if (p == TypeManager.ushort_type){
3939 if (q == TypeManager.short_type &&
3940 value >= Int16.MinValue && value <= Int16.MaxValue)
3942 else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3944 } else if (p == TypeManager.int32_type){
3945 if (value >= Int32.MinValue && value <= Int32.MaxValue)
3947 } else if (p == TypeManager.uint32_type){
3949 // we can optimize this case: a positive int32
3950 // always fits on a uint32
3954 } else if (p == TypeManager.uint64_type){
3956 // we can optimize this case: a positive int32
3957 // always fits on a uint64
3959 if (q == TypeManager.int64_type)
3961 else if (value >= 0)
3963 } else if (p == TypeManager.int64_type){
3966 } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
3967 LongConstant lc = (LongConstant) argument_expr;
3969 if (p == TypeManager.uint64_type){
3976 Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
3984 Expression p_tmp = new EmptyExpression (p);
3985 Expression q_tmp = new EmptyExpression (q);
3987 if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true &&
3988 Convert.ImplicitConversionExists (ec, q_tmp, p) == false)
3991 if (p == TypeManager.sbyte_type)
3992 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3993 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3996 if (p == TypeManager.short_type)
3997 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3998 q == TypeManager.uint64_type)
4001 if (p == TypeManager.int32_type)
4002 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4005 if (p == TypeManager.int64_type)
4006 if (q == TypeManager.uint64_type)
4013 /// Determines "Better function"
4016 /// and returns an integer indicating :
4017 /// 0 if candidate ain't better
4018 /// 1 if candidate is better than the current best match
4020 static int BetterFunction (EmitContext ec, ArrayList args,
4021 MethodBase candidate, MethodBase best,
4022 bool expanded_form, Location loc)
4024 ParameterData candidate_pd = GetParameterData (candidate);
4025 ParameterData best_pd;
4031 argument_count = args.Count;
4033 int cand_count = candidate_pd.Count;
4035 if (cand_count == 0 && argument_count == 0)
4038 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
4039 if (cand_count != argument_count)
4045 if (argument_count == 0 && cand_count == 1 &&
4046 candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
4049 for (int j = argument_count; j > 0;) {
4052 Argument a = (Argument) args [j];
4053 Type t = candidate_pd.ParameterType (j);
4055 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4057 t = t.GetElementType ();
4059 x = BetterConversion (ec, a, t, null, loc);
4071 best_pd = GetParameterData (best);
4073 int rating1 = 0, rating2 = 0;
4075 for (int j = 0; j < argument_count; ++j) {
4078 Argument a = (Argument) args [j];
4080 Type ct = candidate_pd.ParameterType (j);
4081 Type bt = best_pd.ParameterType (j);
4083 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4085 ct = ct.GetElementType ();
4087 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4089 bt = bt.GetElementType ();
4091 x = BetterConversion (ec, a, ct, bt, loc);
4092 y = BetterConversion (ec, a, bt, ct, loc);
4101 if (rating1 > rating2)
4107 public static string FullMethodDesc (MethodBase mb)
4109 string ret_type = "";
4111 if (mb is MethodInfo)
4112 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4114 StringBuilder sb = new StringBuilder (ret_type);
4116 sb.Append (mb.ReflectedType.ToString ());
4118 sb.Append (mb.Name);
4120 ParameterData pd = GetParameterData (mb);
4122 int count = pd.Count;
4125 for (int i = count; i > 0; ) {
4128 sb.Append (pd.ParameterDesc (count - i - 1));
4134 return sb.ToString ();
4137 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4139 MemberInfo [] miset;
4140 MethodGroupExpr union;
4145 return (MethodGroupExpr) mg2;
4148 return (MethodGroupExpr) mg1;
4151 MethodGroupExpr left_set = null, right_set = null;
4152 int length1 = 0, length2 = 0;
4154 left_set = (MethodGroupExpr) mg1;
4155 length1 = left_set.Methods.Length;
4157 right_set = (MethodGroupExpr) mg2;
4158 length2 = right_set.Methods.Length;
4160 ArrayList common = new ArrayList ();
4162 foreach (MethodBase l in left_set.Methods){
4163 foreach (MethodBase r in right_set.Methods){
4171 miset = new MemberInfo [length1 + length2 - common.Count];
4172 left_set.Methods.CopyTo (miset, 0);
4176 foreach (MemberInfo mi in right_set.Methods){
4177 if (!common.Contains (mi))
4181 union = new MethodGroupExpr (miset, loc);
4187 /// Determines is the candidate method, if a params method, is applicable
4188 /// in its expanded form to the given set of arguments
4190 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4194 if (arguments == null)
4197 arg_count = arguments.Count;
4199 ParameterData pd = GetParameterData (candidate);
4201 int pd_count = pd.Count;
4206 if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
4209 if (pd_count - 1 > arg_count)
4212 if (pd_count == 1 && arg_count == 0)
4216 // If we have come this far, the case which remains is when the number of parameters
4217 // is less than or equal to the argument count.
4219 for (int i = 0; i < pd_count - 1; ++i) {
4221 Argument a = (Argument) arguments [i];
4223 Parameter.Modifier a_mod = a.GetParameterModifier () &
4224 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4225 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4226 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4228 if (a_mod == p_mod) {
4230 if (a_mod == Parameter.Modifier.NONE)
4231 if (!Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
4234 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4235 Type pt = pd.ParameterType (i);
4238 pt = TypeManager.GetReferenceType (pt);
4248 Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
4250 for (int i = pd_count - 1; i < arg_count; i++) {
4251 Argument a = (Argument) arguments [i];
4253 if (!Convert.ImplicitStandardConversionExists (a.Expr, element_type))
4261 /// Determines if the candidate method is applicable (section 14.4.2.1)
4262 /// to the given set of arguments
4264 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4268 if (arguments == null)
4271 arg_count = arguments.Count;
4273 ParameterData pd = GetParameterData (candidate);
4275 int pd_count = pd.Count;
4277 if (arg_count != pd.Count)
4280 for (int i = arg_count; i > 0; ) {
4283 Argument a = (Argument) arguments [i];
4285 Parameter.Modifier a_mod = a.GetParameterModifier () &
4286 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4287 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4288 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4290 if (a_mod == p_mod ||
4291 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4292 if (a_mod == Parameter.Modifier.NONE)
4293 if (!Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
4296 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4297 Type pt = pd.ParameterType (i);
4300 pt = TypeManager.GetReferenceType (pt);
4315 /// Find the Applicable Function Members (7.4.2.1)
4317 /// me: Method Group expression with the members to select.
4318 /// it might contain constructors or methods (or anything
4319 /// that maps to a method).
4321 /// Arguments: ArrayList containing resolved Argument objects.
4323 /// loc: The location if we want an error to be reported, or a Null
4324 /// location for "probing" purposes.
4326 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4327 /// that is the best match of me on Arguments.
4330 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4331 ArrayList Arguments, Location loc)
4333 MethodBase method = null;
4334 Type current_type = null;
4336 ArrayList candidates = new ArrayList ();
4339 foreach (MethodBase candidate in me.Methods){
4342 // If we're going one level higher in the class hierarchy, abort if
4343 // we already found an applicable method.
4344 if (candidate.DeclaringType != current_type) {
4345 current_type = candidate.DeclaringType;
4350 // Check if candidate is applicable (section 14.4.2.1)
4351 if (!IsApplicable (ec, Arguments, candidate))
4354 candidates.Add (candidate);
4355 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
4363 if (Arguments == null)
4366 argument_count = Arguments.Count;
4369 // Now we see if we can find params functions, applicable in their expanded form
4370 // since if they were applicable in their normal form, they would have been selected
4373 bool chose_params_expanded = false;
4375 if (method == null) {
4376 candidates = new ArrayList ();
4377 foreach (MethodBase candidate in me.Methods){
4378 if (!IsParamsMethodApplicable (ec, Arguments, candidate))
4381 candidates.Add (candidate);
4383 int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
4388 chose_params_expanded = true;
4392 if (method == null) {
4394 // Okay so we have failed to find anything so we
4395 // return by providing info about the closest match
4397 for (int i = 0; i < me.Methods.Length; ++i) {
4399 MethodBase c = (MethodBase) me.Methods [i];
4400 ParameterData pd = GetParameterData (c);
4402 if (pd.Count != argument_count)
4405 VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4413 // Now check that there are no ambiguities i.e the selected method
4414 // should be better than all the others
4417 foreach (MethodBase candidate in candidates){
4418 if (candidate == method)
4422 // If a normal method is applicable in the sense that it has the same
4423 // number of arguments, then the expanded params method is never applicable
4424 // so we debar the params method.
4426 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
4427 IsApplicable (ec, Arguments, method))
4430 int x = BetterFunction (ec, Arguments, method, candidate,
4431 chose_params_expanded, loc);
4436 "Ambiguous call when selecting function due to implicit casts");
4442 // And now check if the arguments are all compatible, perform conversions
4443 // if necessary etc. and return if everything is all right
4446 if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4447 chose_params_expanded, null, loc))
4453 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4454 Type delegate_type, string arg_sig, string par_desc)
4456 if (delegate_type == null)
4457 Report.Error (1502, loc,
4458 "The best overloaded match for method '" +
4459 FullMethodDesc (method) +
4460 "' has some invalid arguments");
4462 Report.Error (1594, loc,
4463 "Delegate '" + delegate_type.ToString () +
4464 "' has some invalid arguments.");
4465 Report.Error (1503, loc,
4466 String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4467 idx, arg_sig, par_desc));
4470 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4473 bool chose_params_expanded,
4477 ParameterData pd = GetParameterData (method);
4478 int pd_count = pd.Count;
4480 for (int j = 0; j < argument_count; j++) {
4481 Argument a = (Argument) Arguments [j];
4482 Expression a_expr = a.Expr;
4483 Type parameter_type = pd.ParameterType (j);
4484 Parameter.Modifier pm = pd.ParameterModifier (j);
4486 if (pm == Parameter.Modifier.PARAMS){
4487 if (chose_params_expanded)
4488 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
4493 if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4494 if (!Location.IsNull (loc))
4495 Error_InvalidArguments (
4496 loc, j, method, delegate_type,
4497 Argument.FullDesc (a), pd.ParameterDesc (j));
4505 if (a.Type != parameter_type){
4508 conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
4511 if (!Location.IsNull (loc))
4512 Error_InvalidArguments (
4513 loc, j, method, delegate_type,
4514 Argument.FullDesc (a), pd.ParameterDesc (j));
4519 // Update the argument with the implicit conversion
4525 Parameter.Modifier a_mod = a.GetParameterModifier () &
4526 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4527 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4528 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4531 if (a_mod != p_mod &&
4532 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4533 if (!Location.IsNull (loc)) {
4534 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
4535 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
4536 Console.WriteLine ("PT: " + parameter_type.IsByRef);
4537 Report.Error (1502, loc,
4538 "The best overloaded match for method '" + FullMethodDesc (method)+
4539 "' has some invalid arguments");
4540 Report.Error (1503, loc,
4541 "Argument " + (j+1) +
4542 ": Cannot convert from '" + Argument.FullDesc (a)
4543 + "' to '" + pd.ParameterDesc (j) + "'");
4553 public override Expression DoResolve (EmitContext ec)
4556 // First, resolve the expression that is used to
4557 // trigger the invocation
4559 if (expr is BaseAccess)
4562 Expression old = expr;
4564 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4568 if (!(expr is MethodGroupExpr)) {
4569 Type expr_type = expr.Type;
4571 if (expr_type != null){
4572 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4574 return (new DelegateInvocation (
4575 this.expr, Arguments, loc)).Resolve (ec);
4579 if (!(expr is MethodGroupExpr)){
4580 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
4585 // Next, evaluate all the expressions in the argument list
4587 if (Arguments != null){
4588 foreach (Argument a in Arguments){
4589 if (!a.Resolve (ec, loc))
4594 MethodGroupExpr mg = (MethodGroupExpr) expr;
4595 method = OverloadResolve (ec, mg, Arguments, loc);
4597 if (method == null){
4599 "Could not find any applicable function for this argument list");
4603 MethodInfo mi = method as MethodInfo;
4605 type = TypeManager.TypeToCoreType (mi.ReturnType);
4606 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4607 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4610 if (type.IsPointer){
4618 // Only base will allow this invocation to happen.
4620 if (is_base && method.IsAbstract){
4621 Report.Error (205, loc, "Cannot call an abstract base member: " +
4622 FullMethodDesc (method));
4626 if ((method.Attributes & MethodAttributes.SpecialName) != 0){
4627 if (TypeManager.IsSpecialMethod (method))
4628 Report.Error (571, loc, method.Name + ": can not call operator or accessor");
4631 eclass = ExprClass.Value;
4636 // Emits the list of arguments as an array
4638 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4640 ILGenerator ig = ec.ig;
4641 int count = arguments.Count - idx;
4642 Argument a = (Argument) arguments [idx];
4643 Type t = a.Expr.Type;
4644 string array_type = t.FullName + "[]";
4647 array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4648 IntConstant.EmitInt (ig, count);
4649 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4650 ig.Emit (OpCodes.Stloc, array);
4652 int top = arguments.Count;
4653 for (int j = idx; j < top; j++){
4654 a = (Argument) arguments [j];
4656 ig.Emit (OpCodes.Ldloc, array);
4657 IntConstant.EmitInt (ig, j - idx);
4660 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
4662 ig.Emit (OpCodes.Ldelema, t);
4667 ig.Emit (OpCodes.Stobj, t);
4671 ig.Emit (OpCodes.Ldloc, array);
4675 /// Emits a list of resolved Arguments that are in the arguments
4678 /// The MethodBase argument might be null if the
4679 /// emission of the arguments is known not to contain
4680 /// a `params' field (for example in constructors or other routines
4681 /// that keep their arguments in this structure)
4683 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4687 pd = GetParameterData (mb);
4692 // If we are calling a params method with no arguments, special case it
4694 if (arguments == null){
4695 if (pd != null && pd.Count > 0 &&
4696 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4697 ILGenerator ig = ec.ig;
4699 IntConstant.EmitInt (ig, 0);
4700 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4706 int top = arguments.Count;
4708 for (int i = 0; i < top; i++){
4709 Argument a = (Argument) arguments [i];
4712 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4714 // Special case if we are passing the same data as the
4715 // params argument, do not put it in an array.
4717 if (pd.ParameterType (i) == a.Type)
4720 EmitParams (ec, i, arguments);
4728 if (pd != null && pd.Count > top &&
4729 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4730 ILGenerator ig = ec.ig;
4732 IntConstant.EmitInt (ig, 0);
4733 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4738 /// is_base tells whether we want to force the use of the `call'
4739 /// opcode instead of using callvirt. Call is required to call
4740 /// a specific method, while callvirt will always use the most
4741 /// recent method in the vtable.
4743 /// is_static tells whether this is an invocation on a static method
4745 /// instance_expr is an expression that represents the instance
4746 /// it must be non-null if is_static is false.
4748 /// method is the method to invoke.
4750 /// Arguments is the list of arguments to pass to the method or constructor.
4752 public static void EmitCall (EmitContext ec, bool is_base,
4753 bool is_static, Expression instance_expr,
4754 MethodBase method, ArrayList Arguments, Location loc)
4756 ILGenerator ig = ec.ig;
4757 bool struct_call = false;
4759 Type decl_type = method.DeclaringType;
4761 if (!RootContext.StdLib) {
4762 // Replace any calls to the system's System.Array type with calls to
4763 // the newly created one.
4764 if (method == TypeManager.system_int_array_get_length)
4765 method = TypeManager.int_array_get_length;
4766 else if (method == TypeManager.system_int_array_get_rank)
4767 method = TypeManager.int_array_get_rank;
4768 else if (method == TypeManager.system_object_array_clone)
4769 method = TypeManager.object_array_clone;
4770 else if (method == TypeManager.system_int_array_get_length_int)
4771 method = TypeManager.int_array_get_length_int;
4772 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4773 method = TypeManager.int_array_get_lower_bound_int;
4774 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4775 method = TypeManager.int_array_get_upper_bound_int;
4776 else if (method == TypeManager.system_void_array_copyto_array_int)
4777 method = TypeManager.void_array_copyto_array_int;
4781 // This checks the `ConditionalAttribute' on the method, and the
4782 // ObsoleteAttribute
4784 TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4785 if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4787 if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4791 if (decl_type.IsValueType)
4794 // If this is ourselves, push "this"
4796 if (instance_expr == null){
4797 ig.Emit (OpCodes.Ldarg_0);
4800 // Push the instance expression
4802 if (instance_expr.Type.IsValueType){
4804 // Special case: calls to a function declared in a
4805 // reference-type with a value-type argument need
4806 // to have their value boxed.
4809 if (decl_type.IsValueType){
4811 // If the expression implements IMemoryLocation, then
4812 // we can optimize and use AddressOf on the
4815 // If not we have to use some temporary storage for
4817 if (instance_expr is IMemoryLocation){
4818 ((IMemoryLocation)instance_expr).
4819 AddressOf (ec, AddressOp.LoadStore);
4822 Type t = instance_expr.Type;
4824 instance_expr.Emit (ec);
4825 LocalBuilder temp = ig.DeclareLocal (t);
4826 ig.Emit (OpCodes.Stloc, temp);
4827 ig.Emit (OpCodes.Ldloca, temp);
4830 instance_expr.Emit (ec);
4831 ig.Emit (OpCodes.Box, instance_expr.Type);
4834 instance_expr.Emit (ec);
4838 EmitArguments (ec, method, Arguments);
4840 if (is_static || struct_call || is_base){
4841 if (method is MethodInfo) {
4842 ig.Emit (OpCodes.Call, (MethodInfo) method);
4844 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4846 if (method is MethodInfo)
4847 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4849 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4853 public override void Emit (EmitContext ec)
4855 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4857 EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4860 public override void EmitStatement (EmitContext ec)
4865 // Pop the return value if there is one
4867 if (method is MethodInfo){
4868 Type ret = ((MethodInfo)method).ReturnType;
4869 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4870 ec.ig.Emit (OpCodes.Pop);
4876 // This class is used to "disable" the code generation for the
4877 // temporary variable when initializing value types.
4879 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4880 public void AddressOf (EmitContext ec, AddressOp Mode)
4887 /// Implements the new expression
4889 public class New : ExpressionStatement, IMemoryLocation {
4890 public readonly ArrayList Arguments;
4891 public readonly Expression RequestedType;
4893 MethodBase method = null;
4896 // If set, the new expression is for a value_target, and
4897 // we will not leave anything on the stack.
4899 Expression value_target;
4900 bool value_target_set = false;
4902 public New (Expression requested_type, ArrayList arguments, Location l)
4904 RequestedType = requested_type;
4905 Arguments = arguments;
4909 public Expression ValueTypeVariable {
4911 return value_target;
4915 value_target = value;
4916 value_target_set = true;
4921 // This function is used to disable the following code sequence for
4922 // value type initialization:
4924 // AddressOf (temporary)
4928 // Instead the provide will have provided us with the address on the
4929 // stack to store the results.
4931 static Expression MyEmptyExpression;
4933 public void DisableTemporaryValueType ()
4935 if (MyEmptyExpression == null)
4936 MyEmptyExpression = new EmptyAddressOf ();
4939 // To enable this, look into:
4940 // test-34 and test-89 and self bootstrapping.
4942 // For instance, we can avoid a copy by using `newobj'
4943 // instead of Call + Push-temp on value types.
4944 // value_target = MyEmptyExpression;
4947 public override Expression DoResolve (EmitContext ec)
4950 // The New DoResolve might be called twice when initializing field
4951 // expressions (see EmitFieldInitializers, the call to
4952 // GetInitializerExpression will perform a resolve on the expression,
4953 // and later the assign will trigger another resolution
4955 // This leads to bugs (#37014)
4960 type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
4965 bool IsDelegate = TypeManager.IsDelegateType (type);
4968 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4970 if (type.IsInterface || type.IsAbstract){
4971 Error (144, "It is not possible to create instances of interfaces or abstract classes");
4975 bool is_struct = false;
4976 is_struct = type.IsValueType;
4977 eclass = ExprClass.Value;
4980 // SRE returns a match for .ctor () on structs (the object constructor),
4981 // so we have to manually ignore it.
4983 if (is_struct && Arguments == null)
4987 ml = MemberLookupFinal (ec, null, type, ".ctor",
4988 MemberTypes.Constructor,
4989 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4994 if (! (ml is MethodGroupExpr)){
4996 ml.Error_UnexpectedKind ("method group");
5002 if (Arguments != null){
5003 foreach (Argument a in Arguments){
5004 if (!a.Resolve (ec, loc))
5009 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
5014 if (method == null) {
5015 if (!is_struct || Arguments.Count > 0) {
5016 Error (1501, String.Format (
5017 "New invocation: Can not find a constructor in `{0}' for this argument list",
5018 TypeManager.CSharpName (type)));
5026 // This DoEmit can be invoked in two contexts:
5027 // * As a mechanism that will leave a value on the stack (new object)
5028 // * As one that wont (init struct)
5030 // You can control whether a value is required on the stack by passing
5031 // need_value_on_stack. The code *might* leave a value on the stack
5032 // so it must be popped manually
5034 // If we are dealing with a ValueType, we have a few
5035 // situations to deal with:
5037 // * The target is a ValueType, and we have been provided
5038 // the instance (this is easy, we are being assigned).
5040 // * The target of New is being passed as an argument,
5041 // to a boxing operation or a function that takes a
5044 // In this case, we need to create a temporary variable
5045 // that is the argument of New.
5047 // Returns whether a value is left on the stack
5049 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5051 bool is_value_type = type.IsValueType;
5052 ILGenerator ig = ec.ig;
5057 // Allow DoEmit() to be called multiple times.
5058 // We need to create a new LocalTemporary each time since
5059 // you can't share LocalBuilders among ILGeneators.
5060 if (!value_target_set)
5061 value_target = new LocalTemporary (ec, type);
5063 ml = (IMemoryLocation) value_target;
5064 ml.AddressOf (ec, AddressOp.Store);
5068 Invocation.EmitArguments (ec, method, Arguments);
5072 ig.Emit (OpCodes.Initobj, type);
5074 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5075 if (need_value_on_stack){
5076 value_target.Emit (ec);
5081 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5086 public override void Emit (EmitContext ec)
5091 public override void EmitStatement (EmitContext ec)
5093 if (DoEmit (ec, false))
5094 ec.ig.Emit (OpCodes.Pop);
5097 public void AddressOf (EmitContext ec, AddressOp Mode)
5099 if (!type.IsValueType){
5101 // We throw an exception. So far, I believe we only need to support
5103 // foreach (int j in new StructType ())
5106 throw new Exception ("AddressOf should not be used for classes");
5109 if (!value_target_set)
5110 value_target = new LocalTemporary (ec, type);
5112 IMemoryLocation ml = (IMemoryLocation) value_target;
5113 ml.AddressOf (ec, AddressOp.Store);
5115 Invocation.EmitArguments (ec, method, Arguments);
5118 ec.ig.Emit (OpCodes.Initobj, type);
5120 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5122 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5127 /// 14.5.10.2: Represents an array creation expression.
5131 /// There are two possible scenarios here: one is an array creation
5132 /// expression that specifies the dimensions and optionally the
5133 /// initialization data and the other which does not need dimensions
5134 /// specified but where initialization data is mandatory.
5136 public class ArrayCreation : ExpressionStatement {
5137 Expression requested_base_type;
5138 ArrayList initializers;
5141 // The list of Argument types.
5142 // This is used to construct the `newarray' or constructor signature
5144 ArrayList arguments;
5147 // Method used to create the array object.
5149 MethodBase new_method = null;
5151 Type array_element_type;
5152 Type underlying_type;
5153 bool is_one_dimensional = false;
5154 bool is_builtin_type = false;
5155 bool expect_initializers = false;
5156 int num_arguments = 0;
5160 ArrayList array_data;
5165 // The number of array initializers that we can handle
5166 // via the InitializeArray method - through EmitStaticInitializers
5168 int num_automatic_initializers;
5170 const int max_automatic_initializers = 6;
5172 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5174 this.requested_base_type = requested_base_type;
5175 this.initializers = initializers;
5179 arguments = new ArrayList ();
5181 foreach (Expression e in exprs) {
5182 arguments.Add (new Argument (e, Argument.AType.Expression));
5187 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5189 this.requested_base_type = requested_base_type;
5190 this.initializers = initializers;
5194 //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
5196 //string tmp = rank.Substring (rank.LastIndexOf ("["));
5198 //dimensions = tmp.Length - 1;
5199 expect_initializers = true;
5202 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5204 StringBuilder sb = new StringBuilder (rank);
5207 for (int i = 1; i < idx_count; i++)
5212 return new ComposedCast (base_type, sb.ToString (), loc);
5215 void Error_IncorrectArrayInitializer ()
5217 Error (178, "Incorrectly structured array initializer");
5220 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5222 if (specified_dims) {
5223 Argument a = (Argument) arguments [idx];
5225 if (!a.Resolve (ec, loc))
5228 if (!(a.Expr is Constant)) {
5229 Error (150, "A constant value is expected");
5233 int value = (int) ((Constant) a.Expr).GetValue ();
5235 if (value != probe.Count) {
5236 Error_IncorrectArrayInitializer ();
5240 bounds [idx] = value;
5243 int child_bounds = -1;
5244 foreach (object o in probe) {
5245 if (o is ArrayList) {
5246 int current_bounds = ((ArrayList) o).Count;
5248 if (child_bounds == -1)
5249 child_bounds = current_bounds;
5251 else if (child_bounds != current_bounds){
5252 Error_IncorrectArrayInitializer ();
5255 if (specified_dims && (idx + 1 >= arguments.Count)){
5256 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5260 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5264 if (child_bounds != -1){
5265 Error_IncorrectArrayInitializer ();
5269 Expression tmp = (Expression) o;
5270 tmp = tmp.Resolve (ec);
5274 // Console.WriteLine ("I got: " + tmp);
5275 // Handle initialization from vars, fields etc.
5277 Expression conv = Convert.ImplicitConversionRequired (
5278 ec, tmp, underlying_type, loc);
5283 if (conv is StringConstant)
5284 array_data.Add (conv);
5285 else if (conv is Constant) {
5286 array_data.Add (conv);
5287 num_automatic_initializers++;
5289 array_data.Add (conv);
5296 public void UpdateIndices (EmitContext ec)
5299 for (ArrayList probe = initializers; probe != null;) {
5300 if (probe.Count > 0 && probe [0] is ArrayList) {
5301 Expression e = new IntConstant (probe.Count);
5302 arguments.Add (new Argument (e, Argument.AType.Expression));
5304 bounds [i++] = probe.Count;
5306 probe = (ArrayList) probe [0];
5309 Expression e = new IntConstant (probe.Count);
5310 arguments.Add (new Argument (e, Argument.AType.Expression));
5312 bounds [i++] = probe.Count;
5319 public bool ValidateInitializers (EmitContext ec, Type array_type)
5321 if (initializers == null) {
5322 if (expect_initializers)
5328 if (underlying_type == null)
5332 // We use this to store all the date values in the order in which we
5333 // will need to store them in the byte blob later
5335 array_data = new ArrayList ();
5336 bounds = new Hashtable ();
5340 if (arguments != null) {
5341 ret = CheckIndices (ec, initializers, 0, true);
5344 arguments = new ArrayList ();
5346 ret = CheckIndices (ec, initializers, 0, false);
5353 if (arguments.Count != dimensions) {
5354 Error_IncorrectArrayInitializer ();
5362 void Error_NegativeArrayIndex ()
5364 Error (284, "Can not create array with a negative size");
5368 // Converts `source' to an int, uint, long or ulong.
5370 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5374 bool old_checked = ec.CheckState;
5375 ec.CheckState = true;
5377 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
5378 if (target == null){
5379 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
5380 if (target == null){
5381 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
5382 if (target == null){
5383 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
5385 Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
5389 ec.CheckState = old_checked;
5392 // Only positive constants are allowed at compile time
5394 if (target is Constant){
5395 if (target is IntConstant){
5396 if (((IntConstant) target).Value < 0){
5397 Error_NegativeArrayIndex ();
5402 if (target is LongConstant){
5403 if (((LongConstant) target).Value < 0){
5404 Error_NegativeArrayIndex ();
5415 // Creates the type of the array
5417 bool LookupType (EmitContext ec)
5419 StringBuilder array_qualifier = new StringBuilder (rank);
5422 // `In the first form allocates an array instace of the type that results
5423 // from deleting each of the individual expression from the expression list'
5425 if (num_arguments > 0) {
5426 array_qualifier.Append ("[");
5427 for (int i = num_arguments-1; i > 0; i--)
5428 array_qualifier.Append (",");
5429 array_qualifier.Append ("]");
5435 Expression array_type_expr;
5436 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5437 type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5442 underlying_type = type;
5443 if (underlying_type.IsArray)
5444 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
5445 dimensions = type.GetArrayRank ();
5450 public override Expression DoResolve (EmitContext ec)
5454 if (!LookupType (ec))
5458 // First step is to validate the initializers and fill
5459 // in any missing bits
5461 if (!ValidateInitializers (ec, type))
5464 if (arguments == null)
5467 arg_count = arguments.Count;
5468 foreach (Argument a in arguments){
5469 if (!a.Resolve (ec, loc))
5472 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5473 if (real_arg == null)
5480 array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
5482 if (arg_count == 1) {
5483 is_one_dimensional = true;
5484 eclass = ExprClass.Value;
5488 is_builtin_type = TypeManager.IsBuiltinType (type);
5490 if (is_builtin_type) {
5493 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5494 AllBindingFlags, loc);
5496 if (!(ml is MethodGroupExpr)) {
5497 ml.Error_UnexpectedKind ("method group");
5502 Error (-6, "New invocation: Can not find a constructor for " +
5503 "this argument list");
5507 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5509 if (new_method == null) {
5510 Error (-6, "New invocation: Can not find a constructor for " +
5511 "this argument list");
5515 eclass = ExprClass.Value;
5518 ModuleBuilder mb = CodeGen.ModuleBuilder;
5519 ArrayList args = new ArrayList ();
5521 if (arguments != null) {
5522 for (int i = 0; i < arg_count; i++)
5523 args.Add (TypeManager.int32_type);
5526 Type [] arg_types = null;
5529 arg_types = new Type [args.Count];
5531 args.CopyTo (arg_types, 0);
5533 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5536 if (new_method == null) {
5537 Error (-6, "New invocation: Can not find a constructor for " +
5538 "this argument list");
5542 eclass = ExprClass.Value;
5547 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5552 int count = array_data.Count;
5554 if (underlying_type.IsEnum)
5555 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5557 factor = GetTypeSize (underlying_type);
5559 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5561 data = new byte [(count * factor + 4) & ~3];
5564 for (int i = 0; i < count; ++i) {
5565 object v = array_data [i];
5567 if (v is EnumConstant)
5568 v = ((EnumConstant) v).Child;
5570 if (v is Constant && !(v is StringConstant))
5571 v = ((Constant) v).GetValue ();
5577 if (underlying_type == TypeManager.int64_type){
5578 if (!(v is Expression)){
5579 long val = (long) v;
5581 for (int j = 0; j < factor; ++j) {
5582 data [idx + j] = (byte) (val & 0xFF);
5586 } else if (underlying_type == TypeManager.uint64_type){
5587 if (!(v is Expression)){
5588 ulong val = (ulong) v;
5590 for (int j = 0; j < factor; ++j) {
5591 data [idx + j] = (byte) (val & 0xFF);
5595 } else if (underlying_type == TypeManager.float_type) {
5596 if (!(v is Expression)){
5597 element = BitConverter.GetBytes ((float) v);
5599 for (int j = 0; j < factor; ++j)
5600 data [idx + j] = element [j];
5602 } else if (underlying_type == TypeManager.double_type) {
5603 if (!(v is Expression)){
5604 element = BitConverter.GetBytes ((double) v);
5606 for (int j = 0; j < factor; ++j)
5607 data [idx + j] = element [j];
5609 } else if (underlying_type == TypeManager.char_type){
5610 if (!(v is Expression)){
5611 int val = (int) ((char) v);
5613 data [idx] = (byte) (val & 0xff);
5614 data [idx+1] = (byte) (val >> 8);
5616 } else if (underlying_type == TypeManager.short_type){
5617 if (!(v is Expression)){
5618 int val = (int) ((short) v);
5620 data [idx] = (byte) (val & 0xff);
5621 data [idx+1] = (byte) (val >> 8);
5623 } else if (underlying_type == TypeManager.ushort_type){
5624 if (!(v is Expression)){
5625 int val = (int) ((ushort) v);
5627 data [idx] = (byte) (val & 0xff);
5628 data [idx+1] = (byte) (val >> 8);
5630 } else if (underlying_type == TypeManager.int32_type) {
5631 if (!(v is Expression)){
5634 data [idx] = (byte) (val & 0xff);
5635 data [idx+1] = (byte) ((val >> 8) & 0xff);
5636 data [idx+2] = (byte) ((val >> 16) & 0xff);
5637 data [idx+3] = (byte) (val >> 24);
5639 } else if (underlying_type == TypeManager.uint32_type) {
5640 if (!(v is Expression)){
5641 uint val = (uint) v;
5643 data [idx] = (byte) (val & 0xff);
5644 data [idx+1] = (byte) ((val >> 8) & 0xff);
5645 data [idx+2] = (byte) ((val >> 16) & 0xff);
5646 data [idx+3] = (byte) (val >> 24);
5648 } else if (underlying_type == TypeManager.sbyte_type) {
5649 if (!(v is Expression)){
5650 sbyte val = (sbyte) v;
5651 data [idx] = (byte) val;
5653 } else if (underlying_type == TypeManager.byte_type) {
5654 if (!(v is Expression)){
5655 byte val = (byte) v;
5656 data [idx] = (byte) val;
5658 } else if (underlying_type == TypeManager.bool_type) {
5659 if (!(v is Expression)){
5660 bool val = (bool) v;
5661 data [idx] = (byte) (val ? 1 : 0);
5663 } else if (underlying_type == TypeManager.decimal_type){
5664 if (!(v is Expression)){
5665 int [] bits = Decimal.GetBits ((decimal) v);
5668 for (int j = 0; j < 4; j++){
5669 data [p++] = (byte) (bits [j] & 0xff);
5670 data [p++] = (byte) ((bits [j] >> 8) & 0xff);
5671 data [p++] = (byte) ((bits [j] >> 16) & 0xff);
5672 data [p++] = (byte) (bits [j] >> 24);
5676 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5685 // Emits the initializers for the array
5687 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5690 // First, the static data
5693 ILGenerator ig = ec.ig;
5695 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5697 fb = RootContext.MakeStaticData (data);
5700 ig.Emit (OpCodes.Dup);
5701 ig.Emit (OpCodes.Ldtoken, fb);
5702 ig.Emit (OpCodes.Call,
5703 TypeManager.void_initializearray_array_fieldhandle);
5707 // Emits pieces of the array that can not be computed at compile
5708 // time (variables and string locations).
5710 // This always expect the top value on the stack to be the array
5712 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5714 ILGenerator ig = ec.ig;
5715 int dims = bounds.Count;
5716 int [] current_pos = new int [dims];
5717 int top = array_data.Count;
5718 LocalBuilder temp = ig.DeclareLocal (type);
5720 ig.Emit (OpCodes.Stloc, temp);
5722 MethodInfo set = null;
5726 ModuleBuilder mb = null;
5727 mb = CodeGen.ModuleBuilder;
5728 args = new Type [dims + 1];
5731 for (j = 0; j < dims; j++)
5732 args [j] = TypeManager.int32_type;
5734 args [j] = array_element_type;
5736 set = mb.GetArrayMethod (
5738 CallingConventions.HasThis | CallingConventions.Standard,
5739 TypeManager.void_type, args);
5742 for (int i = 0; i < top; i++){
5744 Expression e = null;
5746 if (array_data [i] is Expression)
5747 e = (Expression) array_data [i];
5751 // Basically we do this for string literals and
5752 // other non-literal expressions
5754 if (e is EnumConstant){
5755 e = ((EnumConstant) e).Child;
5758 if (e is StringConstant || !(e is Constant) ||
5759 num_automatic_initializers <= max_automatic_initializers) {
5760 Type etype = e.Type;
5762 ig.Emit (OpCodes.Ldloc, temp);
5764 for (int idx = 0; idx < dims; idx++)
5765 IntConstant.EmitInt (ig, current_pos [idx]);
5768 // If we are dealing with a struct, get the
5769 // address of it, so we can store it.
5772 etype.IsSubclassOf (TypeManager.value_type) &&
5773 (!TypeManager.IsBuiltinType (etype) ||
5774 etype == TypeManager.decimal_type)) {
5779 // Let new know that we are providing
5780 // the address where to store the results
5782 n.DisableTemporaryValueType ();
5785 ig.Emit (OpCodes.Ldelema, etype);
5791 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
5793 ig.Emit (OpCodes.Call, set);
5801 for (int j = dims - 1; j >= 0; j--){
5803 if (current_pos [j] < (int) bounds [j])
5805 current_pos [j] = 0;
5810 ig.Emit (OpCodes.Ldloc, temp);
5813 void EmitArrayArguments (EmitContext ec)
5815 ILGenerator ig = ec.ig;
5817 foreach (Argument a in arguments) {
5818 Type atype = a.Type;
5821 if (atype == TypeManager.uint64_type)
5822 ig.Emit (OpCodes.Conv_Ovf_U4);
5823 else if (atype == TypeManager.int64_type)
5824 ig.Emit (OpCodes.Conv_Ovf_I4);
5828 void DoEmit (EmitContext ec, bool is_statement)
5830 ILGenerator ig = ec.ig;
5832 EmitArrayArguments (ec);
5833 if (is_one_dimensional)
5834 ig.Emit (OpCodes.Newarr, array_element_type);
5836 if (is_builtin_type)
5837 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
5839 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
5842 if (initializers != null){
5844 // FIXME: Set this variable correctly.
5846 bool dynamic_initializers = true;
5848 if (underlying_type != TypeManager.string_type &&
5849 underlying_type != TypeManager.object_type) {
5850 if (num_automatic_initializers > max_automatic_initializers)
5851 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
5854 if (dynamic_initializers)
5855 EmitDynamicInitializers (ec, !is_statement);
5859 public override void Emit (EmitContext ec)
5864 public override void EmitStatement (EmitContext ec)
5869 public object EncodeAsAttribute ()
5871 if (!is_one_dimensional){
5872 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
5876 if (array_data == null){
5877 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
5881 object [] ret = new object [array_data.Count];
5883 foreach (Expression e in array_data){
5886 if (e is NullLiteral)
5889 if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
5899 /// Represents the `this' construct
5901 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
5904 VariableInfo variable_info;
5906 public This (Block block, Location loc)
5912 public This (Location loc)
5917 public VariableInfo VariableInfo {
5918 get { return variable_info; }
5921 public bool ResolveBase (EmitContext ec)
5923 eclass = ExprClass.Variable;
5924 type = ec.ContainerType;
5927 Error (26, "Keyword this not valid in static code");
5931 if ((block != null) && (block.ThisVariable != null))
5932 variable_info = block.GetVariableInfo (block.ThisVariable);
5937 public override Expression DoResolve (EmitContext ec)
5939 if (!ResolveBase (ec))
5942 if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
5943 Error (188, "The this object cannot be used before all " +
5944 "of its fields are assigned to");
5945 variable_info.SetAssigned (ec);
5949 if (ec.IsFieldInitializer) {
5950 Error (27, "Keyword `this' can't be used outside a constructor, " +
5951 "a method or a property.");
5958 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5960 if (!ResolveBase (ec))
5963 if (variable_info != null)
5964 variable_info.SetAssigned (ec);
5966 if (ec.TypeContainer is Class){
5967 Error (1604, "Cannot assign to `this'");
5974 public override void Emit (EmitContext ec)
5976 ILGenerator ig = ec.ig;
5978 ig.Emit (OpCodes.Ldarg_0);
5979 if (ec.TypeContainer is Struct)
5980 ig.Emit (OpCodes.Ldobj, type);
5983 public void EmitAssign (EmitContext ec, Expression source)
5985 ILGenerator ig = ec.ig;
5987 if (ec.TypeContainer is Struct){
5988 ig.Emit (OpCodes.Ldarg_0);
5990 ig.Emit (OpCodes.Stobj, type);
5993 ig.Emit (OpCodes.Starg, 0);
5997 public void AddressOf (EmitContext ec, AddressOp mode)
5999 ec.ig.Emit (OpCodes.Ldarg_0);
6002 // FIGURE OUT WHY LDARG_S does not work
6004 // consider: struct X { int val; int P { set { val = value; }}}
6006 // Yes, this looks very bad. Look at `NOTAS' for
6008 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6013 /// Implements the typeof operator
6015 public class TypeOf : Expression {
6016 public readonly Expression QueriedType;
6019 public TypeOf (Expression queried_type, Location l)
6021 QueriedType = queried_type;
6025 public override Expression DoResolve (EmitContext ec)
6027 typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6029 if (typearg == null)
6032 type = TypeManager.type_type;
6033 eclass = ExprClass.Type;
6037 public override void Emit (EmitContext ec)
6039 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6040 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6043 public Type TypeArg {
6044 get { return typearg; }
6049 /// Implements the sizeof expression
6051 public class SizeOf : Expression {
6052 public readonly Expression QueriedType;
6055 public SizeOf (Expression queried_type, Location l)
6057 this.QueriedType = queried_type;
6061 public override Expression DoResolve (EmitContext ec)
6065 233, loc, "Sizeof may only be used in an unsafe context " +
6066 "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
6070 type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6071 if (type_queried == null)
6074 if (!TypeManager.IsUnmanagedType (type_queried)){
6075 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6079 type = TypeManager.int32_type;
6080 eclass = ExprClass.Value;
6084 public override void Emit (EmitContext ec)
6086 int size = GetTypeSize (type_queried);
6089 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6091 IntConstant.EmitInt (ec.ig, size);
6096 /// Implements the member access expression
6098 public class MemberAccess : Expression {
6099 public readonly string Identifier;
6102 public MemberAccess (Expression expr, string id, Location l)
6109 public Expression Expr {
6115 static void error176 (Location loc, string name)
6117 Report.Error (176, loc, "Static member `" +
6118 name + "' cannot be accessed " +
6119 "with an instance reference, qualify with a " +
6120 "type name instead");
6123 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6125 if (left_original == null)
6128 if (!(left_original is SimpleName))
6131 SimpleName sn = (SimpleName) left_original;
6133 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6140 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6141 Expression left, Location loc,
6142 Expression left_original)
6144 bool left_is_type, left_is_explicit;
6146 // If `left' is null, then we're called from SimpleNameResolve and this is
6147 // a member in the currently defining class.
6149 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6150 left_is_explicit = false;
6152 // Implicitly default to `this' unless we're static.
6153 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6156 left_is_type = left is TypeExpr;
6157 left_is_explicit = true;
6160 if (member_lookup is FieldExpr){
6161 FieldExpr fe = (FieldExpr) member_lookup;
6162 FieldInfo fi = fe.FieldInfo;
6163 Type decl_type = fi.DeclaringType;
6165 if (fi is FieldBuilder) {
6166 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6169 object o = c.LookupConstantValue ();
6173 object real_value = ((Constant) c.Expr).GetValue ();
6175 return Constantify (real_value, fi.FieldType);
6180 Type t = fi.FieldType;
6184 if (fi is FieldBuilder)
6185 o = TypeManager.GetValue ((FieldBuilder) fi);
6187 o = fi.GetValue (fi);
6189 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6190 if (left_is_explicit && !left_is_type &&
6191 !IdenticalNameAndTypeName (ec, left_original, loc)) {
6192 error176 (loc, fe.FieldInfo.Name);
6196 Expression enum_member = MemberLookup (
6197 ec, decl_type, "value__", MemberTypes.Field,
6198 AllBindingFlags, loc);
6200 Enum en = TypeManager.LookupEnum (decl_type);
6204 c = Constantify (o, en.UnderlyingType);
6206 c = Constantify (o, enum_member.Type);
6208 return new EnumConstant (c, decl_type);
6211 Expression exp = Constantify (o, t);
6213 if (left_is_explicit && !left_is_type) {
6214 error176 (loc, fe.FieldInfo.Name);
6221 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6227 if (member_lookup is EventExpr) {
6229 EventExpr ee = (EventExpr) member_lookup;
6232 // If the event is local to this class, we transform ourselves into
6236 if (ee.EventInfo.DeclaringType == ec.ContainerType) {
6237 MemberInfo mi = GetFieldFromEvent (ee);
6241 // If this happens, then we have an event with its own
6242 // accessors and private field etc so there's no need
6243 // to transform ourselves : we should instead flag an error
6245 Assign.error70 (ee.EventInfo, loc);
6249 Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
6252 Report.Error (-200, loc, "Internal error!!");
6256 return ResolveMemberAccess (ec, ml, left, loc, left_original);
6260 if (member_lookup is IMemberExpr) {
6261 IMemberExpr me = (IMemberExpr) member_lookup;
6264 MethodGroupExpr mg = me as MethodGroupExpr;
6265 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6266 mg.IsExplicitImpl = left_is_explicit;
6269 if (IdenticalNameAndTypeName (ec, left_original, loc))
6270 return member_lookup;
6272 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6277 if (!me.IsInstance){
6278 if (IdenticalNameAndTypeName (ec, left_original, loc))
6279 return member_lookup;
6281 if (left_is_explicit) {
6282 error176 (loc, me.Name);
6288 // Since we can not check for instance objects in SimpleName,
6289 // becaue of the rule that allows types and variables to share
6290 // the name (as long as they can be de-ambiguated later, see
6291 // IdenticalNameAndTypeName), we have to check whether left
6292 // is an instance variable in a static context
6294 // However, if the left-hand value is explicitly given, then
6295 // it is already our instance expression, so we aren't in
6299 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6300 IMemberExpr mexp = (IMemberExpr) left;
6302 if (!mexp.IsStatic){
6303 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6308 me.InstanceExpression = left;
6311 return member_lookup;
6314 Console.WriteLine ("Left is: " + left);
6315 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6316 Environment.Exit (0);
6320 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6323 throw new Exception ();
6326 // Resolve the expression with flow analysis turned off, we'll do the definite
6327 // assignment checks later. This is because we don't know yet what the expression
6328 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6329 // definite assignment check on the actual field and not on the whole struct.
6332 Expression original = expr;
6333 expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6337 if (expr is SimpleName){
6338 SimpleName child_expr = (SimpleName) expr;
6340 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6342 return new_expr.Resolve (ec, flags);
6346 // TODO: I mailed Ravi about this, and apparently we can get rid
6347 // of this and put it in the right place.
6349 // Handle enums here when they are in transit.
6350 // Note that we cannot afford to hit MemberLookup in this case because
6351 // it will fail to find any members at all
6354 int errors = Report.Errors;
6356 Type expr_type = expr.Type;
6357 if (expr is TypeExpr){
6358 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
6359 Error (122, "`" + expr_type + "' " +
6360 "is inaccessible because of its protection level");
6364 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6365 Enum en = TypeManager.LookupEnum (expr_type);
6368 object value = en.LookupEnumValue (ec, Identifier, loc);
6371 Constant c = Constantify (value, en.UnderlyingType);
6372 return new EnumConstant (c, expr_type);
6378 if (expr_type.IsPointer){
6379 Error (23, "The `.' operator can not be applied to pointer operands (" +
6380 TypeManager.CSharpName (expr_type) + ")");
6384 Expression member_lookup;
6385 member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6386 if (member_lookup == null)
6389 if (member_lookup is TypeExpr)
6390 return member_lookup;
6392 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6393 if (member_lookup == null)
6396 // The following DoResolve/DoResolveLValue will do the definite assignment
6399 if (right_side != null)
6400 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6402 member_lookup = member_lookup.DoResolve (ec);
6404 return member_lookup;
6407 public override Expression DoResolve (EmitContext ec)
6409 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6410 ResolveFlags.SimpleName | ResolveFlags.Type);
6413 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6415 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6416 ResolveFlags.SimpleName | ResolveFlags.Type);
6419 public override Expression ResolveAsTypeStep (EmitContext ec)
6421 Expression new_expr = expr.ResolveAsTypeStep (ec);
6423 if (new_expr == null)
6426 if (new_expr is SimpleName){
6427 SimpleName child_expr = (SimpleName) new_expr;
6429 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6431 return new_expr.ResolveAsTypeStep (ec);
6434 Type expr_type = new_expr.Type;
6436 if (expr_type.IsPointer){
6437 Error (23, "The `.' operator can not be applied to pointer operands (" +
6438 TypeManager.CSharpName (expr_type) + ")");
6442 Expression member_lookup;
6443 member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6444 if (member_lookup == null)
6447 if (member_lookup is TypeExpr){
6448 member_lookup.Resolve (ec, ResolveFlags.Type);
6449 return member_lookup;
6455 public override void Emit (EmitContext ec)
6457 throw new Exception ("Should not happen");
6460 public override string ToString ()
6462 return expr + "." + Identifier;
6467 /// Implements checked expressions
6469 public class CheckedExpr : Expression {
6471 public Expression Expr;
6473 public CheckedExpr (Expression e, Location l)
6479 public override Expression DoResolve (EmitContext ec)
6481 bool last_check = ec.CheckState;
6482 bool last_const_check = ec.ConstantCheckState;
6484 ec.CheckState = true;
6485 ec.ConstantCheckState = true;
6486 Expr = Expr.Resolve (ec);
6487 ec.CheckState = last_check;
6488 ec.ConstantCheckState = last_const_check;
6493 if (Expr is Constant)
6496 eclass = Expr.eclass;
6501 public override void Emit (EmitContext ec)
6503 bool last_check = ec.CheckState;
6504 bool last_const_check = ec.ConstantCheckState;
6506 ec.CheckState = true;
6507 ec.ConstantCheckState = true;
6509 ec.CheckState = last_check;
6510 ec.ConstantCheckState = last_const_check;
6516 /// Implements the unchecked expression
6518 public class UnCheckedExpr : Expression {
6520 public Expression Expr;
6522 public UnCheckedExpr (Expression e, Location l)
6528 public override Expression DoResolve (EmitContext ec)
6530 bool last_check = ec.CheckState;
6531 bool last_const_check = ec.ConstantCheckState;
6533 ec.CheckState = false;
6534 ec.ConstantCheckState = false;
6535 Expr = Expr.Resolve (ec);
6536 ec.CheckState = last_check;
6537 ec.ConstantCheckState = last_const_check;
6542 if (Expr is Constant)
6545 eclass = Expr.eclass;
6550 public override void Emit (EmitContext ec)
6552 bool last_check = ec.CheckState;
6553 bool last_const_check = ec.ConstantCheckState;
6555 ec.CheckState = false;
6556 ec.ConstantCheckState = false;
6558 ec.CheckState = last_check;
6559 ec.ConstantCheckState = last_const_check;
6565 /// An Element Access expression.
6567 /// During semantic analysis these are transformed into
6568 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
6570 public class ElementAccess : Expression {
6571 public ArrayList Arguments;
6572 public Expression Expr;
6574 public ElementAccess (Expression e, ArrayList e_list, Location l)
6583 Arguments = new ArrayList ();
6584 foreach (Expression tmp in e_list)
6585 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6589 bool CommonResolve (EmitContext ec)
6591 Expr = Expr.Resolve (ec);
6596 if (Arguments == null)
6599 foreach (Argument a in Arguments){
6600 if (!a.Resolve (ec, loc))
6607 Expression MakePointerAccess ()
6611 if (t == TypeManager.void_ptr_type){
6612 Error (242, "The array index operation is not valid for void pointers");
6615 if (Arguments.Count != 1){
6616 Error (196, "A pointer must be indexed by a single value");
6621 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
6622 return new Indirection (p, loc);
6625 public override Expression DoResolve (EmitContext ec)
6627 if (!CommonResolve (ec))
6631 // We perform some simple tests, and then to "split" the emit and store
6632 // code we create an instance of a different class, and return that.
6634 // I am experimenting with this pattern.
6638 if (t == TypeManager.array_type){
6639 Report.Error (21, loc, "Cannot use indexer on System.Array");
6644 return (new ArrayAccess (this, loc)).Resolve (ec);
6645 else if (t.IsPointer)
6646 return MakePointerAccess ();
6648 return (new IndexerAccess (this, loc)).Resolve (ec);
6651 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6653 if (!CommonResolve (ec))
6658 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
6659 else if (t.IsPointer)
6660 return MakePointerAccess ();
6662 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
6665 public override void Emit (EmitContext ec)
6667 throw new Exception ("Should never be reached");
6672 /// Implements array access
6674 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
6676 // Points to our "data" repository
6680 LocalTemporary [] cached_locations;
6682 public ArrayAccess (ElementAccess ea_data, Location l)
6685 eclass = ExprClass.Variable;
6689 public override Expression DoResolve (EmitContext ec)
6691 ExprClass eclass = ea.Expr.eclass;
6694 // As long as the type is valid
6695 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
6696 eclass == ExprClass.Value)) {
6697 ea.Expr.Error_UnexpectedKind ("variable or value");
6702 Type t = ea.Expr.Type;
6703 if (t.GetArrayRank () != ea.Arguments.Count){
6705 "Incorrect number of indexes for array " +
6706 " expected: " + t.GetArrayRank () + " got: " +
6707 ea.Arguments.Count);
6710 type = TypeManager.TypeToCoreType (t.GetElementType ());
6711 if (type.IsPointer && !ec.InUnsafe){
6712 UnsafeError (ea.Location);
6716 foreach (Argument a in ea.Arguments){
6717 Type argtype = a.Type;
6719 if (argtype == TypeManager.int32_type ||
6720 argtype == TypeManager.uint32_type ||
6721 argtype == TypeManager.int64_type ||
6722 argtype == TypeManager.uint64_type)
6726 // Mhm. This is strage, because the Argument.Type is not the same as
6727 // Argument.Expr.Type: the value changes depending on the ref/out setting.
6729 // Wonder if I will run into trouble for this.
6731 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
6736 eclass = ExprClass.Variable;
6742 /// Emits the right opcode to load an object of Type `t'
6743 /// from an array of T
6745 static public void EmitLoadOpcode (ILGenerator ig, Type type)
6747 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
6748 ig.Emit (OpCodes.Ldelem_U1);
6749 else if (type == TypeManager.sbyte_type)
6750 ig.Emit (OpCodes.Ldelem_I1);
6751 else if (type == TypeManager.short_type)
6752 ig.Emit (OpCodes.Ldelem_I2);
6753 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
6754 ig.Emit (OpCodes.Ldelem_U2);
6755 else if (type == TypeManager.int32_type)
6756 ig.Emit (OpCodes.Ldelem_I4);
6757 else if (type == TypeManager.uint32_type)
6758 ig.Emit (OpCodes.Ldelem_U4);
6759 else if (type == TypeManager.uint64_type)
6760 ig.Emit (OpCodes.Ldelem_I8);
6761 else if (type == TypeManager.int64_type)
6762 ig.Emit (OpCodes.Ldelem_I8);
6763 else if (type == TypeManager.float_type)
6764 ig.Emit (OpCodes.Ldelem_R4);
6765 else if (type == TypeManager.double_type)
6766 ig.Emit (OpCodes.Ldelem_R8);
6767 else if (type == TypeManager.intptr_type)
6768 ig.Emit (OpCodes.Ldelem_I);
6769 else if (type.IsValueType){
6770 ig.Emit (OpCodes.Ldelema, type);
6771 ig.Emit (OpCodes.Ldobj, type);
6773 ig.Emit (OpCodes.Ldelem_Ref);
6777 /// Emits the right opcode to store an object of Type `t'
6778 /// from an array of T.
6780 static public void EmitStoreOpcode (ILGenerator ig, Type t)
6783 OpCode op = GetStoreOpcode (t, out is_stobj);
6785 ig.Emit (OpCodes.Stobj, t);
6791 /// Returns the right opcode to store an object of Type `t'
6792 /// from an array of T.
6794 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
6796 //Console.WriteLine (new System.Diagnostics.StackTrace ());
6798 t = TypeManager.TypeToCoreType (t);
6799 if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
6800 t = TypeManager.EnumToUnderlying (t);
6801 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
6802 t == TypeManager.bool_type)
6803 return OpCodes.Stelem_I1;
6804 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
6805 t == TypeManager.char_type)
6806 return OpCodes.Stelem_I2;
6807 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
6808 return OpCodes.Stelem_I4;
6809 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
6810 return OpCodes.Stelem_I8;
6811 else if (t == TypeManager.float_type)
6812 return OpCodes.Stelem_R4;
6813 else if (t == TypeManager.double_type)
6814 return OpCodes.Stelem_R8;
6815 else if (t == TypeManager.intptr_type) {
6817 return OpCodes.Stobj;
6818 } else if (t.IsValueType) {
6820 return OpCodes.Stobj;
6822 return OpCodes.Stelem_Ref;
6825 MethodInfo FetchGetMethod ()
6827 ModuleBuilder mb = CodeGen.ModuleBuilder;
6828 int arg_count = ea.Arguments.Count;
6829 Type [] args = new Type [arg_count];
6832 for (int i = 0; i < arg_count; i++){
6833 //args [i++] = a.Type;
6834 args [i] = TypeManager.int32_type;
6837 get = mb.GetArrayMethod (
6838 ea.Expr.Type, "Get",
6839 CallingConventions.HasThis |
6840 CallingConventions.Standard,
6846 MethodInfo FetchAddressMethod ()
6848 ModuleBuilder mb = CodeGen.ModuleBuilder;
6849 int arg_count = ea.Arguments.Count;
6850 Type [] args = new Type [arg_count];
6854 ret_type = TypeManager.GetReferenceType (type);
6856 for (int i = 0; i < arg_count; i++){
6857 //args [i++] = a.Type;
6858 args [i] = TypeManager.int32_type;
6861 address = mb.GetArrayMethod (
6862 ea.Expr.Type, "Address",
6863 CallingConventions.HasThis |
6864 CallingConventions.Standard,
6871 // Load the array arguments into the stack.
6873 // If we have been requested to cache the values (cached_locations array
6874 // initialized), then load the arguments the first time and store them
6875 // in locals. otherwise load from local variables.
6877 void LoadArrayAndArguments (EmitContext ec)
6879 ILGenerator ig = ec.ig;
6881 if (cached_locations == null){
6883 foreach (Argument a in ea.Arguments){
6884 Type argtype = a.Expr.Type;
6888 if (argtype == TypeManager.int64_type)
6889 ig.Emit (OpCodes.Conv_Ovf_I);
6890 else if (argtype == TypeManager.uint64_type)
6891 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6896 if (cached_locations [0] == null){
6897 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
6899 ig.Emit (OpCodes.Dup);
6900 cached_locations [0].Store (ec);
6904 foreach (Argument a in ea.Arguments){
6905 Type argtype = a.Expr.Type;
6907 cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
6909 if (argtype == TypeManager.int64_type)
6910 ig.Emit (OpCodes.Conv_Ovf_I);
6911 else if (argtype == TypeManager.uint64_type)
6912 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6914 ig.Emit (OpCodes.Dup);
6915 cached_locations [j].Store (ec);
6921 foreach (LocalTemporary lt in cached_locations)
6925 public new void CacheTemporaries (EmitContext ec)
6927 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
6930 public override void Emit (EmitContext ec)
6932 int rank = ea.Expr.Type.GetArrayRank ();
6933 ILGenerator ig = ec.ig;
6935 LoadArrayAndArguments (ec);
6938 EmitLoadOpcode (ig, type);
6942 method = FetchGetMethod ();
6943 ig.Emit (OpCodes.Call, method);
6947 public void EmitAssign (EmitContext ec, Expression source)
6949 int rank = ea.Expr.Type.GetArrayRank ();
6950 ILGenerator ig = ec.ig;
6951 Type t = source.Type;
6953 LoadArrayAndArguments (ec);
6956 // The stobj opcode used by value types will need
6957 // an address on the stack, not really an array/array
6961 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
6962 (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
6963 ig.Emit (OpCodes.Ldelema, t);
6969 EmitStoreOpcode (ig, t);
6971 ModuleBuilder mb = CodeGen.ModuleBuilder;
6972 int arg_count = ea.Arguments.Count;
6973 Type [] args = new Type [arg_count + 1];
6976 for (int i = 0; i < arg_count; i++){
6977 //args [i++] = a.Type;
6978 args [i] = TypeManager.int32_type;
6981 args [arg_count] = type;
6983 set = mb.GetArrayMethod (
6984 ea.Expr.Type, "Set",
6985 CallingConventions.HasThis |
6986 CallingConventions.Standard,
6987 TypeManager.void_type, args);
6989 ig.Emit (OpCodes.Call, set);
6993 public void AddressOf (EmitContext ec, AddressOp mode)
6995 int rank = ea.Expr.Type.GetArrayRank ();
6996 ILGenerator ig = ec.ig;
6998 LoadArrayAndArguments (ec);
7001 ig.Emit (OpCodes.Ldelema, type);
7003 MethodInfo address = FetchAddressMethod ();
7004 ig.Emit (OpCodes.Call, address);
7011 public ArrayList properties;
7012 static Hashtable map;
7016 map = new Hashtable ();
7021 properties = new ArrayList ();
7024 void Append (MemberInfo [] mi)
7026 foreach (PropertyInfo property in mi){
7027 MethodInfo get, set;
7029 get = property.GetGetMethod (true);
7030 set = property.GetSetMethod (true);
7031 properties.Add (new Pair (get, set));
7035 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7037 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7039 MemberInfo [] mi = TypeManager.MemberLookup (
7040 caller_type, caller_type, lookup_type, MemberTypes.Property,
7041 BindingFlags.Public | BindingFlags.Instance |
7042 BindingFlags.DeclaredOnly, p_name);
7044 if (mi == null || mi.Length == 0)
7050 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
7052 Indexers ix = (Indexers) map [lookup_type];
7057 Type copy = lookup_type;
7058 while (copy != TypeManager.object_type && copy != null){
7059 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
7063 ix = new Indexers ();
7068 copy = copy.BaseType;
7071 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7072 if (ifaces != null) {
7073 foreach (Type itype in ifaces) {
7074 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
7077 ix = new Indexers ();
7089 /// Expressions that represent an indexer call.
7091 public class IndexerAccess : Expression, IAssignMethod {
7093 // Points to our "data" repository
7095 MethodInfo get, set;
7096 ArrayList set_arguments;
7097 bool is_base_indexer;
7099 protected Type indexer_type;
7100 protected Type current_type;
7101 protected Expression instance_expr;
7102 protected ArrayList arguments;
7104 public IndexerAccess (ElementAccess ea, Location loc)
7105 : this (ea.Expr, false, loc)
7107 this.arguments = ea.Arguments;
7110 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7113 this.instance_expr = instance_expr;
7114 this.is_base_indexer = is_base_indexer;
7115 this.eclass = ExprClass.Value;
7119 protected virtual bool CommonResolve (EmitContext ec)
7121 indexer_type = instance_expr.Type;
7122 current_type = ec.ContainerType;
7127 public override Expression DoResolve (EmitContext ec)
7129 ArrayList AllGetters = new ArrayList();
7130 if (!CommonResolve (ec))
7134 // Step 1: Query for all `Item' *properties*. Notice
7135 // that the actual methods are pointed from here.
7137 // This is a group of properties, piles of them.
7139 bool found_any = false, found_any_getters = false;
7140 Type lookup_type = indexer_type;
7143 ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
7144 if (ilist != null) {
7146 if (ilist.properties != null) {
7147 foreach (Pair o in ilist.properties) {
7148 if (o.First != null)
7149 AllGetters.Add(o.First);
7154 if (AllGetters.Count > 0) {
7155 found_any_getters = true;
7156 get = (MethodInfo) Invocation.OverloadResolve (
7157 ec, new MethodGroupExpr (AllGetters, loc), arguments, loc);
7161 Report.Error (21, loc,
7162 "Type `" + TypeManager.CSharpName (indexer_type) +
7163 "' does not have any indexers defined");
7167 if (!found_any_getters) {
7168 Error (154, "indexer can not be used in this context, because " +
7169 "it lacks a `get' accessor");
7174 Error (1501, "No Overload for method `this' takes `" +
7175 arguments.Count + "' arguments");
7180 // Only base will allow this invocation to happen.
7182 if (get.IsAbstract && this is BaseIndexerAccess){
7183 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
7187 type = get.ReturnType;
7188 if (type.IsPointer && !ec.InUnsafe){
7193 eclass = ExprClass.IndexerAccess;
7197 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7199 ArrayList AllSetters = new ArrayList();
7200 if (!CommonResolve (ec))
7203 Type right_type = right_side.Type;
7205 bool found_any = false, found_any_setters = false;
7207 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
7208 if (ilist != null) {
7210 if (ilist.properties != null) {
7211 foreach (Pair o in ilist.properties) {
7212 if (o.Second != null)
7213 AllSetters.Add(o.Second);
7217 if (AllSetters.Count > 0) {
7218 found_any_setters = true;
7219 set_arguments = (ArrayList) arguments.Clone ();
7220 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7221 set = (MethodInfo) Invocation.OverloadResolve (
7222 ec, new MethodGroupExpr (AllSetters, loc),
7223 set_arguments, loc);
7227 Report.Error (21, loc,
7228 "Type `" + TypeManager.CSharpName (indexer_type) +
7229 "' does not have any indexers defined");
7233 if (!found_any_setters) {
7234 Error (154, "indexer can not be used in this context, because " +
7235 "it lacks a `set' accessor");
7240 Error (1501, "No Overload for method `this' takes `" +
7241 arguments.Count + "' arguments");
7246 // Only base will allow this invocation to happen.
7248 if (set.IsAbstract && this is BaseIndexerAccess){
7249 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
7254 // Now look for the actual match in the list of indexers to set our "return" type
7256 type = TypeManager.void_type; // default value
7257 foreach (Pair t in ilist.properties){
7258 if (t.Second == set){
7259 if (t.First != null)
7260 type = ((MethodInfo) t.First).ReturnType;
7265 eclass = ExprClass.IndexerAccess;
7269 public override void Emit (EmitContext ec)
7271 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc);
7275 // source is ignored, because we already have a copy of it from the
7276 // LValue resolution and we have already constructed a pre-cached
7277 // version of the arguments (ea.set_arguments);
7279 public void EmitAssign (EmitContext ec, Expression source)
7281 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc);
7286 /// The base operator for method names
7288 public class BaseAccess : Expression {
7291 public BaseAccess (string member, Location l)
7293 this.member = member;
7297 public override Expression DoResolve (EmitContext ec)
7299 Expression c = CommonResolve (ec);
7305 // MethodGroups use this opportunity to flag an error on lacking ()
7307 if (!(c is MethodGroupExpr))
7308 return c.Resolve (ec);
7312 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7314 Expression c = CommonResolve (ec);
7320 // MethodGroups use this opportunity to flag an error on lacking ()
7322 if (! (c is MethodGroupExpr))
7323 return c.DoResolveLValue (ec, right_side);
7328 Expression CommonResolve (EmitContext ec)
7330 Expression member_lookup;
7331 Type current_type = ec.ContainerType;
7332 Type base_type = current_type.BaseType;
7336 Error (1511, "Keyword base is not allowed in static method");
7340 member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
7341 AllMemberTypes, AllBindingFlags, loc);
7342 if (member_lookup == null) {
7343 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
7350 left = new TypeExpr (base_type, loc);
7354 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7356 if (e is PropertyExpr){
7357 PropertyExpr pe = (PropertyExpr) e;
7365 public override void Emit (EmitContext ec)
7367 throw new Exception ("Should never be called");
7372 /// The base indexer operator
7374 public class BaseIndexerAccess : IndexerAccess {
7375 public BaseIndexerAccess (ArrayList args, Location loc)
7376 : base (null, true, loc)
7378 arguments = new ArrayList ();
7379 foreach (Expression tmp in args)
7380 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7383 protected override bool CommonResolve (EmitContext ec)
7385 instance_expr = ec.This;
7387 current_type = ec.ContainerType.BaseType;
7388 indexer_type = current_type;
7390 foreach (Argument a in arguments){
7391 if (!a.Resolve (ec, loc))
7400 /// This class exists solely to pass the Type around and to be a dummy
7401 /// that can be passed to the conversion functions (this is used by
7402 /// foreach implementation to typecast the object return value from
7403 /// get_Current into the proper type. All code has been generated and
7404 /// we only care about the side effect conversions to be performed
7406 /// This is also now used as a placeholder where a no-action expression
7407 /// is needed (the `New' class).
7409 public class EmptyExpression : Expression {
7410 public EmptyExpression ()
7412 type = TypeManager.object_type;
7413 eclass = ExprClass.Value;
7414 loc = Location.Null;
7417 public EmptyExpression (Type t)
7420 eclass = ExprClass.Value;
7421 loc = Location.Null;
7424 public override Expression DoResolve (EmitContext ec)
7429 public override void Emit (EmitContext ec)
7431 // nothing, as we only exist to not do anything.
7435 // This is just because we might want to reuse this bad boy
7436 // instead of creating gazillions of EmptyExpressions.
7437 // (CanImplicitConversion uses it)
7439 public void SetType (Type t)
7445 public class UserCast : Expression {
7449 public UserCast (MethodInfo method, Expression source, Location l)
7451 this.method = method;
7452 this.source = source;
7453 type = method.ReturnType;
7454 eclass = ExprClass.Value;
7458 public override Expression DoResolve (EmitContext ec)
7461 // We are born fully resolved
7466 public override void Emit (EmitContext ec)
7468 ILGenerator ig = ec.ig;
7472 if (method is MethodInfo)
7473 ig.Emit (OpCodes.Call, (MethodInfo) method);
7475 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7481 // This class is used to "construct" the type during a typecast
7482 // operation. Since the Type.GetType class in .NET can parse
7483 // the type specification, we just use this to construct the type
7484 // one bit at a time.
7486 public class ComposedCast : Expression {
7490 public ComposedCast (Expression left, string dim, Location l)
7497 public override Expression ResolveAsTypeStep (EmitContext ec)
7499 Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7504 // ltype.Fullname is already fully qualified, so we can skip
7505 // a lot of probes, and go directly to TypeManager.LookupType
7507 string cname = ltype.FullName + dim;
7508 type = TypeManager.LookupTypeDirect (cname);
7511 // For arrays of enumerations we are having a problem
7512 // with the direct lookup. Need to investigate.
7514 // For now, fall back to the full lookup in that case.
7516 type = RootContext.LookupType (
7517 ec.DeclSpace, cname, false, loc);
7523 if (!ec.ResolvingTypeTree){
7525 // If the above flag is set, this is being invoked from the ResolveType function.
7526 // Upper layers take care of the type validity in this context.
7528 if (!ec.InUnsafe && type.IsPointer){
7534 eclass = ExprClass.Type;
7538 public override Expression DoResolve (EmitContext ec)
7540 return ResolveAsTypeStep (ec);
7543 public override void Emit (EmitContext ec)
7545 throw new Exception ("This should never be called");
7548 public override string ToString ()
7555 // This class is used to represent the address of an array, used
7556 // only by the Fixed statement, this is like the C "&a [0]" construct.
7558 public class ArrayPtr : Expression {
7561 public ArrayPtr (Expression array, Location l)
7563 Type array_type = array.Type.GetElementType ();
7567 type = TypeManager.GetPointerType (array_type);
7568 eclass = ExprClass.Value;
7572 public override void Emit (EmitContext ec)
7574 ILGenerator ig = ec.ig;
7577 IntLiteral.EmitInt (ig, 0);
7578 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
7581 public override Expression DoResolve (EmitContext ec)
7584 // We are born fully resolved
7591 // Used by the fixed statement
7593 public class StringPtr : Expression {
7596 public StringPtr (LocalBuilder b, Location l)
7599 eclass = ExprClass.Value;
7600 type = TypeManager.char_ptr_type;
7604 public override Expression DoResolve (EmitContext ec)
7606 // This should never be invoked, we are born in fully
7607 // initialized state.
7612 public override void Emit (EmitContext ec)
7614 ILGenerator ig = ec.ig;
7616 ig.Emit (OpCodes.Ldloc, b);
7617 ig.Emit (OpCodes.Conv_I);
7618 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
7619 ig.Emit (OpCodes.Add);
7624 // Implements the `stackalloc' keyword
7626 public class StackAlloc : Expression {
7631 public StackAlloc (Expression type, Expression count, Location l)
7638 public override Expression DoResolve (EmitContext ec)
7640 count = count.Resolve (ec);
7644 if (count.Type != TypeManager.int32_type){
7645 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
7650 if (ec.InCatch || ec.InFinally){
7652 "stackalloc can not be used in a catch or finally block");
7656 otype = ec.DeclSpace.ResolveType (t, false, loc);
7661 if (!TypeManager.VerifyUnManaged (otype, loc))
7664 type = TypeManager.GetPointerType (otype);
7665 eclass = ExprClass.Value;
7670 public override void Emit (EmitContext ec)
7672 int size = GetTypeSize (otype);
7673 ILGenerator ig = ec.ig;
7676 ig.Emit (OpCodes.Sizeof, otype);
7678 IntConstant.EmitInt (ig, size);
7680 ig.Emit (OpCodes.Mul);
7681 ig.Emit (OpCodes.Localloc);