2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// This is just a helper class, it is generated by Unary, UnaryMutator
22 /// when an overloaded method has been found. It just emits the code for a
25 public class StaticCallExpr : ExpressionStatement {
29 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
35 eclass = ExprClass.Value;
39 public override Expression DoResolve (EmitContext ec)
42 // We are born fully resolved
47 public override void Emit (EmitContext ec)
50 Invocation.EmitArguments (ec, mi, args, false, null);
52 ec.ig.Emit (OpCodes.Call, mi);
56 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
57 Expression e, Location loc)
62 args = new ArrayList (1);
63 Argument a = new Argument (e, Argument.AType.Expression);
65 // We need to resolve the arguments before sending them in !
66 if (!a.Resolve (ec, loc))
70 method = Invocation.OverloadResolve (
71 ec, (MethodGroupExpr) mg, args, false, loc);
76 return new StaticCallExpr ((MethodInfo) method, args, loc);
79 public override void EmitStatement (EmitContext ec)
82 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
83 ec.ig.Emit (OpCodes.Pop);
86 public MethodInfo Method {
91 public class ParenthesizedExpression : Expression
93 public Expression Expr;
95 public ParenthesizedExpression (Expression expr)
100 public override Expression DoResolve (EmitContext ec)
102 Expr = Expr.Resolve (ec);
106 public override void Emit (EmitContext ec)
108 throw new Exception ("Should not happen");
111 public override Location Location
114 return Expr.Location;
120 /// Unary expressions.
124 /// Unary implements unary expressions. It derives from
125 /// ExpressionStatement becuase the pre/post increment/decrement
126 /// operators can be used in a statement context.
128 public class Unary : Expression {
129 public enum Operator : byte {
130 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 Indirection, AddressOf, TOP
134 public Operator Oper;
135 public Expression Expr;
137 public Unary (Operator op, Expression expr, Location loc)
145 /// Returns a stringified representation of the Operator
147 static public string OperName (Operator oper)
150 case Operator.UnaryPlus:
152 case Operator.UnaryNegation:
154 case Operator.LogicalNot:
156 case Operator.OnesComplement:
158 case Operator.AddressOf:
160 case Operator.Indirection:
164 return oper.ToString ();
167 public static readonly string [] oper_names;
171 oper_names = new string [(int)Operator.TOP];
173 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
174 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
175 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
176 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
177 oper_names [(int) Operator.Indirection] = "op_Indirection";
178 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
181 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
183 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
186 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
188 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
192 void Error23 (Type t)
194 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
198 // This routine will attempt to simplify the unary expression when the
199 // argument is a constant.
201 Constant TryReduceConstant (EmitContext ec, Constant e)
203 Type expr_type = e.Type;
206 case Operator.UnaryPlus:
207 // Unary numeric promotions
208 if (expr_type == TypeManager.byte_type)
209 return new IntConstant (((ByteConstant)e).Value, e.Location);
210 if (expr_type == TypeManager.sbyte_type)
211 return new IntConstant (((SByteConstant)e).Value, e.Location);
212 if (expr_type == TypeManager.short_type)
213 return new IntConstant (((ShortConstant)e).Value, e.Location);
214 if (expr_type == TypeManager.ushort_type)
215 return new IntConstant (((UShortConstant)e).Value, e.Location);
216 if (expr_type == TypeManager.char_type)
217 return new IntConstant (((CharConstant)e).Value, e.Location);
219 // Predefined operators
220 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
221 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
222 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
223 expr_type == TypeManager.decimal_type)
230 case Operator.UnaryNegation:
231 // Unary numeric promotions
232 if (expr_type == TypeManager.byte_type)
233 return new IntConstant (-((ByteConstant)e).Value, e.Location);
234 if (expr_type == TypeManager.sbyte_type)
235 return new IntConstant (-((SByteConstant)e).Value, e.Location);
236 if (expr_type == TypeManager.short_type)
237 return new IntConstant (-((ShortConstant)e).Value, e.Location);
238 if (expr_type == TypeManager.ushort_type)
239 return new IntConstant (-((UShortConstant)e).Value, e.Location);
240 if (expr_type == TypeManager.char_type)
241 return new IntConstant (-((CharConstant)e).Value, e.Location);
243 // Predefined operators
244 if (expr_type == TypeManager.int32_type) {
245 int value = ((IntConstant)e).Value;
246 if (value == int.MinValue) {
247 if (ec.ConstantCheckState) {
248 ConstantFold.Error_CompileTimeOverflow (loc);
253 return new IntConstant (-value, e.Location);
255 if (expr_type == TypeManager.int64_type) {
256 long value = ((LongConstant)e).Value;
257 if (value == long.MinValue) {
258 if (ec.ConstantCheckState) {
259 ConstantFold.Error_CompileTimeOverflow (loc);
264 return new LongConstant (-value, e.Location);
267 if (expr_type == TypeManager.uint32_type) {
268 UIntLiteral uil = e as UIntLiteral;
270 if (uil.Value == 2147483648)
271 return new IntLiteral (int.MinValue, e.Location);
272 return new LongLiteral (-uil.Value, e.Location);
274 return new LongConstant (-((UIntConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.uint64_type) {
278 ULongLiteral ull = e as ULongLiteral;
279 if (ull != null && ull.Value == 9223372036854775808)
280 return new LongLiteral (long.MinValue, e.Location);
284 if (expr_type == TypeManager.float_type) {
285 FloatLiteral fl = e as FloatLiteral;
286 // For better error reporting
288 fl.Value = -fl.Value;
291 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
293 if (expr_type == TypeManager.double_type) {
294 DoubleLiteral dl = e as DoubleLiteral;
295 // For better error reporting
297 dl.Value = -dl.Value;
301 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
303 if (expr_type == TypeManager.decimal_type)
304 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
308 case Operator.LogicalNot:
309 if (expr_type != TypeManager.bool_type)
312 BoolConstant b = (BoolConstant) e;
313 return new BoolConstant (!(b.Value), b.Location);
315 case Operator.OnesComplement:
316 // Unary numeric promotions
317 if (expr_type == TypeManager.byte_type)
318 return new IntConstant (~((ByteConstant)e).Value, e.Location);
319 if (expr_type == TypeManager.sbyte_type)
320 return new IntConstant (~((SByteConstant)e).Value, e.Location);
321 if (expr_type == TypeManager.short_type)
322 return new IntConstant (~((ShortConstant)e).Value, e.Location);
323 if (expr_type == TypeManager.ushort_type)
324 return new IntConstant (~((UShortConstant)e).Value, e.Location);
325 if (expr_type == TypeManager.char_type)
326 return new IntConstant (~((CharConstant)e).Value, e.Location);
328 // Predefined operators
329 if (expr_type == TypeManager.int32_type)
330 return new IntConstant (~((IntConstant)e).Value, e.Location);
331 if (expr_type == TypeManager.uint32_type)
332 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
333 if (expr_type == TypeManager.int64_type)
334 return new LongConstant (~((LongConstant)e).Value, e.Location);
335 if (expr_type == TypeManager.uint64_type)
336 return new ULongConstant (~((UIntConstant)e).Value, e.Location);
337 if (e is EnumConstant) {
338 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
340 e = new EnumConstant (e, expr_type);
345 case Operator.AddressOf:
348 case Operator.Indirection:
351 throw new Exception ("Can not constant fold: " + Oper.ToString());
354 Expression ResolveOperator (EmitContext ec)
357 // Step 1: Default operations on CLI native types.
360 // Attempt to use a constant folding operation.
361 Constant cexpr = Expr as Constant;
363 cexpr = TryReduceConstant (ec, cexpr);
370 // Step 2: Perform Operator Overload location
372 Type expr_type = Expr.Type;
373 string op_name = oper_names [(int) Oper];
375 Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
377 Expression e = StaticCallExpr.MakeSimpleCall (
378 ec, (MethodGroupExpr) mg, Expr, loc);
389 case Operator.LogicalNot:
390 if (expr_type != TypeManager.bool_type) {
391 Expr = ResolveBoolean (ec, Expr, loc);
398 type = TypeManager.bool_type;
401 case Operator.OnesComplement:
402 // Unary numeric promotions
403 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
404 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
405 expr_type == TypeManager.char_type)
407 type = TypeManager.int32_type;
408 return new EmptyCast (this, type);
411 // Predefined operators
412 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
413 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
414 TypeManager.IsEnumType (expr_type))
420 type = TypeManager.int32_type;
421 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
428 case Operator.AddressOf:
434 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
438 IVariable variable = Expr as IVariable;
439 bool is_fixed = variable != null && variable.VerifyFixed ();
441 if (!ec.InFixedInitializer && !is_fixed) {
442 Error (212, "You can only take the address of unfixed expression inside " +
443 "of a fixed statement initializer");
447 if (ec.InFixedInitializer && is_fixed) {
448 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
452 LocalVariableReference lr = Expr as LocalVariableReference;
454 if (lr.local_info.IsCaptured){
455 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
458 lr.local_info.AddressTaken = true;
459 lr.local_info.Used = true;
462 ParameterReference pr = Expr as ParameterReference;
463 if ((pr != null) && pr.Parameter.IsCaptured) {
464 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
468 // According to the specs, a variable is considered definitely assigned if you take
470 if ((variable != null) && (variable.VariableInfo != null)){
471 variable.VariableInfo.SetAssigned (ec);
474 type = TypeManager.GetPointerType (Expr.Type);
477 case Operator.Indirection:
483 if (!expr_type.IsPointer){
484 Error (193, "The * or -> operator must be applied to a pointer");
489 // We create an Indirection expression, because
490 // it can implement the IMemoryLocation.
492 return new Indirection (Expr, loc);
494 case Operator.UnaryPlus:
495 // Unary numeric promotions
496 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
497 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
498 expr_type == TypeManager.char_type)
500 return new EmptyCast (Expr, TypeManager.int32_type);
503 // Predefined operators
504 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
505 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
506 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
507 expr_type == TypeManager.decimal_type)
512 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
514 // Because we can completely ignore unary +
521 case Operator.UnaryNegation:
523 // transform - - expr into expr
525 Unary u = Expr as Unary;
526 if (u != null && u.Oper == Operator.UnaryNegation) {
530 // Unary numeric promotions
531 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
532 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
533 expr_type == TypeManager.char_type)
535 type = TypeManager.int32_type;
536 return new EmptyCast (this, type);
540 // Predefined operators
542 if (expr_type == TypeManager.uint32_type) {
543 type = TypeManager.int64_type;
544 Expr = Convert.ImplicitNumericConversion (Expr, type);
548 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
549 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
550 expr_type == TypeManager.decimal_type)
559 type = TypeManager.int32_type;
560 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
568 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
569 TypeManager.CSharpName (expr_type) + "'");
573 public override Expression DoResolve (EmitContext ec)
575 if (Oper == Operator.AddressOf) {
576 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
578 if (Expr == null || Expr.eclass != ExprClass.Variable){
579 Error (211, "Cannot take the address of the given expression");
584 Expr = Expr.Resolve (ec);
590 if (TypeManager.IsNullableValueType (Expr.Type))
591 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).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:
615 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
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 (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 (expr.Type);
713 temporary.Store (ec);
716 StoreFromPtr (ec.ig, type);
718 if (temporary != null) {
720 temporary.Release (ec);
724 public void AddressOf (EmitContext ec, AddressOp Mode)
729 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
731 return DoResolve (ec);
734 public override Expression DoResolve (EmitContext ec)
737 // Born fully resolved
742 public override string ToString ()
744 return "*(" + expr + ")";
747 #region IVariable Members
749 public VariableInfo VariableInfo {
753 public bool VerifyFixed ()
755 // A pointer-indirection is always fixed.
763 /// Unary Mutator expressions (pre and post ++ and --)
767 /// UnaryMutator implements ++ and -- expressions. It derives from
768 /// ExpressionStatement becuase the pre/post increment/decrement
769 /// operators can be used in a statement context.
771 /// FIXME: Idea, we could split this up in two classes, one simpler
772 /// for the common case, and one with the extra fields for more complex
773 /// classes (indexers require temporary access; overloaded require method)
776 public class UnaryMutator : ExpressionStatement {
778 public enum Mode : byte {
785 PreDecrement = IsDecrement,
786 PostIncrement = IsPost,
787 PostDecrement = IsPost | IsDecrement
791 bool is_expr = false;
792 bool recurse = false;
797 // This is expensive for the simplest case.
799 StaticCallExpr method;
801 public UnaryMutator (Mode m, Expression e, Location l)
808 static string OperName (Mode mode)
810 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
815 /// Returns whether an object of type `t' can be incremented
816 /// or decremented with add/sub (ie, basically whether we can
817 /// use pre-post incr-decr operations on it, but it is not a
818 /// System.Decimal, which we require operator overloading to catch)
820 static bool IsIncrementableNumber (Type t)
822 return (t == TypeManager.sbyte_type) ||
823 (t == TypeManager.byte_type) ||
824 (t == TypeManager.short_type) ||
825 (t == TypeManager.ushort_type) ||
826 (t == TypeManager.int32_type) ||
827 (t == TypeManager.uint32_type) ||
828 (t == TypeManager.int64_type) ||
829 (t == TypeManager.uint64_type) ||
830 (t == TypeManager.char_type) ||
831 (t.IsSubclassOf (TypeManager.enum_type)) ||
832 (t == TypeManager.float_type) ||
833 (t == TypeManager.double_type) ||
834 (t.IsPointer && t != TypeManager.void_ptr_type);
837 Expression ResolveOperator (EmitContext ec)
839 Type expr_type = expr.Type;
842 // Step 1: Perform Operator Overload location
847 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
848 op_name = "op_Increment";
850 op_name = "op_Decrement";
852 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
855 method = StaticCallExpr.MakeSimpleCall (
856 ec, (MethodGroupExpr) mg, expr, loc);
859 } else if (!IsIncrementableNumber (expr_type)) {
860 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
861 TypeManager.CSharpName (expr_type) + "'");
866 // The operand of the prefix/postfix increment decrement operators
867 // should be an expression that is classified as a variable,
868 // a property access or an indexer access
871 if (expr.eclass == ExprClass.Variable){
872 LocalVariableReference var = expr as LocalVariableReference;
873 if ((var != null) && var.IsReadOnly) {
874 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
877 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
878 expr = expr.ResolveLValue (ec, this, Location);
882 if (expr.eclass == ExprClass.Value) {
883 Error_ValueAssignment (loc);
885 expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
893 public override Expression DoResolve (EmitContext ec)
895 expr = expr.Resolve (ec);
900 eclass = ExprClass.Value;
903 if (TypeManager.IsNullableValueType (expr.Type))
904 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
907 return ResolveOperator (ec);
910 static int PtrTypeSize (Type t)
912 return GetTypeSize (TypeManager.GetElementType (t));
916 // Loads the proper "1" into the stack based on the type, then it emits the
917 // opcode for the operation requested
919 void LoadOneAndEmitOp (EmitContext ec, Type t)
922 // Measure if getting the typecode and using that is more/less efficient
923 // that comparing types. t.GetTypeCode() is an internal call.
925 ILGenerator ig = ec.ig;
927 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
928 LongConstant.EmitLong (ig, 1);
929 else if (t == TypeManager.double_type)
930 ig.Emit (OpCodes.Ldc_R8, 1.0);
931 else if (t == TypeManager.float_type)
932 ig.Emit (OpCodes.Ldc_R4, 1.0F);
933 else if (t.IsPointer){
934 int n = PtrTypeSize (t);
937 ig.Emit (OpCodes.Sizeof, t);
939 IntConstant.EmitInt (ig, n);
941 ig.Emit (OpCodes.Ldc_I4_1);
944 // Now emit the operation
947 if (t == TypeManager.int32_type ||
948 t == TypeManager.int64_type){
949 if ((mode & Mode.IsDecrement) != 0)
950 ig.Emit (OpCodes.Sub_Ovf);
952 ig.Emit (OpCodes.Add_Ovf);
953 } else if (t == TypeManager.uint32_type ||
954 t == TypeManager.uint64_type){
955 if ((mode & Mode.IsDecrement) != 0)
956 ig.Emit (OpCodes.Sub_Ovf_Un);
958 ig.Emit (OpCodes.Add_Ovf_Un);
960 if ((mode & Mode.IsDecrement) != 0)
961 ig.Emit (OpCodes.Sub_Ovf);
963 ig.Emit (OpCodes.Add_Ovf);
966 if ((mode & Mode.IsDecrement) != 0)
967 ig.Emit (OpCodes.Sub);
969 ig.Emit (OpCodes.Add);
972 if (t == TypeManager.sbyte_type){
974 ig.Emit (OpCodes.Conv_Ovf_I1);
976 ig.Emit (OpCodes.Conv_I1);
977 } else if (t == TypeManager.byte_type){
979 ig.Emit (OpCodes.Conv_Ovf_U1);
981 ig.Emit (OpCodes.Conv_U1);
982 } else if (t == TypeManager.short_type){
984 ig.Emit (OpCodes.Conv_Ovf_I2);
986 ig.Emit (OpCodes.Conv_I2);
987 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
989 ig.Emit (OpCodes.Conv_Ovf_U2);
991 ig.Emit (OpCodes.Conv_U2);
996 void EmitCode (EmitContext ec, bool is_expr)
999 this.is_expr = is_expr;
1000 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1003 public override void Emit (EmitContext ec)
1006 // We use recurse to allow ourselfs to be the source
1007 // of an assignment. This little hack prevents us from
1008 // having to allocate another expression
1011 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1013 LoadOneAndEmitOp (ec, expr.Type);
1015 ec.ig.Emit (OpCodes.Call, method.Method);
1020 EmitCode (ec, true);
1023 public override void EmitStatement (EmitContext ec)
1025 EmitCode (ec, false);
1030 /// Base class for the `Is' and `As' classes.
1034 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1037 public abstract class Probe : Expression {
1038 public Expression ProbeType;
1039 protected Expression expr;
1040 protected TypeExpr probe_type_expr;
1042 public Probe (Expression expr, Expression probe_type, Location l)
1044 ProbeType = probe_type;
1049 public Expression Expr {
1055 public override Expression DoResolve (EmitContext ec)
1057 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1058 if (probe_type_expr == null)
1061 expr = expr.Resolve (ec);
1065 if (expr.Type.IsPointer) {
1066 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1074 /// Implementation of the `is' operator.
1076 public class Is : Probe {
1077 public Is (Expression expr, Expression probe_type, Location l)
1078 : base (expr, probe_type, l)
1083 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1088 public override void Emit (EmitContext ec)
1090 ILGenerator ig = ec.ig;
1095 case Action.AlwaysFalse:
1096 ig.Emit (OpCodes.Pop);
1097 IntConstant.EmitInt (ig, 0);
1099 case Action.AlwaysTrue:
1100 ig.Emit (OpCodes.Pop);
1101 IntConstant.EmitInt (ig, 1);
1103 case Action.LeaveOnStack:
1104 // the `e != null' rule.
1105 ig.Emit (OpCodes.Ldnull);
1106 ig.Emit (OpCodes.Ceq);
1107 ig.Emit (OpCodes.Ldc_I4_0);
1108 ig.Emit (OpCodes.Ceq);
1111 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1112 ig.Emit (OpCodes.Ldnull);
1113 ig.Emit (OpCodes.Cgt_Un);
1116 throw new Exception ("never reached");
1119 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1121 ILGenerator ig = ec.ig;
1124 case Action.AlwaysFalse:
1126 ig.Emit (OpCodes.Br, target);
1129 case Action.AlwaysTrue:
1131 ig.Emit (OpCodes.Br, target);
1134 case Action.LeaveOnStack:
1135 // the `e != null' rule.
1137 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1141 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1142 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1145 throw new Exception ("never reached");
1148 public override Expression DoResolve (EmitContext ec)
1150 Expression e = base.DoResolve (ec);
1152 if ((e == null) || (expr == null))
1155 Type etype = expr.Type;
1156 type = TypeManager.bool_type;
1157 eclass = ExprClass.Value;
1160 // First case, if at compile time, there is an implicit conversion
1161 // then e != null (objects) or true (value types)
1163 Type probe_type = probe_type_expr.Type;
1164 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1167 if (etype.IsValueType)
1168 action = Action.AlwaysTrue;
1170 action = Action.LeaveOnStack;
1172 Constant c = e as Constant;
1173 if (c != null && c.GetValue () == null) {
1174 action = Action.AlwaysFalse;
1175 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1176 TypeManager.CSharpName (probe_type));
1178 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1179 TypeManager.CSharpName (probe_type));
1184 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1185 if (TypeManager.IsGenericParameter (etype))
1186 expr = new BoxedCast (expr, etype);
1189 // Second case: explicit reference convresion
1191 if (expr is NullLiteral)
1192 action = Action.AlwaysFalse;
1194 action = Action.Probe;
1195 } else if (TypeManager.ContainsGenericParameters (etype) ||
1196 TypeManager.ContainsGenericParameters (probe_type)) {
1197 expr = new BoxedCast (expr, etype);
1198 action = Action.Probe;
1200 action = Action.AlwaysFalse;
1201 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1202 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1210 /// Implementation of the `as' operator.
1212 public class As : Probe {
1213 public As (Expression expr, Expression probe_type, Location l)
1214 : base (expr, probe_type, l)
1218 bool do_isinst = false;
1219 Expression resolved_type;
1221 public override void Emit (EmitContext ec)
1223 ILGenerator ig = ec.ig;
1228 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1231 static void Error_CannotConvertType (Type source, Type target, Location loc)
1233 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1234 TypeManager.CSharpName (source),
1235 TypeManager.CSharpName (target));
1238 public override Expression DoResolve (EmitContext ec)
1240 if (resolved_type == null) {
1241 resolved_type = base.DoResolve (ec);
1243 if (resolved_type == null)
1247 type = probe_type_expr.Type;
1248 eclass = ExprClass.Value;
1249 Type etype = expr.Type;
1251 if (type.IsValueType) {
1252 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1253 TypeManager.CSharpName (type) + "' is a value type)");
1260 // If the type is a type parameter, ensure
1261 // that it is constrained by a class
1263 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1265 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1268 if (constraints == null)
1271 if (!constraints.HasClassConstraint)
1272 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1276 Report.Error (413, loc,
1277 "The as operator requires that the `{0}' type parameter be constrained by a class",
1278 probe_type_expr.GetSignatureForError ());
1284 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1291 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1292 if (TypeManager.IsGenericParameter (etype))
1293 expr = new BoxedCast (expr, etype);
1299 if (TypeManager.ContainsGenericParameters (etype) ||
1300 TypeManager.ContainsGenericParameters (type)) {
1301 expr = new BoxedCast (expr, etype);
1306 Error_CannotConvertType (etype, type, loc);
1310 public override bool GetAttributableValue (Type valueType, out object value)
1312 return expr.GetAttributableValue (valueType, out value);
1317 /// This represents a typecast in the source language.
1319 /// FIXME: Cast expressions have an unusual set of parsing
1320 /// rules, we need to figure those out.
1322 public class Cast : Expression {
1323 Expression target_type;
1326 public Cast (Expression cast_type, Expression expr)
1327 : this (cast_type, expr, cast_type.Location)
1331 public Cast (Expression cast_type, Expression expr, Location loc)
1333 this.target_type = cast_type;
1337 if (target_type == TypeManager.system_void_expr)
1338 Error_VoidInvalidInTheContext (loc);
1341 public Expression TargetType {
1342 get { return target_type; }
1345 public Expression Expr {
1346 get { return expr; }
1347 set { expr = value; }
1350 public override Expression DoResolve (EmitContext ec)
1352 expr = expr.Resolve (ec);
1356 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1362 if (type.IsAbstract && type.IsSealed) {
1363 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1367 eclass = ExprClass.Value;
1369 Constant c = expr as Constant;
1371 c = c.TryReduce (ec, type, loc);
1376 if (type.IsPointer && !ec.InUnsafe) {
1380 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1384 public override void Emit (EmitContext ec)
1386 throw new Exception ("Should not happen");
1391 /// Binary operators
1393 public class Binary : Expression {
1394 public enum Operator : byte {
1395 Multiply, Division, Modulus,
1396 Addition, Subtraction,
1397 LeftShift, RightShift,
1398 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1399 Equality, Inequality,
1409 Expression left, right;
1411 // This must be kept in sync with Operator!!!
1412 public static readonly string [] oper_names;
1416 oper_names = new string [(int) Operator.TOP];
1418 oper_names [(int) Operator.Multiply] = "op_Multiply";
1419 oper_names [(int) Operator.Division] = "op_Division";
1420 oper_names [(int) Operator.Modulus] = "op_Modulus";
1421 oper_names [(int) Operator.Addition] = "op_Addition";
1422 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1423 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1424 oper_names [(int) Operator.RightShift] = "op_RightShift";
1425 oper_names [(int) Operator.LessThan] = "op_LessThan";
1426 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1427 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1428 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1429 oper_names [(int) Operator.Equality] = "op_Equality";
1430 oper_names [(int) Operator.Inequality] = "op_Inequality";
1431 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1432 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1433 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1434 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1435 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1438 public Binary (Operator oper, Expression left, Expression right)
1443 this.loc = left.Location;
1446 public Operator Oper {
1455 public Expression Left {
1464 public Expression Right {
1475 /// Returns a stringified representation of the Operator
1477 public static string OperName (Operator oper)
1480 case Operator.Multiply:
1482 case Operator.Division:
1484 case Operator.Modulus:
1486 case Operator.Addition:
1488 case Operator.Subtraction:
1490 case Operator.LeftShift:
1492 case Operator.RightShift:
1494 case Operator.LessThan:
1496 case Operator.GreaterThan:
1498 case Operator.LessThanOrEqual:
1500 case Operator.GreaterThanOrEqual:
1502 case Operator.Equality:
1504 case Operator.Inequality:
1506 case Operator.BitwiseAnd:
1508 case Operator.BitwiseOr:
1510 case Operator.ExclusiveOr:
1512 case Operator.LogicalOr:
1514 case Operator.LogicalAnd:
1518 return oper.ToString ();
1521 public override string ToString ()
1523 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1524 right.ToString () + ")";
1527 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1529 if (expr.Type == target_type)
1532 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1535 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1538 34, loc, "Operator `" + OperName (oper)
1539 + "' is ambiguous on operands of type `"
1540 + TypeManager.CSharpName (l) + "' "
1541 + "and `" + TypeManager.CSharpName (r)
1545 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1547 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1550 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1552 if (!IsConvertible (ec, left, right, t))
1554 left = ForceConversion (ec, left, t);
1555 right = ForceConversion (ec, right, t);
1560 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1562 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1563 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1565 if (oper == Operator.Equality || oper == Operator.Inequality)
1567 if (oper == Operator.Addition)
1572 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1574 if (!IsApplicable_String (ec, left, right, oper))
1576 Type t = TypeManager.string_type;
1577 if (Convert.ImplicitConversionExists (ec, left, t))
1578 left = ForceConversion (ec, left, t);
1579 if (Convert.ImplicitConversionExists (ec, right, t))
1580 right = ForceConversion (ec, right, t);
1585 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1587 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1588 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1589 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1590 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1594 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1596 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1597 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1601 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1603 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1606 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1608 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1612 void Error_OperatorCannotBeApplied ()
1614 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1615 TypeManager.CSharpName(right.Type));
1618 static bool is_unsigned (Type t)
1620 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1621 t == TypeManager.short_type || t == TypeManager.byte_type);
1624 Expression Make32or64 (EmitContext ec, Expression e)
1628 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1629 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1631 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1634 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1637 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1640 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1646 Expression CheckShiftArguments (EmitContext ec)
1648 Expression new_left = Make32or64 (ec, left);
1649 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1650 if (new_left == null || new_right == null) {
1651 Error_OperatorCannotBeApplied ();
1654 type = new_left.Type;
1655 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1657 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1662 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1663 // i.e., not invoke op_Equality.
1665 static bool EqualsNullIsReferenceEquals (Type t)
1667 return t == TypeManager.object_type || t == TypeManager.string_type ||
1668 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1671 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1673 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1674 "Possible unintended reference comparison; to get a value comparison, " +
1675 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1678 Expression ResolveOperator (EmitContext ec)
1681 Type r = right.Type;
1683 if (oper == Operator.Equality || oper == Operator.Inequality){
1684 if (TypeManager.IsGenericParameter (l) && (right is NullLiteral)) {
1685 if (l.BaseType == TypeManager.value_type) {
1686 Error_OperatorCannotBeApplied ();
1690 left = new BoxedCast (left, TypeManager.object_type);
1691 Type = TypeManager.bool_type;
1695 if (TypeManager.IsGenericParameter (r) && (left is NullLiteral)) {
1696 if (r.BaseType == TypeManager.value_type) {
1697 Error_OperatorCannotBeApplied ();
1701 right = new BoxedCast (right, TypeManager.object_type);
1702 Type = TypeManager.bool_type;
1707 // Optimize out call to op_Equality in a few cases.
1709 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1710 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1711 Type = TypeManager.bool_type;
1716 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1717 Type = TypeManager.bool_type;
1723 // Do not perform operator overload resolution when both sides are
1726 Expression left_operators = null, right_operators = null;
1727 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1729 // Step 1: Perform Operator Overload location
1731 string op = oper_names [(int) oper];
1733 MethodGroupExpr union;
1734 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc);
1736 right_operators = MemberLookup (
1737 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc);
1738 union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
1740 union = (MethodGroupExpr) left_operators;
1742 if (union != null) {
1743 ArrayList args = new ArrayList (2);
1744 args.Add (new Argument (left, Argument.AType.Expression));
1745 args.Add (new Argument (right, Argument.AType.Expression));
1747 MethodBase method = Invocation.OverloadResolve (ec, union, args, true, Location.Null);
1749 if (method != null) {
1750 MethodInfo mi = (MethodInfo) method;
1751 return new BinaryMethod (mi.ReturnType, method, args);
1757 // Step 0: String concatenation (because overloading will get this wrong)
1759 if (oper == Operator.Addition){
1761 // If any of the arguments is a string, cast to string
1764 // Simple constant folding
1765 if (left is StringConstant && right is StringConstant)
1766 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1768 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1770 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1771 Error_OperatorCannotBeApplied ();
1775 // try to fold it in on the left
1776 if (left is StringConcat) {
1779 // We have to test here for not-null, since we can be doubly-resolved
1780 // take care of not appending twice
1783 type = TypeManager.string_type;
1784 ((StringConcat) left).Append (ec, right);
1785 return left.Resolve (ec);
1791 // Otherwise, start a new concat expression
1792 return new StringConcat (ec, loc, left, right).Resolve (ec);
1796 // Transform a + ( - b) into a - b
1798 if (right is Unary){
1799 Unary right_unary = (Unary) right;
1801 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1802 oper = Operator.Subtraction;
1803 right = right_unary.Expr;
1809 if (oper == Operator.Equality || oper == Operator.Inequality){
1810 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1811 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1812 Error_OperatorCannotBeApplied ();
1816 type = TypeManager.bool_type;
1820 if (l.IsPointer || r.IsPointer) {
1821 if (l.IsPointer && r.IsPointer) {
1822 type = TypeManager.bool_type;
1826 if (l.IsPointer && r == TypeManager.null_type) {
1827 right = new EmptyCast (NullPointer.Null, l);
1828 type = TypeManager.bool_type;
1832 if (r.IsPointer && l == TypeManager.null_type) {
1833 left = new EmptyCast (NullPointer.Null, r);
1834 type = TypeManager.bool_type;
1840 if (l.IsGenericParameter && r.IsGenericParameter) {
1841 GenericConstraints l_gc, r_gc;
1843 l_gc = TypeManager.GetTypeParameterConstraints (l);
1844 r_gc = TypeManager.GetTypeParameterConstraints (r);
1846 if ((l_gc == null) || (r_gc == null) ||
1847 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1848 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1849 Error_OperatorCannotBeApplied ();
1857 // operator != (object a, object b)
1858 // operator == (object a, object b)
1860 // For this to be used, both arguments have to be reference-types.
1861 // Read the rationale on the spec (14.9.6)
1863 if (!(l.IsValueType || r.IsValueType)){
1864 type = TypeManager.bool_type;
1870 // Also, a standard conversion must exist from either one
1872 bool left_to_right =
1873 Convert.ImplicitStandardConversionExists (left, r);
1874 bool right_to_left = !left_to_right &&
1875 Convert.ImplicitStandardConversionExists (right, l);
1877 if (!left_to_right && !right_to_left) {
1878 Error_OperatorCannotBeApplied ();
1882 if (left_to_right && left_operators != null &&
1883 RootContext.WarningLevel >= 2) {
1884 ArrayList args = new ArrayList (2);
1885 args.Add (new Argument (left, Argument.AType.Expression));
1886 args.Add (new Argument (left, Argument.AType.Expression));
1887 MethodBase method = Invocation.OverloadResolve (
1888 ec, (MethodGroupExpr) left_operators, args, true, Location.Null);
1890 Warning_UnintendedReferenceComparison (loc, "right", l);
1893 if (right_to_left && right_operators != null &&
1894 RootContext.WarningLevel >= 2) {
1895 ArrayList args = new ArrayList (2);
1896 args.Add (new Argument (right, Argument.AType.Expression));
1897 args.Add (new Argument (right, Argument.AType.Expression));
1898 MethodBase method = Invocation.OverloadResolve (
1899 ec, (MethodGroupExpr) right_operators, args, true, Location.Null);
1901 Warning_UnintendedReferenceComparison (loc, "left", r);
1905 // We are going to have to convert to an object to compare
1907 if (l != TypeManager.object_type)
1908 left = new EmptyCast (left, TypeManager.object_type);
1909 if (r != TypeManager.object_type)
1910 right = new EmptyCast (right, TypeManager.object_type);
1916 // Only perform numeric promotions on:
1917 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1919 if (oper == Operator.Addition || oper == Operator.Subtraction) {
1920 if (TypeManager.IsDelegateType (l)){
1921 if (((right.eclass == ExprClass.MethodGroup) ||
1922 (r == TypeManager.anonymous_method_type))){
1923 if ((RootContext.Version != LanguageVersion.ISO_1)){
1924 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
1932 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
1934 ArrayList args = new ArrayList (2);
1936 args = new ArrayList (2);
1937 args.Add (new Argument (left, Argument.AType.Expression));
1938 args.Add (new Argument (right, Argument.AType.Expression));
1940 if (oper == Operator.Addition)
1941 method = TypeManager.delegate_combine_delegate_delegate;
1943 method = TypeManager.delegate_remove_delegate_delegate;
1945 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
1946 Error_OperatorCannotBeApplied ();
1950 return new BinaryDelegate (l, method, args);
1955 // Pointer arithmetic:
1957 // T* operator + (T* x, int y);
1958 // T* operator + (T* x, uint y);
1959 // T* operator + (T* x, long y);
1960 // T* operator + (T* x, ulong y);
1962 // T* operator + (int y, T* x);
1963 // T* operator + (uint y, T *x);
1964 // T* operator + (long y, T *x);
1965 // T* operator + (ulong y, T *x);
1967 // T* operator - (T* x, int y);
1968 // T* operator - (T* x, uint y);
1969 // T* operator - (T* x, long y);
1970 // T* operator - (T* x, ulong y);
1972 // long operator - (T* x, T *y)
1975 if (r.IsPointer && oper == Operator.Subtraction){
1977 return new PointerArithmetic (
1978 false, left, right, TypeManager.int64_type,
1981 Expression t = Make32or64 (ec, right);
1983 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
1985 } else if (r.IsPointer && oper == Operator.Addition){
1986 Expression t = Make32or64 (ec, left);
1988 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
1993 // Enumeration operators
1995 bool lie = TypeManager.IsEnumType (l);
1996 bool rie = TypeManager.IsEnumType (r);
2000 // U operator - (E e, E f)
2002 if (oper == Operator.Subtraction){
2004 type = TypeManager.EnumToUnderlying (l);
2007 Error_OperatorCannotBeApplied ();
2013 // operator + (E e, U x)
2014 // operator - (E e, U x)
2016 if (oper == Operator.Addition || oper == Operator.Subtraction){
2017 Type enum_type = lie ? l : r;
2018 Type other_type = lie ? r : l;
2019 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2021 if (underlying_type != other_type){
2022 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2032 Error_OperatorCannotBeApplied ();
2041 temp = Convert.ImplicitConversion (ec, right, l, loc);
2045 Error_OperatorCannotBeApplied ();
2049 temp = Convert.ImplicitConversion (ec, left, r, loc);
2054 Error_OperatorCannotBeApplied ();
2059 if (oper == Operator.Equality || oper == Operator.Inequality ||
2060 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2061 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2062 if (left.Type != right.Type){
2063 Error_OperatorCannotBeApplied ();
2066 type = TypeManager.bool_type;
2070 if (oper == Operator.BitwiseAnd ||
2071 oper == Operator.BitwiseOr ||
2072 oper == Operator.ExclusiveOr){
2073 if (left.Type != right.Type){
2074 Error_OperatorCannotBeApplied ();
2080 Error_OperatorCannotBeApplied ();
2084 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2085 return CheckShiftArguments (ec);
2087 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2088 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2089 type = TypeManager.bool_type;
2093 left_operators = l == TypeManager.bool_type ?
2094 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2095 right_operators = r == TypeManager.bool_type ?
2096 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2098 if (left_operators != null && right_operators != null) {
2099 left = left_operators;
2100 right = right_operators;
2101 type = TypeManager.bool_type;
2105 Expression e = new ConditionalLogicalOperator (
2106 oper == Operator.LogicalAnd, left, right, l, loc);
2107 return e.Resolve (ec);
2110 Expression orig_left = left;
2111 Expression orig_right = right;
2114 // operator & (bool x, bool y)
2115 // operator | (bool x, bool y)
2116 // operator ^ (bool x, bool y)
2118 if (oper == Operator.BitwiseAnd ||
2119 oper == Operator.BitwiseOr ||
2120 oper == Operator.ExclusiveOr) {
2121 if (OverloadResolve_PredefinedIntegral (ec)) {
2122 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2123 Error_OperatorAmbiguous (loc, oper, l, r);
2127 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2128 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2129 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2130 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2131 TypeManager.CSharpName (r));
2134 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2135 Error_OperatorCannotBeApplied ();
2142 // Pointer comparison
2144 if (l.IsPointer && r.IsPointer){
2145 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2146 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2147 type = TypeManager.bool_type;
2152 if (OverloadResolve_PredefinedIntegral (ec)) {
2153 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2154 Error_OperatorAmbiguous (loc, oper, l, r);
2157 } else if (OverloadResolve_PredefinedFloating (ec)) {
2158 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2159 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2160 Error_OperatorAmbiguous (loc, oper, l, r);
2163 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2164 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2165 Error_OperatorAmbiguous (loc, oper, l, r);
2168 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2169 Error_OperatorCannotBeApplied ();
2173 if (oper == Operator.Equality ||
2174 oper == Operator.Inequality ||
2175 oper == Operator.LessThanOrEqual ||
2176 oper == Operator.LessThan ||
2177 oper == Operator.GreaterThanOrEqual ||
2178 oper == Operator.GreaterThan)
2179 type = TypeManager.bool_type;
2184 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2186 if (r == TypeManager.string_type)
2188 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2189 ec.ContainerType, lookup, oper_names [(int) oper],
2190 MemberTypes.Method, AllBindingFlags, loc);
2191 ArrayList args = new ArrayList (2);
2192 args.Add (new Argument (left, Argument.AType.Expression));
2193 args.Add (new Argument (right, Argument.AType.Expression));
2194 MethodBase method = Invocation.OverloadResolve (ec, ops, args, true, Location.Null);
2195 return new BinaryMethod (type, method, args);
2201 Constant EnumLiftUp (Constant left, Constant right)
2204 case Operator.BitwiseOr:
2205 case Operator.BitwiseAnd:
2206 case Operator.ExclusiveOr:
2207 case Operator.Equality:
2208 case Operator.Inequality:
2209 case Operator.LessThan:
2210 case Operator.LessThanOrEqual:
2211 case Operator.GreaterThan:
2212 case Operator.GreaterThanOrEqual:
2213 if (left is EnumConstant)
2216 if (left.IsZeroInteger)
2217 return new EnumConstant (left, right.Type);
2221 case Operator.Addition:
2222 case Operator.Subtraction:
2225 case Operator.Multiply:
2226 case Operator.Division:
2227 case Operator.Modulus:
2228 case Operator.LeftShift:
2229 case Operator.RightShift:
2230 if (right is EnumConstant || left is EnumConstant)
2234 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2238 public override Expression DoResolve (EmitContext ec)
2243 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2244 left = ((ParenthesizedExpression) left).Expr;
2245 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2249 if (left.eclass == ExprClass.Type) {
2250 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2254 left = left.Resolve (ec);
2259 Constant lc = left as Constant;
2260 if (lc != null && lc.Type == TypeManager.bool_type &&
2261 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2262 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2264 // TODO: make a sense to resolve unreachable expression as we do for statement
2265 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2269 right = right.Resolve (ec);
2273 eclass = ExprClass.Value;
2274 Constant rc = right as Constant;
2276 // The conversion rules are ignored in enum context but why
2277 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2278 left = lc = EnumLiftUp (lc, rc);
2282 right = rc = EnumLiftUp (rc, lc);
2287 if (oper == Operator.BitwiseAnd) {
2288 if (rc != null && rc.IsZeroInteger) {
2289 return lc is EnumConstant ?
2290 new EnumConstant (rc, lc.Type):
2294 if (lc != null && lc.IsZeroInteger) {
2295 return rc is EnumConstant ?
2296 new EnumConstant (lc, rc.Type):
2300 else if (oper == Operator.BitwiseOr) {
2301 if (lc is EnumConstant &&
2302 rc != null && rc.IsZeroInteger)
2304 if (rc is EnumConstant &&
2305 lc != null && lc.IsZeroInteger)
2307 } else if (oper == Operator.LogicalAnd) {
2308 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2310 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2314 if (rc != null && lc != null){
2315 int prev_e = Report.Errors;
2316 Expression e = ConstantFold.BinaryFold (
2317 ec, oper, lc, rc, loc);
2318 if (e != null || Report.Errors != prev_e)
2323 if ((left is NullLiteral || left.Type.IsValueType) &&
2324 (right is NullLiteral || right.Type.IsValueType) &&
2325 !(left is NullLiteral && right is NullLiteral) &&
2326 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2327 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2330 // Comparison warnings
2331 if (oper == Operator.Equality || oper == Operator.Inequality ||
2332 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2333 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2334 if (left.Equals (right)) {
2335 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2337 CheckUselessComparison (lc, right.Type);
2338 CheckUselessComparison (rc, left.Type);
2341 return ResolveOperator (ec);
2344 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2349 private void CheckUselessComparison (Constant c, Type type)
2351 if (c == null || !IsTypeIntegral (type)
2352 || c is StringConstant
2353 || c is BoolConstant
2354 || c is FloatConstant
2355 || c is DoubleConstant
2356 || c is DecimalConstant
2362 if (c is ULongConstant) {
2363 ulong uvalue = ((ULongConstant) c).Value;
2364 if (uvalue > long.MaxValue) {
2365 if (type == TypeManager.byte_type ||
2366 type == TypeManager.sbyte_type ||
2367 type == TypeManager.short_type ||
2368 type == TypeManager.ushort_type ||
2369 type == TypeManager.int32_type ||
2370 type == TypeManager.uint32_type ||
2371 type == TypeManager.int64_type ||
2372 type == TypeManager.char_type)
2373 WarnUselessComparison (type);
2376 value = (long) uvalue;
2378 else if (c is ByteConstant)
2379 value = ((ByteConstant) c).Value;
2380 else if (c is SByteConstant)
2381 value = ((SByteConstant) c).Value;
2382 else if (c is ShortConstant)
2383 value = ((ShortConstant) c).Value;
2384 else if (c is UShortConstant)
2385 value = ((UShortConstant) c).Value;
2386 else if (c is IntConstant)
2387 value = ((IntConstant) c).Value;
2388 else if (c is UIntConstant)
2389 value = ((UIntConstant) c).Value;
2390 else if (c is LongConstant)
2391 value = ((LongConstant) c).Value;
2392 else if (c is CharConstant)
2393 value = ((CharConstant)c).Value;
2398 if (IsValueOutOfRange (value, type))
2399 WarnUselessComparison (type);
2402 private bool IsValueOutOfRange (long value, Type type)
2404 if (IsTypeUnsigned (type) && value < 0)
2406 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2407 type == TypeManager.byte_type && value >= 0x100 ||
2408 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2409 type == TypeManager.ushort_type && value >= 0x10000 ||
2410 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2411 type == TypeManager.uint32_type && value >= 0x100000000;
2414 private static bool IsTypeIntegral (Type type)
2416 return type == TypeManager.uint64_type ||
2417 type == TypeManager.int64_type ||
2418 type == TypeManager.uint32_type ||
2419 type == TypeManager.int32_type ||
2420 type == TypeManager.ushort_type ||
2421 type == TypeManager.short_type ||
2422 type == TypeManager.sbyte_type ||
2423 type == TypeManager.byte_type ||
2424 type == TypeManager.char_type;
2427 private static bool IsTypeUnsigned (Type type)
2429 return type == TypeManager.uint64_type ||
2430 type == TypeManager.uint32_type ||
2431 type == TypeManager.ushort_type ||
2432 type == TypeManager.byte_type ||
2433 type == TypeManager.char_type;
2436 private void WarnUselessComparison (Type type)
2438 Report.Warning (652, 2, loc, "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
2439 TypeManager.CSharpName (type));
2443 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2444 /// context of a conditional bool expression. This function will return
2445 /// false if it is was possible to use EmitBranchable, or true if it was.
2447 /// The expression's code is generated, and we will generate a branch to `target'
2448 /// if the resulting expression value is equal to isTrue
2450 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2452 ILGenerator ig = ec.ig;
2455 // This is more complicated than it looks, but its just to avoid
2456 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2457 // but on top of that we want for == and != to use a special path
2458 // if we are comparing against null
2460 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2461 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2464 // put the constant on the rhs, for simplicity
2466 if (left is Constant) {
2467 Expression swap = right;
2472 if (((Constant) right).IsZeroInteger) {
2475 ig.Emit (OpCodes.Brtrue, target);
2477 ig.Emit (OpCodes.Brfalse, target);
2480 } else if (right is BoolConstant) {
2482 if (my_on_true != ((BoolConstant) right).Value)
2483 ig.Emit (OpCodes.Brtrue, target);
2485 ig.Emit (OpCodes.Brfalse, target);
2490 } else if (oper == Operator.LogicalAnd) {
2493 Label tests_end = ig.DefineLabel ();
2495 left.EmitBranchable (ec, tests_end, false);
2496 right.EmitBranchable (ec, target, true);
2497 ig.MarkLabel (tests_end);
2500 // This optimizes code like this
2501 // if (true && i > 4)
2503 if (!(left is Constant))
2504 left.EmitBranchable (ec, target, false);
2506 if (!(right is Constant))
2507 right.EmitBranchable (ec, target, false);
2512 } else if (oper == Operator.LogicalOr){
2514 left.EmitBranchable (ec, target, true);
2515 right.EmitBranchable (ec, target, true);
2518 Label tests_end = ig.DefineLabel ();
2519 left.EmitBranchable (ec, tests_end, true);
2520 right.EmitBranchable (ec, target, false);
2521 ig.MarkLabel (tests_end);
2526 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2527 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2528 oper == Operator.Equality || oper == Operator.Inequality)) {
2529 base.EmitBranchable (ec, target, onTrue);
2537 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2540 case Operator.Equality:
2542 ig.Emit (OpCodes.Beq, target);
2544 ig.Emit (OpCodes.Bne_Un, target);
2547 case Operator.Inequality:
2549 ig.Emit (OpCodes.Bne_Un, target);
2551 ig.Emit (OpCodes.Beq, target);
2554 case Operator.LessThan:
2557 ig.Emit (OpCodes.Blt_Un, target);
2559 ig.Emit (OpCodes.Blt, target);
2562 ig.Emit (OpCodes.Bge_Un, target);
2564 ig.Emit (OpCodes.Bge, target);
2567 case Operator.GreaterThan:
2570 ig.Emit (OpCodes.Bgt_Un, target);
2572 ig.Emit (OpCodes.Bgt, target);
2575 ig.Emit (OpCodes.Ble_Un, target);
2577 ig.Emit (OpCodes.Ble, target);
2580 case Operator.LessThanOrEqual:
2583 ig.Emit (OpCodes.Ble_Un, target);
2585 ig.Emit (OpCodes.Ble, target);
2588 ig.Emit (OpCodes.Bgt_Un, target);
2590 ig.Emit (OpCodes.Bgt, target);
2594 case Operator.GreaterThanOrEqual:
2597 ig.Emit (OpCodes.Bge_Un, target);
2599 ig.Emit (OpCodes.Bge, target);
2602 ig.Emit (OpCodes.Blt_Un, target);
2604 ig.Emit (OpCodes.Blt, target);
2607 Console.WriteLine (oper);
2608 throw new Exception ("what is THAT");
2612 public override void Emit (EmitContext ec)
2614 ILGenerator ig = ec.ig;
2619 // Handle short-circuit operators differently
2622 if (oper == Operator.LogicalAnd) {
2623 Label load_zero = ig.DefineLabel ();
2624 Label end = ig.DefineLabel ();
2626 left.EmitBranchable (ec, load_zero, false);
2628 ig.Emit (OpCodes.Br, end);
2630 ig.MarkLabel (load_zero);
2631 ig.Emit (OpCodes.Ldc_I4_0);
2634 } else if (oper == Operator.LogicalOr) {
2635 Label load_one = ig.DefineLabel ();
2636 Label end = ig.DefineLabel ();
2638 left.EmitBranchable (ec, load_one, true);
2640 ig.Emit (OpCodes.Br, end);
2642 ig.MarkLabel (load_one);
2643 ig.Emit (OpCodes.Ldc_I4_1);
2651 bool isUnsigned = is_unsigned (left.Type);
2654 case Operator.Multiply:
2656 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2657 opcode = OpCodes.Mul_Ovf;
2658 else if (isUnsigned)
2659 opcode = OpCodes.Mul_Ovf_Un;
2661 opcode = OpCodes.Mul;
2663 opcode = OpCodes.Mul;
2667 case Operator.Division:
2669 opcode = OpCodes.Div_Un;
2671 opcode = OpCodes.Div;
2674 case Operator.Modulus:
2676 opcode = OpCodes.Rem_Un;
2678 opcode = OpCodes.Rem;
2681 case Operator.Addition:
2683 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2684 opcode = OpCodes.Add_Ovf;
2685 else if (isUnsigned)
2686 opcode = OpCodes.Add_Ovf_Un;
2688 opcode = OpCodes.Add;
2690 opcode = OpCodes.Add;
2693 case Operator.Subtraction:
2695 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2696 opcode = OpCodes.Sub_Ovf;
2697 else if (isUnsigned)
2698 opcode = OpCodes.Sub_Ovf_Un;
2700 opcode = OpCodes.Sub;
2702 opcode = OpCodes.Sub;
2705 case Operator.RightShift:
2707 opcode = OpCodes.Shr_Un;
2709 opcode = OpCodes.Shr;
2712 case Operator.LeftShift:
2713 opcode = OpCodes.Shl;
2716 case Operator.Equality:
2717 opcode = OpCodes.Ceq;
2720 case Operator.Inequality:
2721 ig.Emit (OpCodes.Ceq);
2722 ig.Emit (OpCodes.Ldc_I4_0);
2724 opcode = OpCodes.Ceq;
2727 case Operator.LessThan:
2729 opcode = OpCodes.Clt_Un;
2731 opcode = OpCodes.Clt;
2734 case Operator.GreaterThan:
2736 opcode = OpCodes.Cgt_Un;
2738 opcode = OpCodes.Cgt;
2741 case Operator.LessThanOrEqual:
2742 Type lt = left.Type;
2744 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2745 ig.Emit (OpCodes.Cgt_Un);
2747 ig.Emit (OpCodes.Cgt);
2748 ig.Emit (OpCodes.Ldc_I4_0);
2750 opcode = OpCodes.Ceq;
2753 case Operator.GreaterThanOrEqual:
2754 Type le = left.Type;
2756 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2757 ig.Emit (OpCodes.Clt_Un);
2759 ig.Emit (OpCodes.Clt);
2761 ig.Emit (OpCodes.Ldc_I4_0);
2763 opcode = OpCodes.Ceq;
2766 case Operator.BitwiseOr:
2767 opcode = OpCodes.Or;
2770 case Operator.BitwiseAnd:
2771 opcode = OpCodes.And;
2774 case Operator.ExclusiveOr:
2775 opcode = OpCodes.Xor;
2779 throw new Exception ("This should not happen: Operator = "
2780 + oper.ToString ());
2788 // Object created by Binary when the binary operator uses an method instead of being
2789 // a binary operation that maps to a CIL binary operation.
2791 public class BinaryMethod : Expression {
2792 public MethodBase method;
2793 public ArrayList Arguments;
2795 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2800 eclass = ExprClass.Value;
2803 public override Expression DoResolve (EmitContext ec)
2808 public override void Emit (EmitContext ec)
2810 ILGenerator ig = ec.ig;
2812 if (Arguments != null)
2813 Invocation.EmitArguments (ec, method, Arguments, false, null);
2815 if (method is MethodInfo)
2816 ig.Emit (OpCodes.Call, (MethodInfo) method);
2818 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2823 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2824 // b, c, d... may be strings or objects.
2826 public class StringConcat : Expression {
2828 bool invalid = false;
2829 bool emit_conv_done = false;
2831 // Are we also concating objects?
2833 bool is_strings_only = true;
2835 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2838 type = TypeManager.string_type;
2839 eclass = ExprClass.Value;
2841 operands = new ArrayList (2);
2846 public override Expression DoResolve (EmitContext ec)
2854 public void Append (EmitContext ec, Expression operand)
2859 StringConstant sc = operand as StringConstant;
2861 // TODO: it will be better to do this silently as an optimalization
2863 // string s = "" + i;
2864 // because this code has poor performace
2865 // if (sc.Value.Length == 0)
2866 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2868 if (operands.Count != 0) {
2869 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2870 if (last_operand != null) {
2871 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2878 // Conversion to object
2880 if (operand.Type != TypeManager.string_type) {
2881 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2884 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2890 operands.Add (operand);
2893 public override void Emit (EmitContext ec)
2895 MethodInfo concat_method = null;
2898 // Do conversion to arguments; check for strings only
2901 // This can get called multiple times, so we have to deal with that.
2902 if (!emit_conv_done) {
2903 emit_conv_done = true;
2904 for (int i = 0; i < operands.Count; i ++) {
2905 Expression e = (Expression) operands [i];
2906 is_strings_only &= e.Type == TypeManager.string_type;
2909 for (int i = 0; i < operands.Count; i ++) {
2910 Expression e = (Expression) operands [i];
2912 if (! is_strings_only && e.Type == TypeManager.string_type) {
2913 // need to make sure this is an object, because the EmitParams
2914 // method might look at the type of this expression, see it is a
2915 // string and emit a string [] when we want an object [];
2917 e = new EmptyCast (e, TypeManager.object_type);
2919 operands [i] = new Argument (e, Argument.AType.Expression);
2924 // Find the right method
2926 switch (operands.Count) {
2929 // This should not be possible, because simple constant folding
2930 // is taken care of in the Binary code.
2932 throw new Exception ("how did you get here?");
2935 concat_method = is_strings_only ?
2936 TypeManager.string_concat_string_string :
2937 TypeManager.string_concat_object_object ;
2940 concat_method = is_strings_only ?
2941 TypeManager.string_concat_string_string_string :
2942 TypeManager.string_concat_object_object_object ;
2946 // There is not a 4 param overlaod for object (the one that there is
2947 // is actually a varargs methods, and is only in corlib because it was
2948 // introduced there before.).
2950 if (!is_strings_only)
2953 concat_method = TypeManager.string_concat_string_string_string_string;
2956 concat_method = is_strings_only ?
2957 TypeManager.string_concat_string_dot_dot_dot :
2958 TypeManager.string_concat_object_dot_dot_dot ;
2962 Invocation.EmitArguments (ec, concat_method, operands, false, null);
2963 ec.ig.Emit (OpCodes.Call, concat_method);
2968 // Object created with +/= on delegates
2970 public class BinaryDelegate : Expression {
2974 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
2979 eclass = ExprClass.Value;
2982 public override Expression DoResolve (EmitContext ec)
2987 public override void Emit (EmitContext ec)
2989 ILGenerator ig = ec.ig;
2991 Invocation.EmitArguments (ec, method, args, false, null);
2993 ig.Emit (OpCodes.Call, (MethodInfo) method);
2994 ig.Emit (OpCodes.Castclass, type);
2997 public Expression Right {
2999 Argument arg = (Argument) args [1];
3004 public bool IsAddition {
3006 return method == TypeManager.delegate_combine_delegate_delegate;
3012 // User-defined conditional logical operator
3013 public class ConditionalLogicalOperator : Expression {
3014 Expression left, right;
3017 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3020 eclass = ExprClass.Value;
3024 this.is_and = is_and;
3027 protected void Error19 ()
3029 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3032 protected void Error218 ()
3034 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3035 "declarations of operator true and operator false");
3038 Expression op_true, op_false, op;
3039 LocalTemporary left_temp;
3041 public override Expression DoResolve (EmitContext ec)
3044 Expression operator_group;
3046 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3047 if (operator_group == null) {
3052 left_temp = new LocalTemporary (type);
3054 ArrayList arguments = new ArrayList (2);
3055 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3056 arguments.Add (new Argument (right, Argument.AType.Expression));
3057 method = Invocation.OverloadResolve (
3058 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3060 if (method == null) {
3065 if (method.ReturnType != type) {
3066 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3067 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3071 op = new StaticCallExpr (method, arguments, loc);
3073 op_true = GetOperatorTrue (ec, left_temp, loc);
3074 op_false = GetOperatorFalse (ec, left_temp, loc);
3075 if ((op_true == null) || (op_false == null)) {
3083 public override void Emit (EmitContext ec)
3085 ILGenerator ig = ec.ig;
3086 Label false_target = ig.DefineLabel ();
3087 Label end_target = ig.DefineLabel ();
3090 left_temp.Store (ec);
3092 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3093 left_temp.Emit (ec);
3094 ig.Emit (OpCodes.Br, end_target);
3095 ig.MarkLabel (false_target);
3097 ig.MarkLabel (end_target);
3099 // We release 'left_temp' here since 'op' may refer to it too
3100 left_temp.Release (ec);
3104 public class PointerArithmetic : Expression {
3105 Expression left, right;
3109 // We assume that `l' is always a pointer
3111 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3117 is_add = is_addition;
3120 public override Expression DoResolve (EmitContext ec)
3122 eclass = ExprClass.Variable;
3124 if (left.Type == TypeManager.void_ptr_type) {
3125 Error (242, "The operation in question is undefined on void pointers");
3132 public override void Emit (EmitContext ec)
3134 Type op_type = left.Type;
3135 ILGenerator ig = ec.ig;
3137 // It must be either array or fixed buffer
3138 Type element = TypeManager.HasElementType (op_type) ?
3139 element = TypeManager.GetElementType (op_type) :
3140 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3142 int size = GetTypeSize (element);
3143 Type rtype = right.Type;
3145 if (rtype.IsPointer){
3147 // handle (pointer - pointer)
3151 ig.Emit (OpCodes.Sub);
3155 ig.Emit (OpCodes.Sizeof, element);
3157 IntLiteral.EmitInt (ig, size);
3158 ig.Emit (OpCodes.Div);
3160 ig.Emit (OpCodes.Conv_I8);
3163 // handle + and - on (pointer op int)
3166 ig.Emit (OpCodes.Conv_I);
3168 Constant right_const = right as Constant;
3169 if (right_const != null && size != 0) {
3170 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3178 ig.Emit (OpCodes.Sizeof, element);
3180 IntLiteral.EmitInt (ig, size);
3181 if (rtype == TypeManager.int64_type)
3182 ig.Emit (OpCodes.Conv_I8);
3183 else if (rtype == TypeManager.uint64_type)
3184 ig.Emit (OpCodes.Conv_U8);
3185 ig.Emit (OpCodes.Mul);
3189 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3190 ig.Emit (OpCodes.Conv_I);
3193 ig.Emit (OpCodes.Add);
3195 ig.Emit (OpCodes.Sub);
3201 /// Implements the ternary conditional operator (?:)
3203 public class Conditional : Expression {
3204 Expression expr, trueExpr, falseExpr;
3206 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3209 this.trueExpr = trueExpr;
3210 this.falseExpr = falseExpr;
3211 this.loc = expr.Location;
3214 public Expression Expr {
3220 public Expression TrueExpr {
3226 public Expression FalseExpr {
3232 public override Expression DoResolve (EmitContext ec)
3234 expr = expr.Resolve (ec);
3240 if (TypeManager.IsNullableValueType (expr.Type))
3241 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3244 if (expr.Type != TypeManager.bool_type){
3245 expr = Expression.ResolveBoolean (
3252 Assign ass = expr as Assign;
3253 if (ass != null && ass.Source is Constant) {
3254 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3257 trueExpr = trueExpr.Resolve (ec);
3258 falseExpr = falseExpr.Resolve (ec);
3260 if (trueExpr == null || falseExpr == null)
3263 eclass = ExprClass.Value;
3264 if (trueExpr.Type == falseExpr.Type) {
3265 type = trueExpr.Type;
3266 if (type == TypeManager.null_type) {
3267 // TODO: probably will have to implement ConditionalConstant
3268 // to call method without return constant as well
3269 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3274 Type true_type = trueExpr.Type;
3275 Type false_type = falseExpr.Type;
3278 // First, if an implicit conversion exists from trueExpr
3279 // to falseExpr, then the result type is of type falseExpr.Type
3281 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3284 // Check if both can convert implicitl to each other's type
3286 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3288 "Can not compute type of conditional expression " +
3289 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3290 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3291 "' convert implicitly to each other");
3296 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3300 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3301 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3306 // Dead code optimalization
3307 if (expr is BoolConstant){
3308 BoolConstant bc = (BoolConstant) expr;
3310 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3311 return bc.Value ? trueExpr : falseExpr;
3317 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3322 public override void Emit (EmitContext ec)
3324 ILGenerator ig = ec.ig;
3325 Label false_target = ig.DefineLabel ();
3326 Label end_target = ig.DefineLabel ();
3328 expr.EmitBranchable (ec, false_target, false);
3330 ig.Emit (OpCodes.Br, end_target);
3331 ig.MarkLabel (false_target);
3332 falseExpr.Emit (ec);
3333 ig.MarkLabel (end_target);
3338 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3340 LocalTemporary temp;
3342 public abstract Variable Variable {
3346 public abstract bool IsRef {
3350 public override void Emit (EmitContext ec)
3356 // This method is used by parameters that are references, that are
3357 // being passed as references: we only want to pass the pointer (that
3358 // is already stored in the parameter, not the address of the pointer,
3359 // and not the value of the variable).
3361 public void EmitLoad (EmitContext ec)
3363 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3365 Variable.EmitInstance (ec);
3369 public void Emit (EmitContext ec, bool leave_copy)
3371 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3377 ec.ig.Emit (OpCodes.Dup);
3380 // If we are a reference, we loaded on the stack a pointer
3381 // Now lets load the real value
3383 LoadFromPtr (ec.ig, type);
3387 ec.ig.Emit (OpCodes.Dup);
3389 if (IsRef || Variable.NeedsTemporary) {
3390 temp = new LocalTemporary (Type);
3396 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3397 bool prepare_for_load)
3399 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3402 ILGenerator ig = ec.ig;
3403 prepared = prepare_for_load;
3405 Variable.EmitInstance (ec);
3406 if (prepare_for_load && Variable.HasInstance)
3407 ig.Emit (OpCodes.Dup);
3408 else if (IsRef && !prepared)
3414 ig.Emit (OpCodes.Dup);
3415 if (IsRef || Variable.NeedsTemporary) {
3416 temp = new LocalTemporary (Type);
3422 StoreFromPtr (ig, type);
3424 Variable.EmitAssign (ec);
3432 public void AddressOf (EmitContext ec, AddressOp mode)
3434 Variable.EmitInstance (ec);
3435 Variable.EmitAddressOf (ec);
3442 public class LocalVariableReference : VariableReference, IVariable {
3443 public readonly string Name;
3444 public readonly Block Block;
3445 public LocalInfo local_info;
3449 public LocalVariableReference (Block block, string name, Location l)
3454 eclass = ExprClass.Variable;
3458 // Setting `is_readonly' to false will allow you to create a writable
3459 // reference to a read-only variable. This is used by foreach and using.
3461 public LocalVariableReference (Block block, string name, Location l,
3462 LocalInfo local_info, bool is_readonly)
3463 : this (block, name, l)
3465 this.local_info = local_info;
3466 this.is_readonly = is_readonly;
3469 public VariableInfo VariableInfo {
3470 get { return local_info.VariableInfo; }
3473 public override bool IsRef {
3474 get { return false; }
3477 public bool IsReadOnly {
3478 get { return is_readonly; }
3481 public bool VerifyAssigned (EmitContext ec)
3483 VariableInfo variable_info = local_info.VariableInfo;
3484 return variable_info == null || variable_info.IsAssigned (ec, loc);
3487 void ResolveLocalInfo ()
3489 if (local_info == null) {
3490 local_info = Block.GetLocalInfo (Name);
3491 is_readonly = local_info.ReadOnly;
3495 protected Expression DoResolveBase (EmitContext ec)
3497 type = local_info.VariableType;
3499 Expression e = Block.GetConstantExpression (Name);
3501 return e.Resolve (ec);
3503 if (!VerifyAssigned (ec))
3507 // If we are referencing a variable from the external block
3508 // flag it for capturing
3510 if (ec.MustCaptureVariable (local_info)) {
3511 if (local_info.AddressTaken){
3512 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3516 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3517 variable = scope.AddLocal (local_info);
3518 type = variable.Type;
3524 public override Expression DoResolve (EmitContext ec)
3526 ResolveLocalInfo ();
3527 local_info.Used = true;
3528 return DoResolveBase (ec);
3531 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3533 ResolveLocalInfo ();
3538 if (right_side == EmptyExpression.OutAccess) {
3539 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3540 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3541 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3542 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3543 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3545 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3547 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3552 if (right_side == EmptyExpression.OutAccess)
3553 local_info.Used = true;
3555 if (VariableInfo != null)
3556 VariableInfo.SetAssigned (ec);
3558 return DoResolveBase (ec);
3561 public bool VerifyFixed ()
3563 // A local Variable is always fixed.
3567 public override int GetHashCode ()
3569 return Name.GetHashCode ();
3572 public override bool Equals (object obj)
3574 LocalVariableReference lvr = obj as LocalVariableReference;
3578 return Name == lvr.Name && Block == lvr.Block;
3581 public override Variable Variable {
3582 get { return variable != null ? variable : local_info.Variable; }
3585 public override string ToString ()
3587 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3592 /// This represents a reference to a parameter in the intermediate
3595 public class ParameterReference : VariableReference, IVariable {
3601 public bool is_ref, is_out;
3609 public override bool IsRef {
3615 public string Name {
3621 public Parameter Parameter {
3629 public ParameterReference (Parameter par, Block block, int idx, Location loc)
3632 this.name = par.Name;
3636 eclass = ExprClass.Variable;
3639 public VariableInfo VariableInfo {
3643 public override Variable Variable {
3644 get { return variable != null ? variable : par.Variable; }
3647 public bool VerifyFixed ()
3649 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3650 return par.ModFlags == Parameter.Modifier.NONE;
3653 public bool IsAssigned (EmitContext ec, Location loc)
3655 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3658 Report.Error (269, loc,
3659 "Use of unassigned out parameter `{0}'", par.Name);
3663 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3665 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3668 Report.Error (170, loc,
3669 "Use of possibly unassigned field `" + field_name + "'");
3673 public void SetAssigned (EmitContext ec)
3675 if (is_out && ec.DoFlowAnalysis)
3676 ec.CurrentBranching.SetAssigned (vi);
3679 public void SetFieldAssigned (EmitContext ec, string field_name)
3681 if (is_out && ec.DoFlowAnalysis)
3682 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3685 protected bool DoResolveBase (EmitContext ec)
3687 if (!par.Resolve (ec)) {
3691 type = par.ParameterType;
3692 Parameter.Modifier mod = par.ModFlags;
3693 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3694 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3695 eclass = ExprClass.Variable;
3698 vi = block.ParameterMap [idx];
3700 AnonymousContainer am = ec.CurrentAnonymousMethod;
3704 if (is_ref && !block.Toplevel.IsLocalParameter (name)){
3705 Report.Error (1628, Location,
3706 "Cannot use ref or out parameter `{0}' inside an " +
3707 "anonymous method block", par.Name);
3711 if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
3714 RootScopeInfo host = null;
3715 ToplevelBlock toplevel = block.Toplevel;
3716 while (toplevel != null) {
3717 if (toplevel.IsLocalParameter (name))
3720 toplevel = toplevel.Container;
3723 ScopeInfo scope = toplevel.CreateScopeInfo ();
3724 variable = scope.AddParameter (par, idx);
3725 type = variable.Type;
3729 public override int GetHashCode()
3731 return name.GetHashCode ();
3734 public override bool Equals (object obj)
3736 ParameterReference pr = obj as ParameterReference;
3740 return name == pr.name && block == pr.block;
3744 // Notice that for ref/out parameters, the type exposed is not the
3745 // same type exposed externally.
3748 // externally we expose "int&"
3749 // here we expose "int".
3751 // We record this in "is_ref". This means that the type system can treat
3752 // the type as it is expected, but when we generate the code, we generate
3753 // the alternate kind of code.
3755 public override Expression DoResolve (EmitContext ec)
3757 if (!DoResolveBase (ec))
3760 if (is_out && ec.DoFlowAnalysis &&
3761 (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3767 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3769 if (!DoResolveBase (ec))
3777 static public void EmitLdArg (ILGenerator ig, int x)
3781 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3782 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3783 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3784 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3785 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3788 ig.Emit (OpCodes.Ldarg, x);
3791 public override string ToString ()
3793 return "ParameterReference[" + name + "]";
3798 /// Used for arguments to New(), Invocation()
3800 public class Argument {
3801 public enum AType : byte {
3808 public readonly AType ArgType;
3809 public Expression Expr;
3811 public Argument (Expression expr, AType type)
3814 this.ArgType = type;
3817 public Argument (Expression expr)
3820 this.ArgType = AType.Expression;
3825 if (ArgType == AType.Ref || ArgType == AType.Out)
3826 return TypeManager.GetReferenceType (Expr.Type);
3832 public Parameter.Modifier Modifier
3837 return Parameter.Modifier.OUT;
3840 return Parameter.Modifier.REF;
3843 return Parameter.Modifier.NONE;
3848 public static string FullDesc (Argument a)
3850 if (a.ArgType == AType.ArgList)
3853 return (a.ArgType == AType.Ref ? "ref " :
3854 (a.ArgType == AType.Out ? "out " : "")) +
3855 TypeManager.CSharpName (a.Expr.Type);
3858 public bool ResolveMethodGroup (EmitContext ec)
3860 SimpleName sn = Expr as SimpleName;
3862 Expr = sn.GetMethodGroup ();
3864 // FIXME: csc doesn't report any error if you try to use `ref' or
3865 // `out' in a delegate creation expression.
3866 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3873 public bool Resolve (EmitContext ec, Location loc)
3875 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3876 // Verify that the argument is readable
3877 if (ArgType != AType.Out)
3878 Expr = Expr.Resolve (ec);
3880 // Verify that the argument is writeable
3881 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3882 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3884 return Expr != null;
3888 public void Emit (EmitContext ec)
3890 if (ArgType != AType.Ref && ArgType != AType.Out) {
3895 AddressOp mode = AddressOp.Store;
3896 if (ArgType == AType.Ref)
3897 mode |= AddressOp.Load;
3899 IMemoryLocation ml = (IMemoryLocation) Expr;
3900 ParameterReference pr = ml as ParameterReference;
3903 // ParameterReferences might already be references, so we want
3904 // to pass just the value
3906 if (pr != null && pr.IsRef)
3909 ml.AddressOf (ec, mode);
3914 /// Invocation of methods or delegates.
3916 public class Invocation : ExpressionStatement {
3917 public readonly ArrayList Arguments;
3920 MethodBase method = null;
3923 // arguments is an ArrayList, but we do not want to typecast,
3924 // as it might be null.
3926 // FIXME: only allow expr to be a method invocation or a
3927 // delegate invocation (7.5.5)
3929 public Invocation (Expression expr, ArrayList arguments)
3932 Arguments = arguments;
3933 loc = expr.Location;
3936 public Expression Expr {
3943 /// Determines "better conversion" as specified in 14.4.2.3
3945 /// Returns : p if a->p is better,
3946 /// q if a->q is better,
3947 /// null if neither is better
3949 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3951 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3952 Expression argument_expr = a.Expr;
3954 if (argument_type == null)
3955 throw new Exception ("Expression of type " + a.Expr +
3956 " does not resolve its type");
3958 if (p == null || q == null)
3959 throw new InternalErrorException ("BetterConversion Got a null conversion");
3964 if (argument_expr is NullLiteral) {
3966 // If the argument is null and one of the types to compare is 'object' and
3967 // the other is a reference type, we prefer the other.
3969 // This follows from the usual rules:
3970 // * There is an implicit conversion from 'null' to type 'object'
3971 // * There is an implicit conversion from 'null' to any reference type
3972 // * There is an implicit conversion from any reference type to type 'object'
3973 // * There is no implicit conversion from type 'object' to other reference types
3974 // => Conversion of 'null' to a reference type is better than conversion to 'object'
3976 // FIXME: This probably isn't necessary, since the type of a NullLiteral is the
3977 // null type. I think it used to be 'object' and thus needed a special
3978 // case to avoid the immediately following two checks.
3980 if (!p.IsValueType && q == TypeManager.object_type)
3982 if (!q.IsValueType && p == TypeManager.object_type)
3986 if (argument_type == p)
3989 if (argument_type == q)
3992 Expression p_tmp = new EmptyExpression (p);
3993 Expression q_tmp = new EmptyExpression (q);
3995 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3996 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3998 if (p_to_q && !q_to_p)
4001 if (q_to_p && !p_to_q)
4004 if (p == TypeManager.sbyte_type)
4005 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4006 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4008 if (q == TypeManager.sbyte_type)
4009 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4010 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4013 if (p == TypeManager.short_type)
4014 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4015 q == TypeManager.uint64_type)
4017 if (q == TypeManager.short_type)
4018 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4019 p == TypeManager.uint64_type)
4022 if (p == TypeManager.int32_type)
4023 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4025 if (q == TypeManager.int32_type)
4026 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4029 if (p == TypeManager.int64_type)
4030 if (q == TypeManager.uint64_type)
4032 if (q == TypeManager.int64_type)
4033 if (p == TypeManager.uint64_type)
4039 static Type MoreSpecific (Type p, Type q)
4041 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4043 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4046 if (TypeManager.HasElementType (p)) {
4047 Type pe = TypeManager.GetElementType (p);
4048 Type qe = TypeManager.GetElementType (q);
4049 Type specific = MoreSpecific (pe, qe);
4054 } else if (TypeManager.IsGenericType (p)) {
4055 Type[] pargs = TypeManager.GetTypeArguments (p);
4056 Type[] qargs = TypeManager.GetTypeArguments (q);
4058 bool p_specific_at_least_once = false;
4059 bool q_specific_at_least_once = false;
4061 for (int i = 0; i < pargs.Length; i++) {
4062 Type specific = MoreSpecific (pargs [i], qargs [i]);
4063 if (specific == pargs [i])
4064 p_specific_at_least_once = true;
4065 if (specific == qargs [i])
4066 q_specific_at_least_once = true;
4069 if (p_specific_at_least_once && !q_specific_at_least_once)
4071 if (!p_specific_at_least_once && q_specific_at_least_once)
4079 /// Determines "Better function" between candidate
4080 /// and the current best match
4083 /// Returns a boolean indicating :
4084 /// false if candidate ain't better
4085 /// true if candidate is better than the current best match
4087 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4088 MethodBase candidate, bool candidate_params,
4089 MethodBase best, bool best_params)
4091 ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4092 ParameterData best_pd = TypeManager.GetParameterData (best);
4094 bool better_at_least_one = false;
4096 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx) {
4097 Argument a = (Argument) args [j];
4099 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
4100 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
4102 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS) {
4103 ct = TypeManager.GetElementType (ct);
4107 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS) {
4108 bt = TypeManager.GetElementType (bt);
4116 Type better = BetterConversion (ec, a, ct, bt);
4118 // for each argument, the conversion to 'ct' should be no worse than
4119 // the conversion to 'bt'.
4123 // for at least one argument, the conversion to 'ct' should be better than
4124 // the conversion to 'bt'.
4126 better_at_least_one = true;
4129 if (better_at_least_one)
4133 // This handles the case
4135 // Add (float f1, float f2, float f3);
4136 // Add (params decimal [] foo);
4138 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4139 // first candidate would've chosen as better.
4145 // The two methods have equal parameter types. Now apply tie-breaking rules
4147 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
4149 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
4153 // This handles the following cases:
4155 // Trim () is better than Trim (params char[] chars)
4156 // Concat (string s1, string s2, string s3) is better than
4157 // Concat (string s1, params string [] srest)
4158 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4160 if (!candidate_params && best_params)
4162 if (candidate_params && !best_params)
4165 int candidate_param_count = candidate_pd.Count;
4166 int best_param_count = best_pd.Count;
4168 if (candidate_param_count != best_param_count)
4169 // can only happen if (candidate_params && best_params)
4170 return candidate_param_count > best_param_count;
4173 // now, both methods have the same number of parameters, and the parameters have the same types
4174 // Pick the "more specific" signature
4177 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
4178 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
4180 ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
4181 ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
4183 bool specific_at_least_once = false;
4184 for (int j = 0; j < candidate_param_count; ++j) {
4185 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
4186 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
4189 Type specific = MoreSpecific (ct, bt);
4193 specific_at_least_once = true;
4196 if (specific_at_least_once)
4199 // FIXME: handle lifted operators
4205 internal static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4207 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4210 ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4211 ParameterData base_pd = TypeManager.GetParameterData (base_method);
4213 if (cand_pd.Count != base_pd.Count)
4216 for (int j = 0; j < cand_pd.Count; ++j) {
4217 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4218 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4219 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4220 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4222 if (cm != bm || ct != bt)
4229 public static string FullMethodDesc (MethodBase mb)
4235 if (mb is MethodInfo) {
4236 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4240 sb = new StringBuilder ();
4242 sb.Append (TypeManager.CSharpSignature (mb));
4243 return sb.ToString ();
4246 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4248 MemberInfo [] miset;
4249 MethodGroupExpr union;
4254 return (MethodGroupExpr) mg2;
4257 return (MethodGroupExpr) mg1;
4260 MethodGroupExpr left_set = null, right_set = null;
4261 int length1 = 0, length2 = 0;
4263 left_set = (MethodGroupExpr) mg1;
4264 length1 = left_set.Methods.Length;
4266 right_set = (MethodGroupExpr) mg2;
4267 length2 = right_set.Methods.Length;
4269 ArrayList common = new ArrayList ();
4271 foreach (MethodBase r in right_set.Methods){
4272 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4276 miset = new MemberInfo [length1 + length2 - common.Count];
4277 left_set.Methods.CopyTo (miset, 0);
4281 foreach (MethodBase r in right_set.Methods) {
4282 if (!common.Contains (r))
4286 union = new MethodGroupExpr (miset, loc);
4291 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4292 ArrayList arguments, int arg_count,
4293 ref MethodBase candidate)
4295 return IsParamsMethodApplicable (
4296 ec, me, arguments, arg_count, false, ref candidate) ||
4297 IsParamsMethodApplicable (
4298 ec, me, arguments, arg_count, true, ref candidate);
4303 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4304 ArrayList arguments, int arg_count,
4305 bool do_varargs, ref MethodBase candidate)
4308 if (!me.HasTypeArguments &&
4309 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4312 if (TypeManager.IsGenericMethodDefinition (candidate))
4313 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4316 return IsParamsMethodApplicable (
4317 ec, arguments, arg_count, candidate, do_varargs);
4321 /// Determines if the candidate method, if a params method, is applicable
4322 /// in its expanded form to the given set of arguments
4324 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4325 int arg_count, MethodBase candidate,
4328 ParameterData pd = TypeManager.GetParameterData (candidate);
4330 int pd_count = pd.Count;
4334 int count = pd_count - 1;
4336 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4338 if (pd_count != arg_count)
4341 if (!(((Argument) arguments [count]).Expr is Arglist))
4349 if (count > arg_count)
4352 if (pd_count == 1 && arg_count == 0)
4356 // If we have come this far, the case which
4357 // remains is when the number of parameters is
4358 // less than or equal to the argument count.
4360 int argument_index = 0;
4362 for (int i = 0; i < pd_count; ++i) {
4364 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4365 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4366 int params_args_count = arg_count - pd_count;
4367 if (params_args_count < 0)
4371 a = (Argument) arguments [argument_index++];
4373 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4375 } while (params_args_count-- > 0);
4379 a = (Argument) arguments [argument_index++];
4381 Parameter.Modifier a_mod = a.Modifier &
4382 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4383 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4384 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4386 if (a_mod == p_mod) {
4388 if (a_mod == Parameter.Modifier.NONE)
4389 if (!Convert.ImplicitConversionExists (ec,
4391 pd.ParameterType (i)))
4394 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4395 Type pt = pd.ParameterType (i);
4398 pt = TypeManager.GetReferenceType (pt);
4411 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4412 ArrayList arguments, int arg_count,
4413 ref MethodBase candidate)
4416 if (!me.HasTypeArguments &&
4417 !TypeManager.InferTypeArguments (arguments, ref candidate))
4420 if (TypeManager.IsGenericMethodDefinition (candidate))
4421 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4424 return IsApplicable (ec, arguments, arg_count, candidate);
4428 /// Determines if the candidate method is applicable (section 14.4.2.1)
4429 /// to the given set of arguments
4431 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4432 MethodBase candidate)
4434 ParameterData pd = TypeManager.GetParameterData (candidate);
4436 if (arg_count != pd.Count)
4439 for (int i = arg_count; i > 0; ) {
4442 Argument a = (Argument) arguments [i];
4444 Parameter.Modifier a_mod = a.Modifier &
4445 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4447 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4448 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4450 if (a_mod == p_mod) {
4451 Type pt = pd.ParameterType (i);
4453 if (a_mod == Parameter.Modifier.NONE) {
4454 if (!TypeManager.IsEqual (a.Type, pt) &&
4455 !Convert.ImplicitConversionExists (ec, a.Expr, pt))
4469 static internal bool IsAncestralType (Type first_type, Type second_type)
4471 return first_type != second_type &&
4472 (TypeManager.IsSubclassOf (second_type, first_type) ||
4473 TypeManager.ImplementsInterface (second_type, first_type));
4477 /// Find the Applicable Function Members (7.4.2.1)
4479 /// me: Method Group expression with the members to select.
4480 /// it might contain constructors or methods (or anything
4481 /// that maps to a method).
4483 /// Arguments: ArrayList containing resolved Argument objects.
4485 /// loc: The location if we want an error to be reported, or a Null
4486 /// location for "probing" purposes.
4488 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4489 /// that is the best match of me on Arguments.
4492 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4493 ArrayList Arguments, bool may_fail,
4496 MethodBase method = null;
4497 bool method_params = false;
4498 Type applicable_type = null;
4500 ArrayList candidates = new ArrayList (2);
4501 ArrayList candidate_overrides = null;
4504 // Used to keep a map between the candidate
4505 // and whether it is being considered in its
4506 // normal or expanded form
4508 // false is normal form, true is expanded form
4510 Hashtable candidate_to_form = null;
4512 if (Arguments != null)
4513 arg_count = Arguments.Count;
4515 if ((me.Name == "Invoke") &&
4516 TypeManager.IsDelegateType (me.DeclaringType)) {
4517 Error_InvokeOnDelegate (loc);
4521 MethodBase[] methods = me.Methods;
4523 int nmethods = methods.Length;
4527 // Methods marked 'override' don't take part in 'applicable_type'
4528 // computation, nor in the actual overload resolution.
4529 // However, they still need to be emitted instead of a base virtual method.
4530 // So, we salt them away into the 'candidate_overrides' array.
4532 // In case of reflected methods, we replace each overriding method with
4533 // its corresponding base virtual method. This is to improve compatibility
4534 // with non-C# libraries which change the visibility of overrides (#75636)
4537 for (int i = 0; i < methods.Length; ++i) {
4538 MethodBase m = methods [i];
4540 Type [] gen_args = null;
4541 if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
4542 gen_args = m.GetGenericArguments ();
4544 if (TypeManager.IsOverride (m)) {
4545 if (candidate_overrides == null)
4546 candidate_overrides = new ArrayList ();
4547 candidate_overrides.Add (m);
4548 m = TypeManager.TryGetBaseDefinition (m);
4550 if (m != null && gen_args != null) {
4551 if (!m.IsGenericMethodDefinition)
4552 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
4553 m = ((MethodInfo) m).MakeGenericMethod (gen_args);
4563 int applicable_errors = Report.Errors;
4566 // First we construct the set of applicable methods
4568 bool is_sorted = true;
4569 for (int i = 0; i < nmethods; i++){
4570 Type decl_type = methods [i].DeclaringType;
4573 // If we have already found an applicable method
4574 // we eliminate all base types (Section 14.5.5.1)
4576 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4580 // Check if candidate is applicable (section 14.4.2.1)
4581 // Is candidate applicable in normal form?
4583 bool is_applicable = IsApplicable (ec, me, Arguments, arg_count, ref methods [i]);
4585 if (!is_applicable && IsParamsMethodApplicable (ec, me, Arguments, arg_count, ref methods [i])) {
4586 MethodBase candidate = methods [i];
4587 if (candidate_to_form == null)
4588 candidate_to_form = new PtrHashtable ();
4589 candidate_to_form [candidate] = candidate;
4590 // Candidate is applicable in expanded form
4591 is_applicable = true;
4597 candidates.Add (methods [i]);
4599 if (applicable_type == null)
4600 applicable_type = decl_type;
4601 else if (applicable_type != decl_type) {
4603 if (IsAncestralType (applicable_type, decl_type))
4604 applicable_type = decl_type;
4608 if (applicable_errors != Report.Errors)
4611 int candidate_top = candidates.Count;
4613 if (applicable_type == null) {
4615 // Okay so we have failed to find anything so we
4616 // return by providing info about the closest match
4618 int errors = Report.Errors;
4619 for (int i = 0; i < nmethods; ++i) {
4620 MethodBase c = (MethodBase) methods [i];
4621 ParameterData pd = TypeManager.GetParameterData (c);
4623 if (pd.Count != arg_count)
4627 if (!TypeManager.InferTypeArguments (Arguments, ref c))
4629 if (TypeManager.IsGenericMethodDefinition (c))
4633 VerifyArgumentsCompat (ec, Arguments, arg_count,
4634 c, false, null, may_fail, loc);
4636 if (!may_fail && errors == Report.Errors)
4637 throw new InternalErrorException (
4638 "VerifyArgumentsCompat and IsApplicable do not agree; " +
4639 "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
4644 if (!may_fail && errors == Report.Errors) {
4645 string report_name = me.Name;
4646 if (report_name == ".ctor")
4647 report_name = TypeManager.CSharpName (me.DeclaringType);
4653 for (int i = 0; i < methods.Length; ++i) {
4654 MethodBase c = methods [i];
4655 ParameterData pd = TypeManager.GetParameterData (c);
4657 if (pd.Count != arg_count)
4660 if (TypeManager.InferTypeArguments (Arguments, ref c))
4664 411, loc, "The type arguments for " +
4665 "method `{0}' cannot be inferred from " +
4666 "the usage. Try specifying the type " +
4667 "arguments explicitly.", report_name);
4672 Error_WrongNumArguments (loc, report_name, arg_count);
4680 // At this point, applicable_type is _one_ of the most derived types
4681 // in the set of types containing the methods in this MethodGroup.
4682 // Filter the candidates so that they only contain methods from the
4683 // most derived types.
4686 int finalized = 0; // Number of finalized candidates
4689 // Invariant: applicable_type is a most derived type
4691 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4692 // eliminating all it's base types. At the same time, we'll also move
4693 // every unrelated type to the end of the array, and pick the next
4694 // 'applicable_type'.
4696 Type next_applicable_type = null;
4697 int j = finalized; // where to put the next finalized candidate
4698 int k = finalized; // where to put the next undiscarded candidate
4699 for (int i = finalized; i < candidate_top; ++i) {
4700 MethodBase candidate = (MethodBase) candidates [i];
4701 Type decl_type = candidate.DeclaringType;
4703 if (decl_type == applicable_type) {
4704 candidates [k++] = candidates [j];
4705 candidates [j++] = candidates [i];
4709 if (IsAncestralType (decl_type, applicable_type))
4712 if (next_applicable_type != null &&
4713 IsAncestralType (decl_type, next_applicable_type))
4716 candidates [k++] = candidates [i];
4718 if (next_applicable_type == null ||
4719 IsAncestralType (next_applicable_type, decl_type))
4720 next_applicable_type = decl_type;
4723 applicable_type = next_applicable_type;
4726 } while (applicable_type != null);
4730 // Now we actually find the best method
4733 method = (MethodBase) candidates [0];
4734 method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4735 for (int ix = 1; ix < candidate_top; ix++){
4736 MethodBase candidate = (MethodBase) candidates [ix];
4738 if (candidate == method)
4741 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4743 if (BetterFunction (ec, Arguments, arg_count,
4744 candidate, cand_params,
4745 method, method_params)) {
4747 method_params = cand_params;
4751 // Now check that there are no ambiguities i.e the selected method
4752 // should be better than all the others
4754 MethodBase ambiguous = null;
4755 for (int ix = 0; ix < candidate_top; ix++){
4756 MethodBase candidate = (MethodBase) candidates [ix];
4758 if (candidate == method)
4761 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4762 if (!BetterFunction (ec, Arguments, arg_count,
4763 method, method_params,
4764 candidate, cand_params)) {
4765 Report.SymbolRelatedToPreviousError (candidate);
4766 ambiguous = candidate;
4770 if (ambiguous != null) {
4771 Report.SymbolRelatedToPreviousError (method);
4772 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4773 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
4778 // If the method is a virtual function, pick an override closer to the LHS type.
4780 if (!me.IsBase && method.IsVirtual) {
4781 if (TypeManager.IsOverride (method))
4782 throw new InternalErrorException (
4783 "Should not happen. An 'override' method took part in overload resolution: " + method);
4785 if (candidate_overrides != null)
4786 foreach (MethodBase candidate in candidate_overrides) {
4787 if (IsOverride (candidate, method))
4793 // And now check if the arguments are all
4794 // compatible, perform conversions if
4795 // necessary etc. and return if everything is
4798 if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4799 method_params, null, may_fail, loc))
4805 MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
4807 if (the_method.IsGenericMethodDefinition &&
4808 !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
4812 IMethodData data = TypeManager.GetMethod (the_method);
4814 data.SetMemberIsUsed ();
4819 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4821 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4822 name, arg_count.ToString ());
4825 static void Error_InvokeOnDelegate (Location loc)
4827 Report.Error (1533, loc,
4828 "Invoke cannot be called directly on a delegate");
4831 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4832 Type delegate_type, Argument a, ParameterData expected_par)
4834 if (delegate_type == null)
4835 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4836 TypeManager.CSharpSignature (method));
4838 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4839 TypeManager.CSharpName (delegate_type));
4841 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4843 string index = (idx + 1).ToString ();
4844 if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4845 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4846 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4847 index, Parameter.GetModifierSignature (a.Modifier));
4849 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4850 index, Parameter.GetModifierSignature (mod));
4852 string p1 = Argument.FullDesc (a);
4853 string p2 = expected_par.ParameterDesc (idx);
4856 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4857 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4858 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4860 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'", index, p1, p2);
4864 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4865 int arg_count, MethodBase method,
4866 bool chose_params_expanded,
4867 Type delegate_type, bool may_fail,
4870 ParameterData pd = TypeManager.GetParameterData (method);
4874 for (j = 0; j < pd.Count; j++) {
4875 Type parameter_type = pd.ParameterType (j);
4876 Parameter.Modifier pm = pd.ParameterModifier (j);
4878 if (pm == Parameter.Modifier.ARGLIST) {
4879 a = (Argument) Arguments [a_idx];
4880 if (!(a.Expr is Arglist))
4886 int params_arg_count = 1;
4887 if (pm == Parameter.Modifier.PARAMS) {
4888 pm = Parameter.Modifier.NONE;
4889 params_arg_count = arg_count - pd.Count + 1;
4890 if (chose_params_expanded)
4891 parameter_type = TypeManager.GetElementType (parameter_type);
4894 while (params_arg_count > 0) {
4895 a = (Argument) Arguments [a_idx];
4896 if (pm != a.Modifier)
4899 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4900 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4903 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4907 // Update the argument with the implicit conversion
4915 if (params_arg_count > 0)
4918 if (parameter_type.IsPointer && !ec.InUnsafe) {
4924 if (a_idx == arg_count)
4928 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4932 private bool resolved = false;
4933 public override Expression DoResolve (EmitContext ec)
4936 return this.method == null ? null : this;
4940 // First, resolve the expression that is used to
4941 // trigger the invocation
4943 SimpleName sn = expr as SimpleName;
4945 expr = sn.GetMethodGroup ();
4947 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4951 if (!(expr is MethodGroupExpr)) {
4952 Type expr_type = expr.Type;
4954 if (expr_type != null){
4955 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4957 return (new DelegateInvocation (
4958 this.expr, Arguments, loc)).Resolve (ec);
4962 if (!(expr is MethodGroupExpr)){
4963 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4968 // Next, evaluate all the expressions in the argument list
4970 if (Arguments != null){
4971 foreach (Argument a in Arguments){
4972 if (!a.Resolve (ec, loc))
4977 MethodGroupExpr mg = (MethodGroupExpr) expr;
4978 MethodBase method = OverloadResolve (ec, mg, Arguments, false, loc);
4983 MethodInfo mi = method as MethodInfo;
4985 type = TypeManager.TypeToCoreType (mi.ReturnType);
4986 Expression iexpr = mg.InstanceExpression;
4988 if (iexpr == null ||
4989 iexpr is This || iexpr is EmptyExpression ||
4990 mg.IdenticalTypeName) {
4991 mg.InstanceExpression = null;
4993 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4997 if (iexpr == null || iexpr is EmptyExpression) {
4998 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
5004 if (type.IsPointer){
5012 // Only base will allow this invocation to happen.
5014 if (mg.IsBase && method.IsAbstract){
5015 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
5019 if (Arguments == null && method.Name == "Finalize") {
5021 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5023 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5027 if (IsSpecialMethodInvocation (method)) {
5031 if (mg.InstanceExpression != null){
5032 mg.InstanceExpression.CheckMarshalByRefAccess ();
5035 // This is used to check that no methods are called in struct
5036 // constructors before all the fields on the struct have been
5039 if (!method.IsStatic){
5040 This mgthis = mg.InstanceExpression as This;
5041 if (mgthis != null){
5042 if (!mgthis.CheckThisUsage (ec))
5048 eclass = ExprClass.Value;
5049 this.method = method;
5053 bool IsSpecialMethodInvocation (MethodBase method)
5055 if (!TypeManager.IsSpecialMethod (method))
5058 Report.SymbolRelatedToPreviousError (method);
5059 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5060 TypeManager.CSharpSignature (method, true));
5066 // Emits the list of arguments as an array
5068 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
5070 ILGenerator ig = ec.ig;
5072 for (int j = 0; j < count; j++){
5073 Argument a = (Argument) arguments [j + idx];
5076 IntConstant.EmitInt (ig, count);
5077 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5080 ig.Emit (OpCodes.Dup);
5081 IntConstant.EmitInt (ig, j);
5083 bool is_stobj, has_type_arg;
5084 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5086 ig.Emit (OpCodes.Ldelema, t);
5098 /// Emits a list of resolved Arguments that are in the arguments
5101 /// The MethodBase argument might be null if the
5102 /// emission of the arguments is known not to contain
5103 /// a `params' field (for example in constructors or other routines
5104 /// that keep their arguments in this structure)
5106 /// if `dup_args' is true, a copy of the arguments will be left
5107 /// on the stack. If `dup_args' is true, you can specify `this_arg'
5108 /// which will be duplicated before any other args. Only EmitCall
5109 /// should be using this interface.
5111 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5113 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
5115 LocalTemporary [] temps = null;
5117 if (dup_args && top != 0)
5118 temps = new LocalTemporary [top];
5120 int argument_index = 0;
5122 for (int i = 0; i < top; i++){
5124 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5125 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
5126 int params_args_count = arguments == null ?
5127 0 : arguments.Count - top + 1;
5129 // Fill not provided argument
5130 if (params_args_count <= 0) {
5131 ILGenerator ig = ec.ig;
5132 IntConstant.EmitInt (ig, 0);
5133 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
5138 // Special case if we are passing the same data as the
5139 // params argument, we do not need to recreate an array.
5141 a = (Argument) arguments [argument_index];
5142 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
5148 EmitParams (ec, arguments, i, params_args_count);
5149 argument_index += params_args_count;
5154 a = (Argument) arguments [argument_index++];
5157 ec.ig.Emit (OpCodes.Dup);
5158 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
5163 if (this_arg != null)
5166 for (int i = 0; i < top; i ++) {
5167 temps [i].Emit (ec);
5168 temps [i].Release (ec);
5173 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
5175 ParameterData pd = TypeManager.GetParameterData (mb);
5177 if (arguments == null)
5178 return new Type [0];
5180 Argument a = (Argument) arguments [pd.Count - 1];
5181 Arglist list = (Arglist) a.Expr;
5183 return list.ArgumentTypes;
5187 /// This checks the ConditionalAttribute on the method
5189 static bool IsMethodExcluded (MethodBase method)
5191 if (method.IsConstructor)
5194 IMethodData md = TypeManager.GetMethod (method);
5196 return md.IsExcluded ();
5198 // For some methods (generated by delegate class) GetMethod returns null
5199 // because they are not included in builder_to_method table
5200 if (method.DeclaringType is TypeBuilder)
5203 return AttributeTester.IsConditionalMethodExcluded (method);
5207 /// is_base tells whether we want to force the use of the `call'
5208 /// opcode instead of using callvirt. Call is required to call
5209 /// a specific method, while callvirt will always use the most
5210 /// recent method in the vtable.
5212 /// is_static tells whether this is an invocation on a static method
5214 /// instance_expr is an expression that represents the instance
5215 /// it must be non-null if is_static is false.
5217 /// method is the method to invoke.
5219 /// Arguments is the list of arguments to pass to the method or constructor.
5221 public static void EmitCall (EmitContext ec, bool is_base,
5222 bool is_static, Expression instance_expr,
5223 MethodBase method, ArrayList Arguments, Location loc)
5225 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5228 // `dup_args' leaves an extra copy of the arguments on the stack
5229 // `omit_args' does not leave any arguments at all.
5230 // So, basically, you could make one call with `dup_args' set to true,
5231 // and then another with `omit_args' set to true, and the two calls
5232 // would have the same set of arguments. However, each argument would
5233 // only have been evaluated once.
5234 public static void EmitCall (EmitContext ec, bool is_base,
5235 bool is_static, Expression instance_expr,
5236 MethodBase method, ArrayList Arguments, Location loc,
5237 bool dup_args, bool omit_args)
5239 ILGenerator ig = ec.ig;
5240 bool struct_call = false;
5241 bool this_call = false;
5242 LocalTemporary this_arg = null;
5244 Type decl_type = method.DeclaringType;
5246 if (!RootContext.StdLib) {
5247 // Replace any calls to the system's System.Array type with calls to
5248 // the newly created one.
5249 if (method == TypeManager.system_int_array_get_length)
5250 method = TypeManager.int_array_get_length;
5251 else if (method == TypeManager.system_int_array_get_rank)
5252 method = TypeManager.int_array_get_rank;
5253 else if (method == TypeManager.system_object_array_clone)
5254 method = TypeManager.object_array_clone;
5255 else if (method == TypeManager.system_int_array_get_length_int)
5256 method = TypeManager.int_array_get_length_int;
5257 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5258 method = TypeManager.int_array_get_lower_bound_int;
5259 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5260 method = TypeManager.int_array_get_upper_bound_int;
5261 else if (method == TypeManager.system_void_array_copyto_array_int)
5262 method = TypeManager.void_array_copyto_array_int;
5265 if (!ec.IsInObsoleteScope) {
5267 // This checks ObsoleteAttribute on the method and on the declaring type
5269 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5271 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5273 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5275 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5279 if (IsMethodExcluded (method))
5283 if (instance_expr == EmptyExpression.Null) {
5284 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5288 this_call = instance_expr is This;
5289 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5293 // If this is ourselves, push "this"
5297 Type iexpr_type = instance_expr.Type;
5300 // Push the instance expression
5302 if (TypeManager.IsValueType (iexpr_type)) {
5304 // Special case: calls to a function declared in a
5305 // reference-type with a value-type argument need
5306 // to have their value boxed.
5307 if (decl_type.IsValueType ||
5308 TypeManager.IsGenericParameter (iexpr_type)) {
5310 // If the expression implements IMemoryLocation, then
5311 // we can optimize and use AddressOf on the
5314 // If not we have to use some temporary storage for
5316 if (instance_expr is IMemoryLocation) {
5317 ((IMemoryLocation)instance_expr).
5318 AddressOf (ec, AddressOp.LoadStore);
5320 LocalTemporary temp = new LocalTemporary (iexpr_type);
5321 instance_expr.Emit (ec);
5323 temp.AddressOf (ec, AddressOp.Load);
5326 // avoid the overhead of doing this all the time.
5328 t = TypeManager.GetReferenceType (iexpr_type);
5330 instance_expr.Emit (ec);
5331 ig.Emit (OpCodes.Box, instance_expr.Type);
5332 t = TypeManager.object_type;
5335 instance_expr.Emit (ec);
5336 t = instance_expr.Type;
5340 ig.Emit (OpCodes.Dup);
5341 if (Arguments != null && Arguments.Count != 0) {
5342 this_arg = new LocalTemporary (t);
5343 this_arg.Store (ec);
5350 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5353 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5354 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5358 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5359 call_op = OpCodes.Call;
5361 call_op = OpCodes.Callvirt;
5363 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5364 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5365 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5372 // and DoFoo is not virtual, you can omit the callvirt,
5373 // because you don't need the null checking behavior.
5375 if (method is MethodInfo)
5376 ig.Emit (call_op, (MethodInfo) method);
5378 ig.Emit (call_op, (ConstructorInfo) method);
5381 public override void Emit (EmitContext ec)
5383 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5385 EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5388 public override void EmitStatement (EmitContext ec)
5393 // Pop the return value if there is one
5395 if (method is MethodInfo){
5396 Type ret = ((MethodInfo)method).ReturnType;
5397 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5398 ec.ig.Emit (OpCodes.Pop);
5403 public class InvocationOrCast : ExpressionStatement
5406 Expression argument;
5408 public InvocationOrCast (Expression expr, Expression argument)
5411 this.argument = argument;
5412 this.loc = expr.Location;
5415 public override Expression DoResolve (EmitContext ec)
5418 // First try to resolve it as a cast.
5420 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5421 if ((te != null) && (te.eclass == ExprClass.Type)) {
5422 Cast cast = new Cast (te, argument, loc);
5423 return cast.Resolve (ec);
5427 // This can either be a type or a delegate invocation.
5428 // Let's just resolve it and see what we'll get.
5430 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5435 // Ok, so it's a Cast.
5437 if (expr.eclass == ExprClass.Type) {
5438 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5439 return cast.Resolve (ec);
5443 // It's a delegate invocation.
5445 if (!TypeManager.IsDelegateType (expr.Type)) {
5446 Error (149, "Method name expected");
5450 ArrayList args = new ArrayList ();
5451 args.Add (new Argument (argument, Argument.AType.Expression));
5452 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5453 return invocation.Resolve (ec);
5458 Error (201, "Only assignment, call, increment, decrement and new object " +
5459 "expressions can be used as a statement");
5462 public override ExpressionStatement ResolveStatement (EmitContext ec)
5465 // First try to resolve it as a cast.
5467 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5468 if ((te != null) && (te.eclass == ExprClass.Type)) {
5474 // This can either be a type or a delegate invocation.
5475 // Let's just resolve it and see what we'll get.
5477 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5478 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5484 // It's a delegate invocation.
5486 if (!TypeManager.IsDelegateType (expr.Type)) {
5487 Error (149, "Method name expected");
5491 ArrayList args = new ArrayList ();
5492 args.Add (new Argument (argument, Argument.AType.Expression));
5493 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5494 return invocation.ResolveStatement (ec);
5497 public override void Emit (EmitContext ec)
5499 throw new Exception ("Cannot happen");
5502 public override void EmitStatement (EmitContext ec)
5504 throw new Exception ("Cannot happen");
5509 // This class is used to "disable" the code generation for the
5510 // temporary variable when initializing value types.
5512 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5513 public void AddressOf (EmitContext ec, AddressOp Mode)
5520 /// Implements the new expression
5522 public class New : ExpressionStatement, IMemoryLocation {
5523 public readonly ArrayList Arguments;
5526 // During bootstrap, it contains the RequestedType,
5527 // but if `type' is not null, it *might* contain a NewDelegate
5528 // (because of field multi-initialization)
5530 public Expression RequestedType;
5532 MethodBase method = null;
5535 // If set, the new expression is for a value_target, and
5536 // we will not leave anything on the stack.
5538 Expression value_target;
5539 bool value_target_set = false;
5540 bool is_type_parameter = false;
5542 public New (Expression requested_type, ArrayList arguments, Location l)
5544 RequestedType = requested_type;
5545 Arguments = arguments;
5549 public bool SetValueTypeVariable (Expression value)
5551 value_target = value;
5552 value_target_set = true;
5553 if (!(value_target is IMemoryLocation)){
5554 Error_UnexpectedKind (null, "variable", loc);
5561 // This function is used to disable the following code sequence for
5562 // value type initialization:
5564 // AddressOf (temporary)
5568 // Instead the provide will have provided us with the address on the
5569 // stack to store the results.
5571 static Expression MyEmptyExpression;
5573 public void DisableTemporaryValueType ()
5575 if (MyEmptyExpression == null)
5576 MyEmptyExpression = new EmptyAddressOf ();
5579 // To enable this, look into:
5580 // test-34 and test-89 and self bootstrapping.
5582 // For instance, we can avoid a copy by using `newobj'
5583 // instead of Call + Push-temp on value types.
5584 // value_target = MyEmptyExpression;
5589 /// Converts complex core type syntax like 'new int ()' to simple constant
5591 public static Constant Constantify (Type t)
5593 if (t == TypeManager.int32_type)
5594 return new IntConstant (0, Location.Null);
5595 if (t == TypeManager.uint32_type)
5596 return new UIntConstant (0, Location.Null);
5597 if (t == TypeManager.int64_type)
5598 return new LongConstant (0, Location.Null);
5599 if (t == TypeManager.uint64_type)
5600 return new ULongConstant (0, Location.Null);
5601 if (t == TypeManager.float_type)
5602 return new FloatConstant (0, Location.Null);
5603 if (t == TypeManager.double_type)
5604 return new DoubleConstant (0, Location.Null);
5605 if (t == TypeManager.short_type)
5606 return new ShortConstant (0, Location.Null);
5607 if (t == TypeManager.ushort_type)
5608 return new UShortConstant (0, Location.Null);
5609 if (t == TypeManager.sbyte_type)
5610 return new SByteConstant (0, Location.Null);
5611 if (t == TypeManager.byte_type)
5612 return new ByteConstant (0, Location.Null);
5613 if (t == TypeManager.char_type)
5614 return new CharConstant ('\0', Location.Null);
5615 if (t == TypeManager.bool_type)
5616 return new BoolConstant (false, Location.Null);
5617 if (t == TypeManager.decimal_type)
5618 return new DecimalConstant (0, Location.Null);
5619 if (TypeManager.IsEnumType (t))
5620 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5626 // Checks whether the type is an interface that has the
5627 // [ComImport, CoClass] attributes and must be treated
5630 public Expression CheckComImport (EmitContext ec)
5632 if (!type.IsInterface)
5636 // Turn the call into:
5637 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5639 Type real_class = AttributeTester.GetCoClassAttribute (type);
5640 if (real_class == null)
5643 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5644 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5645 return cast.Resolve (ec);
5648 public override Expression DoResolve (EmitContext ec)
5651 // The New DoResolve might be called twice when initializing field
5652 // expressions (see EmitFieldInitializers, the call to
5653 // GetInitializerExpression will perform a resolve on the expression,
5654 // and later the assign will trigger another resolution
5656 // This leads to bugs (#37014)
5659 if (RequestedType is NewDelegate)
5660 return RequestedType;
5664 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5670 if (type == TypeManager.void_type) {
5671 Error_VoidInvalidInTheContext (loc);
5675 if (Arguments == null) {
5676 Expression c = Constantify (type);
5681 if (TypeManager.IsDelegateType (type)) {
5682 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5683 if (RequestedType != null)
5684 if (!(RequestedType is DelegateCreation))
5685 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5686 return RequestedType;
5690 if (type.IsGenericParameter) {
5691 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5693 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5694 Error (304, String.Format (
5695 "Cannot create an instance of the " +
5696 "variable type '{0}' because it " +
5697 "doesn't have the new() constraint",
5702 if ((Arguments != null) && (Arguments.Count != 0)) {
5703 Error (417, String.Format (
5704 "`{0}': cannot provide arguments " +
5705 "when creating an instance of a " +
5706 "variable type.", type));
5710 is_type_parameter = true;
5711 eclass = ExprClass.Value;
5716 if (type.IsAbstract && type.IsSealed) {
5717 Report.SymbolRelatedToPreviousError (type);
5718 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5722 if (type.IsInterface || type.IsAbstract){
5723 RequestedType = CheckComImport (ec);
5724 if (RequestedType != null)
5725 return RequestedType;
5727 Report.SymbolRelatedToPreviousError (type);
5728 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5732 bool is_struct = type.IsValueType;
5733 eclass = ExprClass.Value;
5736 // SRE returns a match for .ctor () on structs (the object constructor),
5737 // so we have to manually ignore it.
5739 if (is_struct && Arguments == null)
5742 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5743 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5744 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5749 MethodGroupExpr mg = ml as MethodGroupExpr;
5752 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5756 if (Arguments != null){
5757 foreach (Argument a in Arguments){
5758 if (!a.Resolve (ec, loc))
5763 method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
5764 if (method == null) {
5765 if (almostMatchedMembers.Count != 0)
5766 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5773 bool DoEmitTypeParameter (EmitContext ec)
5776 ILGenerator ig = ec.ig;
5778 ig.Emit (OpCodes.Ldtoken, type);
5779 ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5780 ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5781 ig.Emit (OpCodes.Unbox_Any, type);
5784 throw new InternalErrorException ();
5789 // This DoEmit can be invoked in two contexts:
5790 // * As a mechanism that will leave a value on the stack (new object)
5791 // * As one that wont (init struct)
5793 // You can control whether a value is required on the stack by passing
5794 // need_value_on_stack. The code *might* leave a value on the stack
5795 // so it must be popped manually
5797 // If we are dealing with a ValueType, we have a few
5798 // situations to deal with:
5800 // * The target is a ValueType, and we have been provided
5801 // the instance (this is easy, we are being assigned).
5803 // * The target of New is being passed as an argument,
5804 // to a boxing operation or a function that takes a
5807 // In this case, we need to create a temporary variable
5808 // that is the argument of New.
5810 // Returns whether a value is left on the stack
5812 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5814 bool is_value_type = TypeManager.IsValueType (type);
5815 ILGenerator ig = ec.ig;
5820 // Allow DoEmit() to be called multiple times.
5821 // We need to create a new LocalTemporary each time since
5822 // you can't share LocalBuilders among ILGeneators.
5823 if (!value_target_set)
5824 value_target = new LocalTemporary (type);
5826 ml = (IMemoryLocation) value_target;
5827 ml.AddressOf (ec, AddressOp.Store);
5831 Invocation.EmitArguments (ec, method, Arguments, false, null);
5835 ig.Emit (OpCodes.Initobj, type);
5837 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5838 if (need_value_on_stack){
5839 value_target.Emit (ec);
5844 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5849 public override void Emit (EmitContext ec)
5851 if (is_type_parameter)
5852 DoEmitTypeParameter (ec);
5857 public override void EmitStatement (EmitContext ec)
5859 if (is_type_parameter)
5860 throw new InvalidOperationException ();
5862 if (DoEmit (ec, false))
5863 ec.ig.Emit (OpCodes.Pop);
5866 public void AddressOf (EmitContext ec, AddressOp Mode)
5868 if (is_type_parameter)
5869 throw new InvalidOperationException ();
5871 if (!type.IsValueType){
5873 // We throw an exception. So far, I believe we only need to support
5875 // foreach (int j in new StructType ())
5878 throw new Exception ("AddressOf should not be used for classes");
5881 if (!value_target_set)
5882 value_target = new LocalTemporary (type);
5884 IMemoryLocation ml = (IMemoryLocation) value_target;
5885 ml.AddressOf (ec, AddressOp.Store);
5887 Invocation.EmitArguments (ec, method, Arguments, false, null);
5890 ec.ig.Emit (OpCodes.Initobj, type);
5892 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5894 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5899 /// 14.5.10.2: Represents an array creation expression.
5903 /// There are two possible scenarios here: one is an array creation
5904 /// expression that specifies the dimensions and optionally the
5905 /// initialization data and the other which does not need dimensions
5906 /// specified but where initialization data is mandatory.
5908 public class ArrayCreation : Expression {
5909 Expression requested_base_type;
5910 ArrayList initializers;
5913 // The list of Argument types.
5914 // This is used to construct the `newarray' or constructor signature
5916 ArrayList arguments;
5919 // Method used to create the array object.
5921 MethodBase new_method = null;
5923 Type array_element_type;
5924 Type underlying_type;
5925 bool is_one_dimensional = false;
5926 bool is_builtin_type = false;
5927 bool expect_initializers = false;
5928 int num_arguments = 0;
5932 ArrayList array_data;
5936 // The number of constants in array initializers
5937 int const_initializers_count;
5938 bool only_constant_initializers;
5940 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5942 this.requested_base_type = requested_base_type;
5943 this.initializers = initializers;
5947 arguments = new ArrayList ();
5949 foreach (Expression e in exprs) {
5950 arguments.Add (new Argument (e, Argument.AType.Expression));
5955 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5957 this.requested_base_type = requested_base_type;
5958 this.initializers = initializers;
5962 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5964 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5966 //dimensions = tmp.Length - 1;
5967 expect_initializers = true;
5970 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5972 StringBuilder sb = new StringBuilder (rank);
5975 for (int i = 1; i < idx_count; i++)
5980 return new ComposedCast (base_type, sb.ToString (), loc);
5983 void Error_IncorrectArrayInitializer ()
5985 Error (178, "Invalid rank specifier: expected `,' or `]'");
5988 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5990 if (specified_dims) {
5991 Argument a = (Argument) arguments [idx];
5993 if (!a.Resolve (ec, loc))
5996 Constant c = a.Expr as Constant;
5998 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
6002 Report.Error (150, a.Expr.Location, "A constant value is expected");
6006 int value = (int) c.GetValue ();
6008 if (value != probe.Count) {
6009 Error_IncorrectArrayInitializer ();
6013 bounds [idx] = value;
6016 int child_bounds = -1;
6017 only_constant_initializers = true;
6018 for (int i = 0; i < probe.Count; ++i) {
6019 object o = probe [i];
6020 if (o is ArrayList) {
6021 ArrayList sub_probe = o as ArrayList;
6022 int current_bounds = sub_probe.Count;
6024 if (child_bounds == -1)
6025 child_bounds = current_bounds;
6027 else if (child_bounds != current_bounds){
6028 Error_IncorrectArrayInitializer ();
6031 if (idx + 1 >= dimensions){
6032 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6036 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6040 if (child_bounds != -1){
6041 Error_IncorrectArrayInitializer ();
6045 Expression tmp = (Expression) o;
6046 tmp = tmp.Resolve (ec);
6050 Expression conv = Convert.ImplicitConversionRequired (
6051 ec, tmp, underlying_type, loc);
6056 // Initializers with the default values can be ignored
6057 Constant c = conv as Constant;
6059 if (c.IsDefaultInitializer (array_element_type)) {
6063 ++const_initializers_count;
6066 only_constant_initializers = false;
6069 array_data.Add (conv);
6076 public void UpdateIndices ()
6079 for (ArrayList probe = initializers; probe != null;) {
6080 if (probe.Count > 0 && probe [0] is ArrayList) {
6081 Expression e = new IntConstant (probe.Count, Location.Null);
6082 arguments.Add (new Argument (e, Argument.AType.Expression));
6084 bounds [i++] = probe.Count;
6086 probe = (ArrayList) probe [0];
6089 Expression e = new IntConstant (probe.Count, Location.Null);
6090 arguments.Add (new Argument (e, Argument.AType.Expression));
6092 bounds [i++] = probe.Count;
6099 bool ResolveInitializers (EmitContext ec)
6101 if (initializers == null) {
6102 return !expect_initializers;
6105 if (underlying_type == null)
6109 // We use this to store all the date values in the order in which we
6110 // will need to store them in the byte blob later
6112 array_data = new ArrayList ();
6113 bounds = new System.Collections.Specialized.HybridDictionary ();
6115 if (arguments != null)
6116 return CheckIndices (ec, initializers, 0, true);
6118 arguments = new ArrayList ();
6120 if (!CheckIndices (ec, initializers, 0, false))
6125 if (arguments.Count != dimensions) {
6126 Error_IncorrectArrayInitializer ();
6134 // Creates the type of the array
6136 bool LookupType (EmitContext ec)
6138 StringBuilder array_qualifier = new StringBuilder (rank);
6141 // `In the first form allocates an array instace of the type that results
6142 // from deleting each of the individual expression from the expression list'
6144 if (num_arguments > 0) {
6145 array_qualifier.Append ("[");
6146 for (int i = num_arguments-1; i > 0; i--)
6147 array_qualifier.Append (",");
6148 array_qualifier.Append ("]");
6154 TypeExpr array_type_expr;
6155 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6156 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6157 if (array_type_expr == null)
6160 type = array_type_expr.Type;
6161 underlying_type = TypeManager.GetElementType (type);
6162 dimensions = type.GetArrayRank ();
6167 public override Expression DoResolve (EmitContext ec)
6172 if (!LookupType (ec))
6175 array_element_type = TypeManager.GetElementType (type);
6176 if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6177 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6182 // First step is to validate the initializers and fill
6183 // in any missing bits
6185 if (!ResolveInitializers (ec))
6189 if (arguments == null)
6192 arg_count = arguments.Count;
6193 foreach (Argument a in arguments){
6194 if (!a.Resolve (ec, loc))
6197 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6198 if (real_arg == null)
6205 if (arg_count == 1) {
6206 is_one_dimensional = true;
6207 eclass = ExprClass.Value;
6211 is_builtin_type = TypeManager.IsBuiltinType (type);
6213 if (is_builtin_type) {
6216 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
6217 AllBindingFlags, loc);
6219 if (!(ml is MethodGroupExpr)) {
6220 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
6225 Error (-6, "New invocation: Can not find a constructor for " +
6226 "this argument list");
6230 new_method = Invocation.OverloadResolve (
6231 ec, (MethodGroupExpr) ml, arguments, false, loc);
6233 if (new_method == null) {
6234 Error (-6, "New invocation: Can not find a constructor for " +
6235 "this argument list");
6239 eclass = ExprClass.Value;
6242 ModuleBuilder mb = CodeGen.Module.Builder;
6243 ArrayList args = new ArrayList ();
6245 if (arguments != null) {
6246 for (int i = 0; i < arg_count; i++)
6247 args.Add (TypeManager.int32_type);
6250 Type [] arg_types = null;
6253 arg_types = new Type [args.Count];
6255 args.CopyTo (arg_types, 0);
6257 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6260 if (new_method == null) {
6261 Error (-6, "New invocation: Can not find a constructor for " +
6262 "this argument list");
6266 eclass = ExprClass.Value;
6271 byte [] MakeByteBlob ()
6276 int count = array_data.Count;
6278 if (underlying_type.IsEnum)
6279 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6281 factor = GetTypeSize (underlying_type);
6283 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6285 data = new byte [(count * factor + 4) & ~3];
6288 for (int i = 0; i < count; ++i) {
6289 object v = array_data [i];
6291 if (v is EnumConstant)
6292 v = ((EnumConstant) v).Child;
6294 if (v is Constant && !(v is StringConstant))
6295 v = ((Constant) v).GetValue ();
6301 if (underlying_type == TypeManager.int64_type){
6302 if (!(v is Expression)){
6303 long val = (long) v;
6305 for (int j = 0; j < factor; ++j) {
6306 data [idx + j] = (byte) (val & 0xFF);
6310 } else if (underlying_type == TypeManager.uint64_type){
6311 if (!(v is Expression)){
6312 ulong val = (ulong) v;
6314 for (int j = 0; j < factor; ++j) {
6315 data [idx + j] = (byte) (val & 0xFF);
6319 } else if (underlying_type == TypeManager.float_type) {
6320 if (!(v is Expression)){
6321 element = BitConverter.GetBytes ((float) v);
6323 for (int j = 0; j < factor; ++j)
6324 data [idx + j] = element [j];
6326 } else if (underlying_type == TypeManager.double_type) {
6327 if (!(v is Expression)){
6328 element = BitConverter.GetBytes ((double) v);
6330 for (int j = 0; j < factor; ++j)
6331 data [idx + j] = element [j];
6333 } else if (underlying_type == TypeManager.char_type){
6334 if (!(v is Expression)){
6335 int val = (int) ((char) v);
6337 data [idx] = (byte) (val & 0xff);
6338 data [idx+1] = (byte) (val >> 8);
6340 } else if (underlying_type == TypeManager.short_type){
6341 if (!(v is Expression)){
6342 int val = (int) ((short) v);
6344 data [idx] = (byte) (val & 0xff);
6345 data [idx+1] = (byte) (val >> 8);
6347 } else if (underlying_type == TypeManager.ushort_type){
6348 if (!(v is Expression)){
6349 int val = (int) ((ushort) v);
6351 data [idx] = (byte) (val & 0xff);
6352 data [idx+1] = (byte) (val >> 8);
6354 } else if (underlying_type == TypeManager.int32_type) {
6355 if (!(v is Expression)){
6358 data [idx] = (byte) (val & 0xff);
6359 data [idx+1] = (byte) ((val >> 8) & 0xff);
6360 data [idx+2] = (byte) ((val >> 16) & 0xff);
6361 data [idx+3] = (byte) (val >> 24);
6363 } else if (underlying_type == TypeManager.uint32_type) {
6364 if (!(v is Expression)){
6365 uint val = (uint) v;
6367 data [idx] = (byte) (val & 0xff);
6368 data [idx+1] = (byte) ((val >> 8) & 0xff);
6369 data [idx+2] = (byte) ((val >> 16) & 0xff);
6370 data [idx+3] = (byte) (val >> 24);
6372 } else if (underlying_type == TypeManager.sbyte_type) {
6373 if (!(v is Expression)){
6374 sbyte val = (sbyte) v;
6375 data [idx] = (byte) val;
6377 } else if (underlying_type == TypeManager.byte_type) {
6378 if (!(v is Expression)){
6379 byte val = (byte) v;
6380 data [idx] = (byte) val;
6382 } else if (underlying_type == TypeManager.bool_type) {
6383 if (!(v is Expression)){
6384 bool val = (bool) v;
6385 data [idx] = (byte) (val ? 1 : 0);
6387 } else if (underlying_type == TypeManager.decimal_type){
6388 if (!(v is Expression)){
6389 int [] bits = Decimal.GetBits ((decimal) v);
6392 // FIXME: For some reason, this doesn't work on the MS runtime.
6393 int [] nbits = new int [4];
6394 nbits [0] = bits [3];
6395 nbits [1] = bits [2];
6396 nbits [2] = bits [0];
6397 nbits [3] = bits [1];
6399 for (int j = 0; j < 4; j++){
6400 data [p++] = (byte) (nbits [j] & 0xff);
6401 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6402 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6403 data [p++] = (byte) (nbits [j] >> 24);
6407 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6416 // Emits the initializers for the array
6418 void EmitStaticInitializers (EmitContext ec)
6421 // First, the static data
6424 ILGenerator ig = ec.ig;
6426 byte [] data = MakeByteBlob ();
6428 fb = RootContext.MakeStaticData (data);
6430 ig.Emit (OpCodes.Dup);
6431 ig.Emit (OpCodes.Ldtoken, fb);
6432 ig.Emit (OpCodes.Call,
6433 TypeManager.void_initializearray_array_fieldhandle);
6437 // Emits pieces of the array that can not be computed at compile
6438 // time (variables and string locations).
6440 // This always expect the top value on the stack to be the array
6442 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6444 ILGenerator ig = ec.ig;
6445 int dims = bounds.Count;
6446 int [] current_pos = new int [dims];
6448 MethodInfo set = null;
6451 Type [] args = new Type [dims + 1];
6453 for (int j = 0; j < dims; j++)
6454 args [j] = TypeManager.int32_type;
6455 args [dims] = array_element_type;
6457 set = CodeGen.Module.Builder.GetArrayMethod (
6459 CallingConventions.HasThis | CallingConventions.Standard,
6460 TypeManager.void_type, args);
6463 for (int i = 0; i < array_data.Count; i++){
6465 Expression e = (Expression)array_data [i];
6467 // Constant can be initialized via StaticInitializer
6468 if (e != null && !(!emitConstants && e is Constant)) {
6469 Type etype = e.Type;
6471 ig.Emit (OpCodes.Dup);
6473 for (int idx = 0; idx < dims; idx++)
6474 IntConstant.EmitInt (ig, current_pos [idx]);
6477 // If we are dealing with a struct, get the
6478 // address of it, so we can store it.
6480 if ((dims == 1) && etype.IsValueType &&
6481 (!TypeManager.IsBuiltinOrEnum (etype) ||
6482 etype == TypeManager.decimal_type)) {
6487 // Let new know that we are providing
6488 // the address where to store the results
6490 n.DisableTemporaryValueType ();
6493 ig.Emit (OpCodes.Ldelema, etype);
6499 bool is_stobj, has_type_arg;
6500 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6502 ig.Emit (OpCodes.Stobj, etype);
6503 else if (has_type_arg)
6504 ig.Emit (op, etype);
6508 ig.Emit (OpCodes.Call, set);
6515 for (int j = dims - 1; j >= 0; j--){
6517 if (current_pos [j] < (int) bounds [j])
6519 current_pos [j] = 0;
6524 void EmitArrayArguments (EmitContext ec)
6526 ILGenerator ig = ec.ig;
6528 foreach (Argument a in arguments) {
6529 Type atype = a.Type;
6532 if (atype == TypeManager.uint64_type)
6533 ig.Emit (OpCodes.Conv_Ovf_U4);
6534 else if (atype == TypeManager.int64_type)
6535 ig.Emit (OpCodes.Conv_Ovf_I4);
6539 public override void Emit (EmitContext ec)
6541 ILGenerator ig = ec.ig;
6543 EmitArrayArguments (ec);
6544 if (is_one_dimensional)
6545 ig.Emit (OpCodes.Newarr, array_element_type);
6547 if (is_builtin_type)
6548 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6550 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6553 if (initializers == null)
6556 // Emit static initializer for arrays which have contain more than 4 items and
6557 // the static initializer will initialize at least 25% of array values.
6558 // NOTE: const_initializers_count does not contain default constant values.
6559 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6560 TypeManager.IsPrimitiveType (array_element_type)) {
6561 EmitStaticInitializers (ec);
6563 if (!only_constant_initializers)
6564 EmitDynamicInitializers (ec, false);
6566 EmitDynamicInitializers (ec, true);
6570 public override bool GetAttributableValue (Type valueType, out object value)
6572 if (!is_one_dimensional){
6573 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6574 return base.GetAttributableValue (null, out value);
6577 if (array_data == null) {
6578 Constant c = (Constant)((Argument)arguments [0]).Expr;
6579 if (c.IsDefaultValue) {
6580 value = Array.CreateInstance (array_element_type, 0);
6583 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6584 return base.GetAttributableValue (null, out value);
6587 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6588 object element_value;
6589 for (int i = 0; i < ret.Length; ++i)
6591 Expression e = (Expression)array_data [i];
6593 // Is null when an initializer is optimized (value == predefined value)
6597 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6601 ret.SetValue (element_value, i);
6608 public sealed class CompilerGeneratedThis : This
6610 public static This Instance = new CompilerGeneratedThis ();
6612 private CompilerGeneratedThis ()
6613 : base (Location.Null)
6617 public override Expression DoResolve (EmitContext ec)
6619 eclass = ExprClass.Variable;
6620 type = ec.ContainerType;
6621 variable = new SimpleThis (type);
6627 /// Represents the `this' construct
6630 public class This : VariableReference, IVariable
6633 VariableInfo variable_info;
6634 protected Variable variable;
6637 public This (Block block, Location loc)
6643 public This (Location loc)
6648 public VariableInfo VariableInfo {
6649 get { return variable_info; }
6652 public bool VerifyFixed ()
6654 return !TypeManager.IsValueType (Type);
6657 public override bool IsRef {
6658 get { return is_struct; }
6661 public override Variable Variable {
6662 get { return variable; }
6665 public bool ResolveBase (EmitContext ec)
6667 eclass = ExprClass.Variable;
6669 if (ec.TypeContainer.CurrentType != null)
6670 type = ec.TypeContainer.CurrentType;
6672 type = ec.ContainerType;
6674 is_struct = ec.TypeContainer is Struct;
6677 Error (26, "Keyword `this' is not valid in a static property, " +
6678 "static method, or static field initializer");
6682 if (block != null) {
6683 if (block.Toplevel.ThisVariable != null)
6684 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6686 AnonymousContainer am = ec.CurrentAnonymousMethod;
6687 if (is_struct && (am != null) && !am.IsIterator) {
6688 Report.Error (1673, loc, "Anonymous methods inside structs " +
6689 "cannot access instance members of `this'. " +
6690 "Consider copying `this' to a local variable " +
6691 "outside the anonymous method and using the " +
6696 RootScopeInfo host = block.Toplevel.RootScope;
6697 if ((host != null) && !ec.IsConstructor &&
6698 (!is_struct || host.IsIterator)) {
6699 variable = host.CaptureThis ();
6700 type = variable.Type;
6705 if (variable == null)
6706 variable = new SimpleThis (type);
6712 // Called from Invocation to check if the invocation is correct
6714 public bool CheckThisUsage (EmitContext ec)
6716 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6717 !variable_info.IsAssigned (ec)) {
6718 Error (188, "The `this' object cannot be used before all of its " +
6719 "fields are assigned to");
6720 variable_info.SetAssigned (ec);
6727 public override Expression DoResolve (EmitContext ec)
6729 if (!ResolveBase (ec))
6733 if (ec.IsFieldInitializer) {
6734 Error (27, "Keyword `this' is not available in the current context");
6741 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6743 if (!ResolveBase (ec))
6746 if (variable_info != null)
6747 variable_info.SetAssigned (ec);
6749 if (ec.TypeContainer is Class){
6750 Error (1604, "Cannot assign to 'this' because it is read-only");
6756 public override int GetHashCode()
6758 return block.GetHashCode ();
6761 public override bool Equals (object obj)
6763 This t = obj as This;
6767 return block == t.block;
6770 protected class SimpleThis : Variable
6774 public SimpleThis (Type type)
6779 public override Type Type {
6780 get { return type; }
6783 public override bool HasInstance {
6784 get { return false; }
6787 public override bool NeedsTemporary {
6788 get { return false; }
6791 public override void EmitInstance (EmitContext ec)
6796 public override void Emit (EmitContext ec)
6798 ec.ig.Emit (OpCodes.Ldarg_0);
6801 public override void EmitAssign (EmitContext ec)
6803 throw new InvalidOperationException ();
6806 public override void EmitAddressOf (EmitContext ec)
6808 ec.ig.Emit (OpCodes.Ldarg_0);
6814 /// Represents the `__arglist' construct
6816 public class ArglistAccess : Expression
6818 public ArglistAccess (Location loc)
6823 public override Expression DoResolve (EmitContext ec)
6825 eclass = ExprClass.Variable;
6826 type = TypeManager.runtime_argument_handle_type;
6828 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6830 Error (190, "The __arglist construct is valid only within " +
6831 "a variable argument method");
6838 public override void Emit (EmitContext ec)
6840 ec.ig.Emit (OpCodes.Arglist);
6845 /// Represents the `__arglist (....)' construct
6847 public class Arglist : Expression
6849 public readonly Argument[] Arguments;
6851 public Arglist (Argument[] args, Location l)
6857 public Type[] ArgumentTypes {
6859 Type[] retval = new Type [Arguments.Length];
6860 for (int i = 0; i < Arguments.Length; i++)
6861 retval [i] = Arguments [i].Type;
6866 public override Expression DoResolve (EmitContext ec)
6868 eclass = ExprClass.Variable;
6869 type = TypeManager.runtime_argument_handle_type;
6871 foreach (Argument arg in Arguments) {
6872 if (!arg.Resolve (ec, loc))
6879 public override void Emit (EmitContext ec)
6881 foreach (Argument arg in Arguments)
6887 // This produces the value that renders an instance, used by the iterators code
6889 public class ProxyInstance : Expression, IMemoryLocation {
6890 public override Expression DoResolve (EmitContext ec)
6892 eclass = ExprClass.Variable;
6893 type = ec.ContainerType;
6897 public override void Emit (EmitContext ec)
6899 ec.ig.Emit (OpCodes.Ldarg_0);
6903 public void AddressOf (EmitContext ec, AddressOp mode)
6905 ec.ig.Emit (OpCodes.Ldarg_0);
6910 /// Implements the typeof operator
6912 public class TypeOf : Expression {
6913 readonly Expression QueriedType;
6914 protected Type typearg;
6916 public TypeOf (Expression queried_type, Location l)
6918 QueriedType = queried_type;
6922 public override Expression DoResolve (EmitContext ec)
6924 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6928 typearg = texpr.Type;
6930 if (typearg == TypeManager.void_type) {
6931 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6935 if (typearg.IsPointer && !ec.InUnsafe){
6940 type = TypeManager.type_type;
6941 // Even though what is returned is a type object, it's treated as a value by the compiler.
6942 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6943 eclass = ExprClass.Value;
6947 public override void Emit (EmitContext ec)
6949 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6950 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6953 public override bool GetAttributableValue (Type valueType, out object value)
6955 if (TypeManager.ContainsGenericParameters (typearg)) {
6956 Report.SymbolRelatedToPreviousError(typearg);
6957 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6958 TypeManager.CSharpName(typearg));
6963 if (valueType == TypeManager.object_type) {
6964 value = (object)typearg;
6971 public Type TypeArgument
6981 /// Implements the `typeof (void)' operator
6983 public class TypeOfVoid : TypeOf {
6984 public TypeOfVoid (Location l) : base (null, l)
6989 public override Expression DoResolve (EmitContext ec)
6991 type = TypeManager.type_type;
6992 typearg = TypeManager.void_type;
6993 // See description in TypeOf.
6994 eclass = ExprClass.Value;
7000 /// Implements the sizeof expression
7002 public class SizeOf : Expression {
7003 public Expression QueriedType;
7006 public SizeOf (Expression queried_type, Location l)
7008 this.QueriedType = queried_type;
7012 public override Expression DoResolve (EmitContext ec)
7014 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7019 if (texpr is TypeParameterExpr){
7020 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
7025 type_queried = texpr.Type;
7026 if (type_queried.IsEnum)
7027 type_queried = TypeManager.EnumToUnderlying (type_queried);
7029 if (type_queried == TypeManager.void_type) {
7030 Expression.Error_VoidInvalidInTheContext (loc);
7034 int size_of = GetTypeSize (type_queried);
7036 return new IntConstant (size_of, loc);
7040 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)",
7041 TypeManager.CSharpName (type_queried));
7045 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7049 type = TypeManager.int32_type;
7050 eclass = ExprClass.Value;
7054 public override void Emit (EmitContext ec)
7056 int size = GetTypeSize (type_queried);
7059 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7061 IntConstant.EmitInt (ec.ig, size);
7066 /// Implements the qualified-alias-member (::) expression.
7068 public class QualifiedAliasMember : Expression
7070 string alias, identifier;
7072 public QualifiedAliasMember (string alias, string identifier, Location l)
7075 this.identifier = identifier;
7079 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7081 if (alias == "global")
7082 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
7084 int errors = Report.Errors;
7085 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7087 if (errors == Report.Errors)
7088 Report.Error (432, loc, "Alias `{0}' not found", alias);
7091 if (fne.eclass != ExprClass.Namespace) {
7093 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7096 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
7099 public override Expression DoResolve (EmitContext ec)
7101 FullNamedExpression fne;
7102 if (alias == "global") {
7103 fne = RootNamespace.Global;
7105 int errors = Report.Errors;
7106 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7108 if (errors == Report.Errors)
7109 Report.Error (432, loc, "Alias `{0}' not found", alias);
7114 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
7118 if (!(retval is FullNamedExpression)) {
7119 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
7123 // We defer this check till the end to match the behaviour of CSC
7124 if (fne.eclass != ExprClass.Namespace) {
7125 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7131 public override void Emit (EmitContext ec)
7133 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
7137 public override string ToString ()
7139 return alias + "::" + identifier;
7142 public override string GetSignatureForError ()
7149 /// Implements the member access expression
7151 public class MemberAccess : Expression {
7152 public readonly string Identifier;
7155 public MemberAccess (Expression expr, string id)
7156 : this (expr, id, expr.Location)
7160 public MemberAccess (Expression expr, string identifier, Location loc)
7163 Identifier = identifier;
7167 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7168 : this (expr, identifier, loc)
7175 public Expression Expr {
7176 get { return expr; }
7179 protected string LookupIdentifier {
7180 get { return MemberName.MakeName (Identifier, args); }
7183 // TODO: this method has very poor performace for Enum fields and
7184 // probably for other constants as well
7185 Expression DoResolve (EmitContext ec, Expression right_side)
7188 throw new Exception ();
7191 // Resolve the expression with flow analysis turned off, we'll do the definite
7192 // assignment checks later. This is because we don't know yet what the expression
7193 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7194 // definite assignment check on the actual field and not on the whole struct.
7197 SimpleName original = expr as SimpleName;
7198 Expression new_expr = expr.Resolve (ec,
7199 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7200 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7202 if (new_expr == null)
7205 if (new_expr is Namespace) {
7206 Namespace ns = (Namespace) new_expr;
7207 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7209 if ((retval != null) && (args != null))
7210 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
7214 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
7218 Type expr_type = new_expr.Type;
7219 if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
7220 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7223 if (expr_type == TypeManager.anonymous_method_type){
7224 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
7228 Constant c = new_expr as Constant;
7229 if (c != null && c.GetValue () == null) {
7230 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7231 "System.NullReferenceException");
7234 Expression member_lookup;
7235 member_lookup = MemberLookup (
7236 ec.ContainerType, expr_type, expr_type, Identifier, loc);
7238 if ((member_lookup == null) && (args != null)) {
7239 member_lookup = MemberLookup (
7240 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7243 if (member_lookup == null) {
7244 MemberLookupFailed (
7245 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
7249 TypeExpr texpr = member_lookup as TypeExpr;
7250 if (texpr != null) {
7251 if (!(new_expr is TypeExpr) &&
7252 (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
7253 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7254 Identifier, member_lookup.GetSignatureForError ());
7258 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7259 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7260 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7265 ConstructedType ct = new_expr as ConstructedType;
7268 // When looking up a nested type in a generic instance
7269 // via reflection, we always get a generic type definition
7270 // and not a generic instance - so we have to do this here.
7272 // See gtest-172-lib.cs and gtest-172.cs for an example.
7274 ct = new ConstructedType (
7275 member_lookup.Type, ct.TypeArguments, loc);
7277 return ct.ResolveAsTypeStep (ec, false);
7280 return member_lookup;
7283 MemberExpr me = (MemberExpr) member_lookup;
7284 member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
7285 if (member_lookup == null)
7289 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7291 throw new InternalErrorException ();
7293 return mg.ResolveGeneric (ec, args);
7296 if (original != null && !TypeManager.IsValueType (expr_type)) {
7297 me = member_lookup as MemberExpr;
7298 if (me != null && me.IsInstance) {
7299 LocalVariableReference var = new_expr as LocalVariableReference;
7300 if (var != null && !var.VerifyAssigned (ec))
7305 // The following DoResolve/DoResolveLValue will do the definite assignment
7308 if (right_side != null)
7309 return member_lookup.DoResolveLValue (ec, right_side);
7311 return member_lookup.DoResolve (ec);
7314 public override Expression DoResolve (EmitContext ec)
7316 return DoResolve (ec, null);
7319 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7321 return DoResolve (ec, right_side);
7324 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7326 return ResolveNamespaceOrType (ec, silent);
7329 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7331 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7333 if (new_expr == null)
7336 if (new_expr is Namespace) {
7337 Namespace ns = (Namespace) new_expr;
7338 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7340 if ((retval != null) && (args != null))
7341 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
7343 if (!silent && retval == null)
7344 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7348 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7349 if (tnew_expr == null)
7352 Type expr_type = tnew_expr.Type;
7354 if (expr_type.IsPointer){
7355 Error (23, "The `.' operator can not be applied to pointer operands (" +
7356 TypeManager.CSharpName (expr_type) + ")");
7360 Expression member_lookup = MemberLookup (
7361 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7362 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7363 if (member_lookup == null) {
7367 member_lookup = MemberLookup(
7368 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7369 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7371 if (member_lookup == null) {
7372 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7373 Identifier, new_expr.GetSignatureForError ());
7375 // TODO: Report.SymbolRelatedToPreviousError
7376 member_lookup.Error_UnexpectedKind (null, "type", loc);
7381 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7386 TypeArguments the_args = args;
7387 if (TypeManager.HasGenericArguments (expr_type)) {
7388 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7390 TypeArguments new_args = new TypeArguments (loc);
7391 foreach (Type decl in decl_args)
7392 new_args.Add (new TypeExpression (decl, loc));
7395 new_args.Add (args);
7397 the_args = new_args;
7400 if (the_args != null) {
7401 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7402 return ctype.ResolveAsTypeStep (rc, false);
7409 public override void Emit (EmitContext ec)
7411 throw new Exception ("Should not happen");
7414 public override string ToString ()
7416 return expr + "." + MemberName.MakeName (Identifier, args);
7419 public override string GetSignatureForError ()
7421 return expr.GetSignatureForError () + "." + Identifier;
7426 /// Implements checked expressions
7428 public class CheckedExpr : Expression {
7430 public Expression Expr;
7432 public CheckedExpr (Expression e, Location l)
7438 public override Expression DoResolve (EmitContext ec)
7440 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7441 Expr = Expr.Resolve (ec);
7446 if (Expr is Constant)
7449 eclass = Expr.eclass;
7454 public override void Emit (EmitContext ec)
7456 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7460 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7462 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7463 Expr.EmitBranchable (ec, target, onTrue);
7468 /// Implements the unchecked expression
7470 public class UnCheckedExpr : Expression {
7472 public Expression Expr;
7474 public UnCheckedExpr (Expression e, Location l)
7480 public override Expression DoResolve (EmitContext ec)
7482 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7483 Expr = Expr.Resolve (ec);
7488 if (Expr is Constant)
7491 eclass = Expr.eclass;
7496 public override void Emit (EmitContext ec)
7498 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7502 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7504 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7505 Expr.EmitBranchable (ec, target, onTrue);
7510 /// An Element Access expression.
7512 /// During semantic analysis these are transformed into
7513 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7515 public class ElementAccess : Expression {
7516 public ArrayList Arguments;
7517 public Expression Expr;
7519 public ElementAccess (Expression e, ArrayList e_list)
7528 Arguments = new ArrayList ();
7529 foreach (Expression tmp in e_list)
7530 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7534 bool CommonResolve (EmitContext ec)
7536 Expr = Expr.Resolve (ec);
7541 if (Arguments == null)
7544 foreach (Argument a in Arguments){
7545 if (!a.Resolve (ec, loc))
7552 Expression MakePointerAccess (EmitContext ec, Type t)
7554 if (t == TypeManager.void_ptr_type){
7555 Error (242, "The array index operation is not valid on void pointers");
7558 if (Arguments.Count != 1){
7559 Error (196, "A pointer must be indexed by only one value");
7564 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7567 return new Indirection (p, loc).Resolve (ec);
7570 public override Expression DoResolve (EmitContext ec)
7572 if (!CommonResolve (ec))
7576 // We perform some simple tests, and then to "split" the emit and store
7577 // code we create an instance of a different class, and return that.
7579 // I am experimenting with this pattern.
7583 if (t == TypeManager.array_type){
7584 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7589 return (new ArrayAccess (this, loc)).Resolve (ec);
7591 return MakePointerAccess (ec, Expr.Type);
7593 FieldExpr fe = Expr as FieldExpr;
7595 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7597 return MakePointerAccess (ec, ff.ElementType);
7600 return (new IndexerAccess (this, loc)).Resolve (ec);
7603 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7605 if (!CommonResolve (ec))
7610 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7613 return MakePointerAccess (ec, Expr.Type);
7615 FieldExpr fe = Expr as FieldExpr;
7617 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7619 if (!(fe.InstanceExpression is LocalVariableReference) &&
7620 !(fe.InstanceExpression is This)) {
7621 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7624 if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7625 Error (1666, "You cannot use fixed size 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){
7679 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7680 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7684 type = TypeManager.GetElementType (t);
7685 if (type.IsPointer && !ec.InUnsafe){
7686 UnsafeError (ea.Location);
7690 foreach (Argument a in ea.Arguments){
7691 Type argtype = a.Type;
7693 if (argtype == TypeManager.int32_type ||
7694 argtype == TypeManager.uint32_type ||
7695 argtype == TypeManager.int64_type ||
7696 argtype == TypeManager.uint64_type) {
7697 Constant c = a.Expr as Constant;
7698 if (c != null && c.IsNegative) {
7699 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7705 // Mhm. This is strage, because the Argument.Type is not the same as
7706 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7708 // Wonder if I will run into trouble for this.
7710 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7715 eclass = ExprClass.Variable;
7721 /// Emits the right opcode to load an object of Type `t'
7722 /// from an array of T
7724 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7726 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7727 ig.Emit (OpCodes.Ldelem_U1);
7728 else if (type == TypeManager.sbyte_type)
7729 ig.Emit (OpCodes.Ldelem_I1);
7730 else if (type == TypeManager.short_type)
7731 ig.Emit (OpCodes.Ldelem_I2);
7732 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7733 ig.Emit (OpCodes.Ldelem_U2);
7734 else if (type == TypeManager.int32_type)
7735 ig.Emit (OpCodes.Ldelem_I4);
7736 else if (type == TypeManager.uint32_type)
7737 ig.Emit (OpCodes.Ldelem_U4);
7738 else if (type == TypeManager.uint64_type)
7739 ig.Emit (OpCodes.Ldelem_I8);
7740 else if (type == TypeManager.int64_type)
7741 ig.Emit (OpCodes.Ldelem_I8);
7742 else if (type == TypeManager.float_type)
7743 ig.Emit (OpCodes.Ldelem_R4);
7744 else if (type == TypeManager.double_type)
7745 ig.Emit (OpCodes.Ldelem_R8);
7746 else if (type == TypeManager.intptr_type)
7747 ig.Emit (OpCodes.Ldelem_I);
7748 else if (TypeManager.IsEnumType (type)){
7749 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7750 } else if (type.IsValueType){
7751 ig.Emit (OpCodes.Ldelema, type);
7752 ig.Emit (OpCodes.Ldobj, type);
7754 } else if (type.IsGenericParameter) {
7756 ig.Emit (OpCodes.Ldelem, type);
7758 ig.Emit (OpCodes.Ldelem_Any, type);
7761 } else if (type.IsPointer)
7762 ig.Emit (OpCodes.Ldelem_I);
7764 ig.Emit (OpCodes.Ldelem_Ref);
7768 /// Returns the right opcode to store an object of Type `t'
7769 /// from an array of T.
7771 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7773 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7774 has_type_arg = false; is_stobj = false;
7775 t = TypeManager.TypeToCoreType (t);
7776 if (TypeManager.IsEnumType (t))
7777 t = TypeManager.EnumToUnderlying (t);
7778 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7779 t == TypeManager.bool_type)
7780 return OpCodes.Stelem_I1;
7781 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7782 t == TypeManager.char_type)
7783 return OpCodes.Stelem_I2;
7784 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7785 return OpCodes.Stelem_I4;
7786 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7787 return OpCodes.Stelem_I8;
7788 else if (t == TypeManager.float_type)
7789 return OpCodes.Stelem_R4;
7790 else if (t == TypeManager.double_type)
7791 return OpCodes.Stelem_R8;
7792 else if (t == TypeManager.intptr_type) {
7793 has_type_arg = true;
7795 return OpCodes.Stobj;
7796 } else if (t.IsValueType) {
7797 has_type_arg = true;
7799 return OpCodes.Stobj;
7801 } else if (t.IsGenericParameter) {
7802 has_type_arg = true;
7804 return OpCodes.Stelem;
7806 return OpCodes.Stelem_Any;
7810 } else if (t.IsPointer)
7811 return OpCodes.Stelem_I;
7813 return OpCodes.Stelem_Ref;
7816 MethodInfo FetchGetMethod ()
7818 ModuleBuilder mb = CodeGen.Module.Builder;
7819 int arg_count = ea.Arguments.Count;
7820 Type [] args = new Type [arg_count];
7823 for (int i = 0; i < arg_count; i++){
7824 //args [i++] = a.Type;
7825 args [i] = TypeManager.int32_type;
7828 get = mb.GetArrayMethod (
7829 ea.Expr.Type, "Get",
7830 CallingConventions.HasThis |
7831 CallingConventions.Standard,
7837 MethodInfo FetchAddressMethod ()
7839 ModuleBuilder mb = CodeGen.Module.Builder;
7840 int arg_count = ea.Arguments.Count;
7841 Type [] args = new Type [arg_count];
7845 ret_type = TypeManager.GetReferenceType (type);
7847 for (int i = 0; i < arg_count; i++){
7848 //args [i++] = a.Type;
7849 args [i] = TypeManager.int32_type;
7852 address = mb.GetArrayMethod (
7853 ea.Expr.Type, "Address",
7854 CallingConventions.HasThis |
7855 CallingConventions.Standard,
7862 // Load the array arguments into the stack.
7864 // If we have been requested to cache the values (cached_locations array
7865 // initialized), then load the arguments the first time and store them
7866 // in locals. otherwise load from local variables.
7868 void LoadArrayAndArguments (EmitContext ec)
7870 ILGenerator ig = ec.ig;
7873 foreach (Argument a in ea.Arguments){
7874 Type argtype = a.Expr.Type;
7878 if (argtype == TypeManager.int64_type)
7879 ig.Emit (OpCodes.Conv_Ovf_I);
7880 else if (argtype == TypeManager.uint64_type)
7881 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7885 public void Emit (EmitContext ec, bool leave_copy)
7887 int rank = ea.Expr.Type.GetArrayRank ();
7888 ILGenerator ig = ec.ig;
7891 LoadArrayAndArguments (ec);
7894 EmitLoadOpcode (ig, type);
7898 method = FetchGetMethod ();
7899 ig.Emit (OpCodes.Call, method);
7902 LoadFromPtr (ec.ig, this.type);
7905 ec.ig.Emit (OpCodes.Dup);
7906 temp = new LocalTemporary (this.type);
7911 public override void Emit (EmitContext ec)
7916 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7918 int rank = ea.Expr.Type.GetArrayRank ();
7919 ILGenerator ig = ec.ig;
7920 Type t = source.Type;
7921 prepared = prepare_for_load;
7923 if (prepare_for_load) {
7924 AddressOf (ec, AddressOp.LoadStore);
7925 ec.ig.Emit (OpCodes.Dup);
7928 ec.ig.Emit (OpCodes.Dup);
7929 temp = new LocalTemporary (this.type);
7932 StoreFromPtr (ec.ig, t);
7942 LoadArrayAndArguments (ec);
7945 bool is_stobj, has_type_arg;
7946 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7948 // The stobj opcode used by value types will need
7949 // an address on the stack, not really an array/array
7953 ig.Emit (OpCodes.Ldelema, t);
7957 ec.ig.Emit (OpCodes.Dup);
7958 temp = new LocalTemporary (this.type);
7963 ig.Emit (OpCodes.Stobj, t);
7964 else if (has_type_arg)
7969 ModuleBuilder mb = CodeGen.Module.Builder;
7970 int arg_count = ea.Arguments.Count;
7971 Type [] args = new Type [arg_count + 1];
7976 ec.ig.Emit (OpCodes.Dup);
7977 temp = new LocalTemporary (this.type);
7981 for (int i = 0; i < arg_count; i++){
7982 //args [i++] = a.Type;
7983 args [i] = TypeManager.int32_type;
7986 args [arg_count] = type;
7988 set = mb.GetArrayMethod (
7989 ea.Expr.Type, "Set",
7990 CallingConventions.HasThis |
7991 CallingConventions.Standard,
7992 TypeManager.void_type, args);
7994 ig.Emit (OpCodes.Call, set);
8003 public void AddressOf (EmitContext ec, AddressOp mode)
8005 int rank = ea.Expr.Type.GetArrayRank ();
8006 ILGenerator ig = ec.ig;
8008 LoadArrayAndArguments (ec);
8011 ig.Emit (OpCodes.Ldelema, type);
8013 MethodInfo address = FetchAddressMethod ();
8014 ig.Emit (OpCodes.Call, address);
8018 public void EmitGetLength (EmitContext ec, int dim)
8020 int rank = ea.Expr.Type.GetArrayRank ();
8021 ILGenerator ig = ec.ig;
8025 ig.Emit (OpCodes.Ldlen);
8026 ig.Emit (OpCodes.Conv_I4);
8028 IntLiteral.EmitInt (ig, dim);
8029 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8035 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
8036 public readonly ArrayList Properties;
8037 static Indexers empty;
8039 public struct Indexer {
8040 public readonly PropertyInfo PropertyInfo;
8041 public readonly MethodInfo Getter, Setter;
8043 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
8045 this.PropertyInfo = property_info;
8053 empty = new Indexers (null);
8056 Indexers (ArrayList array)
8061 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
8066 foreach (PropertyInfo property in mi){
8067 MethodInfo get, set;
8069 get = property.GetGetMethod (true);
8070 set = property.GetSetMethod (true);
8071 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
8073 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
8075 if (get != null || set != null) {
8077 ix = new Indexers (new ArrayList ());
8078 ix.Properties.Add (new Indexer (property, get, set));
8083 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8085 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8087 return TypeManager.MemberLookup (
8088 caller_type, caller_type, lookup_type, MemberTypes.Property,
8089 BindingFlags.Public | BindingFlags.Instance |
8090 BindingFlags.DeclaredOnly, p_name, null);
8093 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8095 Indexers ix = empty;
8098 if (lookup_type.IsGenericParameter) {
8099 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8103 if (gc.HasClassConstraint)
8104 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8106 Type[] ifaces = gc.InterfaceConstraints;
8107 foreach (Type itype in ifaces)
8108 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8114 Type copy = lookup_type;
8115 while (copy != TypeManager.object_type && copy != null){
8116 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8117 copy = copy.BaseType;
8120 if (lookup_type.IsInterface) {
8121 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8122 if (ifaces != null) {
8123 foreach (Type itype in ifaces)
8124 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8133 /// Expressions that represent an indexer call.
8135 public class IndexerAccess : Expression, IAssignMethod {
8137 // Points to our "data" repository
8139 MethodInfo get, set;
8140 ArrayList set_arguments;
8141 bool is_base_indexer;
8143 protected Type indexer_type;
8144 protected Type current_type;
8145 protected Expression instance_expr;
8146 protected ArrayList arguments;
8148 public IndexerAccess (ElementAccess ea, Location loc)
8149 : this (ea.Expr, false, loc)
8151 this.arguments = ea.Arguments;
8154 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8157 this.instance_expr = instance_expr;
8158 this.is_base_indexer = is_base_indexer;
8159 this.eclass = ExprClass.Value;
8163 protected virtual bool CommonResolve (EmitContext ec)
8165 indexer_type = instance_expr.Type;
8166 current_type = ec.ContainerType;
8171 public override Expression DoResolve (EmitContext ec)
8173 if (!CommonResolve (ec))
8177 // Step 1: Query for all `Item' *properties*. Notice
8178 // that the actual methods are pointed from here.
8180 // This is a group of properties, piles of them.
8182 ArrayList AllGetters = null;
8184 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8185 if (ilist.Properties != null) {
8186 AllGetters = new ArrayList(ilist.Properties.Count);
8187 foreach (Indexers.Indexer ix in ilist.Properties) {
8188 if (ix.Getter != null)
8189 AllGetters.Add (ix.Getter);
8193 if (AllGetters == null) {
8194 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8195 TypeManager.CSharpName (indexer_type));
8199 if (AllGetters.Count == 0) {
8200 // FIXME: we cannot simply select first one as the error message is missleading when
8201 // multiple indexers exist
8202 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
8203 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
8204 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
8208 get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
8209 arguments, false, loc);
8212 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8217 // Only base will allow this invocation to happen.
8219 if (get.IsAbstract && this is BaseIndexerAccess){
8220 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
8224 type = get.ReturnType;
8225 if (type.IsPointer && !ec.InUnsafe){
8230 instance_expr.CheckMarshalByRefAccess ();
8232 eclass = ExprClass.IndexerAccess;
8236 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8238 if (right_side == EmptyExpression.OutAccess) {
8239 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8240 GetSignatureForError ());
8244 // if the indexer returns a value type, and we try to set a field in it
8245 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8246 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
8247 GetSignatureForError ());
8251 ArrayList AllSetters = new ArrayList();
8252 if (!CommonResolve (ec))
8255 bool found_any = false, found_any_setters = false;
8257 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8258 if (ilist.Properties != null) {
8260 foreach (Indexers.Indexer ix in ilist.Properties) {
8261 if (ix.Setter != null)
8262 AllSetters.Add (ix.Setter);
8265 if (AllSetters.Count > 0) {
8266 found_any_setters = true;
8267 set_arguments = (ArrayList) arguments.Clone ();
8268 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8269 set = (MethodInfo) Invocation.OverloadResolve (
8270 ec, new MethodGroupExpr (AllSetters, loc),
8271 set_arguments, false, loc);
8275 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8276 TypeManager.CSharpName (indexer_type));
8280 if (!found_any_setters) {
8281 Error (154, "indexer can not be used in this context, because " +
8282 "it lacks a `set' accessor");
8287 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8292 // Only base will allow this invocation to happen.
8294 if (set.IsAbstract && this is BaseIndexerAccess){
8295 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
8300 // Now look for the actual match in the list of indexers to set our "return" type
8302 type = TypeManager.void_type; // default value
8303 foreach (Indexers.Indexer ix in ilist.Properties){
8304 if (ix.Setter == set){
8305 type = ix.PropertyInfo.PropertyType;
8310 instance_expr.CheckMarshalByRefAccess ();
8312 eclass = ExprClass.IndexerAccess;
8316 bool prepared = false;
8317 LocalTemporary temp;
8319 public void Emit (EmitContext ec, bool leave_copy)
8321 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8323 ec.ig.Emit (OpCodes.Dup);
8324 temp = new LocalTemporary (Type);
8330 // source is ignored, because we already have a copy of it from the
8331 // LValue resolution and we have already constructed a pre-cached
8332 // version of the arguments (ea.set_arguments);
8334 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8336 prepared = prepare_for_load;
8337 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8342 ec.ig.Emit (OpCodes.Dup);
8343 temp = new LocalTemporary (Type);
8346 } else if (leave_copy) {
8347 temp = new LocalTemporary (Type);
8353 Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8362 public override void Emit (EmitContext ec)
8367 public override string GetSignatureForError ()
8369 // FIXME: print the argument list of the indexer
8370 return instance_expr.GetSignatureForError () + ".this[...]";
8375 /// The base operator for method names
8377 public class BaseAccess : Expression {
8378 public readonly string Identifier;
8380 public BaseAccess (string member, Location l)
8382 this.Identifier = member;
8386 public BaseAccess (string member, TypeArguments args, Location l)
8394 public override Expression DoResolve (EmitContext ec)
8396 Expression c = CommonResolve (ec);
8402 // MethodGroups use this opportunity to flag an error on lacking ()
8404 if (!(c is MethodGroupExpr))
8405 return c.Resolve (ec);
8409 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8411 Expression c = CommonResolve (ec);
8417 // MethodGroups use this opportunity to flag an error on lacking ()
8419 if (! (c is MethodGroupExpr))
8420 return c.DoResolveLValue (ec, right_side);
8425 Expression CommonResolve (EmitContext ec)
8427 Expression member_lookup;
8428 Type current_type = ec.ContainerType;
8429 Type base_type = current_type.BaseType;
8432 Error (1511, "Keyword `base' is not available in a static method");
8436 if (ec.IsFieldInitializer){
8437 Error (1512, "Keyword `base' is not available in the current context");
8441 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8442 AllMemberTypes, AllBindingFlags, loc);
8443 if (member_lookup == null) {
8444 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8451 left = new TypeExpression (base_type, loc);
8453 left = ec.GetThis (loc);
8455 MemberExpr me = (MemberExpr) member_lookup;
8457 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8459 if (e is PropertyExpr) {
8460 PropertyExpr pe = (PropertyExpr) e;
8465 MethodGroupExpr mg = e as MethodGroupExpr;
8471 return mg.ResolveGeneric (ec, args);
8473 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8481 public override void Emit (EmitContext ec)
8483 throw new Exception ("Should never be called");
8488 /// The base indexer operator
8490 public class BaseIndexerAccess : IndexerAccess {
8491 public BaseIndexerAccess (ArrayList args, Location loc)
8492 : base (null, true, loc)
8494 arguments = new ArrayList ();
8495 foreach (Expression tmp in args)
8496 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8499 protected override bool CommonResolve (EmitContext ec)
8501 instance_expr = ec.GetThis (loc);
8503 current_type = ec.ContainerType.BaseType;
8504 indexer_type = current_type;
8506 foreach (Argument a in arguments){
8507 if (!a.Resolve (ec, loc))
8516 /// This class exists solely to pass the Type around and to be a dummy
8517 /// that can be passed to the conversion functions (this is used by
8518 /// foreach implementation to typecast the object return value from
8519 /// get_Current into the proper type. All code has been generated and
8520 /// we only care about the side effect conversions to be performed
8522 /// This is also now used as a placeholder where a no-action expression
8523 /// is needed (the `New' class).
8525 public class EmptyExpression : Expression {
8526 public static readonly EmptyExpression Null = new EmptyExpression ();
8528 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8529 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8530 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8532 static EmptyExpression temp = new EmptyExpression ();
8533 public static EmptyExpression Grab ()
8535 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8540 public static void Release (EmptyExpression e)
8545 // TODO: should be protected
8546 public EmptyExpression ()
8548 type = TypeManager.object_type;
8549 eclass = ExprClass.Value;
8550 loc = Location.Null;
8553 public EmptyExpression (Type t)
8556 eclass = ExprClass.Value;
8557 loc = Location.Null;
8560 public override Expression DoResolve (EmitContext ec)
8565 public override void Emit (EmitContext ec)
8567 // nothing, as we only exist to not do anything.
8571 // This is just because we might want to reuse this bad boy
8572 // instead of creating gazillions of EmptyExpressions.
8573 // (CanImplicitConversion uses it)
8575 public void SetType (Type t)
8581 public class UserCast : Expression {
8585 public UserCast (MethodInfo method, Expression source, Location l)
8587 this.method = method;
8588 this.source = source;
8589 type = method.ReturnType;
8590 eclass = ExprClass.Value;
8594 public Expression Source {
8600 public override Expression DoResolve (EmitContext ec)
8603 // We are born fully resolved
8608 public override void Emit (EmitContext ec)
8610 ILGenerator ig = ec.ig;
8614 if (method is MethodInfo)
8615 ig.Emit (OpCodes.Call, (MethodInfo) method);
8617 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8623 // This class is used to "construct" the type during a typecast
8624 // operation. Since the Type.GetType class in .NET can parse
8625 // the type specification, we just use this to construct the type
8626 // one bit at a time.
8628 public class ComposedCast : TypeExpr {
8632 public ComposedCast (Expression left, string dim)
8633 : this (left, dim, left.Location)
8637 public ComposedCast (Expression left, string dim, Location l)
8645 public Expression RemoveNullable ()
8647 if (dim.EndsWith ("?")) {
8648 dim = dim.Substring (0, dim.Length - 1);
8657 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8659 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8663 Type ltype = lexpr.Type;
8664 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8665 Error_VoidInvalidInTheContext (loc);
8670 if ((dim.Length > 0) && (dim [0] == '?')) {
8671 TypeExpr nullable = new NullableType (left, loc);
8673 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8674 return nullable.ResolveAsTypeTerminal (ec, false);
8678 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8681 if (dim != "" && dim [0] == '[' &&
8682 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8683 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8688 type = TypeManager.GetConstructedType (ltype, dim);
8693 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8695 if (type.IsPointer && !ec.IsInUnsafeScope){
8700 eclass = ExprClass.Type;
8704 public override string Name {
8705 get { return left + dim; }
8708 public override string FullName {
8709 get { return type.FullName; }
8712 public override string GetSignatureForError ()
8714 return left.GetSignatureForError () + dim;
8718 public class FixedBufferPtr : Expression {
8721 public FixedBufferPtr (Expression array, Type array_type, Location l)
8726 type = TypeManager.GetPointerType (array_type);
8727 eclass = ExprClass.Value;
8730 public override void Emit(EmitContext ec)
8735 public override Expression DoResolve (EmitContext ec)
8738 // We are born fully resolved
8746 // This class is used to represent the address of an array, used
8747 // only by the Fixed statement, this generates "&a [0]" construct
8748 // for fixed (char *pa = a)
8750 public class ArrayPtr : FixedBufferPtr {
8753 public ArrayPtr (Expression array, Type array_type, Location l):
8754 base (array, array_type, l)
8756 this.array_type = array_type;
8759 public override void Emit (EmitContext ec)
8763 ILGenerator ig = ec.ig;
8764 IntLiteral.EmitInt (ig, 0);
8765 ig.Emit (OpCodes.Ldelema, array_type);
8770 // Used by the fixed statement
8772 public class StringPtr : Expression {
8775 public StringPtr (LocalBuilder b, Location l)
8778 eclass = ExprClass.Value;
8779 type = TypeManager.char_ptr_type;
8783 public override Expression DoResolve (EmitContext ec)
8785 // This should never be invoked, we are born in fully
8786 // initialized state.
8791 public override void Emit (EmitContext ec)
8793 ILGenerator ig = ec.ig;
8795 ig.Emit (OpCodes.Ldloc, b);
8796 ig.Emit (OpCodes.Conv_I);
8797 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8798 ig.Emit (OpCodes.Add);
8803 // Implements the `stackalloc' keyword
8805 public class StackAlloc : Expression {
8810 public StackAlloc (Expression type, Expression count, Location l)
8817 public override Expression DoResolve (EmitContext ec)
8819 count = count.Resolve (ec);
8823 if (count.Type != TypeManager.int32_type){
8824 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8829 Constant c = count as Constant;
8830 if (c != null && c.IsNegative) {
8831 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8835 if (ec.InCatch || ec.InFinally) {
8836 Error (255, "Cannot use stackalloc in finally or catch");
8840 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8846 if (!TypeManager.VerifyUnManaged (otype, loc))
8849 type = TypeManager.GetPointerType (otype);
8850 eclass = ExprClass.Value;
8855 public override void Emit (EmitContext ec)
8857 int size = GetTypeSize (otype);
8858 ILGenerator ig = ec.ig;
8861 ig.Emit (OpCodes.Sizeof, otype);
8863 IntConstant.EmitInt (ig, size);
8865 ig.Emit (OpCodes.Mul);
8866 ig.Emit (OpCodes.Localloc);