2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2003, 2004 Novell, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
20 /// This is just a helper class, it is generated by Unary, UnaryMutator
21 /// when an overloaded method has been found. It just emits the code for a
24 public class StaticCallExpr : ExpressionStatement {
28 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
34 eclass = ExprClass.Value;
38 public override Expression DoResolve (EmitContext ec)
41 // We are born fully resolved
46 public override void Emit (EmitContext ec)
49 Invocation.EmitArguments (ec, mi, args, false, null);
51 ec.ig.Emit (OpCodes.Call, mi);
55 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56 Expression e, Location loc)
61 args = new ArrayList (1);
62 Argument a = new Argument (e, Argument.AType.Expression);
64 // We need to resolve the arguments before sending them in !
65 if (!a.Resolve (ec, loc))
69 method = Invocation.OverloadResolve (
70 ec, (MethodGroupExpr) mg, args, false, loc);
75 return new StaticCallExpr ((MethodInfo) method, args, loc);
78 public override void EmitStatement (EmitContext ec)
81 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
82 ec.ig.Emit (OpCodes.Pop);
85 public MethodInfo Method {
90 public class ParenthesizedExpression : Expression
92 public Expression Expr;
94 public ParenthesizedExpression (Expression expr, Location loc)
100 public override Expression DoResolve (EmitContext ec)
102 Expr = Expr.Resolve (ec);
106 public override void Emit (EmitContext ec)
108 throw new Exception ("Should not happen");
113 /// Unary expressions.
117 /// Unary implements unary expressions. It derives from
118 /// ExpressionStatement becuase the pre/post increment/decrement
119 /// operators can be used in a statement context.
121 public class Unary : Expression {
122 public enum Operator : byte {
123 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
124 Indirection, AddressOf, TOP
127 public Operator Oper;
128 public Expression Expr;
130 public Unary (Operator op, Expression expr, Location loc)
138 /// Returns a stringified representation of the Operator
140 static public string OperName (Operator oper)
143 case Operator.UnaryPlus:
145 case Operator.UnaryNegation:
147 case Operator.LogicalNot:
149 case Operator.OnesComplement:
151 case Operator.AddressOf:
153 case Operator.Indirection:
157 return oper.ToString ();
160 public static readonly string [] oper_names;
164 oper_names = new string [(int)Operator.TOP];
166 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
167 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
168 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
169 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
170 oper_names [(int) Operator.Indirection] = "op_Indirection";
171 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
174 void Error23 (Type t)
177 23, "Operator " + OperName (Oper) +
178 " cannot be applied to operand of type `" +
179 TypeManager.CSharpName (t) + "'");
183 /// The result has been already resolved:
185 /// FIXME: a minus constant -128 sbyte cant be turned into a
188 static Expression TryReduceNegative (Constant expr)
192 if (expr is IntConstant)
193 e = new IntConstant (-((IntConstant) expr).Value);
194 else if (expr is UIntConstant){
195 uint value = ((UIntConstant) expr).Value;
197 if (value < 2147483649)
198 return new IntConstant (-(int)value);
200 e = new LongConstant (-value);
202 else if (expr is LongConstant)
203 e = new LongConstant (-((LongConstant) expr).Value);
204 else if (expr is ULongConstant){
205 ulong value = ((ULongConstant) expr).Value;
207 if (value < 9223372036854775809)
208 return new LongConstant(-(long)value);
210 else if (expr is FloatConstant)
211 e = new FloatConstant (-((FloatConstant) expr).Value);
212 else if (expr is DoubleConstant)
213 e = new DoubleConstant (-((DoubleConstant) expr).Value);
214 else if (expr is DecimalConstant)
215 e = new DecimalConstant (-((DecimalConstant) expr).Value);
216 else if (expr is ShortConstant)
217 e = new IntConstant (-((ShortConstant) expr).Value);
218 else if (expr is UShortConstant)
219 e = new IntConstant (-((UShortConstant) expr).Value);
220 else if (expr is SByteConstant)
221 e = new IntConstant (-((SByteConstant) expr).Value);
222 else if (expr is ByteConstant)
223 e = new IntConstant (-((ByteConstant) expr).Value);
228 // This routine will attempt to simplify the unary expression when the
229 // argument is a constant. The result is returned in `result' and the
230 // function returns true or false depending on whether a reduction
231 // was performed or not
233 bool Reduce (EmitContext ec, Constant e, out Expression result)
235 Type expr_type = e.Type;
238 case Operator.UnaryPlus:
239 if (expr_type == TypeManager.bool_type){
248 case Operator.UnaryNegation:
249 result = TryReduceNegative (e);
250 return result != null;
252 case Operator.LogicalNot:
253 if (expr_type != TypeManager.bool_type) {
259 BoolConstant b = (BoolConstant) e;
260 result = new BoolConstant (!(b.Value));
263 case Operator.OnesComplement:
264 if (!((expr_type == TypeManager.int32_type) ||
265 (expr_type == TypeManager.uint32_type) ||
266 (expr_type == TypeManager.int64_type) ||
267 (expr_type == TypeManager.uint64_type) ||
268 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
271 if (Convert.ImplicitConversionExists (ec, e, TypeManager.int32_type)){
272 result = new Cast (new TypeExpression (TypeManager.int32_type, loc), e, loc);
273 result = result.Resolve (ec);
274 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
275 result = new Cast (new TypeExpression (TypeManager.uint32_type, loc), e, loc);
276 result = result.Resolve (ec);
277 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.int64_type)){
278 result = new Cast (new TypeExpression (TypeManager.int64_type, loc), e, loc);
279 result = result.Resolve (ec);
280 } else if (Convert.ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
281 result = new Cast (new TypeExpression (TypeManager.uint64_type, loc), e, loc);
282 result = result.Resolve (ec);
285 if (result == null || !(result is Constant)){
291 expr_type = result.Type;
292 e = (Constant) result;
295 if (e is EnumConstant){
296 EnumConstant enum_constant = (EnumConstant) e;
299 if (Reduce (ec, enum_constant.Child, out reduced)){
300 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
308 if (expr_type == TypeManager.int32_type){
309 result = new IntConstant (~ ((IntConstant) e).Value);
310 } else if (expr_type == TypeManager.uint32_type){
311 result = new UIntConstant (~ ((UIntConstant) e).Value);
312 } else if (expr_type == TypeManager.int64_type){
313 result = new LongConstant (~ ((LongConstant) e).Value);
314 } else if (expr_type == TypeManager.uint64_type){
315 result = new ULongConstant (~ ((ULongConstant) e).Value);
323 case Operator.AddressOf:
327 case Operator.Indirection:
331 throw new Exception ("Can not constant fold: " + Oper.ToString());
334 Expression ResolveOperator (EmitContext ec)
337 // Step 1: Default operations on CLI native types.
340 // Attempt to use a constant folding operation.
341 if (Expr is Constant){
344 if (Reduce (ec, (Constant) Expr, out result))
349 // Step 2: Perform Operator Overload location
351 Type expr_type = Expr.Type;
355 op_name = oper_names [(int) Oper];
357 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
360 Expression e = StaticCallExpr.MakeSimpleCall (
361 ec, (MethodGroupExpr) mg, Expr, loc);
371 // Only perform numeric promotions on:
374 if (expr_type == null)
378 case Operator.LogicalNot:
379 if (expr_type != TypeManager.bool_type) {
380 Expr = ResolveBoolean (ec, Expr, loc);
387 type = TypeManager.bool_type;
390 case Operator.OnesComplement:
391 if (!((expr_type == TypeManager.int32_type) ||
392 (expr_type == TypeManager.uint32_type) ||
393 (expr_type == TypeManager.int64_type) ||
394 (expr_type == TypeManager.uint64_type) ||
395 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
398 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
400 type = TypeManager.int32_type;
403 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
405 type = TypeManager.uint32_type;
408 e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
410 type = TypeManager.int64_type;
413 e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
415 type = TypeManager.uint64_type;
424 case Operator.AddressOf:
430 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
434 IVariable variable = Expr as IVariable;
435 bool is_fixed = variable != null && variable.VerifyFixed (false);
437 if (!ec.InFixedInitializer && !is_fixed) {
438 Error (212, "You can only take the address of an unfixed expression inside " +
439 "of a fixed statement initializer");
443 if (ec.InFixedInitializer && is_fixed) {
444 Error (213, "You can not fix an already fixed expression");
448 LocalVariableReference lr = Expr as LocalVariableReference;
450 if (lr.local_info.IsCaptured){
451 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
454 lr.local_info.AddressTaken = true;
455 lr.local_info.Used = true;
458 // According to the specs, a variable is considered definitely assigned if you take
460 if ((variable != null) && (variable.VariableInfo != null)){
461 variable.VariableInfo.SetAssigned (ec);
464 type = TypeManager.GetPointerType (Expr.Type);
467 case Operator.Indirection:
473 if (!expr_type.IsPointer){
474 Error (193, "The * or -> operator can only be applied to pointers");
479 // We create an Indirection expression, because
480 // it can implement the IMemoryLocation.
482 return new Indirection (Expr, loc);
484 case Operator.UnaryPlus:
486 // A plus in front of something is just a no-op, so return the child.
490 case Operator.UnaryNegation:
492 // Deals with -literals
493 // int operator- (int x)
494 // long operator- (long x)
495 // float operator- (float f)
496 // double operator- (double d)
497 // decimal operator- (decimal d)
499 Expression expr = null;
502 // transform - - expr into expr
505 Unary unary = (Unary) Expr;
507 if (unary.Oper == Operator.UnaryNegation)
512 // perform numeric promotions to int,
516 // The following is inneficient, because we call
517 // ImplicitConversion too many times.
519 // It is also not clear if we should convert to Float
520 // or Double initially.
522 if (expr_type == TypeManager.uint32_type){
524 // FIXME: handle exception to this rule that
525 // permits the int value -2147483648 (-2^31) to
526 // bt wrote as a decimal interger literal
528 type = TypeManager.int64_type;
529 Expr = Convert.ImplicitConversion (ec, Expr, type, loc);
533 if (expr_type == TypeManager.uint64_type){
535 // FIXME: Handle exception of `long value'
536 // -92233720368547758087 (-2^63) to be wrote as
537 // decimal integer literal.
543 if (expr_type == TypeManager.float_type){
548 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
555 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
562 expr = Convert.ImplicitConversion (ec, Expr, TypeManager.double_type, loc);
573 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
574 TypeManager.CSharpName (expr_type) + "'");
578 public override Expression DoResolve (EmitContext ec)
580 if (Oper == Operator.AddressOf) {
581 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
583 if (Expr == null || Expr.eclass != ExprClass.Variable){
584 Error (211, "Cannot take the address of non-variables");
589 Expr = Expr.Resolve (ec);
594 eclass = ExprClass.Value;
595 return ResolveOperator (ec);
598 public override Expression DoResolveLValue (EmitContext ec, Expression right)
600 if (Oper == Operator.Indirection)
601 return DoResolve (ec);
606 public override void Emit (EmitContext ec)
608 ILGenerator ig = ec.ig;
611 case Operator.UnaryPlus:
612 throw new Exception ("This should be caught by Resolve");
614 case Operator.UnaryNegation:
616 ig.Emit (OpCodes.Ldc_I4_0);
617 if (type == TypeManager.int64_type)
618 ig.Emit (OpCodes.Conv_U8);
620 ig.Emit (OpCodes.Sub_Ovf);
623 ig.Emit (OpCodes.Neg);
628 case Operator.LogicalNot:
630 ig.Emit (OpCodes.Ldc_I4_0);
631 ig.Emit (OpCodes.Ceq);
634 case Operator.OnesComplement:
636 ig.Emit (OpCodes.Not);
639 case Operator.AddressOf:
640 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
644 throw new Exception ("This should not happen: Operator = "
649 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
651 if (Oper == Operator.LogicalNot)
652 Expr.EmitBranchable (ec, target, !onTrue);
654 base.EmitBranchable (ec, target, onTrue);
657 public override string ToString ()
659 return "Unary (" + Oper + ", " + Expr + ")";
665 // Unary operators are turned into Indirection expressions
666 // after semantic analysis (this is so we can take the address
667 // of an indirection).
669 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
671 LocalTemporary temporary;
674 public Indirection (Expression expr, Location l)
677 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
678 eclass = ExprClass.Variable;
682 public override void Emit (EmitContext ec)
687 LoadFromPtr (ec.ig, Type);
690 public void Emit (EmitContext ec, bool leave_copy)
694 ec.ig.Emit (OpCodes.Dup);
695 temporary = new LocalTemporary (ec, expr.Type);
696 temporary.Store (ec);
700 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
702 prepared = prepare_for_load;
706 if (prepare_for_load)
707 ec.ig.Emit (OpCodes.Dup);
711 ec.ig.Emit (OpCodes.Dup);
712 temporary = new LocalTemporary (ec, expr.Type);
713 temporary.Store (ec);
716 StoreFromPtr (ec.ig, type);
718 if (temporary != null)
722 public void AddressOf (EmitContext ec, AddressOp Mode)
727 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
729 return DoResolve (ec);
732 public override Expression DoResolve (EmitContext ec)
735 // Born fully resolved
740 public override string ToString ()
742 return "*(" + expr + ")";
745 #region IVariable Members
747 public VariableInfo VariableInfo {
753 public bool VerifyFixed (bool is_expression)
762 /// Unary Mutator expressions (pre and post ++ and --)
766 /// UnaryMutator implements ++ and -- expressions. It derives from
767 /// ExpressionStatement becuase the pre/post increment/decrement
768 /// operators can be used in a statement context.
770 /// FIXME: Idea, we could split this up in two classes, one simpler
771 /// for the common case, and one with the extra fields for more complex
772 /// classes (indexers require temporary access; overloaded require method)
775 public class UnaryMutator : ExpressionStatement {
777 public enum Mode : byte {
784 PreDecrement = IsDecrement,
785 PostIncrement = IsPost,
786 PostDecrement = IsPost | IsDecrement
790 bool is_expr = false;
791 bool recurse = false;
796 // This is expensive for the simplest case.
798 StaticCallExpr method;
800 public UnaryMutator (Mode m, Expression e, Location l)
807 static string OperName (Mode mode)
809 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
814 /// Returns whether an object of type `t' can be incremented
815 /// or decremented with add/sub (ie, basically whether we can
816 /// use pre-post incr-decr operations on it, but it is not a
817 /// System.Decimal, which we require operator overloading to catch)
819 static bool IsIncrementableNumber (Type t)
821 return (t == TypeManager.sbyte_type) ||
822 (t == TypeManager.byte_type) ||
823 (t == TypeManager.short_type) ||
824 (t == TypeManager.ushort_type) ||
825 (t == TypeManager.int32_type) ||
826 (t == TypeManager.uint32_type) ||
827 (t == TypeManager.int64_type) ||
828 (t == TypeManager.uint64_type) ||
829 (t == TypeManager.char_type) ||
830 (t.IsSubclassOf (TypeManager.enum_type)) ||
831 (t == TypeManager.float_type) ||
832 (t == TypeManager.double_type) ||
833 (t.IsPointer && t != TypeManager.void_ptr_type);
836 Expression ResolveOperator (EmitContext ec)
838 Type expr_type = expr.Type;
841 // Step 1: Perform Operator Overload location
846 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
847 op_name = "op_Increment";
849 op_name = "op_Decrement";
851 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
854 method = StaticCallExpr.MakeSimpleCall (
855 ec, (MethodGroupExpr) mg, expr, loc);
858 } else if (!IsIncrementableNumber (expr_type)) {
859 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
860 TypeManager.CSharpName (expr_type) + "'");
865 // The operand of the prefix/postfix increment decrement operators
866 // should be an expression that is classified as a variable,
867 // a property access or an indexer access
870 if (expr.eclass == ExprClass.Variable){
871 LocalVariableReference var = expr as LocalVariableReference;
872 if ((var != null) && var.IsReadOnly) {
873 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
876 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
877 expr = expr.ResolveLValue (ec, this, Location);
881 expr.Error_UnexpectedKind ("variable, indexer or property access", loc);
888 public override Expression DoResolve (EmitContext ec)
890 expr = expr.Resolve (ec);
895 eclass = ExprClass.Value;
896 return ResolveOperator (ec);
899 static int PtrTypeSize (Type t)
901 return GetTypeSize (TypeManager.GetElementType (t));
905 // Loads the proper "1" into the stack based on the type, then it emits the
906 // opcode for the operation requested
908 void LoadOneAndEmitOp (EmitContext ec, Type t)
911 // Measure if getting the typecode and using that is more/less efficient
912 // that comparing types. t.GetTypeCode() is an internal call.
914 ILGenerator ig = ec.ig;
916 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
917 LongConstant.EmitLong (ig, 1);
918 else if (t == TypeManager.double_type)
919 ig.Emit (OpCodes.Ldc_R8, 1.0);
920 else if (t == TypeManager.float_type)
921 ig.Emit (OpCodes.Ldc_R4, 1.0F);
922 else if (t.IsPointer){
923 int n = PtrTypeSize (t);
926 ig.Emit (OpCodes.Sizeof, t);
928 IntConstant.EmitInt (ig, n);
930 ig.Emit (OpCodes.Ldc_I4_1);
933 // Now emit the operation
936 if (t == TypeManager.int32_type ||
937 t == TypeManager.int64_type){
938 if ((mode & Mode.IsDecrement) != 0)
939 ig.Emit (OpCodes.Sub_Ovf);
941 ig.Emit (OpCodes.Add_Ovf);
942 } else if (t == TypeManager.uint32_type ||
943 t == TypeManager.uint64_type){
944 if ((mode & Mode.IsDecrement) != 0)
945 ig.Emit (OpCodes.Sub_Ovf_Un);
947 ig.Emit (OpCodes.Add_Ovf_Un);
949 if ((mode & Mode.IsDecrement) != 0)
950 ig.Emit (OpCodes.Sub_Ovf);
952 ig.Emit (OpCodes.Add_Ovf);
955 if ((mode & Mode.IsDecrement) != 0)
956 ig.Emit (OpCodes.Sub);
958 ig.Emit (OpCodes.Add);
961 if (t == TypeManager.sbyte_type){
963 ig.Emit (OpCodes.Conv_Ovf_I1);
965 ig.Emit (OpCodes.Conv_I1);
966 } else if (t == TypeManager.byte_type){
968 ig.Emit (OpCodes.Conv_Ovf_U1);
970 ig.Emit (OpCodes.Conv_U1);
971 } else if (t == TypeManager.short_type){
973 ig.Emit (OpCodes.Conv_Ovf_I2);
975 ig.Emit (OpCodes.Conv_I2);
976 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
978 ig.Emit (OpCodes.Conv_Ovf_U2);
980 ig.Emit (OpCodes.Conv_U2);
985 void EmitCode (EmitContext ec, bool is_expr)
988 this.is_expr = is_expr;
989 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
993 public override void Emit (EmitContext ec)
996 // We use recurse to allow ourselfs to be the source
997 // of an assignment. This little hack prevents us from
998 // having to allocate another expression
1001 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1003 LoadOneAndEmitOp (ec, expr.Type);
1005 ec.ig.Emit (OpCodes.Call, method.Method);
1010 EmitCode (ec, true);
1013 public override void EmitStatement (EmitContext ec)
1015 EmitCode (ec, false);
1020 /// Base class for the `Is' and `As' classes.
1024 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1027 public abstract class Probe : Expression {
1028 public Expression ProbeType;
1029 protected Expression expr;
1030 protected Type probe_type;
1032 public Probe (Expression expr, Expression probe_type, Location l)
1034 ProbeType = probe_type;
1039 public Expression Expr {
1045 public override Expression DoResolve (EmitContext ec)
1047 TypeExpr texpr = ProbeType.ResolveAsTypeTerminal (ec, false);
1050 probe_type = texpr.ResolveType (ec);
1052 CheckObsoleteAttribute (probe_type);
1054 expr = expr.Resolve (ec);
1058 if (expr.Type.IsPointer) {
1059 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1067 /// Implementation of the `is' operator.
1069 public class Is : Probe {
1070 public Is (Expression expr, Expression probe_type, Location l)
1071 : base (expr, probe_type, l)
1076 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1081 public override void Emit (EmitContext ec)
1083 ILGenerator ig = ec.ig;
1088 case Action.AlwaysFalse:
1089 ig.Emit (OpCodes.Pop);
1090 IntConstant.EmitInt (ig, 0);
1092 case Action.AlwaysTrue:
1093 ig.Emit (OpCodes.Pop);
1094 IntConstant.EmitInt (ig, 1);
1096 case Action.LeaveOnStack:
1097 // the `e != null' rule.
1098 ig.Emit (OpCodes.Ldnull);
1099 ig.Emit (OpCodes.Ceq);
1100 ig.Emit (OpCodes.Ldc_I4_0);
1101 ig.Emit (OpCodes.Ceq);
1104 ig.Emit (OpCodes.Isinst, probe_type);
1105 ig.Emit (OpCodes.Ldnull);
1106 ig.Emit (OpCodes.Cgt_Un);
1109 throw new Exception ("never reached");
1112 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1114 ILGenerator ig = ec.ig;
1117 case Action.AlwaysFalse:
1119 ig.Emit (OpCodes.Br, target);
1122 case Action.AlwaysTrue:
1124 ig.Emit (OpCodes.Br, target);
1127 case Action.LeaveOnStack:
1128 // the `e != null' rule.
1130 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1134 ig.Emit (OpCodes.Isinst, probe_type);
1135 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1138 throw new Exception ("never reached");
1141 public override Expression DoResolve (EmitContext ec)
1143 Expression e = base.DoResolve (ec);
1145 if ((e == null) || (expr == null))
1148 Type etype = expr.Type;
1149 bool warning_always_matches = false;
1150 bool warning_never_matches = false;
1152 type = TypeManager.bool_type;
1153 eclass = ExprClass.Value;
1156 // First case, if at compile time, there is an implicit conversion
1157 // then e != null (objects) or true (value types)
1159 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1162 if (etype.IsValueType)
1163 action = Action.AlwaysTrue;
1165 action = Action.LeaveOnStack;
1167 warning_always_matches = true;
1168 } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1170 // Second case: explicit reference convresion
1172 if (expr is NullLiteral)
1173 action = Action.AlwaysFalse;
1175 action = Action.Probe;
1177 action = Action.AlwaysFalse;
1178 warning_never_matches = true;
1181 if (warning_always_matches)
1182 Warning (183, "The given expression is always of the provided ('{0}') type", TypeManager.CSharpName (probe_type));
1183 else if (warning_never_matches){
1184 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1185 Warning (184, "The given expression is never of the provided ('{0}') type", TypeManager.CSharpName (probe_type));
1193 /// Implementation of the `as' operator.
1195 public class As : Probe {
1196 public As (Expression expr, Expression probe_type, Location l)
1197 : base (expr, probe_type, l)
1201 bool do_isinst = false;
1203 public override void Emit (EmitContext ec)
1205 ILGenerator ig = ec.ig;
1210 ig.Emit (OpCodes.Isinst, probe_type);
1213 static void Error_CannotConvertType (Type source, Type target, Location loc)
1216 39, loc, "as operator can not convert from `" +
1217 TypeManager.CSharpName (source) + "' to `" +
1218 TypeManager.CSharpName (target) + "'");
1221 public override Expression DoResolve (EmitContext ec)
1223 Expression e = base.DoResolve (ec);
1229 eclass = ExprClass.Value;
1230 Type etype = expr.Type;
1232 if (TypeManager.IsValueType (probe_type)){
1233 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1234 TypeManager.CSharpName (probe_type) + " is a value type)");
1239 e = Convert.ImplicitConversion (ec, expr, probe_type, loc);
1246 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1251 Error_CannotConvertType (etype, probe_type, loc);
1257 /// This represents a typecast in the source language.
1259 /// FIXME: Cast expressions have an unusual set of parsing
1260 /// rules, we need to figure those out.
1262 public class Cast : Expression {
1263 Expression target_type;
1266 public Cast (Expression cast_type, Expression expr, Location loc)
1268 this.target_type = cast_type;
1273 public Expression TargetType {
1279 public Expression Expr {
1288 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1290 if (!ec.ConstantCheckState)
1293 if ((value < min) || (value > max)) {
1294 Error (221, "Constant value `" + value + "' cannot be converted " +
1295 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1296 "syntax to override)");
1303 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1305 if (!ec.ConstantCheckState)
1309 Error (221, "Constant value `" + value + "' cannot be converted " +
1310 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1311 "syntax to override)");
1318 bool CheckUnsigned (EmitContext ec, long value, Type type)
1320 if (!ec.ConstantCheckState)
1324 Error (221, "Constant value `" + value + "' cannot be converted " +
1325 "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1326 "syntax to override)");
1334 /// Attempts to do a compile-time folding of a constant cast.
1336 Expression TryReduce (EmitContext ec, Type target_type)
1338 Expression real_expr = expr;
1339 if (real_expr is EnumConstant)
1340 real_expr = ((EnumConstant) real_expr).Child;
1342 if (real_expr is ByteConstant){
1343 byte v = ((ByteConstant) real_expr).Value;
1345 if (target_type == TypeManager.sbyte_type) {
1346 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1348 return new SByteConstant ((sbyte) v);
1350 if (target_type == TypeManager.short_type)
1351 return new ShortConstant ((short) v);
1352 if (target_type == TypeManager.ushort_type)
1353 return new UShortConstant ((ushort) v);
1354 if (target_type == TypeManager.int32_type)
1355 return new IntConstant ((int) v);
1356 if (target_type == TypeManager.uint32_type)
1357 return new UIntConstant ((uint) v);
1358 if (target_type == TypeManager.int64_type)
1359 return new LongConstant ((long) v);
1360 if (target_type == TypeManager.uint64_type)
1361 return new ULongConstant ((ulong) v);
1362 if (target_type == TypeManager.float_type)
1363 return new FloatConstant ((float) v);
1364 if (target_type == TypeManager.double_type)
1365 return new DoubleConstant ((double) v);
1366 if (target_type == TypeManager.char_type)
1367 return new CharConstant ((char) v);
1368 if (target_type == TypeManager.decimal_type)
1369 return new DecimalConstant ((decimal) v);
1371 if (real_expr is SByteConstant){
1372 sbyte v = ((SByteConstant) real_expr).Value;
1374 if (target_type == TypeManager.byte_type) {
1375 if (!CheckUnsigned (ec, v, target_type))
1377 return new ByteConstant ((byte) v);
1379 if (target_type == TypeManager.short_type)
1380 return new ShortConstant ((short) v);
1381 if (target_type == TypeManager.ushort_type) {
1382 if (!CheckUnsigned (ec, v, target_type))
1384 return new UShortConstant ((ushort) v);
1385 } if (target_type == TypeManager.int32_type)
1386 return new IntConstant ((int) v);
1387 if (target_type == TypeManager.uint32_type) {
1388 if (!CheckUnsigned (ec, v, target_type))
1390 return new UIntConstant ((uint) v);
1391 } if (target_type == TypeManager.int64_type)
1392 return new LongConstant ((long) v);
1393 if (target_type == TypeManager.uint64_type) {
1394 if (!CheckUnsigned (ec, v, target_type))
1396 return new ULongConstant ((ulong) v);
1398 if (target_type == TypeManager.float_type)
1399 return new FloatConstant ((float) v);
1400 if (target_type == TypeManager.double_type)
1401 return new DoubleConstant ((double) v);
1402 if (target_type == TypeManager.char_type) {
1403 if (!CheckUnsigned (ec, v, target_type))
1405 return new CharConstant ((char) v);
1407 if (target_type == TypeManager.decimal_type)
1408 return new DecimalConstant ((decimal) v);
1410 if (real_expr is ShortConstant){
1411 short v = ((ShortConstant) real_expr).Value;
1413 if (target_type == TypeManager.byte_type) {
1414 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1416 return new ByteConstant ((byte) v);
1418 if (target_type == TypeManager.sbyte_type) {
1419 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1421 return new SByteConstant ((sbyte) v);
1423 if (target_type == TypeManager.ushort_type) {
1424 if (!CheckUnsigned (ec, v, target_type))
1426 return new UShortConstant ((ushort) v);
1428 if (target_type == TypeManager.int32_type)
1429 return new IntConstant ((int) v);
1430 if (target_type == TypeManager.uint32_type) {
1431 if (!CheckUnsigned (ec, v, target_type))
1433 return new UIntConstant ((uint) v);
1435 if (target_type == TypeManager.int64_type)
1436 return new LongConstant ((long) v);
1437 if (target_type == TypeManager.uint64_type) {
1438 if (!CheckUnsigned (ec, v, target_type))
1440 return new ULongConstant ((ulong) v);
1442 if (target_type == TypeManager.float_type)
1443 return new FloatConstant ((float) v);
1444 if (target_type == TypeManager.double_type)
1445 return new DoubleConstant ((double) v);
1446 if (target_type == TypeManager.char_type) {
1447 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1449 return new CharConstant ((char) v);
1451 if (target_type == TypeManager.decimal_type)
1452 return new DecimalConstant ((decimal) v);
1454 if (real_expr is UShortConstant){
1455 ushort v = ((UShortConstant) real_expr).Value;
1457 if (target_type == TypeManager.byte_type) {
1458 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1460 return new ByteConstant ((byte) v);
1462 if (target_type == TypeManager.sbyte_type) {
1463 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1465 return new SByteConstant ((sbyte) v);
1467 if (target_type == TypeManager.short_type) {
1468 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1470 return new ShortConstant ((short) v);
1472 if (target_type == TypeManager.int32_type)
1473 return new IntConstant ((int) v);
1474 if (target_type == TypeManager.uint32_type)
1475 return new UIntConstant ((uint) v);
1476 if (target_type == TypeManager.int64_type)
1477 return new LongConstant ((long) v);
1478 if (target_type == TypeManager.uint64_type)
1479 return new ULongConstant ((ulong) v);
1480 if (target_type == TypeManager.float_type)
1481 return new FloatConstant ((float) v);
1482 if (target_type == TypeManager.double_type)
1483 return new DoubleConstant ((double) v);
1484 if (target_type == TypeManager.char_type) {
1485 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1487 return new CharConstant ((char) v);
1489 if (target_type == TypeManager.decimal_type)
1490 return new DecimalConstant ((decimal) v);
1492 if (real_expr is IntConstant){
1493 int v = ((IntConstant) real_expr).Value;
1495 if (target_type == TypeManager.byte_type) {
1496 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1498 return new ByteConstant ((byte) v);
1500 if (target_type == TypeManager.sbyte_type) {
1501 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1503 return new SByteConstant ((sbyte) v);
1505 if (target_type == TypeManager.short_type) {
1506 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1508 return new ShortConstant ((short) v);
1510 if (target_type == TypeManager.ushort_type) {
1511 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1513 return new UShortConstant ((ushort) v);
1515 if (target_type == TypeManager.uint32_type) {
1516 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1518 return new UIntConstant ((uint) v);
1520 if (target_type == TypeManager.int64_type)
1521 return new LongConstant ((long) v);
1522 if (target_type == TypeManager.uint64_type) {
1523 if (!CheckUnsigned (ec, v, target_type))
1525 return new ULongConstant ((ulong) v);
1527 if (target_type == TypeManager.float_type)
1528 return new FloatConstant ((float) v);
1529 if (target_type == TypeManager.double_type)
1530 return new DoubleConstant ((double) v);
1531 if (target_type == TypeManager.char_type) {
1532 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1534 return new CharConstant ((char) v);
1536 if (target_type == TypeManager.decimal_type)
1537 return new DecimalConstant ((decimal) v);
1539 if (real_expr is UIntConstant){
1540 uint v = ((UIntConstant) real_expr).Value;
1542 if (target_type == TypeManager.byte_type) {
1543 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1545 return new ByteConstant ((byte) v);
1547 if (target_type == TypeManager.sbyte_type) {
1548 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1550 return new SByteConstant ((sbyte) v);
1552 if (target_type == TypeManager.short_type) {
1553 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1555 return new ShortConstant ((short) v);
1557 if (target_type == TypeManager.ushort_type) {
1558 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1560 return new UShortConstant ((ushort) v);
1562 if (target_type == TypeManager.int32_type) {
1563 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1565 return new IntConstant ((int) v);
1567 if (target_type == TypeManager.int64_type)
1568 return new LongConstant ((long) v);
1569 if (target_type == TypeManager.uint64_type)
1570 return new ULongConstant ((ulong) v);
1571 if (target_type == TypeManager.float_type)
1572 return new FloatConstant ((float) v);
1573 if (target_type == TypeManager.double_type)
1574 return new DoubleConstant ((double) v);
1575 if (target_type == TypeManager.char_type) {
1576 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1578 return new CharConstant ((char) v);
1580 if (target_type == TypeManager.decimal_type)
1581 return new DecimalConstant ((decimal) v);
1583 if (real_expr is LongConstant){
1584 long v = ((LongConstant) real_expr).Value;
1586 if (target_type == TypeManager.byte_type) {
1587 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1589 return new ByteConstant ((byte) v);
1591 if (target_type == TypeManager.sbyte_type) {
1592 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1594 return new SByteConstant ((sbyte) v);
1596 if (target_type == TypeManager.short_type) {
1597 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1599 return new ShortConstant ((short) v);
1601 if (target_type == TypeManager.ushort_type) {
1602 if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1604 return new UShortConstant ((ushort) v);
1606 if (target_type == TypeManager.int32_type) {
1607 if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1609 return new IntConstant ((int) v);
1611 if (target_type == TypeManager.uint32_type) {
1612 if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1614 return new UIntConstant ((uint) v);
1616 if (target_type == TypeManager.uint64_type) {
1617 if (!CheckUnsigned (ec, v, target_type))
1619 return new ULongConstant ((ulong) v);
1621 if (target_type == TypeManager.float_type)
1622 return new FloatConstant ((float) v);
1623 if (target_type == TypeManager.double_type)
1624 return new DoubleConstant ((double) v);
1625 if (target_type == TypeManager.char_type) {
1626 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1628 return new CharConstant ((char) v);
1630 if (target_type == TypeManager.decimal_type)
1631 return new DecimalConstant ((decimal) v);
1633 if (real_expr is ULongConstant){
1634 ulong v = ((ULongConstant) real_expr).Value;
1636 if (target_type == TypeManager.byte_type) {
1637 if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1639 return new ByteConstant ((byte) v);
1641 if (target_type == TypeManager.sbyte_type) {
1642 if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1644 return new SByteConstant ((sbyte) v);
1646 if (target_type == TypeManager.short_type) {
1647 if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1649 return new ShortConstant ((short) v);
1651 if (target_type == TypeManager.ushort_type) {
1652 if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1654 return new UShortConstant ((ushort) v);
1656 if (target_type == TypeManager.int32_type) {
1657 if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1659 return new IntConstant ((int) v);
1661 if (target_type == TypeManager.uint32_type) {
1662 if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1664 return new UIntConstant ((uint) v);
1666 if (target_type == TypeManager.int64_type) {
1667 if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1669 return new LongConstant ((long) v);
1671 if (target_type == TypeManager.float_type)
1672 return new FloatConstant ((float) v);
1673 if (target_type == TypeManager.double_type)
1674 return new DoubleConstant ((double) v);
1675 if (target_type == TypeManager.char_type) {
1676 if (!CheckRange (ec, v, target_type, Char.MaxValue))
1678 return new CharConstant ((char) v);
1680 if (target_type == TypeManager.decimal_type)
1681 return new DecimalConstant ((decimal) v);
1683 if (real_expr is FloatConstant){
1684 float v = ((FloatConstant) real_expr).Value;
1686 if (target_type == TypeManager.byte_type)
1687 return new ByteConstant ((byte) v);
1688 if (target_type == TypeManager.sbyte_type)
1689 return new SByteConstant ((sbyte) v);
1690 if (target_type == TypeManager.short_type)
1691 return new ShortConstant ((short) v);
1692 if (target_type == TypeManager.ushort_type)
1693 return new UShortConstant ((ushort) v);
1694 if (target_type == TypeManager.int32_type)
1695 return new IntConstant ((int) v);
1696 if (target_type == TypeManager.uint32_type)
1697 return new UIntConstant ((uint) v);
1698 if (target_type == TypeManager.int64_type)
1699 return new LongConstant ((long) v);
1700 if (target_type == TypeManager.uint64_type)
1701 return new ULongConstant ((ulong) v);
1702 if (target_type == TypeManager.double_type)
1703 return new DoubleConstant ((double) v);
1704 if (target_type == TypeManager.char_type)
1705 return new CharConstant ((char) v);
1706 if (target_type == TypeManager.decimal_type)
1707 return new DecimalConstant ((decimal) v);
1709 if (real_expr is DoubleConstant){
1710 double v = ((DoubleConstant) real_expr).Value;
1712 if (target_type == TypeManager.byte_type){
1713 return new ByteConstant ((byte) v);
1714 } if (target_type == TypeManager.sbyte_type)
1715 return new SByteConstant ((sbyte) v);
1716 if (target_type == TypeManager.short_type)
1717 return new ShortConstant ((short) v);
1718 if (target_type == TypeManager.ushort_type)
1719 return new UShortConstant ((ushort) v);
1720 if (target_type == TypeManager.int32_type)
1721 return new IntConstant ((int) v);
1722 if (target_type == TypeManager.uint32_type)
1723 return new UIntConstant ((uint) v);
1724 if (target_type == TypeManager.int64_type)
1725 return new LongConstant ((long) v);
1726 if (target_type == TypeManager.uint64_type)
1727 return new ULongConstant ((ulong) v);
1728 if (target_type == TypeManager.float_type)
1729 return new FloatConstant ((float) v);
1730 if (target_type == TypeManager.char_type)
1731 return new CharConstant ((char) v);
1732 if (target_type == TypeManager.decimal_type)
1733 return new DecimalConstant ((decimal) v);
1736 if (real_expr is CharConstant){
1737 char v = ((CharConstant) real_expr).Value;
1739 if (target_type == TypeManager.byte_type) {
1740 if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1742 return new ByteConstant ((byte) v);
1744 if (target_type == TypeManager.sbyte_type) {
1745 if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1747 return new SByteConstant ((sbyte) v);
1749 if (target_type == TypeManager.short_type) {
1750 if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1752 return new ShortConstant ((short) v);
1754 if (target_type == TypeManager.int32_type)
1755 return new IntConstant ((int) v);
1756 if (target_type == TypeManager.uint32_type)
1757 return new UIntConstant ((uint) v);
1758 if (target_type == TypeManager.int64_type)
1759 return new LongConstant ((long) v);
1760 if (target_type == TypeManager.uint64_type)
1761 return new ULongConstant ((ulong) v);
1762 if (target_type == TypeManager.float_type)
1763 return new FloatConstant ((float) v);
1764 if (target_type == TypeManager.double_type)
1765 return new DoubleConstant ((double) v);
1766 if (target_type == TypeManager.char_type) {
1767 if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1769 return new CharConstant ((char) v);
1771 if (target_type == TypeManager.decimal_type)
1772 return new DecimalConstant ((decimal) v);
1778 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1780 expr = expr.DoResolveLValue (ec, right_side);
1784 return ResolveRest (ec);
1787 public override Expression DoResolve (EmitContext ec)
1789 expr = expr.Resolve (ec);
1793 return ResolveRest (ec);
1796 Expression ResolveRest (EmitContext ec)
1798 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1802 type = target.ResolveType (ec);
1804 CheckObsoleteAttribute (type);
1806 if (type.IsAbstract && type.IsSealed) {
1807 Report.Error (716, loc, "Cannot convert to static type '{0}'", TypeManager.CSharpName (type));
1811 eclass = ExprClass.Value;
1813 if (expr is Constant){
1814 Expression e = TryReduce (ec, type);
1820 if (type.IsPointer && !ec.InUnsafe) {
1824 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1828 public override void Emit (EmitContext ec)
1831 // This one will never happen
1833 throw new Exception ("Should not happen");
1838 /// Binary operators
1840 public class Binary : Expression {
1841 public enum Operator : byte {
1842 Multiply, Division, Modulus,
1843 Addition, Subtraction,
1844 LeftShift, RightShift,
1845 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1846 Equality, Inequality,
1856 Expression left, right;
1858 // This must be kept in sync with Operator!!!
1859 public static readonly string [] oper_names;
1863 oper_names = new string [(int) Operator.TOP];
1865 oper_names [(int) Operator.Multiply] = "op_Multiply";
1866 oper_names [(int) Operator.Division] = "op_Division";
1867 oper_names [(int) Operator.Modulus] = "op_Modulus";
1868 oper_names [(int) Operator.Addition] = "op_Addition";
1869 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1870 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1871 oper_names [(int) Operator.RightShift] = "op_RightShift";
1872 oper_names [(int) Operator.LessThan] = "op_LessThan";
1873 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1874 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1875 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1876 oper_names [(int) Operator.Equality] = "op_Equality";
1877 oper_names [(int) Operator.Inequality] = "op_Inequality";
1878 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1879 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1880 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1881 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1882 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1885 public Binary (Operator oper, Expression left, Expression right, Location loc)
1893 public Operator Oper {
1902 public Expression Left {
1911 public Expression Right {
1922 /// Returns a stringified representation of the Operator
1924 static string OperName (Operator oper)
1927 case Operator.Multiply:
1929 case Operator.Division:
1931 case Operator.Modulus:
1933 case Operator.Addition:
1935 case Operator.Subtraction:
1937 case Operator.LeftShift:
1939 case Operator.RightShift:
1941 case Operator.LessThan:
1943 case Operator.GreaterThan:
1945 case Operator.LessThanOrEqual:
1947 case Operator.GreaterThanOrEqual:
1949 case Operator.Equality:
1951 case Operator.Inequality:
1953 case Operator.BitwiseAnd:
1955 case Operator.BitwiseOr:
1957 case Operator.ExclusiveOr:
1959 case Operator.LogicalOr:
1961 case Operator.LogicalAnd:
1965 return oper.ToString ();
1968 public override string ToString ()
1970 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1971 right.ToString () + ")";
1974 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1976 if (expr.Type == target_type)
1979 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1982 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1985 34, loc, "Operator `" + OperName (oper)
1986 + "' is ambiguous on operands of type `"
1987 + TypeManager.CSharpName (l) + "' "
1988 + "and `" + TypeManager.CSharpName (r)
1992 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
1994 if ((l == t) || (r == t))
1997 if (!check_user_conversions)
2000 if (Convert.ImplicitUserConversionExists (ec, l, t))
2002 else if (Convert.ImplicitUserConversionExists (ec, r, t))
2009 // Note that handling the case l == Decimal || r == Decimal
2010 // is taken care of by the Step 1 Operator Overload resolution.
2012 // If `check_user_conv' is true, we also check whether a user-defined conversion
2013 // exists. Note that we only need to do this if both arguments are of a user-defined
2014 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
2015 // so we don't explicitly check for performance reasons.
2017 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
2019 if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
2021 // If either operand is of type double, the other operand is
2022 // conveted to type double.
2024 if (r != TypeManager.double_type)
2025 right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
2026 if (l != TypeManager.double_type)
2027 left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
2029 type = TypeManager.double_type;
2030 } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
2032 // if either operand is of type float, the other operand is
2033 // converted to type float.
2035 if (r != TypeManager.double_type)
2036 right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
2037 if (l != TypeManager.double_type)
2038 left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
2039 type = TypeManager.float_type;
2040 } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
2044 // If either operand is of type ulong, the other operand is
2045 // converted to type ulong. or an error ocurrs if the other
2046 // operand is of type sbyte, short, int or long
2048 if (l == TypeManager.uint64_type){
2049 if (r != TypeManager.uint64_type){
2050 if (right is IntConstant){
2051 IntConstant ic = (IntConstant) right;
2053 e = Convert.TryImplicitIntConversion (l, ic);
2056 } else if (right is LongConstant){
2057 long ll = ((LongConstant) right).Value;
2060 right = new ULongConstant ((ulong) ll);
2062 e = Convert.ImplicitNumericConversion (ec, right, l, loc);
2069 if (left is IntConstant){
2070 e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
2073 } else if (left is LongConstant){
2074 long ll = ((LongConstant) left).Value;
2077 left = new ULongConstant ((ulong) ll);
2079 e = Convert.ImplicitNumericConversion (ec, left, r, loc);
2086 if ((other == TypeManager.sbyte_type) ||
2087 (other == TypeManager.short_type) ||
2088 (other == TypeManager.int32_type) ||
2089 (other == TypeManager.int64_type))
2090 Error_OperatorAmbiguous (loc, oper, l, r);
2092 left = ForceConversion (ec, left, TypeManager.uint64_type);
2093 right = ForceConversion (ec, right, TypeManager.uint64_type);
2095 type = TypeManager.uint64_type;
2096 } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2098 // If either operand is of type long, the other operand is converted
2101 if (l != TypeManager.int64_type)
2102 left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
2103 if (r != TypeManager.int64_type)
2104 right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
2106 type = TypeManager.int64_type;
2107 } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2109 // If either operand is of type uint, and the other
2110 // operand is of type sbyte, short or int, othe operands are
2111 // converted to type long (unless we have an int constant).
2115 if (l == TypeManager.uint32_type){
2116 if (right is IntConstant){
2117 IntConstant ic = (IntConstant) right;
2121 right = new UIntConstant ((uint) val);
2128 } else if (r == TypeManager.uint32_type){
2129 if (left is IntConstant){
2130 IntConstant ic = (IntConstant) left;
2134 left = new UIntConstant ((uint) val);
2143 if ((other == TypeManager.sbyte_type) ||
2144 (other == TypeManager.short_type) ||
2145 (other == TypeManager.int32_type)){
2146 left = ForceConversion (ec, left, TypeManager.int64_type);
2147 right = ForceConversion (ec, right, TypeManager.int64_type);
2148 type = TypeManager.int64_type;
2151 // if either operand is of type uint, the other
2152 // operand is converd to type uint
2154 left = ForceConversion (ec, left, TypeManager.uint32_type);
2155 right = ForceConversion (ec, right, TypeManager.uint32_type);
2156 type = TypeManager.uint32_type;
2158 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2159 if (l != TypeManager.decimal_type)
2160 left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
2162 if (r != TypeManager.decimal_type)
2163 right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
2164 type = TypeManager.decimal_type;
2166 left = ForceConversion (ec, left, TypeManager.int32_type);
2167 right = ForceConversion (ec, right, TypeManager.int32_type);
2169 type = TypeManager.int32_type;
2172 return (left != null) && (right != null);
2175 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2177 Report.Error (19, loc,
2178 "Operator " + name + " cannot be applied to operands of type `" +
2179 TypeManager.CSharpName (l) + "' and `" +
2180 TypeManager.CSharpName (r) + "'");
2183 void Error_OperatorCannotBeApplied ()
2185 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2188 static bool is_unsigned (Type t)
2190 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2191 t == TypeManager.short_type || t == TypeManager.byte_type);
2194 static bool is_user_defined (Type t)
2196 if (t.IsSubclassOf (TypeManager.value_type) &&
2197 (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2203 Expression Make32or64 (EmitContext ec, Expression e)
2207 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2208 t == TypeManager.int64_type || t == TypeManager.uint64_type)
2210 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
2213 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
2216 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
2219 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
2225 Expression CheckShiftArguments (EmitContext ec)
2229 e = ForceConversion (ec, right, TypeManager.int32_type);
2231 Error_OperatorCannotBeApplied ();
2236 if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
2237 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
2238 ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
2239 ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
2243 if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
2244 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (31), loc);
2245 right = right.DoResolve (ec);
2247 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (63), loc);
2248 right = right.DoResolve (ec);
2253 Error_OperatorCannotBeApplied ();
2258 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2259 // i.e., not invoke op_Equality.
2261 static bool EqualsNullIsReferenceEquals (Type t)
2263 return t == TypeManager.object_type || t == TypeManager.string_type ||
2264 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
2267 Expression ResolveOperator (EmitContext ec)
2270 Type r = right.Type;
2272 if (oper == Operator.Equality || oper == Operator.Inequality){
2274 // Optimize out call to op_Equality in a few cases.
2276 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
2277 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
2279 Type = TypeManager.bool_type;
2285 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
2286 Type = TypeManager.bool_type;
2293 // Do not perform operator overload resolution when both sides are
2296 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){
2298 // Step 1: Perform Operator Overload location
2300 Expression left_expr, right_expr;
2302 string op = oper_names [(int) oper];
2304 MethodGroupExpr union;
2305 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2307 right_expr = MemberLookup (
2308 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2309 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2311 union = (MethodGroupExpr) left_expr;
2313 if (union != null) {
2314 ArrayList args = new ArrayList (2);
2315 args.Add (new Argument (left, Argument.AType.Expression));
2316 args.Add (new Argument (right, Argument.AType.Expression));
2318 MethodBase method = Invocation.OverloadResolve (
2319 ec, union, args, true, Location.Null);
2321 if (method != null) {
2322 MethodInfo mi = (MethodInfo) method;
2324 return new BinaryMethod (mi.ReturnType, method, args);
2330 // Step 0: String concatenation (because overloading will get this wrong)
2332 if (oper == Operator.Addition){
2334 // If any of the arguments is a string, cast to string
2337 // Simple constant folding
2338 if (left is StringConstant && right is StringConstant)
2339 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
2341 if (l == TypeManager.string_type || r == TypeManager.string_type) {
2343 if (r == TypeManager.void_type || l == TypeManager.void_type) {
2344 Error_OperatorCannotBeApplied ();
2348 // try to fold it in on the left
2349 if (left is StringConcat) {
2352 // We have to test here for not-null, since we can be doubly-resolved
2353 // take care of not appending twice
2356 type = TypeManager.string_type;
2357 ((StringConcat) left).Append (ec, right);
2358 return left.Resolve (ec);
2364 // Otherwise, start a new concat expression
2365 return new StringConcat (ec, loc, left, right).Resolve (ec);
2369 // Transform a + ( - b) into a - b
2371 if (right is Unary){
2372 Unary right_unary = (Unary) right;
2374 if (right_unary.Oper == Unary.Operator.UnaryNegation){
2375 oper = Operator.Subtraction;
2376 right = right_unary.Expr;
2382 if (oper == Operator.Equality || oper == Operator.Inequality){
2383 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2384 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2385 Error_OperatorCannotBeApplied ();
2389 type = TypeManager.bool_type;
2393 if (l.IsPointer || r.IsPointer) {
2394 if (l.IsPointer && r.IsPointer) {
2395 type = TypeManager.bool_type;
2399 if (l.IsPointer && r == TypeManager.null_type) {
2400 right = new EmptyCast (NullPointer.Null, l);
2401 type = TypeManager.bool_type;
2405 if (r.IsPointer && l == TypeManager.null_type) {
2406 left = new EmptyCast (NullPointer.Null, r);
2407 type = TypeManager.bool_type;
2413 // operator != (object a, object b)
2414 // operator == (object a, object b)
2416 // For this to be used, both arguments have to be reference-types.
2417 // Read the rationale on the spec (14.9.6)
2419 // Also, if at compile time we know that the classes do not inherit
2420 // one from the other, then we catch the error there.
2422 if (!(l.IsValueType || r.IsValueType)){
2423 type = TypeManager.bool_type;
2428 if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2432 // Also, a standard conversion must exist from either one
2434 if (!(Convert.ImplicitStandardConversionExists (ec, left, r) ||
2435 Convert.ImplicitStandardConversionExists (ec, right, l))){
2436 Error_OperatorCannotBeApplied ();
2440 // We are going to have to convert to an object to compare
2442 if (l != TypeManager.object_type)
2443 left = new EmptyCast (left, TypeManager.object_type);
2444 if (r != TypeManager.object_type)
2445 right = new EmptyCast (right, TypeManager.object_type);
2448 // FIXME: CSC here catches errors cs254 and cs252
2454 // One of them is a valuetype, but the other one is not.
2456 if (!l.IsValueType || !r.IsValueType) {
2457 Error_OperatorCannotBeApplied ();
2462 // Only perform numeric promotions on:
2463 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2465 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2466 if (l.IsSubclassOf (TypeManager.delegate_type)){
2467 if (((right.eclass == ExprClass.MethodGroup) ||
2468 (r == TypeManager.anonymous_method_type))){
2469 if ((RootContext.Version != LanguageVersion.ISO_1)){
2470 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2478 if (r.IsSubclassOf (TypeManager.delegate_type)){
2480 ArrayList args = new ArrayList (2);
2482 args = new ArrayList (2);
2483 args.Add (new Argument (left, Argument.AType.Expression));
2484 args.Add (new Argument (right, Argument.AType.Expression));
2486 if (oper == Operator.Addition)
2487 method = TypeManager.delegate_combine_delegate_delegate;
2489 method = TypeManager.delegate_remove_delegate_delegate;
2492 Error_OperatorCannotBeApplied ();
2496 return new BinaryDelegate (l, method, args);
2501 // Pointer arithmetic:
2503 // T* operator + (T* x, int y);
2504 // T* operator + (T* x, uint y);
2505 // T* operator + (T* x, long y);
2506 // T* operator + (T* x, ulong y);
2508 // T* operator + (int y, T* x);
2509 // T* operator + (uint y, T *x);
2510 // T* operator + (long y, T *x);
2511 // T* operator + (ulong y, T *x);
2513 // T* operator - (T* x, int y);
2514 // T* operator - (T* x, uint y);
2515 // T* operator - (T* x, long y);
2516 // T* operator - (T* x, ulong y);
2518 // long operator - (T* x, T *y)
2521 if (r.IsPointer && oper == Operator.Subtraction){
2523 return new PointerArithmetic (
2524 false, left, right, TypeManager.int64_type,
2527 Expression t = Make32or64 (ec, right);
2529 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2531 } else if (r.IsPointer && oper == Operator.Addition){
2532 Expression t = Make32or64 (ec, left);
2534 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2539 // Enumeration operators
2541 bool lie = TypeManager.IsEnumType (l);
2542 bool rie = TypeManager.IsEnumType (r);
2546 // U operator - (E e, E f)
2548 if (oper == Operator.Subtraction){
2550 type = TypeManager.EnumToUnderlying (l);
2553 Error_OperatorCannotBeApplied ();
2559 // operator + (E e, U x)
2560 // operator - (E e, U x)
2562 if (oper == Operator.Addition || oper == Operator.Subtraction){
2563 Type enum_type = lie ? l : r;
2564 Type other_type = lie ? r : l;
2565 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2567 if (underlying_type != other_type){
2568 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2578 Error_OperatorCannotBeApplied ();
2587 temp = Convert.ImplicitConversion (ec, right, l, loc);
2591 Error_OperatorCannotBeApplied ();
2595 temp = Convert.ImplicitConversion (ec, left, r, loc);
2600 Error_OperatorCannotBeApplied ();
2605 if (oper == Operator.Equality || oper == Operator.Inequality ||
2606 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2607 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2608 if (left.Type != right.Type){
2609 Error_OperatorCannotBeApplied ();
2612 type = TypeManager.bool_type;
2616 if (oper == Operator.BitwiseAnd ||
2617 oper == Operator.BitwiseOr ||
2618 oper == Operator.ExclusiveOr){
2619 if (left.Type != right.Type){
2620 Error_OperatorCannotBeApplied ();
2626 Error_OperatorCannotBeApplied ();
2630 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2631 return CheckShiftArguments (ec);
2633 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2634 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2635 type = TypeManager.bool_type;
2640 Error_OperatorCannotBeApplied ();
2644 Expression e = new ConditionalLogicalOperator (
2645 oper == Operator.LogicalAnd, left, right, l, loc);
2646 return e.Resolve (ec);
2650 // operator & (bool x, bool y)
2651 // operator | (bool x, bool y)
2652 // operator ^ (bool x, bool y)
2654 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2655 if (oper == Operator.BitwiseAnd ||
2656 oper == Operator.BitwiseOr ||
2657 oper == Operator.ExclusiveOr){
2664 // Pointer comparison
2666 if (l.IsPointer && r.IsPointer){
2667 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2668 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2669 type = TypeManager.bool_type;
2675 // This will leave left or right set to null if there is an error
2677 bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2678 DoNumericPromotions (ec, l, r, check_user_conv);
2679 if (left == null || right == null){
2680 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2685 // reload our cached types if required
2690 if (oper == Operator.BitwiseAnd ||
2691 oper == Operator.BitwiseOr ||
2692 oper == Operator.ExclusiveOr){
2694 if (((l == TypeManager.int32_type) ||
2695 (l == TypeManager.uint32_type) ||
2696 (l == TypeManager.short_type) ||
2697 (l == TypeManager.ushort_type) ||
2698 (l == TypeManager.int64_type) ||
2699 (l == TypeManager.uint64_type))){
2702 Error_OperatorCannotBeApplied ();
2706 Error_OperatorCannotBeApplied ();
2711 if (oper == Operator.Equality ||
2712 oper == Operator.Inequality ||
2713 oper == Operator.LessThanOrEqual ||
2714 oper == Operator.LessThan ||
2715 oper == Operator.GreaterThanOrEqual ||
2716 oper == Operator.GreaterThan){
2717 type = TypeManager.bool_type;
2723 public override Expression DoResolve (EmitContext ec)
2725 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2726 left = ((ParenthesizedExpression) left).Expr;
2727 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2731 if (left.eclass == ExprClass.Type) {
2732 Error (75, "Casting a negative value needs to have the value in parentheses.");
2736 left = left.Resolve (ec);
2741 Constant lc = left as Constant;
2742 if (lc != null && lc.Type == TypeManager.bool_type &&
2743 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2744 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2746 // TODO: make a sense to resolve unreachable expression as we do for statement
2747 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2751 right = right.Resolve (ec);
2755 eclass = ExprClass.Value;
2757 Constant rc = right as Constant;
2759 if (oper == Operator.BitwiseAnd) {
2760 if (rc != null && rc.IsZeroInteger) {
2761 return lc is EnumConstant ?
2762 new EnumConstant (rc, lc.Type):
2766 if (lc != null && lc.IsZeroInteger) {
2767 return rc is EnumConstant ?
2768 new EnumConstant (lc, rc.Type):
2773 if (rc != null && lc != null){
2774 Expression e = ConstantFold.BinaryFold (
2775 ec, oper, lc, rc, loc);
2780 return ResolveOperator (ec);
2784 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2785 /// context of a conditional bool expression. This function will return
2786 /// false if it is was possible to use EmitBranchable, or true if it was.
2788 /// The expression's code is generated, and we will generate a branch to `target'
2789 /// if the resulting expression value is equal to isTrue
2791 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2793 ILGenerator ig = ec.ig;
2796 // This is more complicated than it looks, but its just to avoid
2797 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2798 // but on top of that we want for == and != to use a special path
2799 // if we are comparing against null
2801 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2802 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2805 // put the constant on the rhs, for simplicity
2807 if (left is Constant) {
2808 Expression swap = right;
2813 if (((Constant) right).IsZeroInteger) {
2816 ig.Emit (OpCodes.Brtrue, target);
2818 ig.Emit (OpCodes.Brfalse, target);
2821 } else if (right is BoolConstant) {
2823 if (my_on_true != ((BoolConstant) right).Value)
2824 ig.Emit (OpCodes.Brtrue, target);
2826 ig.Emit (OpCodes.Brfalse, target);
2831 } else if (oper == Operator.LogicalAnd) {
2834 Label tests_end = ig.DefineLabel ();
2836 left.EmitBranchable (ec, tests_end, false);
2837 right.EmitBranchable (ec, target, true);
2838 ig.MarkLabel (tests_end);
2840 left.EmitBranchable (ec, target, false);
2841 right.EmitBranchable (ec, target, false);
2846 } else if (oper == Operator.LogicalOr){
2848 left.EmitBranchable (ec, target, true);
2849 right.EmitBranchable (ec, target, true);
2852 Label tests_end = ig.DefineLabel ();
2853 left.EmitBranchable (ec, tests_end, true);
2854 right.EmitBranchable (ec, target, false);
2855 ig.MarkLabel (tests_end);
2860 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2861 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2862 oper == Operator.Equality || oper == Operator.Inequality)) {
2863 base.EmitBranchable (ec, target, onTrue);
2871 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2874 case Operator.Equality:
2876 ig.Emit (OpCodes.Beq, target);
2878 ig.Emit (OpCodes.Bne_Un, target);
2881 case Operator.Inequality:
2883 ig.Emit (OpCodes.Bne_Un, target);
2885 ig.Emit (OpCodes.Beq, target);
2888 case Operator.LessThan:
2891 ig.Emit (OpCodes.Blt_Un, target);
2893 ig.Emit (OpCodes.Blt, target);
2896 ig.Emit (OpCodes.Bge_Un, target);
2898 ig.Emit (OpCodes.Bge, target);
2901 case Operator.GreaterThan:
2904 ig.Emit (OpCodes.Bgt_Un, target);
2906 ig.Emit (OpCodes.Bgt, target);
2909 ig.Emit (OpCodes.Ble_Un, target);
2911 ig.Emit (OpCodes.Ble, target);
2914 case Operator.LessThanOrEqual:
2917 ig.Emit (OpCodes.Ble_Un, target);
2919 ig.Emit (OpCodes.Ble, target);
2922 ig.Emit (OpCodes.Bgt_Un, target);
2924 ig.Emit (OpCodes.Bgt, target);
2928 case Operator.GreaterThanOrEqual:
2931 ig.Emit (OpCodes.Bge_Un, target);
2933 ig.Emit (OpCodes.Bge, target);
2936 ig.Emit (OpCodes.Blt_Un, target);
2938 ig.Emit (OpCodes.Blt, target);
2941 Console.WriteLine (oper);
2942 throw new Exception ("what is THAT");
2946 public override void Emit (EmitContext ec)
2948 ILGenerator ig = ec.ig;
2953 // Handle short-circuit operators differently
2956 if (oper == Operator.LogicalAnd) {
2957 Label load_zero = ig.DefineLabel ();
2958 Label end = ig.DefineLabel ();
2960 left.EmitBranchable (ec, load_zero, false);
2962 ig.Emit (OpCodes.Br, end);
2964 ig.MarkLabel (load_zero);
2965 ig.Emit (OpCodes.Ldc_I4_0);
2968 } else if (oper == Operator.LogicalOr) {
2969 Label load_one = ig.DefineLabel ();
2970 Label end = ig.DefineLabel ();
2972 left.EmitBranchable (ec, load_one, true);
2974 ig.Emit (OpCodes.Br, end);
2976 ig.MarkLabel (load_one);
2977 ig.Emit (OpCodes.Ldc_I4_1);
2985 bool isUnsigned = is_unsigned (left.Type);
2988 case Operator.Multiply:
2990 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2991 opcode = OpCodes.Mul_Ovf;
2992 else if (isUnsigned)
2993 opcode = OpCodes.Mul_Ovf_Un;
2995 opcode = OpCodes.Mul;
2997 opcode = OpCodes.Mul;
3001 case Operator.Division:
3003 opcode = OpCodes.Div_Un;
3005 opcode = OpCodes.Div;
3008 case Operator.Modulus:
3010 opcode = OpCodes.Rem_Un;
3012 opcode = OpCodes.Rem;
3015 case Operator.Addition:
3017 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3018 opcode = OpCodes.Add_Ovf;
3019 else if (isUnsigned)
3020 opcode = OpCodes.Add_Ovf_Un;
3022 opcode = OpCodes.Add;
3024 opcode = OpCodes.Add;
3027 case Operator.Subtraction:
3029 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3030 opcode = OpCodes.Sub_Ovf;
3031 else if (isUnsigned)
3032 opcode = OpCodes.Sub_Ovf_Un;
3034 opcode = OpCodes.Sub;
3036 opcode = OpCodes.Sub;
3039 case Operator.RightShift:
3041 opcode = OpCodes.Shr_Un;
3043 opcode = OpCodes.Shr;
3046 case Operator.LeftShift:
3047 opcode = OpCodes.Shl;
3050 case Operator.Equality:
3051 opcode = OpCodes.Ceq;
3054 case Operator.Inequality:
3055 ig.Emit (OpCodes.Ceq);
3056 ig.Emit (OpCodes.Ldc_I4_0);
3058 opcode = OpCodes.Ceq;
3061 case Operator.LessThan:
3063 opcode = OpCodes.Clt_Un;
3065 opcode = OpCodes.Clt;
3068 case Operator.GreaterThan:
3070 opcode = OpCodes.Cgt_Un;
3072 opcode = OpCodes.Cgt;
3075 case Operator.LessThanOrEqual:
3076 Type lt = left.Type;
3078 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3079 ig.Emit (OpCodes.Cgt_Un);
3081 ig.Emit (OpCodes.Cgt);
3082 ig.Emit (OpCodes.Ldc_I4_0);
3084 opcode = OpCodes.Ceq;
3087 case Operator.GreaterThanOrEqual:
3088 Type le = left.Type;
3090 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3091 ig.Emit (OpCodes.Clt_Un);
3093 ig.Emit (OpCodes.Clt);
3095 ig.Emit (OpCodes.Ldc_I4_0);
3097 opcode = OpCodes.Ceq;
3100 case Operator.BitwiseOr:
3101 opcode = OpCodes.Or;
3104 case Operator.BitwiseAnd:
3105 opcode = OpCodes.And;
3108 case Operator.ExclusiveOr:
3109 opcode = OpCodes.Xor;
3113 throw new Exception ("This should not happen: Operator = "
3114 + oper.ToString ());
3122 // Object created by Binary when the binary operator uses an method instead of being
3123 // a binary operation that maps to a CIL binary operation.
3125 public class BinaryMethod : Expression {
3126 public MethodBase method;
3127 public ArrayList Arguments;
3129 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3134 eclass = ExprClass.Value;
3137 public override Expression DoResolve (EmitContext ec)
3142 public override void Emit (EmitContext ec)
3144 ILGenerator ig = ec.ig;
3146 if (Arguments != null)
3147 Invocation.EmitArguments (ec, method, Arguments, false, null);
3149 if (method is MethodInfo)
3150 ig.Emit (OpCodes.Call, (MethodInfo) method);
3152 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3157 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3158 // b, c, d... may be strings or objects.
3160 public class StringConcat : Expression {
3162 bool invalid = false;
3163 bool emit_conv_done = false;
3165 // Are we also concating objects?
3167 bool is_strings_only = true;
3169 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3172 type = TypeManager.string_type;
3173 eclass = ExprClass.Value;
3175 operands = new ArrayList (2);
3180 public override Expression DoResolve (EmitContext ec)
3188 public void Append (EmitContext ec, Expression operand)
3193 if (operand is StringConstant && operands.Count != 0) {
3194 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3195 if (last_operand != null) {
3196 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
3202 // Conversion to object
3204 if (operand.Type != TypeManager.string_type) {
3205 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3208 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3214 operands.Add (operand);
3217 public override void Emit (EmitContext ec)
3219 MethodInfo concat_method = null;
3222 // Do conversion to arguments; check for strings only
3225 // This can get called multiple times, so we have to deal with that.
3226 if (!emit_conv_done) {
3227 emit_conv_done = true;
3228 for (int i = 0; i < operands.Count; i ++) {
3229 Expression e = (Expression) operands [i];
3230 is_strings_only &= e.Type == TypeManager.string_type;
3233 for (int i = 0; i < operands.Count; i ++) {
3234 Expression e = (Expression) operands [i];
3236 if (! is_strings_only && e.Type == TypeManager.string_type) {
3237 // need to make sure this is an object, because the EmitParams
3238 // method might look at the type of this expression, see it is a
3239 // string and emit a string [] when we want an object [];
3241 e = new EmptyCast (e, TypeManager.object_type);
3243 operands [i] = new Argument (e, Argument.AType.Expression);
3248 // Find the right method
3250 switch (operands.Count) {
3253 // This should not be possible, because simple constant folding
3254 // is taken care of in the Binary code.
3256 throw new Exception ("how did you get here?");
3259 concat_method = is_strings_only ?
3260 TypeManager.string_concat_string_string :
3261 TypeManager.string_concat_object_object ;
3264 concat_method = is_strings_only ?
3265 TypeManager.string_concat_string_string_string :
3266 TypeManager.string_concat_object_object_object ;
3270 // There is not a 4 param overlaod for object (the one that there is
3271 // is actually a varargs methods, and is only in corlib because it was
3272 // introduced there before.).
3274 if (!is_strings_only)
3277 concat_method = TypeManager.string_concat_string_string_string_string;
3280 concat_method = is_strings_only ?
3281 TypeManager.string_concat_string_dot_dot_dot :
3282 TypeManager.string_concat_object_dot_dot_dot ;
3286 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3287 ec.ig.Emit (OpCodes.Call, concat_method);
3292 // Object created with +/= on delegates
3294 public class BinaryDelegate : Expression {
3298 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3303 eclass = ExprClass.Value;
3306 public override Expression DoResolve (EmitContext ec)
3311 public override void Emit (EmitContext ec)
3313 ILGenerator ig = ec.ig;
3315 Invocation.EmitArguments (ec, method, args, false, null);
3317 ig.Emit (OpCodes.Call, (MethodInfo) method);
3318 ig.Emit (OpCodes.Castclass, type);
3321 public Expression Right {
3323 Argument arg = (Argument) args [1];
3328 public bool IsAddition {
3330 return method == TypeManager.delegate_combine_delegate_delegate;
3336 // User-defined conditional logical operator
3337 public class ConditionalLogicalOperator : Expression {
3338 Expression left, right;
3341 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3344 eclass = ExprClass.Value;
3348 this.is_and = is_and;
3351 protected void Error19 ()
3353 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3356 protected void Error218 ()
3358 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3359 "declarations of operator true and operator false");
3362 Expression op_true, op_false, op;
3363 LocalTemporary left_temp;
3365 public override Expression DoResolve (EmitContext ec)
3368 Expression operator_group;
3370 operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3371 if (operator_group == null) {
3376 left_temp = new LocalTemporary (ec, type);
3378 ArrayList arguments = new ArrayList ();
3379 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3380 arguments.Add (new Argument (right, Argument.AType.Expression));
3381 method = Invocation.OverloadResolve (
3382 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3384 if (method == null) {
3389 if (method.ReturnType != type) {
3390 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator ('{0}') " +
3391 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3395 op = new StaticCallExpr (method, arguments, loc);
3397 op_true = GetOperatorTrue (ec, left_temp, loc);
3398 op_false = GetOperatorFalse (ec, left_temp, loc);
3399 if ((op_true == null) || (op_false == null)) {
3407 public override void Emit (EmitContext ec)
3409 ILGenerator ig = ec.ig;
3410 Label false_target = ig.DefineLabel ();
3411 Label end_target = ig.DefineLabel ();
3414 left_temp.Store (ec);
3416 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3417 left_temp.Emit (ec);
3418 ig.Emit (OpCodes.Br, end_target);
3419 ig.MarkLabel (false_target);
3421 ig.MarkLabel (end_target);
3425 public class PointerArithmetic : Expression {
3426 Expression left, right;
3430 // We assume that `l' is always a pointer
3432 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3438 is_add = is_addition;
3441 public override Expression DoResolve (EmitContext ec)
3443 eclass = ExprClass.Variable;
3445 if (left.Type == TypeManager.void_ptr_type) {
3446 Error (242, "The operation in question is undefined on void pointers");
3453 public override void Emit (EmitContext ec)
3455 Type op_type = left.Type;
3456 ILGenerator ig = ec.ig;
3458 // It must be either array or fixed buffer
3459 Type element = TypeManager.HasElementType (op_type) ?
3460 element = TypeManager.GetElementType (op_type) :
3461 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3463 int size = GetTypeSize (element);
3464 Type rtype = right.Type;
3466 if (rtype.IsPointer){
3468 // handle (pointer - pointer)
3472 ig.Emit (OpCodes.Sub);
3476 ig.Emit (OpCodes.Sizeof, element);
3478 IntLiteral.EmitInt (ig, size);
3479 ig.Emit (OpCodes.Div);
3481 ig.Emit (OpCodes.Conv_I8);
3484 // handle + and - on (pointer op int)
3487 ig.Emit (OpCodes.Conv_I);
3489 Constant right_const = right as Constant;
3490 if (right_const != null && size != 0) {
3491 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size), right_const, loc);
3499 ig.Emit (OpCodes.Sizeof, element);
3501 IntLiteral.EmitInt (ig, size);
3502 if (rtype == TypeManager.int64_type)
3503 ig.Emit (OpCodes.Conv_I8);
3504 else if (rtype == TypeManager.uint64_type)
3505 ig.Emit (OpCodes.Conv_U8);
3506 ig.Emit (OpCodes.Mul);
3510 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3511 ig.Emit (OpCodes.Conv_I);
3514 ig.Emit (OpCodes.Add);
3516 ig.Emit (OpCodes.Sub);
3522 /// Implements the ternary conditional operator (?:)
3524 public class Conditional : Expression {
3525 Expression expr, trueExpr, falseExpr;
3527 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3530 this.trueExpr = trueExpr;
3531 this.falseExpr = falseExpr;
3535 public Expression Expr {
3541 public Expression TrueExpr {
3547 public Expression FalseExpr {
3553 public override Expression DoResolve (EmitContext ec)
3555 expr = expr.Resolve (ec);
3560 if (expr.Type != TypeManager.bool_type){
3561 expr = Expression.ResolveBoolean (
3568 trueExpr = trueExpr.Resolve (ec);
3569 falseExpr = falseExpr.Resolve (ec);
3571 if (trueExpr == null || falseExpr == null)
3574 eclass = ExprClass.Value;
3575 if (trueExpr.Type == falseExpr.Type)
3576 type = trueExpr.Type;
3579 Type true_type = trueExpr.Type;
3580 Type false_type = falseExpr.Type;
3583 // First, if an implicit conversion exists from trueExpr
3584 // to falseExpr, then the result type is of type falseExpr.Type
3586 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3589 // Check if both can convert implicitl to each other's type
3591 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3593 "Can not compute type of conditional expression " +
3594 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3595 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3596 "' convert implicitly to each other");
3601 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3605 Error (173, "The type of the conditional expression can " +
3606 "not be computed because there is no implicit conversion" +
3607 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3608 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3613 // Dead code optimalization
3614 if (expr is BoolConstant){
3615 BoolConstant bc = (BoolConstant) expr;
3617 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3618 return bc.Value ? trueExpr : falseExpr;
3624 public override void Emit (EmitContext ec)
3626 ILGenerator ig = ec.ig;
3627 Label false_target = ig.DefineLabel ();
3628 Label end_target = ig.DefineLabel ();
3630 expr.EmitBranchable (ec, false_target, false);
3632 ig.Emit (OpCodes.Br, end_target);
3633 ig.MarkLabel (false_target);
3634 falseExpr.Emit (ec);
3635 ig.MarkLabel (end_target);
3643 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3644 public readonly string Name;
3645 public readonly Block Block;
3646 public LocalInfo local_info;
3649 LocalTemporary temp;
3651 public LocalVariableReference (Block block, string name, Location l)
3656 eclass = ExprClass.Variable;
3660 // Setting `is_readonly' to false will allow you to create a writable
3661 // reference to a read-only variable. This is used by foreach and using.
3663 public LocalVariableReference (Block block, string name, Location l,
3664 LocalInfo local_info, bool is_readonly)
3665 : this (block, name, l)
3667 this.local_info = local_info;
3668 this.is_readonly = is_readonly;
3671 public VariableInfo VariableInfo {
3673 return local_info.VariableInfo;
3677 public bool IsReadOnly {
3683 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3685 if (local_info == null) {
3686 local_info = Block.GetLocalInfo (Name);
3689 if (lvalue_right_side == EmptyExpression.Null)
3690 local_info.Used = true;
3692 is_readonly = local_info.ReadOnly;
3695 type = local_info.VariableType;
3697 VariableInfo variable_info = local_info.VariableInfo;
3698 if (lvalue_right_side != null){
3700 if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.Null)
3701 Report.Error (1657, loc, "Cannot pass '{0}' with '{1}' modifier because it is a '{2}'",
3702 Name, lvalue_right_side == EmptyExpression.Null ? "out" : "ref",
3703 local_info.GetReadOnlyContext ());
3705 Report.Error (1656, loc, "Cannot assign to '{0}' because it is a '{1}'",
3706 Name, local_info.GetReadOnlyContext ());
3710 if (variable_info != null)
3711 variable_info.SetAssigned (ec);
3714 Expression e = Block.GetConstantExpression (Name);
3716 local_info.Used = true;
3717 eclass = ExprClass.Value;
3718 return e.Resolve (ec);
3721 if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3724 if (lvalue_right_side == null)
3725 local_info.Used = true;
3727 if (ec.CurrentAnonymousMethod != null){
3729 // If we are referencing a variable from the external block
3730 // flag it for capturing
3732 if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){
3733 if (local_info.AddressTaken){
3734 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3737 ec.CaptureVariable (local_info);
3744 public override Expression DoResolve (EmitContext ec)
3746 return DoResolveBase (ec, null);
3749 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3751 Expression ret = DoResolveBase (ec, right_side);
3753 CheckObsoleteAttribute (ret.Type);
3758 public bool VerifyFixed (bool is_expression)
3760 return !is_expression || local_info.IsFixed;
3763 public override int GetHashCode()
3765 return Name.GetHashCode ();
3768 public override bool Equals (object obj)
3770 LocalVariableReference lvr = obj as LocalVariableReference;
3774 return Name == lvr.Name && Block == lvr.Block;
3777 public override void Emit (EmitContext ec)
3779 ILGenerator ig = ec.ig;
3781 if (local_info.FieldBuilder == null){
3783 // A local variable on the local CLR stack
3785 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3788 // A local variable captured by anonymous methods.
3791 ec.EmitCapturedVariableInstance (local_info);
3793 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3797 public void Emit (EmitContext ec, bool leave_copy)
3801 ec.ig.Emit (OpCodes.Dup);
3802 if (local_info.FieldBuilder != null){
3803 temp = new LocalTemporary (ec, Type);
3809 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3811 ILGenerator ig = ec.ig;
3812 prepared = prepare_for_load;
3814 if (local_info.FieldBuilder == null){
3816 // A local variable on the local CLR stack
3818 if (local_info.LocalBuilder == null)
3819 throw new Exception ("This should not happen: both Field and Local are null");
3823 ec.ig.Emit (OpCodes.Dup);
3824 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3827 // A local variable captured by anonymous methods or itereators.
3829 ec.EmitCapturedVariableInstance (local_info);
3831 if (prepare_for_load)
3832 ig.Emit (OpCodes.Dup);
3835 ig.Emit (OpCodes.Dup);
3836 temp = new LocalTemporary (ec, Type);
3839 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3845 public void AddressOf (EmitContext ec, AddressOp mode)
3847 ILGenerator ig = ec.ig;
3849 if (local_info.FieldBuilder == null){
3851 // A local variable on the local CLR stack
3853 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3856 // A local variable captured by anonymous methods or iterators
3858 ec.EmitCapturedVariableInstance (local_info);
3859 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3863 public override string ToString ()
3865 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3870 /// This represents a reference to a parameter in the intermediate
3873 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3879 public Parameter.Modifier mod;
3880 public bool is_ref, is_out, prepared;
3894 LocalTemporary temp;
3896 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3903 eclass = ExprClass.Variable;
3906 public VariableInfo VariableInfo {
3910 public bool VerifyFixed (bool is_expression)
3912 return !is_expression || TypeManager.IsValueType (type);
3915 public bool IsAssigned (EmitContext ec, Location loc)
3917 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3920 Report.Error (269, loc,
3921 "Use of unassigned out parameter '{0}'", name);
3925 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3927 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3930 Report.Error (170, loc,
3931 "Use of possibly unassigned field `" + field_name + "'");
3935 public void SetAssigned (EmitContext ec)
3937 if (is_out && ec.DoFlowAnalysis)
3938 ec.CurrentBranching.SetAssigned (vi);
3941 public void SetFieldAssigned (EmitContext ec, string field_name)
3943 if (is_out && ec.DoFlowAnalysis)
3944 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3947 protected void DoResolveBase (EmitContext ec)
3949 type = pars.GetParameterInfo (ec, idx, out mod);
3950 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3951 is_out = (mod & Parameter.Modifier.OUT) != 0;
3952 eclass = ExprClass.Variable;
3955 vi = block.ParameterMap [idx];
3957 if (ec.CurrentAnonymousMethod != null){
3959 Report.Error (1628, Location,
3960 "Can not reference a ref or out parameter in an anonymous method");
3965 // If we are referencing the parameter from the external block
3966 // flag it for capturing
3968 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3969 if (!block.Toplevel.IsLocalParameter (name)){
3970 ec.CaptureParameter (name, type, idx);
3975 public override int GetHashCode()
3977 return name.GetHashCode ();
3980 public override bool Equals (object obj)
3982 ParameterReference pr = obj as ParameterReference;
3986 return name == pr.name && block == pr.block;
3990 // Notice that for ref/out parameters, the type exposed is not the
3991 // same type exposed externally.
3994 // externally we expose "int&"
3995 // here we expose "int".
3997 // We record this in "is_ref". This means that the type system can treat
3998 // the type as it is expected, but when we generate the code, we generate
3999 // the alternate kind of code.
4001 public override Expression DoResolve (EmitContext ec)
4005 if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
4008 if (ec.RemapToProxy)
4009 return ec.RemapParameter (idx);
4014 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4020 if (ec.RemapToProxy)
4021 return ec.RemapParameterLValue (idx, right_side);
4026 static public void EmitLdArg (ILGenerator ig, int x)
4030 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4031 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4032 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4033 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4034 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4037 ig.Emit (OpCodes.Ldarg, x);
4041 // This method is used by parameters that are references, that are
4042 // being passed as references: we only want to pass the pointer (that
4043 // is already stored in the parameter, not the address of the pointer,
4044 // and not the value of the variable).
4046 public void EmitLoad (EmitContext ec)
4048 ILGenerator ig = ec.ig;
4051 if (!ec.MethodIsStatic)
4055 EmitLdArg (ig, arg_idx);
4058 // FIXME: Review for anonymous methods
4062 public override void Emit (EmitContext ec)
4064 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4065 ec.EmitParameter (name);
4072 public void Emit (EmitContext ec, bool leave_copy)
4074 ILGenerator ig = ec.ig;
4077 if (!ec.MethodIsStatic)
4080 EmitLdArg (ig, arg_idx);
4084 ec.ig.Emit (OpCodes.Dup);
4087 // If we are a reference, we loaded on the stack a pointer
4088 // Now lets load the real value
4090 LoadFromPtr (ig, type);
4094 ec.ig.Emit (OpCodes.Dup);
4097 temp = new LocalTemporary (ec, type);
4103 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4105 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4106 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
4110 ILGenerator ig = ec.ig;
4113 prepared = prepare_for_load;
4115 if (!ec.MethodIsStatic)
4118 if (is_ref && !prepared)
4119 EmitLdArg (ig, arg_idx);
4124 ec.ig.Emit (OpCodes.Dup);
4128 temp = new LocalTemporary (ec, type);
4132 StoreFromPtr (ig, type);
4138 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
4140 ig.Emit (OpCodes.Starg, arg_idx);
4144 public void AddressOf (EmitContext ec, AddressOp mode)
4146 if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4147 ec.EmitAddressOfParameter (name);
4153 if (!ec.MethodIsStatic)
4158 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4160 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4163 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4165 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4172 /// Used for arguments to New(), Invocation()
4174 public class Argument {
4175 public enum AType : byte {
4182 public readonly AType ArgType;
4183 public Expression Expr;
4185 public Argument (Expression expr, AType type)
4188 this.ArgType = type;
4191 public Argument (Expression expr)
4194 this.ArgType = AType.Expression;
4199 if (ArgType == AType.Ref || ArgType == AType.Out)
4200 return TypeManager.GetReferenceType (Expr.Type);
4206 public Parameter.Modifier Modifier
4211 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4214 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4217 return Parameter.Modifier.NONE;
4222 public static string FullDesc (Argument a)
4224 if (a.ArgType == AType.ArgList)
4227 return (a.ArgType == AType.Ref ? "ref " :
4228 (a.ArgType == AType.Out ? "out " : "")) +
4229 TypeManager.CSharpName (a.Expr.Type);
4232 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4234 // FIXME: csc doesn't report any error if you try to use `ref' or
4235 // `out' in a delegate creation expression.
4236 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4243 void Error_LValueRequired (Location loc)
4245 Report.Error (1510, loc, "An lvalue is required as an argument to out or ref");
4248 public bool Resolve (EmitContext ec, Location loc)
4250 bool old_do_flow_analysis = ec.DoFlowAnalysis;
4251 ec.DoFlowAnalysis = true;
4253 if (ArgType == AType.Ref) {
4254 ec.InRefOutArgumentResolving = true;
4255 Expr = Expr.Resolve (ec);
4256 ec.InRefOutArgumentResolving = false;
4258 ec.DoFlowAnalysis = old_do_flow_analysis;
4262 Expr = Expr.DoResolveLValue (ec, Expr);
4264 Error_LValueRequired (loc);
4265 } else if (ArgType == AType.Out) {
4266 ec.InRefOutArgumentResolving = true;
4267 Expr = Expr.DoResolveLValue (ec, EmptyExpression.Null);
4268 ec.InRefOutArgumentResolving = false;
4271 Error_LValueRequired (loc);
4274 Expr = Expr.Resolve (ec);
4276 ec.DoFlowAnalysis = old_do_flow_analysis;
4281 if (ArgType == AType.Expression)
4285 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4286 // This is only allowed for `this'
4288 FieldExpr fe = Expr as FieldExpr;
4289 if (fe != null && !fe.IsStatic){
4290 Expression instance = fe.InstanceExpression;
4292 if (instance.GetType () != typeof (This)){
4293 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4294 Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type);
4295 Report.Error (197, loc, "Cannot pass '{0}' as ref or out or take its address because it is a member of a marshal-by-reference class",
4303 if (Expr.eclass != ExprClass.Variable){
4305 // We just probe to match the CSC output
4307 if (Expr.eclass == ExprClass.PropertyAccess ||
4308 Expr.eclass == ExprClass.IndexerAccess){
4311 "A property or indexer can not be passed as an out or ref " +
4314 Error_LValueRequired (loc);
4322 public void Emit (EmitContext ec)
4325 // Ref and Out parameters need to have their addresses taken.
4327 // ParameterReferences might already be references, so we want
4328 // to pass just the value
4330 if (ArgType == AType.Ref || ArgType == AType.Out){
4331 AddressOp mode = AddressOp.Store;
4333 if (ArgType == AType.Ref)
4334 mode |= AddressOp.Load;
4336 if (Expr is ParameterReference){
4337 ParameterReference pr = (ParameterReference) Expr;
4343 pr.AddressOf (ec, mode);
4346 if (Expr is IMemoryLocation)
4347 ((IMemoryLocation) Expr).AddressOf (ec, mode);
4350 1510, Expr.Location,
4351 "An lvalue is required as an argument to out or ref");
4361 /// Invocation of methods or delegates.
4363 public class Invocation : ExpressionStatement {
4364 public readonly ArrayList Arguments;
4367 MethodBase method = null;
4370 // arguments is an ArrayList, but we do not want to typecast,
4371 // as it might be null.
4373 // FIXME: only allow expr to be a method invocation or a
4374 // delegate invocation (7.5.5)
4376 public Invocation (Expression expr, ArrayList arguments, Location l)
4379 Arguments = arguments;
4383 public Expression Expr {
4390 /// Determines "better conversion" as specified in 7.4.2.3
4392 /// Returns : p if a->p is better,
4393 /// q if a->q is better,
4394 /// null if neither is better
4396 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4398 Type argument_type = a.Type;
4399 Expression argument_expr = a.Expr;
4401 if (argument_type == null)
4402 throw new Exception ("Expression of type " + a.Expr +
4403 " does not resolve its type");
4405 if (p == null || q == null)
4406 throw new InternalErrorException ("BetterConversion Got a null conversion");
4411 if (argument_expr is NullLiteral) {
4413 // If the argument is null and one of the types to compare is 'object' and
4414 // the other is a reference type, we prefer the other.
4416 // This follows from the usual rules:
4417 // * There is an implicit conversion from 'null' to type 'object'
4418 // * There is an implicit conversion from 'null' to any reference type
4419 // * There is an implicit conversion from any reference type to type 'object'
4420 // * There is no implicit conversion from type 'object' to other reference types
4421 // => Conversion of 'null' to a reference type is better than conversion to 'object'
4423 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
4424 // null type. I think it used to be 'object' and thus needed a special
4425 // case to avoid the immediately following two checks.
4427 if (!p.IsValueType && q == TypeManager.object_type)
4429 if (!q.IsValueType && p == TypeManager.object_type)
4433 if (argument_type == p)
4436 if (argument_type == q)
4439 Expression p_tmp = new EmptyExpression (p);
4440 Expression q_tmp = new EmptyExpression (q);
4442 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4443 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4445 if (p_to_q && !q_to_p)
4448 if (q_to_p && !p_to_q)
4451 if (p == TypeManager.sbyte_type)
4452 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4453 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4455 if (q == TypeManager.sbyte_type)
4456 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4457 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4460 if (p == TypeManager.short_type)
4461 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4462 q == TypeManager.uint64_type)
4464 if (q == TypeManager.short_type)
4465 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4466 p == TypeManager.uint64_type)
4469 if (p == TypeManager.int32_type)
4470 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4472 if (q == TypeManager.int32_type)
4473 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4476 if (p == TypeManager.int64_type)
4477 if (q == TypeManager.uint64_type)
4479 if (q == TypeManager.int64_type)
4480 if (p == TypeManager.uint64_type)
4487 /// Determines "Better function" between candidate
4488 /// and the current best match
4491 /// Returns an integer indicating :
4492 /// false if candidate ain't better
4493 /// true if candidate is better than the current best match
4495 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4496 MethodBase candidate, bool candidate_params,
4497 MethodBase best, bool best_params, Location loc)
4499 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4500 ParameterData best_pd = TypeManager.GetParameterData (best);
4502 bool better_at_least_one = false;
4504 for (int j = 0; j < argument_count; ++j) {
4505 Argument a = (Argument) args [j];
4507 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4508 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4510 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4511 if (candidate_params)
4512 ct = TypeManager.GetElementType (ct);
4514 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4516 bt = TypeManager.GetElementType (bt);
4522 Type better = BetterConversion (ec, a, ct, bt, loc);
4524 // for each argument, the conversion to 'ct' should be no worse than
4525 // the conversion to 'bt'.
4529 // for at least one argument, the conversion to 'ct' should be better than
4530 // the conversion to 'bt'.
4532 better_at_least_one = true;
4535 if (better_at_least_one)
4539 // This handles the case
4541 // Add (float f1, float f2, float f3);
4542 // Add (params decimal [] foo);
4544 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4545 // first candidate would've chosen as better.
4551 // This handles the following cases:
4553 // Trim () is better than Trim (params char[] chars)
4554 // Concat (string s1, string s2, string s3) is better than
4555 // Concat (string s1, params string [] srest)
4557 return !candidate_params && best_params;
4560 static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4562 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4565 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4566 ParameterData base_pd = TypeManager.GetParameterData (base_method);
4568 if (cand_pd.Count != base_pd.Count)
4571 for (int j = 0; j < cand_pd.Count; ++j) {
4572 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4573 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4574 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4575 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4577 if (cm != bm || ct != bt)
4584 public static string FullMethodDesc (MethodBase mb)
4586 string ret_type = "";
4591 if (mb is MethodInfo)
4592 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4594 StringBuilder sb = new StringBuilder (ret_type);
4596 sb.Append (mb.ReflectedType.ToString ());
4598 sb.Append (mb.Name);
4600 ParameterData pd = TypeManager.GetParameterData (mb);
4602 int count = pd.Count;
4605 for (int i = count; i > 0; ) {
4608 sb.Append (pd.ParameterDesc (count - i - 1));
4614 return sb.ToString ();
4617 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4619 MemberInfo [] miset;
4620 MethodGroupExpr union;
4625 return (MethodGroupExpr) mg2;
4628 return (MethodGroupExpr) mg1;
4631 MethodGroupExpr left_set = null, right_set = null;
4632 int length1 = 0, length2 = 0;
4634 left_set = (MethodGroupExpr) mg1;
4635 length1 = left_set.Methods.Length;
4637 right_set = (MethodGroupExpr) mg2;
4638 length2 = right_set.Methods.Length;
4640 ArrayList common = new ArrayList ();
4642 foreach (MethodBase r in right_set.Methods){
4643 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4647 miset = new MemberInfo [length1 + length2 - common.Count];
4648 left_set.Methods.CopyTo (miset, 0);
4652 foreach (MethodBase r in right_set.Methods) {
4653 if (!common.Contains (r))
4657 union = new MethodGroupExpr (miset, loc);
4662 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4663 ArrayList arguments, int arg_count,
4664 ref MethodBase candidate)
4666 return IsParamsMethodApplicable (
4667 ec, me, arguments, arg_count, false, ref candidate) ||
4668 IsParamsMethodApplicable (
4669 ec, me, arguments, arg_count, true, ref candidate);
4674 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4675 ArrayList arguments, int arg_count,
4676 bool do_varargs, ref MethodBase candidate)
4678 return IsParamsMethodApplicable (
4679 ec, arguments, arg_count, candidate, do_varargs);
4683 /// Determines if the candidate method, if a params method, is applicable
4684 /// in its expanded form to the given set of arguments
4686 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4687 int arg_count, MethodBase candidate,
4690 ParameterData pd = TypeManager.GetParameterData (candidate);
4692 int pd_count = pd.Count;
4696 int count = pd_count - 1;
4698 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4700 if (pd_count != arg_count)
4703 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4707 if (count > arg_count)
4710 if (pd_count == 1 && arg_count == 0)
4714 // If we have come this far, the case which
4715 // remains is when the number of parameters is
4716 // less than or equal to the argument count.
4718 for (int i = 0; i < count; ++i) {
4720 Argument a = (Argument) arguments [i];
4722 Parameter.Modifier a_mod = a.Modifier &
4723 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4724 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4725 (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4727 if (a_mod == p_mod) {
4729 if (a_mod == Parameter.Modifier.NONE)
4730 if (!Convert.ImplicitConversionExists (ec,
4732 pd.ParameterType (i)))
4735 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4736 Type pt = pd.ParameterType (i);
4739 pt = TypeManager.GetReferenceType (pt);
4750 Argument a = (Argument) arguments [count];
4751 if (!(a.Expr is Arglist))
4757 Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4759 for (int i = pd_count - 1; i < arg_count; i++) {
4760 Argument a = (Argument) arguments [i];
4762 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4769 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4770 ArrayList arguments, int arg_count,
4771 ref MethodBase candidate)
4773 return IsApplicable (ec, arguments, arg_count, candidate);
4777 /// Determines if the candidate method is applicable (section 14.4.2.1)
4778 /// to the given set of arguments
4780 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4781 MethodBase candidate)
4783 ParameterData pd = TypeManager.GetParameterData (candidate);
4785 if (arg_count != pd.Count)
4788 for (int i = arg_count; i > 0; ) {
4791 Argument a = (Argument) arguments [i];
4793 Parameter.Modifier a_mod = a.Modifier &
4794 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4795 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4796 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4799 if (a_mod == p_mod ||
4800 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4801 if (a_mod == Parameter.Modifier.NONE) {
4802 if (!Convert.ImplicitConversionExists (ec,
4804 pd.ParameterType (i)))
4808 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4809 Type pt = pd.ParameterType (i);
4812 pt = TypeManager.GetReferenceType (pt);
4824 static private bool IsAncestralType (Type first_type, Type second_type)
4826 return first_type != second_type &&
4827 (second_type.IsSubclassOf (first_type) ||
4828 TypeManager.ImplementsInterface (second_type, first_type));
4832 /// Find the Applicable Function Members (7.4.2.1)
4834 /// me: Method Group expression with the members to select.
4835 /// it might contain constructors or methods (or anything
4836 /// that maps to a method).
4838 /// Arguments: ArrayList containing resolved Argument objects.
4840 /// loc: The location if we want an error to be reported, or a Null
4841 /// location for "probing" purposes.
4843 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4844 /// that is the best match of me on Arguments.
4847 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4848 ArrayList Arguments, bool may_fail,
4851 MethodBase method = null;
4852 bool method_params = false;
4853 Type applicable_type = null;
4855 ArrayList candidates = new ArrayList (2);
4856 ArrayList candidate_overrides = null;
4859 // Used to keep a map between the candidate
4860 // and whether it is being considered in its
4861 // normal or expanded form
4863 // false is normal form, true is expanded form
4865 Hashtable candidate_to_form = null;
4867 if (Arguments != null)
4868 arg_count = Arguments.Count;
4870 if ((me.Name == "Invoke") &&
4871 TypeManager.IsDelegateType (me.DeclaringType)) {
4872 Error_InvokeOnDelegate (loc);
4876 MethodBase[] methods = me.Methods;
4879 // First we construct the set of applicable methods
4881 bool is_sorted = true;
4882 for (int i = 0; i < methods.Length; i++){
4883 Type decl_type = methods [i].DeclaringType;
4886 // If we have already found an applicable method
4887 // we eliminate all base types (Section 14.5.5.1)
4889 if ((applicable_type != null) &&
4890 IsAncestralType (decl_type, applicable_type))
4894 // Methods marked 'override' don't take part in 'applicable_type'
4895 // computation, nor in the actual overload resolution.
4896 // However, they still need to be emitted instead of a base virtual method.
4897 // We avoid doing the 'applicable' test here, since it'll anyway be applied
4898 // to the base virtual function, and IsOverride is much faster than IsApplicable.
4900 if (!me.IsBase && TypeManager.IsOverride (methods [i])) {
4901 if (candidate_overrides == null)
4902 candidate_overrides = new ArrayList ();
4903 candidate_overrides.Add (methods [i]);
4908 // Check if candidate is applicable (section 14.4.2.1)
4909 // Is candidate applicable in normal form?
4911 bool is_applicable = IsApplicable (
4912 ec, me, Arguments, arg_count, ref methods [i]);
4914 if (!is_applicable &&
4915 (IsParamsMethodApplicable (
4916 ec, me, Arguments, arg_count, ref methods [i]))) {
4917 MethodBase candidate = methods [i];
4918 if (candidate_to_form == null)
4919 candidate_to_form = new PtrHashtable ();
4920 candidate_to_form [candidate] = candidate;
4921 // Candidate is applicable in expanded form
4922 is_applicable = true;
4928 candidates.Add (methods [i]);
4930 if (applicable_type == null)
4931 applicable_type = decl_type;
4932 else if (applicable_type != decl_type) {
4934 if (IsAncestralType (applicable_type, decl_type))
4935 applicable_type = decl_type;
4939 int candidate_top = candidates.Count;
4941 if (applicable_type == null) {
4943 // Okay so we have failed to find anything so we
4944 // return by providing info about the closest match
4946 for (int i = 0; i < methods.Length; ++i) {
4947 MethodBase c = (MethodBase) methods [i];
4948 ParameterData pd = TypeManager.GetParameterData (c);
4950 if (pd.Count != arg_count)
4953 VerifyArgumentsCompat (ec, Arguments, arg_count,
4954 c, false, null, may_fail, loc);
4959 string report_name = me.Name;
4960 if (report_name == ".ctor")
4961 report_name = me.DeclaringType.ToString ();
4963 Error_WrongNumArguments (
4964 loc, report_name, arg_count);
4973 // At this point, applicable_type is _one_ of the most derived types
4974 // in the set of types containing the methods in this MethodGroup.
4975 // Filter the candidates so that they only contain methods from the
4976 // most derived types.
4979 int finalized = 0; // Number of finalized candidates
4982 // Invariant: applicable_type is a most derived type
4984 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4985 // eliminating all it's base types. At the same time, we'll also move
4986 // every unrelated type to the end of the array, and pick the next
4987 // 'applicable_type'.
4989 Type next_applicable_type = null;
4990 int j = finalized; // where to put the next finalized candidate
4991 int k = finalized; // where to put the next undiscarded candidate
4992 for (int i = finalized; i < candidate_top; ++i) {
4993 MethodBase candidate = (MethodBase) candidates [i];
4994 Type decl_type = candidate.DeclaringType;
4996 if (decl_type == applicable_type) {
4997 candidates [k++] = candidates [j];
4998 candidates [j++] = candidates [i];
5002 if (IsAncestralType (decl_type, applicable_type))
5005 if (next_applicable_type != null &&
5006 IsAncestralType (decl_type, next_applicable_type))
5009 candidates [k++] = candidates [i];
5011 if (next_applicable_type == null ||
5012 IsAncestralType (next_applicable_type, decl_type))
5013 next_applicable_type = decl_type;
5016 applicable_type = next_applicable_type;
5019 } while (applicable_type != null);
5023 // Now we actually find the best method
5026 method = (MethodBase) candidates [0];
5027 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
5028 for (int ix = 1; ix < candidate_top; ix++){
5029 MethodBase candidate = (MethodBase) candidates [ix];
5031 if (candidate == method)
5034 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5036 if (BetterFunction (ec, Arguments, arg_count,
5037 candidate, cand_params,
5038 method, method_params, loc)) {
5040 method_params = cand_params;
5045 // Now check that there are no ambiguities i.e the selected method
5046 // should be better than all the others
5048 bool ambiguous = false;
5049 for (int ix = 0; ix < candidate_top; ix++){
5050 MethodBase candidate = (MethodBase) candidates [ix];
5052 if (candidate == method)
5055 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5056 if (!BetterFunction (ec, Arguments, arg_count,
5057 method, method_params,
5058 candidate, cand_params,
5060 Report.SymbolRelatedToPreviousError (candidate);
5066 Report.SymbolRelatedToPreviousError (method);
5067 Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts");
5072 // If the method is a virtual function, pick an override closer to the LHS type.
5074 if (!me.IsBase && method.IsVirtual) {
5075 if (TypeManager.IsOverride (method))
5076 throw new InternalErrorException (
5077 "Should not happen. An 'override' method took part in overload resolution: " + method);
5079 if (candidate_overrides != null)
5080 foreach (MethodBase candidate in candidate_overrides) {
5081 if (IsOverride (candidate, method))
5087 // And now check if the arguments are all
5088 // compatible, perform conversions if
5089 // necessary etc. and return if everything is
5092 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
5093 method_params, null, may_fail, loc))
5096 if (method != null) {
5097 IMethodData data = TypeManager.GetMethod (method);
5099 data.SetMemberIsUsed ();
5104 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
5106 if (name == "Finalize" && arg_count == 0) {
5107 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5110 Report.Error (1501, loc,
5111 "No overload for method `" + name + "' takes `" +
5112 arg_count + "' arguments");
5116 static void Error_InvokeOnDelegate (Location loc)
5118 Report.Error (1533, loc,
5119 "Invoke cannot be called directly on a delegate");
5122 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
5123 Type delegate_type, Argument a, ParameterData expected_par)
5125 if (delegate_type == null)
5126 Report.Error (1502, loc, "The best overloaded match for method '{0}' has some invalid arguments",
5127 TypeManager.CSharpSignature (method));
5129 Report.Error (1594, loc,
5130 "Delegate '" + delegate_type.ToString () +
5131 "' has some invalid arguments.");
5133 string par_desc = expected_par.ParameterDesc (idx);
5135 if (a.Modifier != expected_par.ParameterModifier (idx)) {
5136 if ((expected_par.ParameterModifier (idx) & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
5137 Report.Error (1615, loc, "Argument '{0}' should not be passed with the '{1}' keyword",
5138 idx + 1, Parameter.GetModifierSignature (a.Modifier));
5140 Report.Error (1620, loc, "Argument '{0}' must be passed with the '{1}' keyword",
5141 idx + 1, Parameter.GetModifierSignature (expected_par.ParameterModifier (idx)));
5145 Report.Error (1503, loc,
5146 String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
5147 idx + 1, Argument.FullDesc (a), par_desc));
5150 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
5151 int arg_count, MethodBase method,
5152 bool chose_params_expanded,
5153 Type delegate_type, bool may_fail,
5156 ParameterData pd = TypeManager.GetParameterData (method);
5157 int pd_count = pd.Count;
5159 for (int j = 0; j < arg_count; j++) {
5160 Argument a = (Argument) Arguments [j];
5161 Expression a_expr = a.Expr;
5162 Type parameter_type = pd.ParameterType (j);
5163 Parameter.Modifier pm = pd.ParameterModifier (j);
5165 if (pm == Parameter.Modifier.PARAMS){
5166 if ((pm & ~Parameter.Modifier.PARAMS) != a.Modifier) {
5168 Error_InvalidArguments (
5169 loc, j, method, delegate_type,
5174 if (chose_params_expanded)
5175 parameter_type = TypeManager.GetElementType (parameter_type);
5176 } else if (pm == Parameter.Modifier.ARGLIST){
5182 if (pd.ParameterModifier (j) != a.Modifier){
5184 Error_InvalidArguments (
5185 loc, j, method, delegate_type,
5194 if (!a.Type.Equals (parameter_type)){
5197 conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5201 Error_InvalidArguments (loc, j, method, delegate_type, a, pd);
5206 // Update the argument with the implicit conversion
5212 if (parameter_type.IsPointer){
5219 Parameter.Modifier a_mod = a.Modifier &
5220 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5221 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5222 unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5224 if (a_mod != p_mod &&
5225 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5227 Report.Error (1502, loc,
5228 "The best overloaded match for method '" + FullMethodDesc (method)+
5229 "' has some invalid arguments");
5230 Report.Error (1503, loc,
5231 "Argument " + (j+1) +
5232 ": Cannot convert from '" + Argument.FullDesc (a)
5233 + "' to '" + pd.ParameterDesc (j) + "'");
5243 public override Expression DoResolve (EmitContext ec)
5246 // First, resolve the expression that is used to
5247 // trigger the invocation
5249 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5253 if (!(expr is MethodGroupExpr)) {
5254 Type expr_type = expr.Type;
5256 if (expr_type != null){
5257 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5259 return (new DelegateInvocation (
5260 this.expr, Arguments, loc)).Resolve (ec);
5264 if (!(expr is MethodGroupExpr)){
5265 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5270 // Next, evaluate all the expressions in the argument list
5272 if (Arguments != null){
5273 foreach (Argument a in Arguments){
5274 if (!a.Resolve (ec, loc))
5279 MethodGroupExpr mg = (MethodGroupExpr) expr;
5280 method = OverloadResolve (ec, mg, Arguments, false, loc);
5285 MethodInfo mi = method as MethodInfo;
5287 type = TypeManager.TypeToCoreType (mi.ReturnType);
5288 Expression iexpr = mg.InstanceExpression;
5290 if (iexpr == null ||
5291 iexpr is This || iexpr is EmptyExpression ||
5292 mg.IdenticalTypeName) {
5293 mg.InstanceExpression = null;
5295 MemberExpr.error176 (loc, mi.Name);
5299 if (iexpr == null || iexpr is EmptyExpression) {
5300 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5306 if (type.IsPointer){
5314 // Only base will allow this invocation to happen.
5316 if (mg.IsBase && method.IsAbstract){
5317 Report.Error (205, loc, "Cannot call an abstract base member: " +
5318 FullMethodDesc (method));
5322 if (method.Name == "Finalize" && Arguments == null) {
5323 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5327 if ((method.Attributes & MethodAttributes.SpecialName) != 0) {
5328 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5329 Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor");
5334 if (mg.InstanceExpression != null)
5335 mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
5337 eclass = ExprClass.Value;
5342 // Emits the list of arguments as an array
5344 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5346 ILGenerator ig = ec.ig;
5347 int count = arguments.Count - idx;
5348 Argument a = (Argument) arguments [idx];
5349 Type t = a.Expr.Type;
5351 IntConstant.EmitInt (ig, count);
5352 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5354 int top = arguments.Count;
5355 for (int j = idx; j < top; j++){
5356 a = (Argument) arguments [j];
5358 ig.Emit (OpCodes.Dup);
5359 IntConstant.EmitInt (ig, j - idx);
5362 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
5364 ig.Emit (OpCodes.Ldelema, t);
5369 ig.Emit (OpCodes.Stobj, t);
5376 /// Emits a list of resolved Arguments that are in the arguments
5379 /// The MethodBase argument might be null if the
5380 /// emission of the arguments is known not to contain
5381 /// a `params' field (for example in constructors or other routines
5382 /// that keep their arguments in this structure)
5384 /// if `dup_args' is true, a copy of the arguments will be left
5385 /// on the stack. If `dup_args' is true, you can specify `this_arg'
5386 /// which will be duplicated before any other args. Only EmitCall
5387 /// should be using this interface.
5389 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5393 pd = TypeManager.GetParameterData (mb);
5397 LocalTemporary [] temps = null;
5400 temps = new LocalTemporary [arguments.Count];
5403 // If we are calling a params method with no arguments, special case it
5405 if (arguments == null){
5406 if (pd != null && pd.Count > 0 &&
5407 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5408 ILGenerator ig = ec.ig;
5410 IntConstant.EmitInt (ig, 0);
5411 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5417 int top = arguments.Count;
5419 for (int i = 0; i < top; i++){
5420 Argument a = (Argument) arguments [i];
5423 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5425 // Special case if we are passing the same data as the
5426 // params argument, do not put it in an array.
5428 if (pd.ParameterType (i) == a.Type)
5431 EmitParams (ec, i, arguments);
5438 ec.ig.Emit (OpCodes.Dup);
5439 (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5444 if (this_arg != null)
5447 for (int i = 0; i < top; i ++)
5448 temps [i].Emit (ec);
5451 if (pd != null && pd.Count > top &&
5452 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5453 ILGenerator ig = ec.ig;
5455 IntConstant.EmitInt (ig, 0);
5456 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5460 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5461 ArrayList arguments)
5463 ParameterData pd = TypeManager.GetParameterData (mb);
5465 if (arguments == null)
5466 return new Type [0];
5468 Argument a = (Argument) arguments [pd.Count - 1];
5469 Arglist list = (Arglist) a.Expr;
5471 return list.ArgumentTypes;
5475 /// This checks the ConditionalAttribute on the method
5477 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5479 if (method.IsConstructor)
5482 IMethodData md = TypeManager.GetMethod (method);
5484 return md.IsExcluded (ec);
5486 // For some methods (generated by delegate class) GetMethod returns null
5487 // because they are not included in builder_to_method table
5488 if (method.DeclaringType is TypeBuilder)
5491 return AttributeTester.IsConditionalMethodExcluded (method);
5495 /// is_base tells whether we want to force the use of the `call'
5496 /// opcode instead of using callvirt. Call is required to call
5497 /// a specific method, while callvirt will always use the most
5498 /// recent method in the vtable.
5500 /// is_static tells whether this is an invocation on a static method
5502 /// instance_expr is an expression that represents the instance
5503 /// it must be non-null if is_static is false.
5505 /// method is the method to invoke.
5507 /// Arguments is the list of arguments to pass to the method or constructor.
5509 public static void EmitCall (EmitContext ec, bool is_base,
5510 bool is_static, Expression instance_expr,
5511 MethodBase method, ArrayList Arguments, Location loc)
5513 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5516 // `dup_args' leaves an extra copy of the arguments on the stack
5517 // `omit_args' does not leave any arguments at all.
5518 // So, basically, you could make one call with `dup_args' set to true,
5519 // and then another with `omit_args' set to true, and the two calls
5520 // would have the same set of arguments. However, each argument would
5521 // only have been evaluated once.
5522 public static void EmitCall (EmitContext ec, bool is_base,
5523 bool is_static, Expression instance_expr,
5524 MethodBase method, ArrayList Arguments, Location loc,
5525 bool dup_args, bool omit_args)
5527 ILGenerator ig = ec.ig;
5528 bool struct_call = false;
5529 bool this_call = false;
5530 LocalTemporary this_arg = null;
5532 Type decl_type = method.DeclaringType;
5534 if (!RootContext.StdLib) {
5535 // Replace any calls to the system's System.Array type with calls to
5536 // the newly created one.
5537 if (method == TypeManager.system_int_array_get_length)
5538 method = TypeManager.int_array_get_length;
5539 else if (method == TypeManager.system_int_array_get_rank)
5540 method = TypeManager.int_array_get_rank;
5541 else if (method == TypeManager.system_object_array_clone)
5542 method = TypeManager.object_array_clone;
5543 else if (method == TypeManager.system_int_array_get_length_int)
5544 method = TypeManager.int_array_get_length_int;
5545 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5546 method = TypeManager.int_array_get_lower_bound_int;
5547 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5548 method = TypeManager.int_array_get_upper_bound_int;
5549 else if (method == TypeManager.system_void_array_copyto_array_int)
5550 method = TypeManager.void_array_copyto_array_int;
5553 if (ec.TestObsoleteMethodUsage) {
5555 // This checks ObsoleteAttribute on the method and on the declaring type
5557 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5559 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5562 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5564 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5568 if (IsMethodExcluded (method, ec))
5572 this_call = instance_expr is This;
5573 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5579 // Push the instance expression
5581 if (instance_expr.Type.IsValueType) {
5583 // Special case: calls to a function declared in a
5584 // reference-type with a value-type argument need
5585 // to have their value boxed.
5586 if (decl_type.IsValueType) {
5588 // If the expression implements IMemoryLocation, then
5589 // we can optimize and use AddressOf on the
5592 // If not we have to use some temporary storage for
5594 if (instance_expr is IMemoryLocation) {
5595 ((IMemoryLocation)instance_expr).
5596 AddressOf (ec, AddressOp.LoadStore);
5598 LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type);
5599 instance_expr.Emit (ec);
5601 temp.AddressOf (ec, AddressOp.Load);
5604 // avoid the overhead of doing this all the time.
5606 t = TypeManager.GetReferenceType (instance_expr.Type);
5608 instance_expr.Emit (ec);
5609 ig.Emit (OpCodes.Box, instance_expr.Type);
5610 t = TypeManager.object_type;
5613 instance_expr.Emit (ec);
5614 t = instance_expr.Type;
5618 this_arg = new LocalTemporary (ec, t);
5619 ig.Emit (OpCodes.Dup);
5620 this_arg.Store (ec);
5626 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5629 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5630 call_op = OpCodes.Call;
5632 call_op = OpCodes.Callvirt;
5634 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5635 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5636 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5643 // and DoFoo is not virtual, you can omit the callvirt,
5644 // because you don't need the null checking behavior.
5646 if (method is MethodInfo)
5647 ig.Emit (call_op, (MethodInfo) method);
5649 ig.Emit (call_op, (ConstructorInfo) method);
5652 public override void Emit (EmitContext ec)
5654 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5656 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5659 public override void EmitStatement (EmitContext ec)
5664 // Pop the return value if there is one
5666 if (method is MethodInfo){
5667 Type ret = ((MethodInfo)method).ReturnType;
5668 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5669 ec.ig.Emit (OpCodes.Pop);
5674 public class InvocationOrCast : ExpressionStatement
5677 Expression argument;
5679 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5682 this.argument = argument;
5686 public override Expression DoResolve (EmitContext ec)
5689 // First try to resolve it as a cast.
5691 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5693 Cast cast = new Cast (te, argument, loc);
5694 return cast.Resolve (ec);
5698 // This can either be a type or a delegate invocation.
5699 // Let's just resolve it and see what we'll get.
5701 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5706 // Ok, so it's a Cast.
5708 if (expr.eclass == ExprClass.Type) {
5709 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5710 return cast.Resolve (ec);
5714 // It's a delegate invocation.
5716 if (!TypeManager.IsDelegateType (expr.Type)) {
5717 Error (149, "Method name expected");
5721 ArrayList args = new ArrayList ();
5722 args.Add (new Argument (argument, Argument.AType.Expression));
5723 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5724 return invocation.Resolve (ec);
5729 Error (201, "Only assignment, call, increment, decrement and new object " +
5730 "expressions can be used as a statement");
5733 public override ExpressionStatement ResolveStatement (EmitContext ec)
5736 // First try to resolve it as a cast.
5738 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5745 // This can either be a type or a delegate invocation.
5746 // Let's just resolve it and see what we'll get.
5748 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5749 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5755 // It's a delegate invocation.
5757 if (!TypeManager.IsDelegateType (expr.Type)) {
5758 Error (149, "Method name expected");
5762 ArrayList args = new ArrayList ();
5763 args.Add (new Argument (argument, Argument.AType.Expression));
5764 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5765 return invocation.ResolveStatement (ec);
5768 public override void Emit (EmitContext ec)
5770 throw new Exception ("Cannot happen");
5773 public override void EmitStatement (EmitContext ec)
5775 throw new Exception ("Cannot happen");
5780 // This class is used to "disable" the code generation for the
5781 // temporary variable when initializing value types.
5783 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5784 public void AddressOf (EmitContext ec, AddressOp Mode)
5791 /// Implements the new expression
5793 public class New : ExpressionStatement, IMemoryLocation {
5794 public readonly ArrayList Arguments;
5797 // During bootstrap, it contains the RequestedType,
5798 // but if `type' is not null, it *might* contain a NewDelegate
5799 // (because of field multi-initialization)
5801 public Expression RequestedType;
5803 MethodBase method = null;
5806 // If set, the new expression is for a value_target, and
5807 // we will not leave anything on the stack.
5809 Expression value_target;
5810 bool value_target_set = false;
5812 public New (Expression requested_type, ArrayList arguments, Location l)
5814 RequestedType = requested_type;
5815 Arguments = arguments;
5819 public bool SetValueTypeVariable (Expression value)
5821 value_target = value;
5822 value_target_set = true;
5823 if (!(value_target is IMemoryLocation)){
5824 Error_UnexpectedKind ("variable", loc);
5831 // This function is used to disable the following code sequence for
5832 // value type initialization:
5834 // AddressOf (temporary)
5838 // Instead the provide will have provided us with the address on the
5839 // stack to store the results.
5841 static Expression MyEmptyExpression;
5843 public void DisableTemporaryValueType ()
5845 if (MyEmptyExpression == null)
5846 MyEmptyExpression = new EmptyAddressOf ();
5849 // To enable this, look into:
5850 // test-34 and test-89 and self bootstrapping.
5852 // For instance, we can avoid a copy by using `newobj'
5853 // instead of Call + Push-temp on value types.
5854 // value_target = MyEmptyExpression;
5859 /// Converts complex core type syntax like 'new int ()' to simple constant
5861 Expression Constantify (Type t)
5863 if (t == TypeManager.int32_type)
5864 return new IntConstant (0);
5865 if (t == TypeManager.uint32_type)
5866 return new UIntConstant (0);
5867 if (t == TypeManager.int64_type)
5868 return new LongConstant (0);
5869 if (t == TypeManager.uint64_type)
5870 return new ULongConstant (0);
5871 if (t == TypeManager.float_type)
5872 return new FloatConstant (0);
5873 if (t == TypeManager.double_type)
5874 return new DoubleConstant (0);
5875 if (t == TypeManager.short_type)
5876 return new ShortConstant (0);
5877 if (t == TypeManager.ushort_type)
5878 return new UShortConstant (0);
5879 if (t == TypeManager.sbyte_type)
5880 return new SByteConstant (0);
5881 if (t == TypeManager.byte_type)
5882 return new ByteConstant (0);
5883 if (t == TypeManager.char_type)
5884 return new CharConstant ('\0');
5885 if (t == TypeManager.bool_type)
5886 return new BoolConstant (false);
5887 if (t == TypeManager.decimal_type)
5888 return new DecimalConstant (0);
5893 public override Expression DoResolve (EmitContext ec)
5896 // The New DoResolve might be called twice when initializing field
5897 // expressions (see EmitFieldInitializers, the call to
5898 // GetInitializerExpression will perform a resolve on the expression,
5899 // and later the assign will trigger another resolution
5901 // This leads to bugs (#37014)
5904 if (RequestedType is NewDelegate)
5905 return RequestedType;
5909 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5913 type = texpr.ResolveType (ec);
5915 if (Arguments == null) {
5916 Expression c = Constantify (type);
5921 CheckObsoleteAttribute (type);
5923 bool IsDelegate = TypeManager.IsDelegateType (type);
5926 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5927 if (RequestedType != null)
5928 if (!(RequestedType is DelegateCreation))
5929 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5930 return RequestedType;
5933 if (type.IsAbstract && type.IsSealed) {
5934 Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type));
5938 if (type.IsInterface || type.IsAbstract){
5939 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5943 bool is_struct = type.IsValueType;
5944 eclass = ExprClass.Value;
5947 // SRE returns a match for .ctor () on structs (the object constructor),
5948 // so we have to manually ignore it.
5950 if (is_struct && Arguments == null)
5954 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5955 ml = MemberLookupFinal (ec, type, type, ".ctor",
5956 MemberTypes.Constructor,
5957 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5962 if (! (ml is MethodGroupExpr)){
5964 ml.Error_UnexpectedKind ("method group", loc);
5970 if (Arguments != null){
5971 foreach (Argument a in Arguments){
5972 if (!a.Resolve (ec, loc))
5977 method = Invocation.OverloadResolve (
5978 ec, (MethodGroupExpr) ml, Arguments, true, loc);
5982 if (method == null) {
5983 if (almostMatchedMembers.Count != 0) {
5984 MemberLookupFailed (ec, type, type, ".ctor", null, true, loc);
5988 if (!is_struct || Arguments.Count > 0) {
5989 Error (1501, String.Format (
5990 "New invocation: Can not find a constructor in `{0}' for this argument list",
5991 TypeManager.CSharpName (type)));
6000 // This DoEmit can be invoked in two contexts:
6001 // * As a mechanism that will leave a value on the stack (new object)
6002 // * As one that wont (init struct)
6004 // You can control whether a value is required on the stack by passing
6005 // need_value_on_stack. The code *might* leave a value on the stack
6006 // so it must be popped manually
6008 // If we are dealing with a ValueType, we have a few
6009 // situations to deal with:
6011 // * The target is a ValueType, and we have been provided
6012 // the instance (this is easy, we are being assigned).
6014 // * The target of New is being passed as an argument,
6015 // to a boxing operation or a function that takes a
6018 // In this case, we need to create a temporary variable
6019 // that is the argument of New.
6021 // Returns whether a value is left on the stack
6023 bool DoEmit (EmitContext ec, bool need_value_on_stack)
6025 bool is_value_type = type.IsValueType;
6026 ILGenerator ig = ec.ig;
6031 // Allow DoEmit() to be called multiple times.
6032 // We need to create a new LocalTemporary each time since
6033 // you can't share LocalBuilders among ILGeneators.
6034 if (!value_target_set)
6035 value_target = new LocalTemporary (ec, type);
6037 ml = (IMemoryLocation) value_target;
6038 ml.AddressOf (ec, AddressOp.Store);
6042 Invocation.EmitArguments (ec, method, Arguments, false, null);
6046 ig.Emit (OpCodes.Initobj, type);
6048 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6049 if (need_value_on_stack){
6050 value_target.Emit (ec);
6055 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6060 public override void Emit (EmitContext ec)
6065 public override void EmitStatement (EmitContext ec)
6067 if (DoEmit (ec, false))
6068 ec.ig.Emit (OpCodes.Pop);
6071 public void AddressOf (EmitContext ec, AddressOp Mode)
6073 if (!type.IsValueType){
6075 // We throw an exception. So far, I believe we only need to support
6077 // foreach (int j in new StructType ())
6080 throw new Exception ("AddressOf should not be used for classes");
6083 if (!value_target_set)
6084 value_target = new LocalTemporary (ec, type);
6086 IMemoryLocation ml = (IMemoryLocation) value_target;
6087 ml.AddressOf (ec, AddressOp.Store);
6089 Invocation.EmitArguments (ec, method, Arguments, false, null);
6092 ec.ig.Emit (OpCodes.Initobj, type);
6094 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6096 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6101 /// 14.5.10.2: Represents an array creation expression.
6105 /// There are two possible scenarios here: one is an array creation
6106 /// expression that specifies the dimensions and optionally the
6107 /// initialization data and the other which does not need dimensions
6108 /// specified but where initialization data is mandatory.
6110 public class ArrayCreation : Expression {
6111 Expression requested_base_type;
6112 ArrayList initializers;
6115 // The list of Argument types.
6116 // This is used to construct the `newarray' or constructor signature
6118 ArrayList arguments;
6121 // Method used to create the array object.
6123 MethodBase new_method = null;
6125 Type array_element_type;
6126 Type underlying_type;
6127 bool is_one_dimensional = false;
6128 bool is_builtin_type = false;
6129 bool expect_initializers = false;
6130 int num_arguments = 0;
6134 ArrayList array_data;
6139 // The number of array initializers that we can handle
6140 // via the InitializeArray method - through EmitStaticInitializers
6142 int num_automatic_initializers;
6144 const int max_automatic_initializers = 6;
6146 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6148 this.requested_base_type = requested_base_type;
6149 this.initializers = initializers;
6153 arguments = new ArrayList ();
6155 foreach (Expression e in exprs) {
6156 arguments.Add (new Argument (e, Argument.AType.Expression));
6161 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6163 this.requested_base_type = requested_base_type;
6164 this.initializers = initializers;
6168 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6170 //string tmp = rank.Substring (rank.LastIndexOf ('['));
6172 //dimensions = tmp.Length - 1;
6173 expect_initializers = true;
6176 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6178 StringBuilder sb = new StringBuilder (rank);
6181 for (int i = 1; i < idx_count; i++)
6186 return new ComposedCast (base_type, sb.ToString (), loc);
6189 void Error_IncorrectArrayInitializer ()
6191 Error (178, "Incorrectly structured array initializer");
6194 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6196 if (specified_dims) {
6197 Argument a = (Argument) arguments [idx];
6199 if (!a.Resolve (ec, loc))
6202 if (!(a.Expr is Constant)) {
6203 Error (150, "A constant value is expected");
6207 int value = (int) ((Constant) a.Expr).GetValue ();
6209 if (value != probe.Count) {
6210 Error_IncorrectArrayInitializer ();
6214 bounds [idx] = value;
6217 int child_bounds = -1;
6218 for (int i = 0; i < probe.Count; ++i) {
6219 object o = probe [i];
6220 if (o is ArrayList) {
6221 ArrayList sub_probe = o as ArrayList;
6222 int current_bounds = sub_probe.Count;
6224 if (child_bounds == -1)
6225 child_bounds = current_bounds;
6227 else if (child_bounds != current_bounds){
6228 Error_IncorrectArrayInitializer ();
6231 if (specified_dims && (idx + 1 >= arguments.Count)){
6232 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6236 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6240 if (child_bounds != -1){
6241 Error_IncorrectArrayInitializer ();
6245 Expression tmp = (Expression) o;
6246 tmp = tmp.Resolve (ec);
6251 // Console.WriteLine ("I got: " + tmp);
6252 // Handle initialization from vars, fields etc.
6254 Expression conv = Convert.ImplicitConversionRequired (
6255 ec, tmp, underlying_type, loc);
6260 if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6261 // These are subclasses of Constant that can appear as elements of an
6262 // array that cannot be statically initialized (with num_automatic_initializers
6263 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6264 array_data.Add (conv);
6265 } else if (conv is Constant) {
6266 // These are the types of Constant that can appear in arrays that can be
6267 // statically allocated.
6268 array_data.Add (conv);
6269 num_automatic_initializers++;
6271 array_data.Add (conv);
6278 public void UpdateIndices (EmitContext ec)
6281 for (ArrayList probe = initializers; probe != null;) {
6282 if (probe.Count > 0 && probe [0] is ArrayList) {
6283 Expression e = new IntConstant (probe.Count);
6284 arguments.Add (new Argument (e, Argument.AType.Expression));
6286 bounds [i++] = probe.Count;
6288 probe = (ArrayList) probe [0];
6291 Expression e = new IntConstant (probe.Count);
6292 arguments.Add (new Argument (e, Argument.AType.Expression));
6294 bounds [i++] = probe.Count;
6301 public bool ValidateInitializers (EmitContext ec, Type array_type)
6303 if (initializers == null) {
6304 if (expect_initializers)
6310 if (underlying_type == null)
6314 // We use this to store all the date values in the order in which we
6315 // will need to store them in the byte blob later
6317 array_data = new ArrayList ();
6318 bounds = new Hashtable ();
6322 if (arguments != null) {
6323 ret = CheckIndices (ec, initializers, 0, true);
6326 arguments = new ArrayList ();
6328 ret = CheckIndices (ec, initializers, 0, false);
6335 if (arguments.Count != dimensions) {
6336 Error_IncorrectArrayInitializer ();
6345 // Creates the type of the array
6347 bool LookupType (EmitContext ec)
6349 StringBuilder array_qualifier = new StringBuilder (rank);
6352 // `In the first form allocates an array instace of the type that results
6353 // from deleting each of the individual expression from the expression list'
6355 if (num_arguments > 0) {
6356 array_qualifier.Append ("[");
6357 for (int i = num_arguments-1; i > 0; i--)
6358 array_qualifier.Append (",");
6359 array_qualifier.Append ("]");
6365 TypeExpr array_type_expr;
6366 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6367 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6368 if (array_type_expr == null)
6371 type = array_type_expr.ResolveType (ec);
6373 if (!type.IsArray) {
6374 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6377 underlying_type = TypeManager.GetElementType (type);
6378 dimensions = type.GetArrayRank ();
6383 public override Expression DoResolve (EmitContext ec)
6387 if (!LookupType (ec))
6391 // First step is to validate the initializers and fill
6392 // in any missing bits
6394 if (!ValidateInitializers (ec, type))
6397 if (arguments == null)
6400 arg_count = arguments.Count;
6401 foreach (Argument a in arguments){
6402 if (!a.Resolve (ec, loc))
6405 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6406 if (real_arg == null)
6413 array_element_type = TypeManager.GetElementType (type);
6415 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6416 Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6420 if (arg_count == 1) {
6421 is_one_dimensional = true;
6422 eclass = ExprClass.Value;
6426 is_builtin_type = TypeManager.IsBuiltinType (type);
6428 if (is_builtin_type) {
6431 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6432 AllBindingFlags, loc);
6434 if (!(ml is MethodGroupExpr)) {
6435 ml.Error_UnexpectedKind ("method group", loc);
6440 Error (-6, "New invocation: Can not find a constructor for " +
6441 "this argument list");
6445 new_method = Invocation.OverloadResolve (
6446 ec, (MethodGroupExpr) ml, arguments, false, loc);
6448 if (new_method == null) {
6449 Error (-6, "New invocation: Can not find a constructor for " +
6450 "this argument list");
6454 eclass = ExprClass.Value;
6457 ModuleBuilder mb = CodeGen.Module.Builder;
6458 ArrayList args = new ArrayList ();
6460 if (arguments != null) {
6461 for (int i = 0; i < arg_count; i++)
6462 args.Add (TypeManager.int32_type);
6465 Type [] arg_types = null;
6468 arg_types = new Type [args.Count];
6470 args.CopyTo (arg_types, 0);
6472 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6475 if (new_method == null) {
6476 Error (-6, "New invocation: Can not find a constructor for " +
6477 "this argument list");
6481 eclass = ExprClass.Value;
6486 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6491 int count = array_data.Count;
6493 if (underlying_type.IsEnum)
6494 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6496 factor = GetTypeSize (underlying_type);
6498 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6500 data = new byte [(count * factor + 4) & ~3];
6503 for (int i = 0; i < count; ++i) {
6504 object v = array_data [i];
6506 if (v is EnumConstant)
6507 v = ((EnumConstant) v).Child;
6509 if (v is Constant && !(v is StringConstant))
6510 v = ((Constant) v).GetValue ();
6516 if (underlying_type == TypeManager.int64_type){
6517 if (!(v is Expression)){
6518 long val = (long) v;
6520 for (int j = 0; j < factor; ++j) {
6521 data [idx + j] = (byte) (val & 0xFF);
6525 } else if (underlying_type == TypeManager.uint64_type){
6526 if (!(v is Expression)){
6527 ulong val = (ulong) v;
6529 for (int j = 0; j < factor; ++j) {
6530 data [idx + j] = (byte) (val & 0xFF);
6534 } else if (underlying_type == TypeManager.float_type) {
6535 if (!(v is Expression)){
6536 element = BitConverter.GetBytes ((float) v);
6538 for (int j = 0; j < factor; ++j)
6539 data [idx + j] = element [j];
6541 } else if (underlying_type == TypeManager.double_type) {
6542 if (!(v is Expression)){
6543 element = BitConverter.GetBytes ((double) v);
6545 for (int j = 0; j < factor; ++j)
6546 data [idx + j] = element [j];
6548 } else if (underlying_type == TypeManager.char_type){
6549 if (!(v is Expression)){
6550 int val = (int) ((char) v);
6552 data [idx] = (byte) (val & 0xff);
6553 data [idx+1] = (byte) (val >> 8);
6555 } else if (underlying_type == TypeManager.short_type){
6556 if (!(v is Expression)){
6557 int val = (int) ((short) v);
6559 data [idx] = (byte) (val & 0xff);
6560 data [idx+1] = (byte) (val >> 8);
6562 } else if (underlying_type == TypeManager.ushort_type){
6563 if (!(v is Expression)){
6564 int val = (int) ((ushort) v);
6566 data [idx] = (byte) (val & 0xff);
6567 data [idx+1] = (byte) (val >> 8);
6569 } else if (underlying_type == TypeManager.int32_type) {
6570 if (!(v is Expression)){
6573 data [idx] = (byte) (val & 0xff);
6574 data [idx+1] = (byte) ((val >> 8) & 0xff);
6575 data [idx+2] = (byte) ((val >> 16) & 0xff);
6576 data [idx+3] = (byte) (val >> 24);
6578 } else if (underlying_type == TypeManager.uint32_type) {
6579 if (!(v is Expression)){
6580 uint val = (uint) v;
6582 data [idx] = (byte) (val & 0xff);
6583 data [idx+1] = (byte) ((val >> 8) & 0xff);
6584 data [idx+2] = (byte) ((val >> 16) & 0xff);
6585 data [idx+3] = (byte) (val >> 24);
6587 } else if (underlying_type == TypeManager.sbyte_type) {
6588 if (!(v is Expression)){
6589 sbyte val = (sbyte) v;
6590 data [idx] = (byte) val;
6592 } else if (underlying_type == TypeManager.byte_type) {
6593 if (!(v is Expression)){
6594 byte val = (byte) v;
6595 data [idx] = (byte) val;
6597 } else if (underlying_type == TypeManager.bool_type) {
6598 if (!(v is Expression)){
6599 bool val = (bool) v;
6600 data [idx] = (byte) (val ? 1 : 0);
6602 } else if (underlying_type == TypeManager.decimal_type){
6603 if (!(v is Expression)){
6604 int [] bits = Decimal.GetBits ((decimal) v);
6607 // FIXME: For some reason, this doesn't work on the MS runtime.
6608 int [] nbits = new int [4];
6609 nbits [0] = bits [3];
6610 nbits [1] = bits [2];
6611 nbits [2] = bits [0];
6612 nbits [3] = bits [1];
6614 for (int j = 0; j < 4; j++){
6615 data [p++] = (byte) (nbits [j] & 0xff);
6616 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6617 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6618 data [p++] = (byte) (nbits [j] >> 24);
6622 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6631 // Emits the initializers for the array
6633 void EmitStaticInitializers (EmitContext ec)
6636 // First, the static data
6639 ILGenerator ig = ec.ig;
6641 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6643 fb = RootContext.MakeStaticData (data);
6645 ig.Emit (OpCodes.Dup);
6646 ig.Emit (OpCodes.Ldtoken, fb);
6647 ig.Emit (OpCodes.Call,
6648 TypeManager.void_initializearray_array_fieldhandle);
6652 // Emits pieces of the array that can not be computed at compile
6653 // time (variables and string locations).
6655 // This always expect the top value on the stack to be the array
6657 void EmitDynamicInitializers (EmitContext ec)
6659 ILGenerator ig = ec.ig;
6660 int dims = bounds.Count;
6661 int [] current_pos = new int [dims];
6662 int top = array_data.Count;
6664 MethodInfo set = null;
6668 ModuleBuilder mb = null;
6669 mb = CodeGen.Module.Builder;
6670 args = new Type [dims + 1];
6673 for (j = 0; j < dims; j++)
6674 args [j] = TypeManager.int32_type;
6676 args [j] = array_element_type;
6678 set = mb.GetArrayMethod (
6680 CallingConventions.HasThis | CallingConventions.Standard,
6681 TypeManager.void_type, args);
6684 for (int i = 0; i < top; i++){
6686 Expression e = null;
6688 if (array_data [i] is Expression)
6689 e = (Expression) array_data [i];
6693 // Basically we do this for string literals and
6694 // other non-literal expressions
6696 if (e is EnumConstant){
6697 e = ((EnumConstant) e).Child;
6700 if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6701 num_automatic_initializers <= max_automatic_initializers) {
6702 Type etype = e.Type;
6704 ig.Emit (OpCodes.Dup);
6706 for (int idx = 0; idx < dims; idx++)
6707 IntConstant.EmitInt (ig, current_pos [idx]);
6710 // If we are dealing with a struct, get the
6711 // address of it, so we can store it.
6714 etype.IsSubclassOf (TypeManager.value_type) &&
6715 (!TypeManager.IsBuiltinOrEnum (etype) ||
6716 etype == TypeManager.decimal_type)) {
6721 // Let new know that we are providing
6722 // the address where to store the results
6724 n.DisableTemporaryValueType ();
6727 ig.Emit (OpCodes.Ldelema, etype);
6734 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj);
6736 ig.Emit (OpCodes.Stobj, etype);
6740 ig.Emit (OpCodes.Call, set);
6748 for (int j = dims - 1; j >= 0; j--){
6750 if (current_pos [j] < (int) bounds [j])
6752 current_pos [j] = 0;
6757 void EmitArrayArguments (EmitContext ec)
6759 ILGenerator ig = ec.ig;
6761 foreach (Argument a in arguments) {
6762 Type atype = a.Type;
6765 if (atype == TypeManager.uint64_type)
6766 ig.Emit (OpCodes.Conv_Ovf_U4);
6767 else if (atype == TypeManager.int64_type)
6768 ig.Emit (OpCodes.Conv_Ovf_I4);
6772 public override void Emit (EmitContext ec)
6774 ILGenerator ig = ec.ig;
6776 EmitArrayArguments (ec);
6777 if (is_one_dimensional)
6778 ig.Emit (OpCodes.Newarr, array_element_type);
6780 if (is_builtin_type)
6781 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6783 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6786 if (initializers != null){
6788 // FIXME: Set this variable correctly.
6790 bool dynamic_initializers = true;
6792 // This will never be true for array types that cannot be statically
6793 // initialized. num_automatic_initializers will always be zero. See
6795 if (num_automatic_initializers > max_automatic_initializers)
6796 EmitStaticInitializers (ec);
6798 if (dynamic_initializers)
6799 EmitDynamicInitializers (ec);
6803 public object EncodeAsAttribute ()
6805 if (!is_one_dimensional){
6806 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6810 if (array_data == null){
6811 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6815 object [] ret = new object [array_data.Count];
6817 foreach (Expression e in array_data){
6820 if (e is NullLiteral)
6823 if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6833 /// Represents the `this' construct
6835 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6838 VariableInfo variable_info;
6840 public This (Block block, Location loc)
6846 public This (Location loc)
6851 public VariableInfo VariableInfo {
6852 get { return variable_info; }
6855 public bool VerifyFixed (bool is_expression)
6857 if ((variable_info == null) || (variable_info.LocalInfo == null))
6860 return variable_info.LocalInfo.IsFixed;
6863 public bool ResolveBase (EmitContext ec)
6865 eclass = ExprClass.Variable;
6866 type = ec.ContainerType;
6869 Error (26, "Keyword this not valid in static code");
6873 if ((block != null) && (block.ThisVariable != null))
6874 variable_info = block.ThisVariable.VariableInfo;
6876 if (ec.CurrentAnonymousMethod != null)
6882 public override Expression DoResolve (EmitContext ec)
6884 if (!ResolveBase (ec))
6887 if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6888 Error (188, "The this object cannot be used before all " +
6889 "of its fields are assigned to");
6890 variable_info.SetAssigned (ec);
6894 if (ec.IsFieldInitializer) {
6895 Error (27, "Keyword `this' can't be used outside a constructor, " +
6896 "a method or a property.");
6903 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6905 if (!ResolveBase (ec))
6908 if (variable_info != null)
6909 variable_info.SetAssigned (ec);
6911 if (ec.TypeContainer is Class){
6912 Error (1604, "Cannot assign to 'this' because it is read-only");
6919 public void Emit (EmitContext ec, bool leave_copy)
6923 ec.ig.Emit (OpCodes.Dup);
6926 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6928 ILGenerator ig = ec.ig;
6930 if (ec.TypeContainer is Struct){
6934 ec.ig.Emit (OpCodes.Dup);
6935 ig.Emit (OpCodes.Stobj, type);
6937 throw new Exception ("how did you get here");
6941 public override void Emit (EmitContext ec)
6943 ILGenerator ig = ec.ig;
6946 if (ec.TypeContainer is Struct)
6947 ig.Emit (OpCodes.Ldobj, type);
6950 public override int GetHashCode()
6952 return block.GetHashCode ();
6955 public override bool Equals (object obj)
6957 This t = obj as This;
6961 return block == t.block;
6964 public void AddressOf (EmitContext ec, AddressOp mode)
6969 // FIGURE OUT WHY LDARG_S does not work
6971 // consider: struct X { int val; int P { set { val = value; }}}
6973 // Yes, this looks very bad. Look at `NOTAS' for
6975 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6980 /// Represents the `__arglist' construct
6982 public class ArglistAccess : Expression
6984 public ArglistAccess (Location loc)
6989 public bool ResolveBase (EmitContext ec)
6991 eclass = ExprClass.Variable;
6992 type = TypeManager.runtime_argument_handle_type;
6996 public override Expression DoResolve (EmitContext ec)
6998 if (!ResolveBase (ec))
7001 if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
7002 Error (190, "The __arglist construct is valid only within " +
7003 "a variable argument method.");
7010 public override void Emit (EmitContext ec)
7012 ec.ig.Emit (OpCodes.Arglist);
7017 /// Represents the `__arglist (....)' construct
7019 public class Arglist : Expression
7021 public readonly Argument[] Arguments;
7023 public Arglist (Argument[] args, Location l)
7029 public Type[] ArgumentTypes {
7031 Type[] retval = new Type [Arguments.Length];
7032 for (int i = 0; i < Arguments.Length; i++)
7033 retval [i] = Arguments [i].Type;
7038 public override Expression DoResolve (EmitContext ec)
7040 eclass = ExprClass.Variable;
7041 type = TypeManager.runtime_argument_handle_type;
7043 foreach (Argument arg in Arguments) {
7044 if (!arg.Resolve (ec, loc))
7051 public override void Emit (EmitContext ec)
7053 foreach (Argument arg in Arguments)
7059 // This produces the value that renders an instance, used by the iterators code
7061 public class ProxyInstance : Expression, IMemoryLocation {
7062 public override Expression DoResolve (EmitContext ec)
7064 eclass = ExprClass.Variable;
7065 type = ec.ContainerType;
7069 public override void Emit (EmitContext ec)
7071 ec.ig.Emit (OpCodes.Ldarg_0);
7075 public void AddressOf (EmitContext ec, AddressOp mode)
7077 ec.ig.Emit (OpCodes.Ldarg_0);
7082 /// Implements the typeof operator
7084 public class TypeOf : Expression {
7085 public Expression QueriedType;
7086 protected Type typearg;
7088 public TypeOf (Expression queried_type, Location l)
7090 QueriedType = queried_type;
7094 public override Expression DoResolve (EmitContext ec)
7096 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7100 typearg = texpr.ResolveType (ec);
7102 if (typearg == TypeManager.void_type) {
7103 Error (673, "System.Void cannot be used from C# - " +
7104 "use typeof (void) to get the void type object");
7108 if (typearg.IsPointer && !ec.InUnsafe){
7112 CheckObsoleteAttribute (typearg);
7114 type = TypeManager.type_type;
7115 // Even though what is returned is a type object, it's treated as a value by the compiler.
7116 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7117 eclass = ExprClass.Value;
7121 public override void Emit (EmitContext ec)
7123 ec.ig.Emit (OpCodes.Ldtoken, typearg);
7124 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7127 public Type TypeArg {
7128 get { return typearg; }
7133 /// Implements the `typeof (void)' operator
7135 public class TypeOfVoid : TypeOf {
7136 public TypeOfVoid (Location l) : base (null, l)
7141 public override Expression DoResolve (EmitContext ec)
7143 type = TypeManager.type_type;
7144 typearg = TypeManager.void_type;
7145 // See description in TypeOf.
7146 eclass = ExprClass.Value;
7152 /// Implements the sizeof expression
7154 public class SizeOf : Expression {
7155 public Expression QueriedType;
7158 public SizeOf (Expression queried_type, Location l)
7160 this.QueriedType = queried_type;
7164 public override Expression DoResolve (EmitContext ec)
7166 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7170 type_queried = texpr.ResolveType (ec);
7172 int size_of = GetTypeSize (type_queried);
7174 return new IntConstant (size_of);
7178 Report.Error (233, loc, "'{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7179 TypeManager.CSharpName (type_queried));
7183 CheckObsoleteAttribute (type_queried);
7185 if (!TypeManager.IsUnmanagedType (type_queried)){
7186 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
7190 type = TypeManager.int32_type;
7191 eclass = ExprClass.Value;
7195 public override void Emit (EmitContext ec)
7197 int size = GetTypeSize (type_queried);
7200 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7202 IntConstant.EmitInt (ec.ig, size);
7207 /// Implements the member access expression
7209 public class MemberAccess : Expression {
7210 public readonly string Identifier;
7213 public MemberAccess (Expression expr, string id, Location l)
7220 public Expression Expr {
7226 Expression DoResolve (EmitContext ec, Expression right_side)
7229 throw new Exception ();
7232 // Resolve the expression with flow analysis turned off, we'll do the definite
7233 // assignment checks later. This is because we don't know yet what the expression
7234 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7235 // definite assignment check on the actual field and not on the whole struct.
7238 SimpleName original = expr as SimpleName;
7239 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type |
7240 ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7245 if (expr is Namespace) {
7246 Namespace ns = (Namespace) expr;
7247 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, Identifier, loc);
7249 Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName);
7254 // TODO: I mailed Ravi about this, and apparently we can get rid
7255 // of this and put it in the right place.
7257 // Handle enums here when they are in transit.
7258 // Note that we cannot afford to hit MemberLookup in this case because
7259 // it will fail to find any members at all
7262 Type expr_type = expr.Type;
7263 if (expr is TypeExpr){
7264 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7265 Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type);
7269 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7270 Enum en = TypeManager.LookupEnum (expr_type);
7273 object value = en.LookupEnumValue (Identifier, loc);
7276 MemberCore mc = en.GetDefinition (Identifier);
7277 ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7279 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7281 oa = en.GetObsoleteAttribute (en);
7283 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7286 Constant c = Constantify (value, en.UnderlyingType);
7287 return new EnumConstant (c, expr_type);
7290 CheckObsoleteAttribute (expr_type);
7292 FieldInfo fi = expr_type.GetField (Identifier);
7294 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7296 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7302 if (expr_type.IsPointer){
7303 Error (23, "The `.' operator can not be applied to pointer operands (" +
7304 TypeManager.CSharpName (expr_type) + ")");
7308 Expression member_lookup;
7309 member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7310 if (member_lookup == null)
7313 if (member_lookup is TypeExpr) {
7314 if (!(expr is TypeExpr) &&
7315 (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) {
7316 Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7317 member_lookup.Type + "' instead");
7321 return member_lookup;
7324 MemberExpr me = (MemberExpr) member_lookup;
7325 member_lookup = me.ResolveMemberAccess (ec, expr, loc, original);
7326 if (member_lookup == null)
7329 // The following DoResolve/DoResolveLValue will do the definite assignment
7332 if (right_side != null)
7333 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7335 member_lookup = member_lookup.DoResolve (ec);
7337 return member_lookup;
7340 public override Expression DoResolve (EmitContext ec)
7342 return DoResolve (ec, null);
7345 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7347 return DoResolve (ec, right_side);
7350 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
7352 return ResolveNamespaceOrType (ec, false);
7355 public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent)
7357 FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec);
7359 if (new_expr == null)
7362 if (new_expr is Namespace) {
7363 Namespace ns = (Namespace) new_expr;
7364 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, Identifier, loc);
7365 if (!silent && retval == null)
7366 Report.Error (234, loc, "The type or namespace name `{0}' could not be found in namespace `{1}'", Identifier, ns.FullName);
7370 Type expr_type = new_expr.Type;
7372 if (expr_type.IsPointer){
7373 Error (23, "The `.' operator can not be applied to pointer operands (" +
7374 TypeManager.CSharpName (expr_type) + ")");
7378 Expression member_lookup = MemberLookup (ec, expr_type, expr_type, Identifier, loc);
7379 if (member_lookup == null) {
7380 int errors = Report.Errors;
7381 MemberLookupFailed (ec, expr_type, expr_type, Identifier, null, false, loc);
7383 if (!silent && errors == Report.Errors)
7384 Report.Error (234, loc, "The type name `{0}' could not be found in type `{1}'",
7385 Identifier, new_expr.FullName);
7389 if (!(member_lookup is TypeExpr)) {
7390 Report.Error (118, loc, "'{0}.{1}' denotes a '{2}', where a type was expected",
7391 new_expr.FullName, Identifier, member_lookup.ExprClassName ());
7395 member_lookup = member_lookup.Resolve (ec, ResolveFlags.Type);
7396 return (member_lookup as TypeExpr);
7399 public override void Emit (EmitContext ec)
7401 throw new Exception ("Should not happen");
7404 public override string ToString ()
7406 return expr + "." + Identifier;
7411 /// Implements checked expressions
7413 public class CheckedExpr : Expression {
7415 public Expression Expr;
7417 public CheckedExpr (Expression e, Location l)
7423 public override Expression DoResolve (EmitContext ec)
7425 bool last_check = ec.CheckState;
7426 bool last_const_check = ec.ConstantCheckState;
7428 ec.CheckState = true;
7429 ec.ConstantCheckState = true;
7430 Expr = Expr.Resolve (ec);
7431 ec.CheckState = last_check;
7432 ec.ConstantCheckState = last_const_check;
7437 if (Expr is Constant)
7440 eclass = Expr.eclass;
7445 public override void Emit (EmitContext ec)
7447 bool last_check = ec.CheckState;
7448 bool last_const_check = ec.ConstantCheckState;
7450 ec.CheckState = true;
7451 ec.ConstantCheckState = true;
7453 ec.CheckState = last_check;
7454 ec.ConstantCheckState = last_const_check;
7460 /// Implements the unchecked expression
7462 public class UnCheckedExpr : Expression {
7464 public Expression Expr;
7466 public UnCheckedExpr (Expression e, Location l)
7472 public override Expression DoResolve (EmitContext ec)
7474 bool last_check = ec.CheckState;
7475 bool last_const_check = ec.ConstantCheckState;
7477 ec.CheckState = false;
7478 ec.ConstantCheckState = false;
7479 Expr = Expr.Resolve (ec);
7480 ec.CheckState = last_check;
7481 ec.ConstantCheckState = last_const_check;
7486 if (Expr is Constant)
7489 eclass = Expr.eclass;
7494 public override void Emit (EmitContext ec)
7496 bool last_check = ec.CheckState;
7497 bool last_const_check = ec.ConstantCheckState;
7499 ec.CheckState = false;
7500 ec.ConstantCheckState = false;
7502 ec.CheckState = last_check;
7503 ec.ConstantCheckState = last_const_check;
7509 /// An Element Access expression.
7511 /// During semantic analysis these are transformed into
7512 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7514 public class ElementAccess : Expression {
7515 public ArrayList Arguments;
7516 public Expression Expr;
7518 public ElementAccess (Expression e, ArrayList e_list, Location l)
7527 Arguments = new ArrayList ();
7528 foreach (Expression tmp in e_list)
7529 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7533 bool CommonResolve (EmitContext ec)
7535 Expr = Expr.Resolve (ec);
7540 if (Arguments == null)
7543 foreach (Argument a in Arguments){
7544 if (!a.Resolve (ec, loc))
7551 Expression MakePointerAccess (EmitContext ec, Type t)
7553 if (t == TypeManager.void_ptr_type){
7554 Error (242, "The array index operation is not valid for void pointers");
7557 if (Arguments.Count != 1){
7558 Error (196, "A pointer must be indexed by a single value");
7563 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7566 return new Indirection (p, loc).Resolve (ec);
7569 public override Expression DoResolve (EmitContext ec)
7571 if (!CommonResolve (ec))
7575 // We perform some simple tests, and then to "split" the emit and store
7576 // code we create an instance of a different class, and return that.
7578 // I am experimenting with this pattern.
7582 if (t == TypeManager.array_type){
7583 Report.Error (21, loc, "Cannot use indexer on System.Array");
7588 return (new ArrayAccess (this, loc)).Resolve (ec);
7590 return MakePointerAccess (ec, Expr.Type);
7592 FieldExpr fe = Expr as FieldExpr;
7594 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7596 return MakePointerAccess (ec, ff.ElementType);
7599 return (new IndexerAccess (this, loc)).Resolve (ec);
7602 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7604 if (!CommonResolve (ec))
7609 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7612 return MakePointerAccess (ec, Expr.Type);
7614 FieldExpr fe = Expr as FieldExpr;
7616 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7618 if (!(fe.InstanceExpression is LocalVariableReference) &&
7619 !(fe.InstanceExpression is This)) {
7620 Error (1708, "Fixed buffers can only be accessed through locals or fields");
7623 // TODO: not sure whether it is correct
7624 // if (!ec.InFixedInitializer) {
7625 // Error (1666, "You cannot use fixed sized buffers contained in unfixed expressions. Try using the fixed statement");
7628 return MakePointerAccess (ec, ff.ElementType);
7631 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7634 public override void Emit (EmitContext ec)
7636 throw new Exception ("Should never be reached");
7641 /// Implements array access
7643 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7645 // Points to our "data" repository
7649 LocalTemporary temp;
7652 public ArrayAccess (ElementAccess ea_data, Location l)
7655 eclass = ExprClass.Variable;
7659 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7661 return DoResolve (ec);
7664 public override Expression DoResolve (EmitContext ec)
7667 ExprClass eclass = ea.Expr.eclass;
7669 // As long as the type is valid
7670 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7671 eclass == ExprClass.Value)) {
7672 ea.Expr.Error_UnexpectedKind ("variable or value");
7677 Type t = ea.Expr.Type;
7678 if (t.GetArrayRank () != ea.Arguments.Count){
7680 "Incorrect number of indexes for array " +
7681 " expected: " + t.GetArrayRank () + " got: " +
7682 ea.Arguments.Count);
7686 type = TypeManager.GetElementType (t);
7687 if (type.IsPointer && !ec.InUnsafe){
7688 UnsafeError (ea.Location);
7692 foreach (Argument a in ea.Arguments){
7693 Type argtype = a.Type;
7695 if (argtype == TypeManager.int32_type ||
7696 argtype == TypeManager.uint32_type ||
7697 argtype == TypeManager.int64_type ||
7698 argtype == TypeManager.uint64_type) {
7699 Constant c = a.Expr as Constant;
7700 if (c != null && c.IsNegative) {
7701 Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)");
7707 // Mhm. This is strage, because the Argument.Type is not the same as
7708 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7710 // Wonder if I will run into trouble for this.
7712 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7717 eclass = ExprClass.Variable;
7723 /// Emits the right opcode to load an object of Type `t'
7724 /// from an array of T
7726 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7728 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7729 ig.Emit (OpCodes.Ldelem_U1);
7730 else if (type == TypeManager.sbyte_type)
7731 ig.Emit (OpCodes.Ldelem_I1);
7732 else if (type == TypeManager.short_type)
7733 ig.Emit (OpCodes.Ldelem_I2);
7734 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7735 ig.Emit (OpCodes.Ldelem_U2);
7736 else if (type == TypeManager.int32_type)
7737 ig.Emit (OpCodes.Ldelem_I4);
7738 else if (type == TypeManager.uint32_type)
7739 ig.Emit (OpCodes.Ldelem_U4);
7740 else if (type == TypeManager.uint64_type)
7741 ig.Emit (OpCodes.Ldelem_I8);
7742 else if (type == TypeManager.int64_type)
7743 ig.Emit (OpCodes.Ldelem_I8);
7744 else if (type == TypeManager.float_type)
7745 ig.Emit (OpCodes.Ldelem_R4);
7746 else if (type == TypeManager.double_type)
7747 ig.Emit (OpCodes.Ldelem_R8);
7748 else if (type == TypeManager.intptr_type)
7749 ig.Emit (OpCodes.Ldelem_I);
7750 else if (TypeManager.IsEnumType (type)){
7751 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7752 } else if (type.IsValueType){
7753 ig.Emit (OpCodes.Ldelema, type);
7754 ig.Emit (OpCodes.Ldobj, type);
7756 ig.Emit (OpCodes.Ldelem_Ref);
7760 /// Returns the right opcode to store an object of Type `t'
7761 /// from an array of T.
7763 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7765 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7767 t = TypeManager.TypeToCoreType (t);
7768 if (TypeManager.IsEnumType (t))
7769 t = TypeManager.EnumToUnderlying (t);
7770 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7771 t == TypeManager.bool_type)
7772 return OpCodes.Stelem_I1;
7773 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7774 t == TypeManager.char_type)
7775 return OpCodes.Stelem_I2;
7776 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7777 return OpCodes.Stelem_I4;
7778 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7779 return OpCodes.Stelem_I8;
7780 else if (t == TypeManager.float_type)
7781 return OpCodes.Stelem_R4;
7782 else if (t == TypeManager.double_type)
7783 return OpCodes.Stelem_R8;
7784 else if (t == TypeManager.intptr_type) {
7786 return OpCodes.Stobj;
7787 } else if (t.IsValueType) {
7789 return OpCodes.Stobj;
7791 return OpCodes.Stelem_Ref;
7794 MethodInfo FetchGetMethod ()
7796 ModuleBuilder mb = CodeGen.Module.Builder;
7797 int arg_count = ea.Arguments.Count;
7798 Type [] args = new Type [arg_count];
7801 for (int i = 0; i < arg_count; i++){
7802 //args [i++] = a.Type;
7803 args [i] = TypeManager.int32_type;
7806 get = mb.GetArrayMethod (
7807 ea.Expr.Type, "Get",
7808 CallingConventions.HasThis |
7809 CallingConventions.Standard,
7815 MethodInfo FetchAddressMethod ()
7817 ModuleBuilder mb = CodeGen.Module.Builder;
7818 int arg_count = ea.Arguments.Count;
7819 Type [] args = new Type [arg_count];
7823 ret_type = TypeManager.GetReferenceType (type);
7825 for (int i = 0; i < arg_count; i++){
7826 //args [i++] = a.Type;
7827 args [i] = TypeManager.int32_type;
7830 address = mb.GetArrayMethod (
7831 ea.Expr.Type, "Address",
7832 CallingConventions.HasThis |
7833 CallingConventions.Standard,
7840 // Load the array arguments into the stack.
7842 // If we have been requested to cache the values (cached_locations array
7843 // initialized), then load the arguments the first time and store them
7844 // in locals. otherwise load from local variables.
7846 void LoadArrayAndArguments (EmitContext ec)
7848 ILGenerator ig = ec.ig;
7851 foreach (Argument a in ea.Arguments){
7852 Type argtype = a.Expr.Type;
7856 if (argtype == TypeManager.int64_type)
7857 ig.Emit (OpCodes.Conv_Ovf_I);
7858 else if (argtype == TypeManager.uint64_type)
7859 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7863 public void Emit (EmitContext ec, bool leave_copy)
7865 int rank = ea.Expr.Type.GetArrayRank ();
7866 ILGenerator ig = ec.ig;
7869 LoadArrayAndArguments (ec);
7872 EmitLoadOpcode (ig, type);
7876 method = FetchGetMethod ();
7877 ig.Emit (OpCodes.Call, method);
7880 LoadFromPtr (ec.ig, this.type);
7883 ec.ig.Emit (OpCodes.Dup);
7884 temp = new LocalTemporary (ec, this.type);
7889 public override void Emit (EmitContext ec)
7894 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7896 int rank = ea.Expr.Type.GetArrayRank ();
7897 ILGenerator ig = ec.ig;
7898 Type t = source.Type;
7899 prepared = prepare_for_load;
7901 if (prepare_for_load) {
7902 AddressOf (ec, AddressOp.LoadStore);
7903 ec.ig.Emit (OpCodes.Dup);
7906 ec.ig.Emit (OpCodes.Dup);
7907 temp = new LocalTemporary (ec, this.type);
7910 StoreFromPtr (ec.ig, t);
7918 LoadArrayAndArguments (ec);
7922 OpCode op = GetStoreOpcode (t, out is_stobj);
7924 // The stobj opcode used by value types will need
7925 // an address on the stack, not really an array/array
7929 ig.Emit (OpCodes.Ldelema, t);
7933 ec.ig.Emit (OpCodes.Dup);
7934 temp = new LocalTemporary (ec, this.type);
7939 ig.Emit (OpCodes.Stobj, t);
7943 ModuleBuilder mb = CodeGen.Module.Builder;
7944 int arg_count = ea.Arguments.Count;
7945 Type [] args = new Type [arg_count + 1];
7950 ec.ig.Emit (OpCodes.Dup);
7951 temp = new LocalTemporary (ec, this.type);
7955 for (int i = 0; i < arg_count; i++){
7956 //args [i++] = a.Type;
7957 args [i] = TypeManager.int32_type;
7960 args [arg_count] = type;
7962 set = mb.GetArrayMethod (
7963 ea.Expr.Type, "Set",
7964 CallingConventions.HasThis |
7965 CallingConventions.Standard,
7966 TypeManager.void_type, args);
7968 ig.Emit (OpCodes.Call, set);
7975 public void AddressOf (EmitContext ec, AddressOp mode)
7977 int rank = ea.Expr.Type.GetArrayRank ();
7978 ILGenerator ig = ec.ig;
7980 LoadArrayAndArguments (ec);
7983 ig.Emit (OpCodes.Ldelema, type);
7985 MethodInfo address = FetchAddressMethod ();
7986 ig.Emit (OpCodes.Call, address);
7990 public void EmitGetLength (EmitContext ec, int dim)
7992 int rank = ea.Expr.Type.GetArrayRank ();
7993 ILGenerator ig = ec.ig;
7997 ig.Emit (OpCodes.Ldlen);
7998 ig.Emit (OpCodes.Conv_I4);
8000 IntLiteral.EmitInt (ig, dim);
8001 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8007 public ArrayList Properties;
8008 static Hashtable map;
8010 public struct Indexer {
8011 public readonly Type Type;
8012 public readonly MethodInfo Getter, Setter;
8014 public Indexer (Type type, MethodInfo get, MethodInfo set)
8024 map = new Hashtable ();
8029 Properties = new ArrayList ();
8032 void Append (MemberInfo [] mi)
8034 foreach (PropertyInfo property in mi){
8035 MethodInfo get, set;
8037 get = property.GetGetMethod (true);
8038 set = property.GetSetMethod (true);
8039 Properties.Add (new Indexer (property.PropertyType, get, set));
8043 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8045 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8047 MemberInfo [] mi = TypeManager.MemberLookup (
8048 caller_type, caller_type, lookup_type, MemberTypes.Property,
8049 BindingFlags.Public | BindingFlags.Instance |
8050 BindingFlags.DeclaredOnly, p_name, null);
8052 if (mi == null || mi.Length == 0)
8058 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
8060 Indexers ix = (Indexers) map [lookup_type];
8065 Type copy = lookup_type;
8066 while (copy != TypeManager.object_type && copy != null){
8067 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8071 ix = new Indexers ();
8076 copy = copy.BaseType;
8079 if (!lookup_type.IsInterface)
8082 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8083 if (ifaces != null) {
8084 foreach (Type itype in ifaces) {
8085 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8088 ix = new Indexers ();
8100 /// Expressions that represent an indexer call.
8102 public class IndexerAccess : Expression, IAssignMethod {
8104 // Points to our "data" repository
8106 MethodInfo get, set;
8107 ArrayList set_arguments;
8108 bool is_base_indexer;
8110 protected Type indexer_type;
8111 protected Type current_type;
8112 protected Expression instance_expr;
8113 protected ArrayList arguments;
8115 public IndexerAccess (ElementAccess ea, Location loc)
8116 : this (ea.Expr, false, loc)
8118 this.arguments = ea.Arguments;
8121 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8124 this.instance_expr = instance_expr;
8125 this.is_base_indexer = is_base_indexer;
8126 this.eclass = ExprClass.Value;
8130 protected virtual bool CommonResolve (EmitContext ec)
8132 indexer_type = instance_expr.Type;
8133 current_type = ec.ContainerType;
8138 public override Expression DoResolve (EmitContext ec)
8140 ArrayList AllGetters = new ArrayList();
8141 if (!CommonResolve (ec))
8145 // Step 1: Query for all `Item' *properties*. Notice
8146 // that the actual methods are pointed from here.
8148 // This is a group of properties, piles of them.
8150 bool found_any = false, found_any_getters = false;
8151 Type lookup_type = indexer_type;
8154 ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8155 if (ilist != null) {
8157 if (ilist.Properties != null) {
8158 foreach (Indexers.Indexer ix in ilist.Properties) {
8159 if (ix.Getter != null)
8160 AllGetters.Add(ix.Getter);
8165 if (AllGetters.Count > 0) {
8166 found_any_getters = true;
8167 get = (MethodInfo) Invocation.OverloadResolve (
8168 ec, new MethodGroupExpr (AllGetters, loc),
8169 arguments, false, loc);
8173 Report.Error (21, loc,
8174 "Type `" + TypeManager.CSharpName (indexer_type) +
8175 "' does not have any indexers defined");
8179 if (!found_any_getters) {
8180 Error (154, "indexer can not be used in this context, because " +
8181 "it lacks a `get' accessor");
8186 Error (1501, "No Overload for method `this' takes `" +
8187 arguments.Count + "' arguments");
8192 // Only base will allow this invocation to happen.
8194 if (get.IsAbstract && this is BaseIndexerAccess){
8195 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8199 type = get.ReturnType;
8200 if (type.IsPointer && !ec.InUnsafe){
8205 instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8207 eclass = ExprClass.IndexerAccess;
8211 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8213 ArrayList AllSetters = new ArrayList();
8214 if (!CommonResolve (ec))
8217 bool found_any = false, found_any_setters = false;
8219 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8220 if (ilist != null) {
8222 if (ilist.Properties != null) {
8223 foreach (Indexers.Indexer ix in ilist.Properties) {
8224 if (ix.Setter != null)
8225 AllSetters.Add(ix.Setter);
8229 if (AllSetters.Count > 0) {
8230 found_any_setters = true;
8231 set_arguments = (ArrayList) arguments.Clone ();
8232 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8233 set = (MethodInfo) Invocation.OverloadResolve (
8234 ec, new MethodGroupExpr (AllSetters, loc),
8235 set_arguments, false, loc);
8239 Report.Error (21, loc,
8240 "Type `" + TypeManager.CSharpName (indexer_type) +
8241 "' does not have any indexers defined");
8245 if (!found_any_setters) {
8246 Error (154, "indexer can not be used in this context, because " +
8247 "it lacks a `set' accessor");
8252 Error (1501, "No Overload for method `this' takes `" +
8253 arguments.Count + "' arguments");
8258 // Only base will allow this invocation to happen.
8260 if (set.IsAbstract && this is BaseIndexerAccess){
8261 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8266 // Now look for the actual match in the list of indexers to set our "return" type
8268 type = TypeManager.void_type; // default value
8269 foreach (Indexers.Indexer ix in ilist.Properties){
8270 if (ix.Setter == set){
8276 instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8278 eclass = ExprClass.IndexerAccess;
8282 bool prepared = false;
8283 LocalTemporary temp;
8285 public void Emit (EmitContext ec, bool leave_copy)
8287 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8289 ec.ig.Emit (OpCodes.Dup);
8290 temp = new LocalTemporary (ec, Type);
8296 // source is ignored, because we already have a copy of it from the
8297 // LValue resolution and we have already constructed a pre-cached
8298 // version of the arguments (ea.set_arguments);
8300 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8302 prepared = prepare_for_load;
8303 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8308 ec.ig.Emit (OpCodes.Dup);
8309 temp = new LocalTemporary (ec, Type);
8312 } else if (leave_copy) {
8313 temp = new LocalTemporary (ec, Type);
8319 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8326 public override void Emit (EmitContext ec)
8333 /// The base operator for method names
8335 public class BaseAccess : Expression {
8338 public BaseAccess (string member, Location l)
8340 this.member = member;
8344 public override Expression DoResolve (EmitContext ec)
8346 Expression c = CommonResolve (ec);
8352 // MethodGroups use this opportunity to flag an error on lacking ()
8354 if (!(c is MethodGroupExpr))
8355 return c.Resolve (ec);
8359 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8361 Expression c = CommonResolve (ec);
8367 // MethodGroups use this opportunity to flag an error on lacking ()
8369 if (! (c is MethodGroupExpr))
8370 return c.DoResolveLValue (ec, right_side);
8375 Expression CommonResolve (EmitContext ec)
8377 Expression member_lookup;
8378 Type current_type = ec.ContainerType;
8379 Type base_type = current_type.BaseType;
8382 Error (1511, "Keyword base is not allowed in static method");
8386 if (ec.IsFieldInitializer){
8387 Error (1512, "Keyword base is not available in the current context");
8391 member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
8392 AllMemberTypes, AllBindingFlags, loc);
8393 if (member_lookup == null) {
8394 MemberLookupFailed (ec, base_type, base_type, member, null, true, loc);
8401 left = new TypeExpression (base_type, loc);
8403 left = ec.GetThis (loc);
8405 MemberExpr me = (MemberExpr) member_lookup;
8407 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8409 if (e is PropertyExpr) {
8410 PropertyExpr pe = (PropertyExpr) e;
8415 if (e is MethodGroupExpr)
8416 ((MethodGroupExpr) e).IsBase = true;
8421 public override void Emit (EmitContext ec)
8423 throw new Exception ("Should never be called");
8428 /// The base indexer operator
8430 public class BaseIndexerAccess : IndexerAccess {
8431 public BaseIndexerAccess (ArrayList args, Location loc)
8432 : base (null, true, loc)
8434 arguments = new ArrayList ();
8435 foreach (Expression tmp in args)
8436 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8439 protected override bool CommonResolve (EmitContext ec)
8441 instance_expr = ec.GetThis (loc);
8443 current_type = ec.ContainerType.BaseType;
8444 indexer_type = current_type;
8446 foreach (Argument a in arguments){
8447 if (!a.Resolve (ec, loc))
8456 /// This class exists solely to pass the Type around and to be a dummy
8457 /// that can be passed to the conversion functions (this is used by
8458 /// foreach implementation to typecast the object return value from
8459 /// get_Current into the proper type. All code has been generated and
8460 /// we only care about the side effect conversions to be performed
8462 /// This is also now used as a placeholder where a no-action expression
8463 /// is needed (the `New' class).
8465 public class EmptyExpression : Expression {
8466 public static readonly EmptyExpression Null = new EmptyExpression ();
8468 static EmptyExpression temp = new EmptyExpression ();
8469 public static EmptyExpression Grab ()
8472 throw new InternalErrorException ("Nested Grab");
8473 EmptyExpression retval = temp;
8478 public static void Release (EmptyExpression e)
8481 throw new InternalErrorException ("Already released");
8485 // TODO: should be protected
8486 public EmptyExpression ()
8488 type = TypeManager.object_type;
8489 eclass = ExprClass.Value;
8490 loc = Location.Null;
8493 public EmptyExpression (Type t)
8496 eclass = ExprClass.Value;
8497 loc = Location.Null;
8500 public override Expression DoResolve (EmitContext ec)
8505 public override void Emit (EmitContext ec)
8507 // nothing, as we only exist to not do anything.
8511 // This is just because we might want to reuse this bad boy
8512 // instead of creating gazillions of EmptyExpressions.
8513 // (CanImplicitConversion uses it)
8515 public void SetType (Type t)
8521 public class UserCast : Expression {
8525 public UserCast (MethodInfo method, Expression source, Location l)
8527 this.method = method;
8528 this.source = source;
8529 type = method.ReturnType;
8530 eclass = ExprClass.Value;
8534 public Expression Source {
8540 public override Expression DoResolve (EmitContext ec)
8543 // We are born fully resolved
8548 public override void Emit (EmitContext ec)
8550 ILGenerator ig = ec.ig;
8554 if (method is MethodInfo)
8555 ig.Emit (OpCodes.Call, (MethodInfo) method);
8557 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8563 // This class is used to "construct" the type during a typecast
8564 // operation. Since the Type.GetType class in .NET can parse
8565 // the type specification, we just use this to construct the type
8566 // one bit at a time.
8568 public class ComposedCast : TypeExpr {
8572 public ComposedCast (Expression left, string dim, Location l)
8579 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8581 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8585 Type ltype = lexpr.ResolveType (ec);
8587 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8588 Report.Error (1547, Location,
8589 "Keyword 'void' cannot be used in this context");
8593 if (dim == "*" && !TypeManager.IsUnmanagedType (ltype)) {
8594 Report.Error (208, loc, "Cannot declare a pointer to a managed type ('{0}')", ltype);
8598 type = TypeManager.GetConstructedType (ltype, dim);
8600 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8603 if (!ec.InUnsafe && type.IsPointer){
8608 if (type.IsArray && (type.GetElementType () == TypeManager.arg_iterator_type ||
8609 type.GetElementType () == TypeManager.typed_reference_type)) {
8610 Report.Error (611, loc, "Array elements cannot be of type '{0}'", TypeManager.CSharpName (type.GetElementType ()));
8614 eclass = ExprClass.Type;
8618 public override string Name {
8624 public override string FullName {
8626 return type.FullName;
8631 public class FixedBufferPtr: Expression {
8634 public FixedBufferPtr (Expression array, Type array_type, Location l)
8639 type = TypeManager.GetPointerType (array_type);
8640 eclass = ExprClass.Value;
8643 public override void Emit(EmitContext ec)
8648 public override Expression DoResolve (EmitContext ec)
8651 // We are born fully resolved
8659 // This class is used to represent the address of an array, used
8660 // only by the Fixed statement, this generates "&a [0]" construct
8661 // for fixed (char *pa = a)
8663 public class ArrayPtr : FixedBufferPtr {
8666 public ArrayPtr (Expression array, Type array_type, Location l):
8667 base (array, array_type, l)
8669 this.array_type = array_type;
8672 public override void Emit (EmitContext ec)
8676 ILGenerator ig = ec.ig;
8677 IntLiteral.EmitInt (ig, 0);
8678 ig.Emit (OpCodes.Ldelema, array_type);
8683 // Used by the fixed statement
8685 public class StringPtr : Expression {
8688 public StringPtr (LocalBuilder b, Location l)
8691 eclass = ExprClass.Value;
8692 type = TypeManager.char_ptr_type;
8696 public override Expression DoResolve (EmitContext ec)
8698 // This should never be invoked, we are born in fully
8699 // initialized state.
8704 public override void Emit (EmitContext ec)
8706 ILGenerator ig = ec.ig;
8708 ig.Emit (OpCodes.Ldloc, b);
8709 ig.Emit (OpCodes.Conv_I);
8710 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8711 ig.Emit (OpCodes.Add);
8716 // Implements the `stackalloc' keyword
8718 public class StackAlloc : Expression {
8723 public StackAlloc (Expression type, Expression count, Location l)
8730 public override Expression DoResolve (EmitContext ec)
8732 count = count.Resolve (ec);
8736 if (count.Type != TypeManager.int32_type){
8737 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8742 Constant c = count as Constant;
8743 if (c != null && c.IsNegative) {
8744 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8748 if (ec.InCatch || ec.InFinally) {
8750 "stackalloc can not be used in a catch or finally block");
8754 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8758 otype = texpr.ResolveType (ec);
8760 if (!TypeManager.VerifyUnManaged (otype, loc))
8763 type = TypeManager.GetPointerType (otype);
8764 eclass = ExprClass.Value;
8769 public override void Emit (EmitContext ec)
8771 int size = GetTypeSize (otype);
8772 ILGenerator ig = ec.ig;
8775 ig.Emit (OpCodes.Sizeof, otype);
8777 IntConstant.EmitInt (ig, size);
8779 ig.Emit (OpCodes.Mul);
8780 ig.Emit (OpCodes.Localloc);