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)
61 args = new ArrayList (1);
62 Argument a = new Argument (e, Argument.AType.Expression);
64 // We need to resolve the arguments before sending them in !
65 if (!a.Resolve (ec, loc))
69 mg = mg.OverloadResolve (ec, args, false, loc);
74 return new StaticCallExpr ((MethodInfo) mg, args, loc);
77 public override void EmitStatement (EmitContext ec)
80 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
81 ec.ig.Emit (OpCodes.Pop);
84 public MethodInfo Method {
89 public class ParenthesizedExpression : Expression
91 public Expression Expr;
93 public ParenthesizedExpression (Expression expr)
98 public override Expression DoResolve (EmitContext ec)
100 Expr = Expr.Resolve (ec);
104 public override void Emit (EmitContext ec)
106 throw new Exception ("Should not happen");
109 public override Location Location
112 return Expr.Location;
116 protected override void CloneTo (CloneContext clonectx, Expression t)
118 ParenthesizedExpression target = (ParenthesizedExpression) t;
120 target.Expr = Expr.Clone (clonectx);
125 /// Unary expressions.
129 /// Unary implements unary expressions. It derives from
130 /// ExpressionStatement becuase the pre/post increment/decrement
131 /// operators can be used in a statement context.
133 public class Unary : Expression {
134 public enum Operator : byte {
135 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
136 Indirection, AddressOf, TOP
139 public readonly Operator Oper;
140 public Expression Expr;
142 public Unary (Operator op, Expression expr, Location loc)
150 /// Returns a stringified representation of the Operator
152 static public string OperName (Operator oper)
155 case Operator.UnaryPlus:
157 case Operator.UnaryNegation:
159 case Operator.LogicalNot:
161 case Operator.OnesComplement:
163 case Operator.AddressOf:
165 case Operator.Indirection:
169 return oper.ToString ();
172 public static readonly string [] oper_names;
176 oper_names = new string [(int)Operator.TOP];
178 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
179 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
180 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
181 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
182 oper_names [(int) Operator.Indirection] = "op_Indirection";
183 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
186 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
188 Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
191 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
193 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
197 void Error23 (Type t)
199 Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
203 // This routine will attempt to simplify the unary expression when the
204 // argument is a constant.
206 Constant TryReduceConstant (EmitContext ec, Constant e)
208 Type expr_type = e.Type;
211 case Operator.UnaryPlus:
212 // Unary numeric promotions
213 if (expr_type == TypeManager.byte_type)
214 return new IntConstant (((ByteConstant)e).Value, e.Location);
215 if (expr_type == TypeManager.sbyte_type)
216 return new IntConstant (((SByteConstant)e).Value, e.Location);
217 if (expr_type == TypeManager.short_type)
218 return new IntConstant (((ShortConstant)e).Value, e.Location);
219 if (expr_type == TypeManager.ushort_type)
220 return new IntConstant (((UShortConstant)e).Value, e.Location);
221 if (expr_type == TypeManager.char_type)
222 return new IntConstant (((CharConstant)e).Value, e.Location);
224 // Predefined operators
225 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
226 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
227 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
228 expr_type == TypeManager.decimal_type)
235 case Operator.UnaryNegation:
236 // Unary numeric promotions
237 if (expr_type == TypeManager.byte_type)
238 return new IntConstant (-((ByteConstant)e).Value, e.Location);
239 if (expr_type == TypeManager.sbyte_type)
240 return new IntConstant (-((SByteConstant)e).Value, e.Location);
241 if (expr_type == TypeManager.short_type)
242 return new IntConstant (-((ShortConstant)e).Value, e.Location);
243 if (expr_type == TypeManager.ushort_type)
244 return new IntConstant (-((UShortConstant)e).Value, e.Location);
245 if (expr_type == TypeManager.char_type)
246 return new IntConstant (-((CharConstant)e).Value, e.Location);
248 // Predefined operators
249 if (expr_type == TypeManager.int32_type) {
250 int value = ((IntConstant)e).Value;
251 if (value == int.MinValue) {
252 if (ec.ConstantCheckState) {
253 ConstantFold.Error_CompileTimeOverflow (loc);
258 return new IntConstant (-value, e.Location);
260 if (expr_type == TypeManager.int64_type) {
261 long value = ((LongConstant)e).Value;
262 if (value == long.MinValue) {
263 if (ec.ConstantCheckState) {
264 ConstantFold.Error_CompileTimeOverflow (loc);
269 return new LongConstant (-value, e.Location);
272 if (expr_type == TypeManager.uint32_type) {
273 UIntLiteral uil = e as UIntLiteral;
275 if (uil.Value == 2147483648)
276 return new IntLiteral (int.MinValue, e.Location);
277 return new LongLiteral (-uil.Value, e.Location);
279 return new LongConstant (-((UIntConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.uint64_type) {
283 ULongLiteral ull = e as ULongLiteral;
284 if (ull != null && ull.Value == 9223372036854775808)
285 return new LongLiteral (long.MinValue, e.Location);
289 if (expr_type == TypeManager.float_type) {
290 FloatLiteral fl = e as FloatLiteral;
291 // For better error reporting
293 fl.Value = -fl.Value;
296 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
298 if (expr_type == TypeManager.double_type) {
299 DoubleLiteral dl = e as DoubleLiteral;
300 // For better error reporting
302 dl.Value = -dl.Value;
306 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
308 if (expr_type == TypeManager.decimal_type)
309 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
313 case Operator.LogicalNot:
314 if (expr_type != TypeManager.bool_type)
317 BoolConstant b = (BoolConstant) e;
318 return new BoolConstant (!(b.Value), b.Location);
320 case Operator.OnesComplement:
321 // Unary numeric promotions
322 if (expr_type == TypeManager.byte_type)
323 return new IntConstant (~((ByteConstant)e).Value, e.Location);
324 if (expr_type == TypeManager.sbyte_type)
325 return new IntConstant (~((SByteConstant)e).Value, e.Location);
326 if (expr_type == TypeManager.short_type)
327 return new IntConstant (~((ShortConstant)e).Value, e.Location);
328 if (expr_type == TypeManager.ushort_type)
329 return new IntConstant (~((UShortConstant)e).Value, e.Location);
330 if (expr_type == TypeManager.char_type)
331 return new IntConstant (~((CharConstant)e).Value, e.Location);
333 // Predefined operators
334 if (expr_type == TypeManager.int32_type)
335 return new IntConstant (~((IntConstant)e).Value, e.Location);
336 if (expr_type == TypeManager.uint32_type)
337 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
338 if (expr_type == TypeManager.int64_type)
339 return new LongConstant (~((LongConstant)e).Value, e.Location);
340 if (expr_type == TypeManager.uint64_type){
341 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
343 if (e is EnumConstant) {
344 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
346 e = new EnumConstant (e, expr_type);
351 case Operator.AddressOf:
354 case Operator.Indirection:
357 throw new Exception ("Can not constant fold: " + Oper.ToString());
360 Expression ResolveOperator (EmitContext ec)
363 // Step 1: Default operations on CLI native types.
366 // Attempt to use a constant folding operation.
367 Constant cexpr = Expr as Constant;
369 cexpr = TryReduceConstant (ec, cexpr);
376 // Step 2: Perform Operator Overload location
378 Type expr_type = Expr.Type;
379 string op_name = oper_names [(int) Oper];
381 Expression mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
383 Expression e = StaticCallExpr.MakeSimpleCall (
384 ec, (MethodGroupExpr) mg, Expr, loc);
395 case Operator.LogicalNot:
396 if (expr_type != TypeManager.bool_type) {
397 Expr = ResolveBoolean (ec, Expr, loc);
404 type = TypeManager.bool_type;
407 case Operator.OnesComplement:
408 // Unary numeric promotions
409 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
410 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
411 expr_type == TypeManager.char_type)
413 type = TypeManager.int32_type;
414 return EmptyCast.Create (this, type);
417 // Predefined operators
418 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
419 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
420 TypeManager.IsEnumType (expr_type))
426 type = TypeManager.int32_type;
427 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
434 case Operator.AddressOf:
440 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
444 IVariable variable = Expr as IVariable;
445 bool is_fixed = variable != null && variable.VerifyFixed ();
447 if (!ec.InFixedInitializer && !is_fixed) {
448 Error (212, "You can only take the address of unfixed expression inside " +
449 "of a fixed statement initializer");
453 if (ec.InFixedInitializer && is_fixed) {
454 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
458 LocalVariableReference lr = Expr as LocalVariableReference;
460 if (lr.local_info.IsCaptured){
461 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
464 lr.local_info.AddressTaken = true;
465 lr.local_info.Used = true;
468 ParameterReference pr = Expr as ParameterReference;
469 if ((pr != null) && pr.Parameter.IsCaptured) {
470 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
474 // According to the specs, a variable is considered definitely assigned if you take
476 if ((variable != null) && (variable.VariableInfo != null)){
477 variable.VariableInfo.SetAssigned (ec);
480 type = TypeManager.GetPointerType (Expr.Type);
483 case Operator.Indirection:
489 if (!expr_type.IsPointer){
490 Error (193, "The * or -> operator must be applied to a pointer");
495 // We create an Indirection expression, because
496 // it can implement the IMemoryLocation.
498 return new Indirection (Expr, loc);
500 case Operator.UnaryPlus:
501 // Unary numeric promotions
502 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
503 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
504 expr_type == TypeManager.char_type)
506 return EmptyCast.Create (Expr, TypeManager.int32_type);
509 // Predefined operators
510 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
511 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
512 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
513 expr_type == TypeManager.decimal_type)
518 Expr = Convert.ImplicitUserConversion(ec, Expr, TypeManager.int32_type, loc);
520 // Because we can completely ignore unary +
527 case Operator.UnaryNegation:
529 // transform - - expr into expr
531 Unary u = Expr as Unary;
532 if (u != null && u.Oper == Operator.UnaryNegation) {
536 // Unary numeric promotions
537 if (expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
538 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
539 expr_type == TypeManager.char_type)
541 type = TypeManager.int32_type;
542 return EmptyCast.Create (this, type);
546 // Predefined operators
548 if (expr_type == TypeManager.uint32_type) {
549 type = TypeManager.int64_type;
550 Expr = Convert.ImplicitNumericConversion (Expr, type);
554 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.int64_type ||
555 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
556 expr_type == TypeManager.decimal_type)
565 type = TypeManager.int32_type;
566 Expr = Convert.ImplicitUserConversion(ec, Expr, type, loc);
574 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
575 TypeManager.CSharpName (expr_type) + "'");
579 public override Expression DoResolve (EmitContext ec)
581 if (Oper == Operator.AddressOf) {
582 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
584 if (Expr == null || Expr.eclass != ExprClass.Variable){
585 Error (211, "Cannot take the address of the given expression");
590 Expr = Expr.Resolve (ec);
596 if (TypeManager.IsNullableValueType (Expr.Type))
597 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
600 eclass = ExprClass.Value;
601 return ResolveOperator (ec);
604 public override Expression DoResolveLValue (EmitContext ec, Expression right)
606 if (Oper == Operator.Indirection)
607 return DoResolve (ec);
612 public override void Emit (EmitContext ec)
614 ILGenerator ig = ec.ig;
617 case Operator.UnaryPlus:
618 throw new Exception ("This should be caught by Resolve");
620 case Operator.UnaryNegation:
621 if (ec.CheckState && type != TypeManager.float_type && type != TypeManager.double_type) {
622 ig.Emit (OpCodes.Ldc_I4_0);
623 if (type == TypeManager.int64_type)
624 ig.Emit (OpCodes.Conv_U8);
626 ig.Emit (OpCodes.Sub_Ovf);
629 ig.Emit (OpCodes.Neg);
634 case Operator.LogicalNot:
636 ig.Emit (OpCodes.Ldc_I4_0);
637 ig.Emit (OpCodes.Ceq);
640 case Operator.OnesComplement:
642 ig.Emit (OpCodes.Not);
645 case Operator.AddressOf:
646 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
650 throw new Exception ("This should not happen: Operator = "
655 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
657 if (Oper == Operator.LogicalNot)
658 Expr.EmitBranchable (ec, target, !onTrue);
660 base.EmitBranchable (ec, target, onTrue);
663 public override string ToString ()
665 return "Unary (" + Oper + ", " + Expr + ")";
668 protected override void CloneTo (CloneContext clonectx, Expression t)
670 Unary target = (Unary) t;
672 target.Expr = Expr.Clone (clonectx);
677 // Unary operators are turned into Indirection expressions
678 // after semantic analysis (this is so we can take the address
679 // of an indirection).
681 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
683 LocalTemporary temporary;
686 public Indirection (Expression expr, Location l)
689 type = TypeManager.HasElementType (expr.Type) ? TypeManager.GetElementType (expr.Type) : expr.Type;
690 eclass = ExprClass.Variable;
694 public override void Emit (EmitContext ec)
699 LoadFromPtr (ec.ig, Type);
702 public void Emit (EmitContext ec, bool leave_copy)
706 ec.ig.Emit (OpCodes.Dup);
707 temporary = new LocalTemporary (expr.Type);
708 temporary.Store (ec);
712 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
714 prepared = prepare_for_load;
718 if (prepare_for_load)
719 ec.ig.Emit (OpCodes.Dup);
723 ec.ig.Emit (OpCodes.Dup);
724 temporary = new LocalTemporary (expr.Type);
725 temporary.Store (ec);
728 StoreFromPtr (ec.ig, type);
730 if (temporary != null) {
732 temporary.Release (ec);
736 public void AddressOf (EmitContext ec, AddressOp Mode)
741 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
743 return DoResolve (ec);
746 public override Expression DoResolve (EmitContext ec)
749 // Born fully resolved
754 public override string ToString ()
756 return "*(" + expr + ")";
759 #region IVariable Members
761 public VariableInfo VariableInfo {
765 public bool VerifyFixed ()
767 // A pointer-indirection is always fixed.
775 /// Unary Mutator expressions (pre and post ++ and --)
779 /// UnaryMutator implements ++ and -- expressions. It derives from
780 /// ExpressionStatement becuase the pre/post increment/decrement
781 /// operators can be used in a statement context.
783 /// FIXME: Idea, we could split this up in two classes, one simpler
784 /// for the common case, and one with the extra fields for more complex
785 /// classes (indexers require temporary access; overloaded require method)
788 public class UnaryMutator : ExpressionStatement {
790 public enum Mode : byte {
797 PreDecrement = IsDecrement,
798 PostIncrement = IsPost,
799 PostDecrement = IsPost | IsDecrement
803 bool is_expr = false;
804 bool recurse = false;
809 // This is expensive for the simplest case.
811 StaticCallExpr method;
813 public UnaryMutator (Mode m, Expression e, Location l)
820 static string OperName (Mode mode)
822 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
827 /// Returns whether an object of type `t' can be incremented
828 /// or decremented with add/sub (ie, basically whether we can
829 /// use pre-post incr-decr operations on it, but it is not a
830 /// System.Decimal, which we require operator overloading to catch)
832 static bool IsIncrementableNumber (Type t)
834 return (t == TypeManager.sbyte_type) ||
835 (t == TypeManager.byte_type) ||
836 (t == TypeManager.short_type) ||
837 (t == TypeManager.ushort_type) ||
838 (t == TypeManager.int32_type) ||
839 (t == TypeManager.uint32_type) ||
840 (t == TypeManager.int64_type) ||
841 (t == TypeManager.uint64_type) ||
842 (t == TypeManager.char_type) ||
843 (t.IsSubclassOf (TypeManager.enum_type)) ||
844 (t == TypeManager.float_type) ||
845 (t == TypeManager.double_type) ||
846 (t.IsPointer && t != TypeManager.void_ptr_type);
849 Expression ResolveOperator (EmitContext ec)
851 Type expr_type = expr.Type;
854 // Step 1: Perform Operator Overload location
859 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
860 op_name = "op_Increment";
862 op_name = "op_Decrement";
864 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
867 method = StaticCallExpr.MakeSimpleCall (
868 ec, (MethodGroupExpr) mg, expr, loc);
871 } else if (!IsIncrementableNumber (expr_type)) {
872 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
873 TypeManager.CSharpName (expr_type) + "'");
878 // The operand of the prefix/postfix increment decrement operators
879 // should be an expression that is classified as a variable,
880 // a property access or an indexer access
883 if (expr.eclass == ExprClass.Variable){
884 LocalVariableReference var = expr as LocalVariableReference;
885 if ((var != null) && var.IsReadOnly) {
886 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
889 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
890 expr = expr.ResolveLValue (ec, this, Location);
894 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
901 public override Expression DoResolve (EmitContext ec)
903 expr = expr.Resolve (ec);
908 eclass = ExprClass.Value;
911 if (TypeManager.IsNullableValueType (expr.Type))
912 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
915 return ResolveOperator (ec);
918 static int PtrTypeSize (Type t)
920 return GetTypeSize (TypeManager.GetElementType (t));
924 // Loads the proper "1" into the stack based on the type, then it emits the
925 // opcode for the operation requested
927 void LoadOneAndEmitOp (EmitContext ec, Type t)
930 // Measure if getting the typecode and using that is more/less efficient
931 // that comparing types. t.GetTypeCode() is an internal call.
933 ILGenerator ig = ec.ig;
935 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
936 LongConstant.EmitLong (ig, 1);
937 else if (t == TypeManager.double_type)
938 ig.Emit (OpCodes.Ldc_R8, 1.0);
939 else if (t == TypeManager.float_type)
940 ig.Emit (OpCodes.Ldc_R4, 1.0F);
941 else if (t.IsPointer){
942 int n = PtrTypeSize (t);
945 ig.Emit (OpCodes.Sizeof, t);
947 IntConstant.EmitInt (ig, n);
949 ig.Emit (OpCodes.Ldc_I4_1);
952 // Now emit the operation
955 if (t == TypeManager.int32_type ||
956 t == TypeManager.int64_type){
957 if ((mode & Mode.IsDecrement) != 0)
958 ig.Emit (OpCodes.Sub_Ovf);
960 ig.Emit (OpCodes.Add_Ovf);
961 } else if (t == TypeManager.uint32_type ||
962 t == TypeManager.uint64_type){
963 if ((mode & Mode.IsDecrement) != 0)
964 ig.Emit (OpCodes.Sub_Ovf_Un);
966 ig.Emit (OpCodes.Add_Ovf_Un);
968 if ((mode & Mode.IsDecrement) != 0)
969 ig.Emit (OpCodes.Sub_Ovf);
971 ig.Emit (OpCodes.Add_Ovf);
974 if ((mode & Mode.IsDecrement) != 0)
975 ig.Emit (OpCodes.Sub);
977 ig.Emit (OpCodes.Add);
980 if (t == TypeManager.sbyte_type){
982 ig.Emit (OpCodes.Conv_Ovf_I1);
984 ig.Emit (OpCodes.Conv_I1);
985 } else if (t == TypeManager.byte_type){
987 ig.Emit (OpCodes.Conv_Ovf_U1);
989 ig.Emit (OpCodes.Conv_U1);
990 } else if (t == TypeManager.short_type){
992 ig.Emit (OpCodes.Conv_Ovf_I2);
994 ig.Emit (OpCodes.Conv_I2);
995 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
997 ig.Emit (OpCodes.Conv_Ovf_U2);
999 ig.Emit (OpCodes.Conv_U2);
1004 void EmitCode (EmitContext ec, bool is_expr)
1007 this.is_expr = is_expr;
1008 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1011 public override void Emit (EmitContext ec)
1014 // We use recurse to allow ourselfs to be the source
1015 // of an assignment. This little hack prevents us from
1016 // having to allocate another expression
1019 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1021 LoadOneAndEmitOp (ec, expr.Type);
1023 ec.ig.Emit (OpCodes.Call, method.Method);
1028 EmitCode (ec, true);
1031 public override void EmitStatement (EmitContext ec)
1033 EmitCode (ec, false);
1036 protected override void CloneTo (CloneContext clonectx, Expression t)
1038 UnaryMutator target = (UnaryMutator) t;
1040 target.expr = expr.Clone (clonectx);
1045 /// Base class for the `Is' and `As' classes.
1049 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1052 public abstract class Probe : Expression {
1053 public Expression ProbeType;
1054 protected Expression expr;
1055 protected TypeExpr probe_type_expr;
1057 public Probe (Expression expr, Expression probe_type, Location l)
1059 ProbeType = probe_type;
1064 public Expression Expr {
1070 public override Expression DoResolve (EmitContext ec)
1072 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1073 if (probe_type_expr == null)
1076 expr = expr.Resolve (ec);
1080 if (expr.Type.IsPointer) {
1081 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1087 protected override void CloneTo (CloneContext clonectx, Expression t)
1089 Probe target = (Probe) t;
1091 target.expr = expr.Clone (clonectx);
1092 target.ProbeType = ProbeType.Clone (clonectx);
1098 /// Implementation of the `is' operator.
1100 public class Is : Probe {
1101 public Is (Expression expr, Expression probe_type, Location l)
1102 : base (expr, probe_type, l)
1107 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1112 public override void Emit (EmitContext ec)
1114 ILGenerator ig = ec.ig;
1119 case Action.AlwaysFalse:
1120 ig.Emit (OpCodes.Pop);
1121 IntConstant.EmitInt (ig, 0);
1123 case Action.AlwaysTrue:
1124 ig.Emit (OpCodes.Pop);
1125 IntConstant.EmitInt (ig, 1);
1127 case Action.LeaveOnStack:
1128 // the `e != null' rule.
1129 ig.Emit (OpCodes.Ldnull);
1130 ig.Emit (OpCodes.Ceq);
1131 ig.Emit (OpCodes.Ldc_I4_0);
1132 ig.Emit (OpCodes.Ceq);
1135 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1136 ig.Emit (OpCodes.Ldnull);
1137 ig.Emit (OpCodes.Cgt_Un);
1140 throw new Exception ("never reached");
1143 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1145 ILGenerator ig = ec.ig;
1148 case Action.AlwaysFalse:
1150 ig.Emit (OpCodes.Br, target);
1153 case Action.AlwaysTrue:
1155 ig.Emit (OpCodes.Br, target);
1158 case Action.LeaveOnStack:
1159 // the `e != null' rule.
1161 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1165 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1166 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1169 throw new Exception ("never reached");
1172 public override Expression DoResolve (EmitContext ec)
1174 Expression e = base.DoResolve (ec);
1176 if ((e == null) || (expr == null))
1179 Type etype = expr.Type;
1180 type = TypeManager.bool_type;
1181 eclass = ExprClass.Value;
1184 // First case, if at compile time, there is an implicit conversion
1185 // then e != null (objects) or true (value types)
1187 Type probe_type = probe_type_expr.Type;
1188 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1191 if (etype.IsValueType)
1192 action = Action.AlwaysTrue;
1194 action = Action.LeaveOnStack;
1196 Constant c = e as Constant;
1197 if (c != null && c.GetValue () == null) {
1198 action = Action.AlwaysFalse;
1199 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1200 TypeManager.CSharpName (probe_type));
1201 } else if (etype.IsValueType) {
1202 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1203 TypeManager.CSharpName (probe_type));
1208 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1209 if (TypeManager.IsGenericParameter (etype))
1210 expr = new BoxedCast (expr, etype);
1213 // Second case: explicit reference convresion
1215 if (expr is NullLiteral)
1216 action = Action.AlwaysFalse;
1218 action = Action.Probe;
1219 } else if (TypeManager.ContainsGenericParameters (etype) ||
1220 TypeManager.ContainsGenericParameters (probe_type)) {
1221 expr = new BoxedCast (expr, etype);
1222 action = Action.Probe;
1224 action = Action.AlwaysFalse;
1225 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1226 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1234 /// Implementation of the `as' operator.
1236 public class As : Probe {
1237 public As (Expression expr, Expression probe_type, Location l)
1238 : base (expr, probe_type, l)
1242 bool do_isinst = false;
1243 Expression resolved_type;
1245 public override void Emit (EmitContext ec)
1247 ILGenerator ig = ec.ig;
1252 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1255 if (TypeManager.IsNullableType (type))
1256 ig.Emit (OpCodes.Unbox_Any, type);
1260 static void Error_CannotConvertType (Type source, Type target, Location loc)
1262 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1263 TypeManager.CSharpName (source),
1264 TypeManager.CSharpName (target));
1267 public override Expression DoResolve (EmitContext ec)
1269 if (resolved_type == null) {
1270 resolved_type = base.DoResolve (ec);
1272 if (resolved_type == null)
1276 type = probe_type_expr.Type;
1277 eclass = ExprClass.Value;
1278 Type etype = expr.Type;
1280 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1281 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1282 TypeManager.CSharpName (type) + "' is a value type)");
1289 // If the type is a type parameter, ensure
1290 // that it is constrained by a class
1292 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1294 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1297 if (constraints == null)
1300 if (!constraints.HasClassConstraint)
1301 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1305 Report.Error (413, loc,
1306 "The as operator requires that the `{0}' type parameter be constrained by a class",
1307 probe_type_expr.GetSignatureForError ());
1313 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1320 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1321 if (TypeManager.IsGenericParameter (etype))
1322 expr = new BoxedCast (expr, etype);
1328 if (TypeManager.ContainsGenericParameters (etype) ||
1329 TypeManager.ContainsGenericParameters (type)) {
1330 expr = new BoxedCast (expr, etype);
1335 Error_CannotConvertType (etype, type, loc);
1339 public override bool GetAttributableValue (Type valueType, out object value)
1341 return expr.GetAttributableValue (valueType, out value);
1346 /// This represents a typecast in the source language.
1348 /// FIXME: Cast expressions have an unusual set of parsing
1349 /// rules, we need to figure those out.
1351 public class Cast : Expression {
1352 Expression target_type;
1355 public Cast (Expression cast_type, Expression expr)
1356 : this (cast_type, expr, cast_type.Location)
1360 public Cast (Expression cast_type, Expression expr, Location loc)
1362 this.target_type = cast_type;
1366 if (target_type == TypeManager.system_void_expr)
1367 Error_VoidInvalidInTheContext (loc);
1370 public Expression TargetType {
1371 get { return target_type; }
1374 public Expression Expr {
1375 get { return expr; }
1378 public override Expression DoResolve (EmitContext ec)
1380 expr = expr.Resolve (ec);
1384 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1390 if (type.IsAbstract && type.IsSealed) {
1391 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1395 eclass = ExprClass.Value;
1397 Constant c = expr as Constant;
1399 c = c.TryReduce (ec, type, loc);
1404 if (type.IsPointer && !ec.InUnsafe) {
1408 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1412 public override void Emit (EmitContext ec)
1414 throw new Exception ("Should not happen");
1417 protected override void CloneTo (CloneContext clonectx, Expression t)
1419 Cast target = (Cast) t;
1421 target.target_type = target_type.Clone (clonectx);
1422 target.expr = expr.Clone (clonectx);
1427 /// Binary operators
1429 public class Binary : Expression {
1430 public enum Operator : byte {
1431 Multiply, Division, Modulus,
1432 Addition, Subtraction,
1433 LeftShift, RightShift,
1434 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1435 Equality, Inequality,
1444 readonly Operator oper;
1445 protected Expression left, right;
1446 readonly bool is_compound;
1448 // This must be kept in sync with Operator!!!
1449 public static readonly string [] oper_names;
1453 oper_names = new string [(int) Operator.TOP];
1455 oper_names [(int) Operator.Multiply] = "op_Multiply";
1456 oper_names [(int) Operator.Division] = "op_Division";
1457 oper_names [(int) Operator.Modulus] = "op_Modulus";
1458 oper_names [(int) Operator.Addition] = "op_Addition";
1459 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1460 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1461 oper_names [(int) Operator.RightShift] = "op_RightShift";
1462 oper_names [(int) Operator.LessThan] = "op_LessThan";
1463 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1464 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1465 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1466 oper_names [(int) Operator.Equality] = "op_Equality";
1467 oper_names [(int) Operator.Inequality] = "op_Inequality";
1468 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1469 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1470 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1471 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1472 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1475 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1476 : this (oper, left, right)
1478 this.is_compound = isCompound;
1481 public Binary (Operator oper, Expression left, Expression right)
1486 this.loc = left.Location;
1489 public Operator Oper {
1496 /// Returns a stringified representation of the Operator
1498 string OperName (Operator oper)
1502 case Operator.Multiply:
1505 case Operator.Division:
1508 case Operator.Modulus:
1511 case Operator.Addition:
1514 case Operator.Subtraction:
1517 case Operator.LeftShift:
1520 case Operator.RightShift:
1523 case Operator.LessThan:
1526 case Operator.GreaterThan:
1529 case Operator.LessThanOrEqual:
1532 case Operator.GreaterThanOrEqual:
1535 case Operator.Equality:
1538 case Operator.Inequality:
1541 case Operator.BitwiseAnd:
1544 case Operator.BitwiseOr:
1547 case Operator.ExclusiveOr:
1550 case Operator.LogicalOr:
1553 case Operator.LogicalAnd:
1557 s = oper.ToString ();
1567 public override string ToString ()
1569 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1570 right.ToString () + ")";
1573 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1575 if (expr.Type == target_type)
1578 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1581 void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1584 34, loc, "Operator `" + OperName (oper)
1585 + "' is ambiguous on operands of type `"
1586 + TypeManager.CSharpName (l) + "' "
1587 + "and `" + TypeManager.CSharpName (r)
1591 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1593 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1596 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1598 if (!IsConvertible (ec, left, right, t))
1600 left = ForceConversion (ec, left, t);
1601 right = ForceConversion (ec, right, t);
1606 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1608 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1609 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1611 if (oper == Operator.Equality || oper == Operator.Inequality)
1613 if (oper == Operator.Addition)
1618 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1620 if (!IsApplicable_String (ec, left, right, oper))
1622 Type t = TypeManager.string_type;
1623 if (Convert.ImplicitConversionExists (ec, left, t))
1624 left = ForceConversion (ec, left, t);
1625 if (Convert.ImplicitConversionExists (ec, right, t))
1626 right = ForceConversion (ec, right, t);
1631 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1633 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1634 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1635 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1636 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1640 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1642 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1643 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1647 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1649 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1652 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1654 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1658 protected void Error_OperatorCannotBeApplied ()
1660 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1661 TypeManager.CSharpName(right.Type));
1664 static bool is_unsigned (Type t)
1667 return is_unsigned (t.GetElementType ());
1669 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1670 t == TypeManager.short_type || t == TypeManager.byte_type);
1673 Expression Make32or64 (EmitContext ec, Expression e)
1677 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1678 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1680 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1683 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1686 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1689 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1695 Expression CheckShiftArguments (EmitContext ec)
1697 Expression new_left = Make32or64 (ec, left);
1698 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1699 if (new_left == null || new_right == null) {
1700 Error_OperatorCannotBeApplied ();
1703 type = new_left.Type;
1704 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1706 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1711 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1712 // i.e., not invoke op_Equality.
1714 static bool EqualsNullIsReferenceEquals (Type t)
1716 return t == TypeManager.object_type || t == TypeManager.string_type ||
1717 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1720 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1722 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1723 "Possible unintended reference comparison; to get a value comparison, " +
1724 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1727 static void Warning_Constant_Result (Location loc, bool result, Type type)
1729 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1730 "This operation is undocumented and it is temporary supported for compatibility reasons only",
1731 TypeManager.CSharpName (type), result ? "true" : "false");
1734 Expression ResolveOperator (EmitContext ec)
1737 Type r = right.Type;
1739 if (oper == Operator.Equality || oper == Operator.Inequality){
1740 if (right.Type == TypeManager.null_type){
1741 if (TypeManager.IsGenericParameter (l)){
1742 if (l.BaseType == TypeManager.value_type) {
1743 Error_OperatorCannotBeApplied ();
1747 left = new BoxedCast (left, TypeManager.object_type);
1748 Type = TypeManager.bool_type;
1753 // CSC 2 has this behavior, it allows structs to be compared
1754 // with the null literal *outside* of a generics context and
1755 // inlines that as true or false.
1757 // This is, in my opinion, completely wrong.
1759 if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType){
1760 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1761 return new BoolLiteral (oper == Operator.Inequality, loc);
1765 if (left is NullLiteral){
1766 if (TypeManager.IsGenericParameter (r)){
1767 if (r.BaseType == TypeManager.value_type) {
1768 Error_OperatorCannotBeApplied ();
1772 right = new BoxedCast (right, TypeManager.object_type);
1773 Type = TypeManager.bool_type;
1778 // CSC 2 has this behavior, it allows structs to be compared
1779 // with the null literal *outside* of a generics context and
1780 // inlines that as true or false.
1782 // This is, in my opinion, completely wrong.
1784 if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1785 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1786 return new BoolLiteral (oper == Operator.Inequality, loc);
1791 // Optimize out call to op_Equality in a few cases.
1793 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1794 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1795 Type = TypeManager.bool_type;
1800 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1801 Type = TypeManager.bool_type;
1807 // Delegate equality
1809 MethodGroupExpr mg = null;
1810 Type delegate_type = null;
1811 if (left.eclass == ExprClass.MethodGroup) {
1812 if (!TypeManager.IsDelegateType(r)) {
1813 Error_OperatorCannotBeApplied(Location, OperName(oper),
1814 left.ExprClassName, right.ExprClassName);
1817 mg = (MethodGroupExpr)left;
1819 } else if (right.eclass == ExprClass.MethodGroup) {
1820 if (!TypeManager.IsDelegateType(l)) {
1821 Error_OperatorCannotBeApplied(Location, OperName(oper),
1822 left.ExprClassName, right.ExprClassName);
1825 mg = (MethodGroupExpr)right;
1830 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1834 // Find operator method
1835 string op = oper_names[(int)oper];
1836 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1837 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1839 ArrayList args = new ArrayList(2);
1840 args.Add(new Argument(e, Argument.AType.Expression));
1841 if (delegate_type == l)
1842 args.Insert(0, new Argument(left, Argument.AType.Expression));
1844 args.Add(new Argument(right, Argument.AType.Expression));
1846 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1849 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1850 Error_OperatorCannotBeApplied(Location, OperName(oper),
1851 left.ExprClassName, right.ExprClassName);
1858 // Do not perform operator overload resolution when both sides are
1861 MethodGroupExpr left_operators = null, right_operators = null;
1862 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1864 // Step 1: Perform Operator Overload location
1866 string op = oper_names [(int) oper];
1868 MethodGroupExpr union;
1869 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1871 right_operators = MemberLookup (
1872 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1873 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
1875 union = left_operators;
1877 if (union != null) {
1878 ArrayList args = new ArrayList (2);
1879 args.Add (new Argument (left, Argument.AType.Expression));
1880 args.Add (new Argument (right, Argument.AType.Expression));
1882 union = union.OverloadResolve (ec, args, true, Location.Null);
1884 if (union != null) {
1885 MethodInfo mi = (MethodInfo) union;
1886 return new BinaryMethod (mi.ReturnType, mi, args);
1892 // Step 0: String concatenation (because overloading will get this wrong)
1894 if (oper == Operator.Addition){
1896 // If any of the arguments is a string, cast to string
1899 // Simple constant folding
1900 if (left is StringConstant && right is StringConstant)
1901 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1903 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1905 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1906 Error_OperatorCannotBeApplied ();
1910 // try to fold it in on the left
1911 if (left is StringConcat) {
1914 // We have to test here for not-null, since we can be doubly-resolved
1915 // take care of not appending twice
1918 type = TypeManager.string_type;
1919 ((StringConcat) left).Append (ec, right);
1920 return left.Resolve (ec);
1926 // Otherwise, start a new concat expression
1927 return new StringConcat (ec, loc, left, right).Resolve (ec);
1931 // Transform a + ( - b) into a - b
1933 if (right is Unary){
1934 Unary right_unary = (Unary) right;
1936 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1937 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
1942 if (oper == Operator.Equality || oper == Operator.Inequality){
1943 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1944 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1945 Error_OperatorCannotBeApplied ();
1949 type = TypeManager.bool_type;
1953 if (l.IsPointer || r.IsPointer) {
1954 if (l.IsPointer && r.IsPointer) {
1955 type = TypeManager.bool_type;
1959 if (l.IsPointer && r == TypeManager.null_type) {
1960 right = new EmptyConstantCast (NullPointer.Null, l);
1961 type = TypeManager.bool_type;
1965 if (r.IsPointer && l == TypeManager.null_type) {
1966 left = new EmptyConstantCast (NullPointer.Null, r);
1967 type = TypeManager.bool_type;
1973 if (l.IsGenericParameter && r.IsGenericParameter) {
1974 GenericConstraints l_gc, r_gc;
1976 l_gc = TypeManager.GetTypeParameterConstraints (l);
1977 r_gc = TypeManager.GetTypeParameterConstraints (r);
1979 if ((l_gc == null) || (r_gc == null) ||
1980 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1981 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1982 Error_OperatorCannotBeApplied ();
1990 // operator != (object a, object b)
1991 // operator == (object a, object b)
1993 // For this to be used, both arguments have to be reference-types.
1994 // Read the rationale on the spec (14.9.6)
1996 if (!(l.IsValueType || r.IsValueType)){
1997 type = TypeManager.bool_type;
2003 // Also, a standard conversion must exist from either one
2005 // NOTE: An interface is converted to the object before the
2006 // standard conversion is applied. It's not clear from the
2007 // standard but it looks like it works like that.
2010 l = TypeManager.object_type;
2012 r = TypeManager.object_type;
2014 bool left_to_right =
2015 Convert.ImplicitStandardConversionExists (left, r);
2016 bool right_to_left = !left_to_right &&
2017 Convert.ImplicitStandardConversionExists (right, l);
2019 if (!left_to_right && !right_to_left) {
2020 Error_OperatorCannotBeApplied ();
2024 if (left_to_right && left_operators != null &&
2025 Report.WarningLevel >= 2) {
2026 ArrayList args = new ArrayList (2);
2027 args.Add (new Argument (left, Argument.AType.Expression));
2028 args.Add (new Argument (left, Argument.AType.Expression));
2029 if (left_operators.OverloadResolve (ec, args, true, Location.Null) != null)
2030 Warning_UnintendedReferenceComparison (loc, "right", l);
2033 if (right_to_left && right_operators != null &&
2034 Report.WarningLevel >= 2) {
2035 ArrayList args = new ArrayList (2);
2036 args.Add (new Argument (right, Argument.AType.Expression));
2037 args.Add (new Argument (right, Argument.AType.Expression));
2038 if (right_operators.OverloadResolve (ec, args, true, Location.Null) != null)
2039 Warning_UnintendedReferenceComparison (loc, "left", r);
2043 // We are going to have to convert to an object to compare
2045 if (l != TypeManager.object_type)
2046 left = EmptyCast.Create (left, TypeManager.object_type);
2047 if (r != TypeManager.object_type)
2048 right = EmptyCast.Create (right, TypeManager.object_type);
2054 // Only perform numeric promotions on:
2055 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2057 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2058 if (TypeManager.IsDelegateType (l)){
2059 if (((right.eclass == ExprClass.MethodGroup) ||
2060 (r == TypeManager.anonymous_method_type))){
2061 if ((RootContext.Version != LanguageVersion.ISO_1)){
2062 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2070 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2072 ArrayList args = new ArrayList (2);
2074 args = new ArrayList (2);
2075 args.Add (new Argument (left, Argument.AType.Expression));
2076 args.Add (new Argument (right, Argument.AType.Expression));
2078 if (oper == Operator.Addition)
2079 method = TypeManager.delegate_combine_delegate_delegate;
2081 method = TypeManager.delegate_remove_delegate_delegate;
2083 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2084 Error_OperatorCannotBeApplied ();
2088 return new BinaryDelegate (l, method, args);
2093 // Pointer arithmetic:
2095 // T* operator + (T* x, int y);
2096 // T* operator + (T* x, uint y);
2097 // T* operator + (T* x, long y);
2098 // T* operator + (T* x, ulong y);
2100 // T* operator + (int y, T* x);
2101 // T* operator + (uint y, T *x);
2102 // T* operator + (long y, T *x);
2103 // T* operator + (ulong y, T *x);
2105 // T* operator - (T* x, int y);
2106 // T* operator - (T* x, uint y);
2107 // T* operator - (T* x, long y);
2108 // T* operator - (T* x, ulong y);
2110 // long operator - (T* x, T *y)
2113 if (r.IsPointer && oper == Operator.Subtraction){
2115 return new PointerArithmetic (
2116 false, left, right, TypeManager.int64_type,
2119 Expression t = Make32or64 (ec, right);
2121 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2123 } else if (r.IsPointer && oper == Operator.Addition){
2124 Expression t = Make32or64 (ec, left);
2126 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2131 // Enumeration operators
2133 bool lie = TypeManager.IsEnumType (l);
2134 bool rie = TypeManager.IsEnumType (r);
2138 // U operator - (E e, E f)
2140 if (oper == Operator.Subtraction){
2142 type = TypeManager.EnumToUnderlying (l);
2145 Error_OperatorCannotBeApplied ();
2151 // operator + (E e, U x)
2152 // operator - (E e, U x)
2154 if (oper == Operator.Addition || oper == Operator.Subtraction){
2155 Type enum_type = lie ? l : r;
2156 Type other_type = lie ? r : l;
2157 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2159 if (underlying_type != other_type){
2160 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2170 Error_OperatorCannotBeApplied ();
2179 temp = Convert.ImplicitConversion (ec, right, l, loc);
2183 Error_OperatorCannotBeApplied ();
2187 temp = Convert.ImplicitConversion (ec, left, r, loc);
2192 Error_OperatorCannotBeApplied ();
2197 if (oper == Operator.Equality || oper == Operator.Inequality ||
2198 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2199 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2200 if (left.Type != right.Type){
2201 Error_OperatorCannotBeApplied ();
2204 type = TypeManager.bool_type;
2208 if (oper == Operator.BitwiseAnd ||
2209 oper == Operator.BitwiseOr ||
2210 oper == Operator.ExclusiveOr){
2211 if (left.Type != right.Type){
2212 Error_OperatorCannotBeApplied ();
2218 Error_OperatorCannotBeApplied ();
2222 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2223 return CheckShiftArguments (ec);
2225 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2226 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2227 type = TypeManager.bool_type;
2231 Expression left_operators_e = l == TypeManager.bool_type ?
2232 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2233 Expression right_operators_e = r == TypeManager.bool_type ?
2234 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2236 if (left_operators_e != null && right_operators_e != null) {
2237 left = left_operators_e;
2238 right = right_operators_e;
2239 type = TypeManager.bool_type;
2243 Expression e = new ConditionalLogicalOperator (
2244 oper == Operator.LogicalAnd, left, right, l, loc);
2245 return e.Resolve (ec);
2248 Expression orig_left = left;
2249 Expression orig_right = right;
2252 // operator & (bool x, bool y)
2253 // operator | (bool x, bool y)
2254 // operator ^ (bool x, bool y)
2256 if (oper == Operator.BitwiseAnd ||
2257 oper == Operator.BitwiseOr ||
2258 oper == Operator.ExclusiveOr) {
2259 if (OverloadResolve_PredefinedIntegral (ec)) {
2260 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2261 Error_OperatorAmbiguous (loc, oper, l, r);
2265 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2266 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2267 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2268 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2269 TypeManager.CSharpName (r));
2272 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2273 Error_OperatorCannotBeApplied ();
2280 // Pointer comparison
2282 if (l.IsPointer && r.IsPointer){
2283 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2284 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2285 type = TypeManager.bool_type;
2290 if (OverloadResolve_PredefinedIntegral (ec)) {
2291 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2292 Error_OperatorAmbiguous (loc, oper, l, r);
2295 } else if (OverloadResolve_PredefinedFloating (ec)) {
2296 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2297 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2298 Error_OperatorAmbiguous (loc, oper, l, r);
2301 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2302 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2303 Error_OperatorAmbiguous (loc, oper, l, r);
2306 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2307 Error_OperatorCannotBeApplied ();
2311 if (oper == Operator.Equality ||
2312 oper == Operator.Inequality ||
2313 oper == Operator.LessThanOrEqual ||
2314 oper == Operator.LessThan ||
2315 oper == Operator.GreaterThanOrEqual ||
2316 oper == Operator.GreaterThan)
2317 type = TypeManager.bool_type;
2322 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2324 if (r == TypeManager.string_type)
2326 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2327 ec.ContainerType, lookup, oper_names [(int) oper],
2328 MemberTypes.Method, AllBindingFlags, loc);
2329 ArrayList args = new ArrayList (2);
2330 args.Add (new Argument (left, Argument.AType.Expression));
2331 args.Add (new Argument (right, Argument.AType.Expression));
2332 ops = ops.OverloadResolve (ec, args, true, Location.Null);
2333 return new BinaryMethod (type, (MethodInfo)ops, args);
2339 Constant EnumLiftUp (Constant left, Constant right)
2342 case Operator.BitwiseOr:
2343 case Operator.BitwiseAnd:
2344 case Operator.ExclusiveOr:
2345 case Operator.Equality:
2346 case Operator.Inequality:
2347 case Operator.LessThan:
2348 case Operator.LessThanOrEqual:
2349 case Operator.GreaterThan:
2350 case Operator.GreaterThanOrEqual:
2351 if (left is EnumConstant)
2354 if (left.IsZeroInteger)
2355 return new EnumConstant (left, right.Type);
2359 case Operator.Addition:
2360 case Operator.Subtraction:
2363 case Operator.Multiply:
2364 case Operator.Division:
2365 case Operator.Modulus:
2366 case Operator.LeftShift:
2367 case Operator.RightShift:
2368 if (right is EnumConstant || left is EnumConstant)
2372 Error_OperatorCannotBeApplied ();
2376 public override Expression DoResolve (EmitContext ec)
2381 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2382 left = ((ParenthesizedExpression) left).Expr;
2383 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2387 if (left.eclass == ExprClass.Type) {
2388 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2392 left = left.Resolve (ec);
2397 Constant lc = left as Constant;
2398 if (lc != null && lc.Type == TypeManager.bool_type &&
2399 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2400 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2402 // TODO: make a sense to resolve unreachable expression as we do for statement
2403 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2407 right = right.Resolve (ec);
2411 eclass = ExprClass.Value;
2412 Constant rc = right as Constant;
2414 // The conversion rules are ignored in enum context but why
2415 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2416 left = lc = EnumLiftUp (lc, rc);
2420 right = rc = EnumLiftUp (rc, lc);
2425 if (oper == Operator.BitwiseAnd) {
2426 if (rc != null && rc.IsZeroInteger) {
2427 return lc is EnumConstant ?
2428 new EnumConstant (rc, lc.Type):
2432 if (lc != null && lc.IsZeroInteger) {
2433 return rc is EnumConstant ?
2434 new EnumConstant (lc, rc.Type):
2438 else if (oper == Operator.BitwiseOr) {
2439 if (lc is EnumConstant &&
2440 rc != null && rc.IsZeroInteger)
2442 if (rc is EnumConstant &&
2443 lc != null && lc.IsZeroInteger)
2445 } else if (oper == Operator.LogicalAnd) {
2446 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2448 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2452 if (rc != null && lc != null){
2453 int prev_e = Report.Errors;
2454 Expression e = ConstantFold.BinaryFold (
2455 ec, oper, lc, rc, loc);
2456 if (e != null || Report.Errors != prev_e)
2461 if ((left is NullLiteral || left.Type.IsValueType) &&
2462 (right is NullLiteral || right.Type.IsValueType) &&
2463 !(left is NullLiteral && right is NullLiteral) &&
2464 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2465 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2468 // Comparison warnings
2469 if (oper == Operator.Equality || oper == Operator.Inequality ||
2470 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2471 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2472 if (left.Equals (right)) {
2473 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2475 CheckUselessComparison (lc, right.Type);
2476 CheckUselessComparison (rc, left.Type);
2479 return ResolveOperator (ec);
2482 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2487 private void CheckUselessComparison (Constant c, Type type)
2489 if (c == null || !IsTypeIntegral (type)
2490 || c is StringConstant
2491 || c is BoolConstant
2492 || c is FloatConstant
2493 || c is DoubleConstant
2494 || c is DecimalConstant
2500 if (c is ULongConstant) {
2501 ulong uvalue = ((ULongConstant) c).Value;
2502 if (uvalue > long.MaxValue) {
2503 if (type == TypeManager.byte_type ||
2504 type == TypeManager.sbyte_type ||
2505 type == TypeManager.short_type ||
2506 type == TypeManager.ushort_type ||
2507 type == TypeManager.int32_type ||
2508 type == TypeManager.uint32_type ||
2509 type == TypeManager.int64_type ||
2510 type == TypeManager.char_type)
2511 WarnUselessComparison (type);
2514 value = (long) uvalue;
2516 else if (c is ByteConstant)
2517 value = ((ByteConstant) c).Value;
2518 else if (c is SByteConstant)
2519 value = ((SByteConstant) c).Value;
2520 else if (c is ShortConstant)
2521 value = ((ShortConstant) c).Value;
2522 else if (c is UShortConstant)
2523 value = ((UShortConstant) c).Value;
2524 else if (c is IntConstant)
2525 value = ((IntConstant) c).Value;
2526 else if (c is UIntConstant)
2527 value = ((UIntConstant) c).Value;
2528 else if (c is LongConstant)
2529 value = ((LongConstant) c).Value;
2530 else if (c is CharConstant)
2531 value = ((CharConstant)c).Value;
2536 if (IsValueOutOfRange (value, type))
2537 WarnUselessComparison (type);
2540 private bool IsValueOutOfRange (long value, Type type)
2542 if (IsTypeUnsigned (type) && value < 0)
2544 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2545 type == TypeManager.byte_type && value >= 0x100 ||
2546 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2547 type == TypeManager.ushort_type && value >= 0x10000 ||
2548 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2549 type == TypeManager.uint32_type && value >= 0x100000000;
2552 private static bool IsTypeIntegral (Type type)
2554 return type == TypeManager.uint64_type ||
2555 type == TypeManager.int64_type ||
2556 type == TypeManager.uint32_type ||
2557 type == TypeManager.int32_type ||
2558 type == TypeManager.ushort_type ||
2559 type == TypeManager.short_type ||
2560 type == TypeManager.sbyte_type ||
2561 type == TypeManager.byte_type ||
2562 type == TypeManager.char_type;
2565 private static bool IsTypeUnsigned (Type type)
2567 return type == TypeManager.uint64_type ||
2568 type == TypeManager.uint32_type ||
2569 type == TypeManager.ushort_type ||
2570 type == TypeManager.byte_type ||
2571 type == TypeManager.char_type;
2574 private void WarnUselessComparison (Type type)
2576 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}'",
2577 TypeManager.CSharpName (type));
2581 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2582 /// context of a conditional bool expression. This function will return
2583 /// false if it is was possible to use EmitBranchable, or true if it was.
2585 /// The expression's code is generated, and we will generate a branch to `target'
2586 /// if the resulting expression value is equal to isTrue
2588 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2590 ILGenerator ig = ec.ig;
2593 // This is more complicated than it looks, but its just to avoid
2594 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2595 // but on top of that we want for == and != to use a special path
2596 // if we are comparing against null
2598 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2599 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2602 // put the constant on the rhs, for simplicity
2604 if (left is Constant) {
2605 Expression swap = right;
2610 if (((Constant) right).IsZeroInteger) {
2613 ig.Emit (OpCodes.Brtrue, target);
2615 ig.Emit (OpCodes.Brfalse, target);
2618 } else if (right is BoolConstant) {
2620 if (my_on_true != ((BoolConstant) right).Value)
2621 ig.Emit (OpCodes.Brtrue, target);
2623 ig.Emit (OpCodes.Brfalse, target);
2628 } else if (oper == Operator.LogicalAnd) {
2631 Label tests_end = ig.DefineLabel ();
2633 left.EmitBranchable (ec, tests_end, false);
2634 right.EmitBranchable (ec, target, true);
2635 ig.MarkLabel (tests_end);
2638 // This optimizes code like this
2639 // if (true && i > 4)
2641 if (!(left is Constant))
2642 left.EmitBranchable (ec, target, false);
2644 if (!(right is Constant))
2645 right.EmitBranchable (ec, target, false);
2650 } else if (oper == Operator.LogicalOr){
2652 left.EmitBranchable (ec, target, true);
2653 right.EmitBranchable (ec, target, true);
2656 Label tests_end = ig.DefineLabel ();
2657 left.EmitBranchable (ec, tests_end, true);
2658 right.EmitBranchable (ec, target, false);
2659 ig.MarkLabel (tests_end);
2664 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2665 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2666 oper == Operator.Equality || oper == Operator.Inequality)) {
2667 base.EmitBranchable (ec, target, onTrue);
2675 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2678 case Operator.Equality:
2680 ig.Emit (OpCodes.Beq, target);
2682 ig.Emit (OpCodes.Bne_Un, target);
2685 case Operator.Inequality:
2687 ig.Emit (OpCodes.Bne_Un, target);
2689 ig.Emit (OpCodes.Beq, target);
2692 case Operator.LessThan:
2695 ig.Emit (OpCodes.Blt_Un, target);
2697 ig.Emit (OpCodes.Blt, target);
2700 ig.Emit (OpCodes.Bge_Un, target);
2702 ig.Emit (OpCodes.Bge, target);
2705 case Operator.GreaterThan:
2708 ig.Emit (OpCodes.Bgt_Un, target);
2710 ig.Emit (OpCodes.Bgt, target);
2713 ig.Emit (OpCodes.Ble_Un, target);
2715 ig.Emit (OpCodes.Ble, target);
2718 case Operator.LessThanOrEqual:
2721 ig.Emit (OpCodes.Ble_Un, target);
2723 ig.Emit (OpCodes.Ble, target);
2726 ig.Emit (OpCodes.Bgt_Un, target);
2728 ig.Emit (OpCodes.Bgt, target);
2732 case Operator.GreaterThanOrEqual:
2735 ig.Emit (OpCodes.Bge_Un, target);
2737 ig.Emit (OpCodes.Bge, target);
2740 ig.Emit (OpCodes.Blt_Un, target);
2742 ig.Emit (OpCodes.Blt, target);
2745 Console.WriteLine (oper);
2746 throw new Exception ("what is THAT");
2750 public override void Emit (EmitContext ec)
2752 ILGenerator ig = ec.ig;
2757 // Handle short-circuit operators differently
2760 if (oper == Operator.LogicalAnd) {
2761 Label load_zero = ig.DefineLabel ();
2762 Label end = ig.DefineLabel ();
2764 left.EmitBranchable (ec, load_zero, false);
2766 ig.Emit (OpCodes.Br, end);
2768 ig.MarkLabel (load_zero);
2769 ig.Emit (OpCodes.Ldc_I4_0);
2772 } else if (oper == Operator.LogicalOr) {
2773 Label load_one = ig.DefineLabel ();
2774 Label end = ig.DefineLabel ();
2776 left.EmitBranchable (ec, load_one, true);
2778 ig.Emit (OpCodes.Br, end);
2780 ig.MarkLabel (load_one);
2781 ig.Emit (OpCodes.Ldc_I4_1);
2789 bool isUnsigned = is_unsigned (left.Type);
2792 case Operator.Multiply:
2794 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2795 opcode = OpCodes.Mul_Ovf;
2796 else if (isUnsigned)
2797 opcode = OpCodes.Mul_Ovf_Un;
2799 opcode = OpCodes.Mul;
2801 opcode = OpCodes.Mul;
2805 case Operator.Division:
2807 opcode = OpCodes.Div_Un;
2809 opcode = OpCodes.Div;
2812 case Operator.Modulus:
2814 opcode = OpCodes.Rem_Un;
2816 opcode = OpCodes.Rem;
2819 case Operator.Addition:
2821 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2822 opcode = OpCodes.Add_Ovf;
2823 else if (isUnsigned)
2824 opcode = OpCodes.Add_Ovf_Un;
2826 opcode = OpCodes.Add;
2828 opcode = OpCodes.Add;
2831 case Operator.Subtraction:
2833 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2834 opcode = OpCodes.Sub_Ovf;
2835 else if (isUnsigned)
2836 opcode = OpCodes.Sub_Ovf_Un;
2838 opcode = OpCodes.Sub;
2840 opcode = OpCodes.Sub;
2843 case Operator.RightShift:
2845 opcode = OpCodes.Shr_Un;
2847 opcode = OpCodes.Shr;
2850 case Operator.LeftShift:
2851 opcode = OpCodes.Shl;
2854 case Operator.Equality:
2855 opcode = OpCodes.Ceq;
2858 case Operator.Inequality:
2859 ig.Emit (OpCodes.Ceq);
2860 ig.Emit (OpCodes.Ldc_I4_0);
2862 opcode = OpCodes.Ceq;
2865 case Operator.LessThan:
2867 opcode = OpCodes.Clt_Un;
2869 opcode = OpCodes.Clt;
2872 case Operator.GreaterThan:
2874 opcode = OpCodes.Cgt_Un;
2876 opcode = OpCodes.Cgt;
2879 case Operator.LessThanOrEqual:
2880 Type lt = left.Type;
2882 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2883 ig.Emit (OpCodes.Cgt_Un);
2885 ig.Emit (OpCodes.Cgt);
2886 ig.Emit (OpCodes.Ldc_I4_0);
2888 opcode = OpCodes.Ceq;
2891 case Operator.GreaterThanOrEqual:
2892 Type le = left.Type;
2894 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2895 ig.Emit (OpCodes.Clt_Un);
2897 ig.Emit (OpCodes.Clt);
2899 ig.Emit (OpCodes.Ldc_I4_0);
2901 opcode = OpCodes.Ceq;
2904 case Operator.BitwiseOr:
2905 opcode = OpCodes.Or;
2908 case Operator.BitwiseAnd:
2909 opcode = OpCodes.And;
2912 case Operator.ExclusiveOr:
2913 opcode = OpCodes.Xor;
2917 throw new Exception ("This should not happen: Operator = "
2918 + oper.ToString ());
2924 protected override void CloneTo (CloneContext clonectx, Expression t)
2926 Binary target = (Binary) t;
2928 target.left = left.Clone (clonectx);
2929 target.right = right.Clone (clonectx);
2934 // Object created by Binary when the binary operator uses an method instead of being
2935 // a binary operation that maps to a CIL binary operation.
2937 public class BinaryMethod : Expression {
2938 public MethodBase method;
2939 public ArrayList Arguments;
2941 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2946 eclass = ExprClass.Value;
2949 public override Expression DoResolve (EmitContext ec)
2954 public override void Emit (EmitContext ec)
2956 ILGenerator ig = ec.ig;
2958 if (Arguments != null)
2959 Invocation.EmitArguments (ec, method, Arguments, false, null);
2961 if (method is MethodInfo)
2962 ig.Emit (OpCodes.Call, (MethodInfo) method);
2964 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2969 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2970 // b, c, d... may be strings or objects.
2972 public class StringConcat : Expression {
2974 bool invalid = false;
2975 bool emit_conv_done = false;
2977 // Are we also concating objects?
2979 bool is_strings_only = true;
2981 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2984 type = TypeManager.string_type;
2985 eclass = ExprClass.Value;
2987 operands = new ArrayList (2);
2992 public override Expression DoResolve (EmitContext ec)
3000 public void Append (EmitContext ec, Expression operand)
3005 StringConstant sc = operand as StringConstant;
3007 // TODO: it will be better to do this silently as an optimalization
3009 // string s = "" + i;
3010 // because this code has poor performace
3011 // if (sc.Value.Length == 0)
3012 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
3014 if (operands.Count != 0) {
3015 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3016 if (last_operand != null) {
3017 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
3025 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3027 StringConcat concat_oper = operand as StringConcat;
3028 if (concat_oper != null) {
3029 operands.AddRange (concat_oper.operands);
3034 // Conversion to object
3036 if (operand.Type != TypeManager.string_type) {
3037 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3040 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3046 operands.Add (operand);
3049 public override void Emit (EmitContext ec)
3051 MethodInfo concat_method = null;
3054 // Do conversion to arguments; check for strings only
3057 // This can get called multiple times, so we have to deal with that.
3058 if (!emit_conv_done) {
3059 emit_conv_done = true;
3060 for (int i = 0; i < operands.Count; i ++) {
3061 Expression e = (Expression) operands [i];
3062 is_strings_only &= e.Type == TypeManager.string_type;
3065 for (int i = 0; i < operands.Count; i ++) {
3066 Expression e = (Expression) operands [i];
3068 if (! is_strings_only && e.Type == TypeManager.string_type) {
3069 // need to make sure this is an object, because the EmitParams
3070 // method might look at the type of this expression, see it is a
3071 // string and emit a string [] when we want an object [];
3073 e = EmptyCast.Create (e, TypeManager.object_type);
3075 operands [i] = new Argument (e, Argument.AType.Expression);
3080 // Find the right method
3082 switch (operands.Count) {
3085 // This should not be possible, because simple constant folding
3086 // is taken care of in the Binary code.
3088 throw new Exception ("how did you get here?");
3091 concat_method = is_strings_only ?
3092 TypeManager.string_concat_string_string :
3093 TypeManager.string_concat_object_object ;
3096 concat_method = is_strings_only ?
3097 TypeManager.string_concat_string_string_string :
3098 TypeManager.string_concat_object_object_object ;
3102 // There is not a 4 param overlaod for object (the one that there is
3103 // is actually a varargs methods, and is only in corlib because it was
3104 // introduced there before.).
3106 if (!is_strings_only)
3109 concat_method = TypeManager.string_concat_string_string_string_string;
3112 concat_method = is_strings_only ?
3113 TypeManager.string_concat_string_dot_dot_dot :
3114 TypeManager.string_concat_object_dot_dot_dot ;
3118 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3119 ec.ig.Emit (OpCodes.Call, concat_method);
3124 // Object created with +/= on delegates
3126 public class BinaryDelegate : Expression {
3130 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3135 eclass = ExprClass.Value;
3138 public override Expression DoResolve (EmitContext ec)
3143 public override void Emit (EmitContext ec)
3145 ILGenerator ig = ec.ig;
3147 Invocation.EmitArguments (ec, method, args, false, null);
3149 ig.Emit (OpCodes.Call, (MethodInfo) method);
3150 ig.Emit (OpCodes.Castclass, type);
3153 public Expression Right {
3155 Argument arg = (Argument) args [1];
3160 public bool IsAddition {
3162 return method == TypeManager.delegate_combine_delegate_delegate;
3168 // User-defined conditional logical operator
3169 public class ConditionalLogicalOperator : Expression {
3170 Expression left, right;
3173 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3176 eclass = ExprClass.Value;
3180 this.is_and = is_and;
3183 protected void Error19 ()
3185 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3188 protected void Error218 ()
3190 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3191 "declarations of operator true and operator false");
3194 Expression op_true, op_false, op;
3195 LocalTemporary left_temp;
3197 public override Expression DoResolve (EmitContext ec)
3199 MethodGroupExpr operator_group;
3201 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3202 if (operator_group == null) {
3207 left_temp = new LocalTemporary (type);
3209 ArrayList arguments = new ArrayList (2);
3210 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3211 arguments.Add (new Argument (right, Argument.AType.Expression));
3212 operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3213 if (operator_group == null) {
3218 MethodInfo method = (MethodInfo)operator_group;
3219 if (method.ReturnType != type) {
3220 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3221 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3225 op = new StaticCallExpr (method, arguments, loc);
3227 op_true = GetOperatorTrue (ec, left_temp, loc);
3228 op_false = GetOperatorFalse (ec, left_temp, loc);
3229 if ((op_true == null) || (op_false == null)) {
3237 public override void Emit (EmitContext ec)
3239 ILGenerator ig = ec.ig;
3240 Label false_target = ig.DefineLabel ();
3241 Label end_target = ig.DefineLabel ();
3244 left_temp.Store (ec);
3246 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3247 left_temp.Emit (ec);
3248 ig.Emit (OpCodes.Br, end_target);
3249 ig.MarkLabel (false_target);
3251 ig.MarkLabel (end_target);
3253 // We release 'left_temp' here since 'op' may refer to it too
3254 left_temp.Release (ec);
3258 public class PointerArithmetic : Expression {
3259 Expression left, right;
3263 // We assume that `l' is always a pointer
3265 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3271 is_add = is_addition;
3274 public override Expression DoResolve (EmitContext ec)
3276 eclass = ExprClass.Variable;
3278 if (left.Type == TypeManager.void_ptr_type) {
3279 Error (242, "The operation in question is undefined on void pointers");
3286 public override void Emit (EmitContext ec)
3288 Type op_type = left.Type;
3289 ILGenerator ig = ec.ig;
3291 // It must be either array or fixed buffer
3292 Type element = TypeManager.HasElementType (op_type) ?
3293 element = TypeManager.GetElementType (op_type) :
3294 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3296 int size = GetTypeSize (element);
3297 Type rtype = right.Type;
3299 if (rtype.IsPointer){
3301 // handle (pointer - pointer)
3305 ig.Emit (OpCodes.Sub);
3309 ig.Emit (OpCodes.Sizeof, element);
3311 IntLiteral.EmitInt (ig, size);
3312 ig.Emit (OpCodes.Div);
3314 ig.Emit (OpCodes.Conv_I8);
3317 // handle + and - on (pointer op int)
3320 ig.Emit (OpCodes.Conv_I);
3322 Constant right_const = right as Constant;
3323 if (right_const != null && size != 0) {
3324 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3332 ig.Emit (OpCodes.Sizeof, element);
3334 IntLiteral.EmitInt (ig, size);
3335 if (rtype == TypeManager.int64_type)
3336 ig.Emit (OpCodes.Conv_I8);
3337 else if (rtype == TypeManager.uint64_type)
3338 ig.Emit (OpCodes.Conv_U8);
3339 ig.Emit (OpCodes.Mul);
3343 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3344 ig.Emit (OpCodes.Conv_I);
3347 ig.Emit (OpCodes.Add);
3349 ig.Emit (OpCodes.Sub);
3355 /// Implements the ternary conditional operator (?:)
3357 public class Conditional : Expression {
3358 Expression expr, trueExpr, falseExpr;
3360 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3363 this.trueExpr = trueExpr;
3364 this.falseExpr = falseExpr;
3365 this.loc = expr.Location;
3368 public Expression Expr {
3374 public Expression TrueExpr {
3380 public Expression FalseExpr {
3386 public override Expression DoResolve (EmitContext ec)
3388 expr = expr.Resolve (ec);
3394 if (TypeManager.IsNullableValueType (expr.Type))
3395 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3398 if (expr.Type != TypeManager.bool_type){
3399 expr = Expression.ResolveBoolean (
3406 Assign ass = expr as Assign;
3407 if (ass != null && ass.Source is Constant) {
3408 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3411 trueExpr = trueExpr.Resolve (ec);
3412 falseExpr = falseExpr.Resolve (ec);
3414 if (trueExpr == null || falseExpr == null)
3417 eclass = ExprClass.Value;
3418 if (trueExpr.Type == falseExpr.Type) {
3419 type = trueExpr.Type;
3420 if (type == TypeManager.null_type) {
3421 // TODO: probably will have to implement ConditionalConstant
3422 // to call method without return constant as well
3423 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3428 Type true_type = trueExpr.Type;
3429 Type false_type = falseExpr.Type;
3432 // First, if an implicit conversion exists from trueExpr
3433 // to falseExpr, then the result type is of type falseExpr.Type
3435 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3438 // Check if both can convert implicitl to each other's type
3440 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3442 "Can not compute type of conditional expression " +
3443 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3444 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3445 "' convert implicitly to each other");
3450 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3454 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3455 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3460 // Dead code optimalization
3461 if (expr is BoolConstant){
3462 BoolConstant bc = (BoolConstant) expr;
3464 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3465 return bc.Value ? trueExpr : falseExpr;
3471 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3476 public override void Emit (EmitContext ec)
3478 ILGenerator ig = ec.ig;
3479 Label false_target = ig.DefineLabel ();
3480 Label end_target = ig.DefineLabel ();
3482 expr.EmitBranchable (ec, false_target, false);
3484 ig.Emit (OpCodes.Br, end_target);
3485 ig.MarkLabel (false_target);
3486 falseExpr.Emit (ec);
3487 ig.MarkLabel (end_target);
3490 protected override void CloneTo (CloneContext clonectx, Expression t)
3492 Conditional target = (Conditional) t;
3494 target.expr = expr.Clone (clonectx);
3495 target.trueExpr = trueExpr.Clone (clonectx);
3496 target.falseExpr = falseExpr.Clone (clonectx);
3500 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3502 LocalTemporary temp;
3504 public abstract Variable Variable {
3508 public abstract bool IsRef {
3512 public override void Emit (EmitContext ec)
3518 // This method is used by parameters that are references, that are
3519 // being passed as references: we only want to pass the pointer (that
3520 // is already stored in the parameter, not the address of the pointer,
3521 // and not the value of the variable).
3523 public void EmitLoad (EmitContext ec)
3525 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3527 Variable.EmitInstance (ec);
3531 public void Emit (EmitContext ec, bool leave_copy)
3533 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3539 // If we are a reference, we loaded on the stack a pointer
3540 // Now lets load the real value
3542 LoadFromPtr (ec.ig, type);
3546 ec.ig.Emit (OpCodes.Dup);
3548 if (IsRef || Variable.NeedsTemporary) {
3549 temp = new LocalTemporary (Type);
3555 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3556 bool prepare_for_load)
3558 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3561 ILGenerator ig = ec.ig;
3562 prepared = prepare_for_load;
3564 Variable.EmitInstance (ec);
3565 if (prepare_for_load) {
3566 if (Variable.HasInstance)
3567 ig.Emit (OpCodes.Dup);
3576 ig.Emit (OpCodes.Dup);
3577 if (IsRef || Variable.NeedsTemporary) {
3578 temp = new LocalTemporary (Type);
3584 StoreFromPtr (ig, type);
3586 Variable.EmitAssign (ec);
3594 public void AddressOf (EmitContext ec, AddressOp mode)
3596 Variable.EmitInstance (ec);
3597 Variable.EmitAddressOf (ec);
3604 public class LocalVariableReference : VariableReference, IVariable {
3605 public readonly string Name;
3607 public LocalInfo local_info;
3611 public LocalVariableReference (Block block, string name, Location l)
3616 eclass = ExprClass.Variable;
3620 // Setting `is_readonly' to false will allow you to create a writable
3621 // reference to a read-only variable. This is used by foreach and using.
3623 public LocalVariableReference (Block block, string name, Location l,
3624 LocalInfo local_info, bool is_readonly)
3625 : this (block, name, l)
3627 this.local_info = local_info;
3628 this.is_readonly = is_readonly;
3631 public VariableInfo VariableInfo {
3632 get { return local_info.VariableInfo; }
3635 public override bool IsRef {
3636 get { return false; }
3639 public bool IsReadOnly {
3640 get { return is_readonly; }
3643 public bool VerifyAssigned (EmitContext ec)
3645 VariableInfo variable_info = local_info.VariableInfo;
3646 return variable_info == null || variable_info.IsAssigned (ec, loc);
3649 void ResolveLocalInfo ()
3651 if (local_info == null) {
3652 local_info = Block.GetLocalInfo (Name);
3653 type = local_info.VariableType;
3654 is_readonly = local_info.ReadOnly;
3658 protected Expression DoResolveBase (EmitContext ec)
3660 type = local_info.VariableType;
3662 Expression e = Block.GetConstantExpression (Name);
3664 return e.Resolve (ec);
3666 if (!VerifyAssigned (ec))
3670 // If we are referencing a variable from the external block
3671 // flag it for capturing
3673 if (ec.MustCaptureVariable (local_info)) {
3674 if (local_info.AddressTaken){
3675 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3679 if (!ec.IsInProbingMode)
3681 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3682 variable = scope.AddLocal (local_info);
3683 type = variable.Type;
3690 public override Expression DoResolve (EmitContext ec)
3692 ResolveLocalInfo ();
3693 local_info.Used = true;
3695 if (type == null && local_info.Type is VarExpr) {
3696 local_info.VariableType = TypeManager.object_type;
3697 Error_VariableIsUsedBeforeItIsDeclared (Name);
3701 return DoResolveBase (ec);
3704 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3706 ResolveLocalInfo ();
3709 if (right_side == EmptyExpression.OutAccess)
3710 local_info.Used = true;
3712 // Infer implicitly typed local variable
3714 VarExpr ve = local_info.Type as VarExpr;
3716 ve.DoResolveLValue (ec, right_side);
3717 type = local_info.VariableType = ve.Type;
3724 if (right_side == EmptyExpression.OutAccess) {
3725 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3726 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3727 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3728 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3729 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3731 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3733 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3737 if (VariableInfo != null)
3738 VariableInfo.SetAssigned (ec);
3740 return DoResolveBase (ec);
3743 public bool VerifyFixed ()
3745 // A local Variable is always fixed.
3749 public override int GetHashCode ()
3751 return Name.GetHashCode ();
3754 public override bool Equals (object obj)
3756 LocalVariableReference lvr = obj as LocalVariableReference;
3760 return Name == lvr.Name && Block == lvr.Block;
3763 public override Variable Variable {
3764 get { return variable != null ? variable : local_info.Variable; }
3767 public override string ToString ()
3769 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3772 protected override void CloneTo (CloneContext clonectx, Expression t)
3774 LocalVariableReference target = (LocalVariableReference) t;
3776 target.Block = clonectx.LookupBlock (Block);
3777 if (local_info != null)
3778 target.local_info = clonectx.LookupVariable (local_info);
3783 /// This represents a reference to a parameter in the intermediate
3786 public class ParameterReference : VariableReference, IVariable {
3787 readonly ToplevelParameterInfo pi;
3788 readonly ToplevelBlock referenced;
3791 public bool is_ref, is_out;
3794 get { return is_out; }
3797 public override bool IsRef {
3798 get { return is_ref; }
3801 public string Name {
3802 get { return Parameter.Name; }
3805 public Parameter Parameter {
3806 get { return pi.Parameter; }
3809 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3812 this.referenced = referenced;
3814 eclass = ExprClass.Variable;
3817 public VariableInfo VariableInfo {
3818 get { return pi.VariableInfo; }
3821 public override Variable Variable {
3822 get { return variable != null ? variable : Parameter.Variable; }
3825 public bool VerifyFixed ()
3827 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3828 return Parameter.ModFlags == Parameter.Modifier.NONE;
3831 public bool IsAssigned (EmitContext ec, Location loc)
3833 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3836 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3840 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3842 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3845 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3849 public void SetAssigned (EmitContext ec)
3851 if (is_out && ec.DoFlowAnalysis)
3852 ec.CurrentBranching.SetAssigned (VariableInfo);
3855 public void SetFieldAssigned (EmitContext ec, string field_name)
3857 if (is_out && ec.DoFlowAnalysis)
3858 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3861 protected bool DoResolveBase (EmitContext ec)
3863 Parameter par = Parameter;
3864 if (!par.Resolve (ec)) {
3868 type = par.ParameterType;
3869 Parameter.Modifier mod = par.ModFlags;
3870 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3871 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3872 eclass = ExprClass.Variable;
3874 AnonymousContainer am = ec.CurrentAnonymousMethod;
3878 ToplevelBlock declared = pi.Block;
3879 if (is_ref && declared != referenced) {
3880 Report.Error (1628, Location,
3881 "Cannot use ref or out parameter `{0}' inside an " +
3882 "anonymous method block", par.Name);
3886 if (!am.IsIterator && declared == referenced)
3889 // Don't capture aruments when the probing is on
3890 if (!ec.IsInProbingMode) {
3891 ScopeInfo scope = declared.CreateScopeInfo ();
3892 variable = scope.AddParameter (par, pi.Index);
3893 type = variable.Type;
3898 public override int GetHashCode ()
3900 return Name.GetHashCode ();
3903 public override bool Equals (object obj)
3905 ParameterReference pr = obj as ParameterReference;
3909 return Name == pr.Name && referenced == pr.referenced;
3913 // Notice that for ref/out parameters, the type exposed is not the
3914 // same type exposed externally.
3917 // externally we expose "int&"
3918 // here we expose "int".
3920 // We record this in "is_ref". This means that the type system can treat
3921 // the type as it is expected, but when we generate the code, we generate
3922 // the alternate kind of code.
3924 public override Expression DoResolve (EmitContext ec)
3926 if (!DoResolveBase (ec))
3929 if (is_out && ec.DoFlowAnalysis &&
3930 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3936 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3938 if (!DoResolveBase (ec))
3941 // HACK: parameters are not captured when probing is on
3942 if (!ec.IsInProbingMode)
3948 static public void EmitLdArg (ILGenerator ig, int x)
3952 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3953 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3954 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3955 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3956 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3959 ig.Emit (OpCodes.Ldarg, x);
3962 public override string ToString ()
3964 return "ParameterReference[" + Name + "]";
3969 /// Used for arguments to New(), Invocation()
3971 public class Argument {
3972 public enum AType : byte {
3979 public static readonly Argument[] Empty = new Argument [0];
3981 public readonly AType ArgType;
3982 public Expression Expr;
3984 public Argument (Expression expr, AType type)
3987 this.ArgType = type;
3990 public Argument (Expression expr)
3993 this.ArgType = AType.Expression;
3998 if (ArgType == AType.Ref || ArgType == AType.Out)
3999 return TypeManager.GetReferenceType (Expr.Type);
4005 public Parameter.Modifier Modifier
4010 return Parameter.Modifier.OUT;
4013 return Parameter.Modifier.REF;
4016 return Parameter.Modifier.NONE;
4021 public static string FullDesc (Argument a)
4023 if (a.ArgType == AType.ArgList)
4026 return (a.ArgType == AType.Ref ? "ref " :
4027 (a.ArgType == AType.Out ? "out " : "")) +
4028 TypeManager.CSharpName (a.Expr.Type);
4031 public bool ResolveMethodGroup (EmitContext ec)
4033 SimpleName sn = Expr as SimpleName;
4035 Expr = sn.GetMethodGroup ();
4037 // FIXME: csc doesn't report any error if you try to use `ref' or
4038 // `out' in a delegate creation expression.
4039 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4046 public bool Resolve (EmitContext ec, Location loc)
4048 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4049 // Verify that the argument is readable
4050 if (ArgType != AType.Out)
4051 Expr = Expr.Resolve (ec);
4053 // Verify that the argument is writeable
4054 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4055 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4057 return Expr != null;
4061 public void Emit (EmitContext ec)
4063 if (ArgType != AType.Ref && ArgType != AType.Out) {
4068 AddressOp mode = AddressOp.Store;
4069 if (ArgType == AType.Ref)
4070 mode |= AddressOp.Load;
4072 IMemoryLocation ml = (IMemoryLocation) Expr;
4073 ParameterReference pr = ml as ParameterReference;
4076 // ParameterReferences might already be references, so we want
4077 // to pass just the value
4079 if (pr != null && pr.IsRef)
4082 ml.AddressOf (ec, mode);
4085 public void EmitArrayArgument (EmitContext ec)
4087 Type argtype = Expr.Type;
4090 if (argtype == TypeManager.uint32_type)
4091 ec.ig.Emit (OpCodes.Conv_U);
4092 else if (argtype == TypeManager.int64_type)
4093 ec.ig.Emit (OpCodes.Conv_Ovf_I);
4094 else if (argtype == TypeManager.uint64_type)
4095 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
4098 public Argument Clone (CloneContext clonectx)
4100 return new Argument (Expr.Clone (clonectx), ArgType);
4105 /// Invocation of methods or delegates.
4107 public class Invocation : ExpressionStatement {
4108 protected ArrayList Arguments;
4110 protected MethodGroupExpr mg;
4113 // arguments is an ArrayList, but we do not want to typecast,
4114 // as it might be null.
4116 public Invocation (Expression expr, ArrayList arguments)
4118 SimpleName sn = expr as SimpleName;
4120 this.expr = sn.GetMethodGroup ();
4124 Arguments = arguments;
4125 loc = expr.Location;
4128 public static string FullMethodDesc (MethodBase mb)
4134 if (mb is MethodInfo) {
4135 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4139 sb = new StringBuilder ();
4141 sb.Append (TypeManager.CSharpSignature (mb));
4142 return sb.ToString ();
4145 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4147 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4148 name, arg_count.ToString ());
4151 public override Expression DoResolve (EmitContext ec)
4153 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4154 if (expr_resolved == null)
4157 mg = expr_resolved as MethodGroupExpr;
4159 Type expr_type = expr_resolved.Type;
4161 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4162 return (new DelegateInvocation (
4163 expr_resolved, Arguments, loc)).Resolve (ec);
4165 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4170 // Next, evaluate all the expressions in the argument list
4172 if (Arguments != null){
4173 foreach (Argument a in Arguments){
4174 if (!a.Resolve (ec, loc))
4179 mg = DoResolveOverload (ec);
4183 MethodInfo method = (MethodInfo)mg;
4184 if (method != null) {
4185 type = TypeManager.TypeToCoreType (method.ReturnType);
4186 Expression iexpr = mg.InstanceExpression;
4187 if (method.IsStatic) {
4188 if (iexpr == null ||
4189 iexpr is This || iexpr is EmptyExpression ||
4190 mg.IdenticalTypeName) {
4191 mg.InstanceExpression = null;
4193 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4197 if (iexpr == null || iexpr is EmptyExpression) {
4198 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4204 if (type.IsPointer){
4212 // Only base will allow this invocation to happen.
4214 if (mg.IsBase && method.IsAbstract){
4215 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4219 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4221 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4223 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4227 if (IsSpecialMethodInvocation (method)) {
4231 if (mg.InstanceExpression != null){
4232 mg.InstanceExpression.CheckMarshalByRefAccess ();
4235 // This is used to check that no methods are called in struct
4236 // constructors before all the fields on the struct have been
4239 if (!method.IsStatic){
4240 This mgthis = mg.InstanceExpression as This;
4241 if (mgthis != null){
4242 if (!mgthis.CheckThisUsage (ec))
4248 eclass = ExprClass.Value;
4252 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4254 return mg.OverloadResolve (ec, Arguments, false, loc);
4257 bool IsSpecialMethodInvocation (MethodBase method)
4259 if (!TypeManager.IsSpecialMethod (method))
4262 Report.SymbolRelatedToPreviousError (method);
4263 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4264 TypeManager.CSharpSignature (method, true));
4270 // Emits the list of arguments as an array
4272 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4274 ILGenerator ig = ec.ig;
4276 for (int j = 0; j < count; j++){
4277 Argument a = (Argument) arguments [j + idx];
4280 IntConstant.EmitInt (ig, count);
4281 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4284 ig.Emit (OpCodes.Dup);
4285 IntConstant.EmitInt (ig, j);
4287 bool is_stobj, has_type_arg;
4288 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4290 ig.Emit (OpCodes.Ldelema, t);
4302 /// Emits a list of resolved Arguments that are in the arguments
4305 /// The MethodBase argument might be null if the
4306 /// emission of the arguments is known not to contain
4307 /// a `params' field (for example in constructors or other routines
4308 /// that keep their arguments in this structure)
4310 /// if `dup_args' is true, a copy of the arguments will be left
4311 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4312 /// which will be duplicated before any other args. Only EmitCall
4313 /// should be using this interface.
4315 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4317 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4319 LocalTemporary [] temps = null;
4321 if (dup_args && top != 0)
4322 temps = new LocalTemporary [top];
4324 int argument_index = 0;
4326 for (int i = 0; i < top; i++){
4328 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4329 Type p_type = pd.ParameterType (i);
4330 int params_args_count = arguments == null ?
4331 0 : arguments.Count - top + 1;
4333 // Fill not provided argument
4334 if (params_args_count <= 0) {
4335 ILGenerator ig = ec.ig;
4336 IntConstant.EmitInt (ig, 0);
4337 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (p_type));
4340 // Special case if we are passing the same data as the
4341 // params argument, we do not need to recreate an array.
4343 a = (Argument) arguments [argument_index];
4344 if (params_args_count == 1 && p_type == a.Type) {
4348 EmitParams (ec, arguments, i, params_args_count);
4349 argument_index += params_args_count;
4354 ec.ig.Emit (OpCodes.Dup);
4355 temps [i] = new LocalTemporary (p_type);
4356 temps [i].Store (ec);
4362 a = (Argument) arguments [argument_index++];
4365 ec.ig.Emit (OpCodes.Dup);
4366 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4371 if (this_arg != null)
4374 for (int i = 0; i < top; i ++) {
4375 temps [i].Emit (ec);
4376 temps [i].Release (ec);
4381 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4383 ParameterData pd = TypeManager.GetParameterData (mb);
4385 if (arguments == null)
4386 return new Type [0];
4388 Argument a = (Argument) arguments [pd.Count - 1];
4389 Arglist list = (Arglist) a.Expr;
4391 return list.ArgumentTypes;
4395 /// This checks the ConditionalAttribute on the method
4397 static bool IsMethodExcluded (MethodBase method)
4399 if (method.IsConstructor)
4402 IMethodData md = TypeManager.GetMethod (method);
4404 return md.IsExcluded ();
4406 // For some methods (generated by delegate class) GetMethod returns null
4407 // because they are not included in builder_to_method table
4408 if (method.DeclaringType is TypeBuilder)
4411 return AttributeTester.IsConditionalMethodExcluded (method);
4415 /// is_base tells whether we want to force the use of the `call'
4416 /// opcode instead of using callvirt. Call is required to call
4417 /// a specific method, while callvirt will always use the most
4418 /// recent method in the vtable.
4420 /// is_static tells whether this is an invocation on a static method
4422 /// instance_expr is an expression that represents the instance
4423 /// it must be non-null if is_static is false.
4425 /// method is the method to invoke.
4427 /// Arguments is the list of arguments to pass to the method or constructor.
4429 public static void EmitCall (EmitContext ec, bool is_base,
4430 Expression instance_expr,
4431 MethodBase method, ArrayList Arguments, Location loc)
4433 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4436 // `dup_args' leaves an extra copy of the arguments on the stack
4437 // `omit_args' does not leave any arguments at all.
4438 // So, basically, you could make one call with `dup_args' set to true,
4439 // and then another with `omit_args' set to true, and the two calls
4440 // would have the same set of arguments. However, each argument would
4441 // only have been evaluated once.
4442 public static void EmitCall (EmitContext ec, bool is_base,
4443 Expression instance_expr,
4444 MethodBase method, ArrayList Arguments, Location loc,
4445 bool dup_args, bool omit_args)
4447 ILGenerator ig = ec.ig;
4448 bool struct_call = false;
4449 bool this_call = false;
4450 LocalTemporary this_arg = null;
4452 Type decl_type = method.DeclaringType;
4454 if (!RootContext.StdLib) {
4455 // Replace any calls to the system's System.Array type with calls to
4456 // the newly created one.
4457 if (method == TypeManager.system_int_array_get_length)
4458 method = TypeManager.int_array_get_length;
4459 else if (method == TypeManager.system_int_array_get_rank)
4460 method = TypeManager.int_array_get_rank;
4461 else if (method == TypeManager.system_object_array_clone)
4462 method = TypeManager.object_array_clone;
4463 else if (method == TypeManager.system_int_array_get_length_int)
4464 method = TypeManager.int_array_get_length_int;
4465 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4466 method = TypeManager.int_array_get_lower_bound_int;
4467 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4468 method = TypeManager.int_array_get_upper_bound_int;
4469 else if (method == TypeManager.system_void_array_copyto_array_int)
4470 method = TypeManager.void_array_copyto_array_int;
4473 if (!ec.IsInObsoleteScope) {
4475 // This checks ObsoleteAttribute on the method and on the declaring type
4477 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4479 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4481 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4483 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4487 if (IsMethodExcluded (method))
4490 bool is_static = method.IsStatic;
4492 if (instance_expr == EmptyExpression.Null) {
4493 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4497 this_call = instance_expr is This;
4498 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4502 // If this is ourselves, push "this"
4506 Type iexpr_type = instance_expr.Type;
4509 // Push the instance expression
4511 if (TypeManager.IsValueType (iexpr_type)) {
4513 // Special case: calls to a function declared in a
4514 // reference-type with a value-type argument need
4515 // to have their value boxed.
4516 if (decl_type.IsValueType ||
4517 TypeManager.IsGenericParameter (iexpr_type)) {
4519 // If the expression implements IMemoryLocation, then
4520 // we can optimize and use AddressOf on the
4523 // If not we have to use some temporary storage for
4525 if (instance_expr is IMemoryLocation) {
4526 ((IMemoryLocation)instance_expr).
4527 AddressOf (ec, AddressOp.LoadStore);
4529 LocalTemporary temp = new LocalTemporary (iexpr_type);
4530 instance_expr.Emit (ec);
4532 temp.AddressOf (ec, AddressOp.Load);
4535 // avoid the overhead of doing this all the time.
4537 t = TypeManager.GetReferenceType (iexpr_type);
4539 instance_expr.Emit (ec);
4540 ig.Emit (OpCodes.Box, instance_expr.Type);
4541 t = TypeManager.object_type;
4544 instance_expr.Emit (ec);
4545 t = instance_expr.Type;
4549 ig.Emit (OpCodes.Dup);
4550 if (Arguments != null && Arguments.Count != 0) {
4551 this_arg = new LocalTemporary (t);
4552 this_arg.Store (ec);
4559 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4562 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4563 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4567 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4568 call_op = OpCodes.Call;
4570 call_op = OpCodes.Callvirt;
4572 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4573 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4574 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4581 // and DoFoo is not virtual, you can omit the callvirt,
4582 // because you don't need the null checking behavior.
4584 if (method is MethodInfo)
4585 ig.Emit (call_op, (MethodInfo) method);
4587 ig.Emit (call_op, (ConstructorInfo) method);
4590 public override void Emit (EmitContext ec)
4592 mg.EmitCall (ec, Arguments);
4595 public override void EmitStatement (EmitContext ec)
4600 // Pop the return value if there is one
4602 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4603 ec.ig.Emit (OpCodes.Pop);
4606 protected override void CloneTo (CloneContext clonectx, Expression t)
4608 Invocation target = (Invocation) t;
4610 if (Arguments != null) {
4611 target.Arguments = new ArrayList (Arguments.Count);
4612 foreach (Argument a in Arguments)
4613 target.Arguments.Add (a.Clone (clonectx));
4616 target.expr = expr.Clone (clonectx);
4620 public class InvocationOrCast : ExpressionStatement
4623 Expression argument;
4625 public InvocationOrCast (Expression expr, Expression argument)
4628 this.argument = argument;
4629 this.loc = expr.Location;
4632 public override Expression DoResolve (EmitContext ec)
4635 // First try to resolve it as a cast.
4637 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4638 if ((te != null) && (te.eclass == ExprClass.Type)) {
4639 Cast cast = new Cast (te, argument, loc);
4640 return cast.Resolve (ec);
4644 // This can either be a type or a delegate invocation.
4645 // Let's just resolve it and see what we'll get.
4647 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4652 // Ok, so it's a Cast.
4654 if (expr.eclass == ExprClass.Type) {
4655 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4656 return cast.Resolve (ec);
4660 // It's a delegate invocation.
4662 if (!TypeManager.IsDelegateType (expr.Type)) {
4663 Error (149, "Method name expected");
4667 ArrayList args = new ArrayList ();
4668 args.Add (new Argument (argument, Argument.AType.Expression));
4669 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4670 return invocation.Resolve (ec);
4673 public override ExpressionStatement ResolveStatement (EmitContext ec)
4676 // First try to resolve it as a cast.
4678 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4679 if ((te != null) && (te.eclass == ExprClass.Type)) {
4680 Error_InvalidExpressionStatement ();
4685 // This can either be a type or a delegate invocation.
4686 // Let's just resolve it and see what we'll get.
4688 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4689 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4690 Error_InvalidExpressionStatement ();
4695 // It's a delegate invocation.
4697 if (!TypeManager.IsDelegateType (expr.Type)) {
4698 Error (149, "Method name expected");
4702 ArrayList args = new ArrayList ();
4703 args.Add (new Argument (argument, Argument.AType.Expression));
4704 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4705 return invocation.ResolveStatement (ec);
4708 public override void Emit (EmitContext ec)
4710 throw new Exception ("Cannot happen");
4713 public override void EmitStatement (EmitContext ec)
4715 throw new Exception ("Cannot happen");
4718 protected override void CloneTo (CloneContext clonectx, Expression t)
4720 InvocationOrCast target = (InvocationOrCast) t;
4722 target.expr = expr.Clone (clonectx);
4723 target.argument = argument.Clone (clonectx);
4728 // This class is used to "disable" the code generation for the
4729 // temporary variable when initializing value types.
4731 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4732 public void AddressOf (EmitContext ec, AddressOp Mode)
4739 /// Implements the new expression
4741 public class New : ExpressionStatement, IMemoryLocation {
4742 ArrayList Arguments;
4745 // During bootstrap, it contains the RequestedType,
4746 // but if `type' is not null, it *might* contain a NewDelegate
4747 // (because of field multi-initialization)
4749 public Expression RequestedType;
4751 MethodGroupExpr method;
4754 // If set, the new expression is for a value_target, and
4755 // we will not leave anything on the stack.
4757 Expression value_target;
4758 bool value_target_set = false;
4759 bool is_type_parameter = false;
4761 public New (Expression requested_type, ArrayList arguments, Location l)
4763 RequestedType = requested_type;
4764 Arguments = arguments;
4768 public bool SetValueTypeVariable (Expression value)
4770 value_target = value;
4771 value_target_set = true;
4772 if (!(value_target is IMemoryLocation)){
4773 Error_UnexpectedKind (null, "variable", loc);
4780 // This function is used to disable the following code sequence for
4781 // value type initialization:
4783 // AddressOf (temporary)
4787 // Instead the provide will have provided us with the address on the
4788 // stack to store the results.
4790 static Expression MyEmptyExpression;
4792 public void DisableTemporaryValueType ()
4794 if (MyEmptyExpression == null)
4795 MyEmptyExpression = new EmptyAddressOf ();
4798 // To enable this, look into:
4799 // test-34 and test-89 and self bootstrapping.
4801 // For instance, we can avoid a copy by using `newobj'
4802 // instead of Call + Push-temp on value types.
4803 // value_target = MyEmptyExpression;
4808 /// Converts complex core type syntax like 'new int ()' to simple constant
4810 public static Constant Constantify (Type t)
4812 if (t == TypeManager.int32_type)
4813 return new IntConstant (0, Location.Null);
4814 if (t == TypeManager.uint32_type)
4815 return new UIntConstant (0, Location.Null);
4816 if (t == TypeManager.int64_type)
4817 return new LongConstant (0, Location.Null);
4818 if (t == TypeManager.uint64_type)
4819 return new ULongConstant (0, Location.Null);
4820 if (t == TypeManager.float_type)
4821 return new FloatConstant (0, Location.Null);
4822 if (t == TypeManager.double_type)
4823 return new DoubleConstant (0, Location.Null);
4824 if (t == TypeManager.short_type)
4825 return new ShortConstant (0, Location.Null);
4826 if (t == TypeManager.ushort_type)
4827 return new UShortConstant (0, Location.Null);
4828 if (t == TypeManager.sbyte_type)
4829 return new SByteConstant (0, Location.Null);
4830 if (t == TypeManager.byte_type)
4831 return new ByteConstant (0, Location.Null);
4832 if (t == TypeManager.char_type)
4833 return new CharConstant ('\0', Location.Null);
4834 if (t == TypeManager.bool_type)
4835 return new BoolConstant (false, Location.Null);
4836 if (t == TypeManager.decimal_type)
4837 return new DecimalConstant (0, Location.Null);
4838 if (TypeManager.IsEnumType (t))
4839 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
4845 // Checks whether the type is an interface that has the
4846 // [ComImport, CoClass] attributes and must be treated
4849 public Expression CheckComImport (EmitContext ec)
4851 if (!type.IsInterface)
4855 // Turn the call into:
4856 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
4858 Type real_class = AttributeTester.GetCoClassAttribute (type);
4859 if (real_class == null)
4862 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
4863 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
4864 return cast.Resolve (ec);
4867 public override Expression DoResolve (EmitContext ec)
4870 // The New DoResolve might be called twice when initializing field
4871 // expressions (see EmitFieldInitializers, the call to
4872 // GetInitializerExpression will perform a resolve on the expression,
4873 // and later the assign will trigger another resolution
4875 // This leads to bugs (#37014)
4878 if (RequestedType is NewDelegate)
4879 return RequestedType;
4883 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
4889 if (type == TypeManager.void_type) {
4890 Error_VoidInvalidInTheContext (loc);
4894 if (type.IsPointer) {
4895 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
4896 TypeManager.CSharpName (type));
4900 if (Arguments == null) {
4901 Expression c = Constantify (type);
4906 if (TypeManager.IsDelegateType (type)) {
4907 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4908 if (RequestedType != null)
4909 if (!(RequestedType is DelegateCreation))
4910 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
4911 return RequestedType;
4915 if (type.IsGenericParameter) {
4916 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
4918 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
4919 Error (304, String.Format (
4920 "Cannot create an instance of the " +
4921 "variable type '{0}' because it " +
4922 "doesn't have the new() constraint",
4927 if ((Arguments != null) && (Arguments.Count != 0)) {
4928 Error (417, String.Format (
4929 "`{0}': cannot provide arguments " +
4930 "when creating an instance of a " +
4931 "variable type.", type));
4935 is_type_parameter = true;
4936 eclass = ExprClass.Value;
4941 if (type.IsAbstract && type.IsSealed) {
4942 Report.SymbolRelatedToPreviousError (type);
4943 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
4947 if (type.IsInterface || type.IsAbstract){
4948 if (!TypeManager.IsGenericType (type)) {
4949 RequestedType = CheckComImport (ec);
4950 if (RequestedType != null)
4951 return RequestedType;
4954 Report.SymbolRelatedToPreviousError (type);
4955 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
4959 bool is_struct = type.IsValueType;
4960 eclass = ExprClass.Value;
4963 // SRE returns a match for .ctor () on structs (the object constructor),
4964 // so we have to manually ignore it.
4966 if (is_struct && Arguments == null)
4969 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
4970 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
4971 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4973 if (Arguments != null){
4974 foreach (Argument a in Arguments){
4975 if (!a.Resolve (ec, loc))
4983 method = ml as MethodGroupExpr;
4984 if (method == null) {
4985 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
4989 method = method.OverloadResolve (ec, Arguments, false, loc);
4996 bool DoEmitTypeParameter (EmitContext ec)
4999 ILGenerator ig = ec.ig;
5000 // IMemoryLocation ml;
5002 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5003 new Type [] { type });
5005 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5006 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5007 ig.Emit (OpCodes.Call, ci);
5011 // Allow DoEmit() to be called multiple times.
5012 // We need to create a new LocalTemporary each time since
5013 // you can't share LocalBuilders among ILGeneators.
5014 LocalTemporary temp = new LocalTemporary (type);
5016 Label label_activator = ig.DefineLabel ();
5017 Label label_end = ig.DefineLabel ();
5019 temp.AddressOf (ec, AddressOp.Store);
5020 ig.Emit (OpCodes.Initobj, type);
5023 ig.Emit (OpCodes.Box, type);
5024 ig.Emit (OpCodes.Brfalse, label_activator);
5026 temp.AddressOf (ec, AddressOp.Store);
5027 ig.Emit (OpCodes.Initobj, type);
5029 ig.Emit (OpCodes.Br, label_end);
5031 ig.MarkLabel (label_activator);
5033 ig.Emit (OpCodes.Call, ci);
5034 ig.MarkLabel (label_end);
5037 throw new InternalErrorException ();
5042 // This DoEmit can be invoked in two contexts:
5043 // * As a mechanism that will leave a value on the stack (new object)
5044 // * As one that wont (init struct)
5046 // You can control whether a value is required on the stack by passing
5047 // need_value_on_stack. The code *might* leave a value on the stack
5048 // so it must be popped manually
5050 // If we are dealing with a ValueType, we have a few
5051 // situations to deal with:
5053 // * The target is a ValueType, and we have been provided
5054 // the instance (this is easy, we are being assigned).
5056 // * The target of New is being passed as an argument,
5057 // to a boxing operation or a function that takes a
5060 // In this case, we need to create a temporary variable
5061 // that is the argument of New.
5063 // Returns whether a value is left on the stack
5065 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5067 bool is_value_type = TypeManager.IsValueType (type);
5068 ILGenerator ig = ec.ig;
5073 // Allow DoEmit() to be called multiple times.
5074 // We need to create a new LocalTemporary each time since
5075 // you can't share LocalBuilders among ILGeneators.
5076 if (!value_target_set)
5077 value_target = new LocalTemporary (type);
5079 ml = (IMemoryLocation) value_target;
5080 ml.AddressOf (ec, AddressOp.Store);
5084 method.EmitArguments (ec, Arguments);
5088 ig.Emit (OpCodes.Initobj, type);
5090 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5091 if (need_value_on_stack){
5092 value_target.Emit (ec);
5097 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5102 public override void Emit (EmitContext ec)
5104 if (is_type_parameter)
5105 DoEmitTypeParameter (ec);
5110 public override void EmitStatement (EmitContext ec)
5112 bool value_on_stack;
5114 if (is_type_parameter)
5115 value_on_stack = DoEmitTypeParameter (ec);
5117 value_on_stack = DoEmit (ec, false);
5120 ec.ig.Emit (OpCodes.Pop);
5124 public void AddressOf (EmitContext ec, AddressOp Mode)
5126 if (is_type_parameter) {
5127 LocalTemporary temp = new LocalTemporary (type);
5128 DoEmitTypeParameter (ec);
5130 temp.AddressOf (ec, Mode);
5134 if (!type.IsValueType){
5136 // We throw an exception. So far, I believe we only need to support
5138 // foreach (int j in new StructType ())
5141 throw new Exception ("AddressOf should not be used for classes");
5144 if (!value_target_set)
5145 value_target = new LocalTemporary (type);
5146 IMemoryLocation ml = (IMemoryLocation) value_target;
5148 ml.AddressOf (ec, AddressOp.Store);
5149 if (method == null) {
5150 ec.ig.Emit (OpCodes.Initobj, type);
5152 method.EmitArguments (ec, Arguments);
5153 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5156 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5159 protected override void CloneTo (CloneContext clonectx, Expression t)
5161 New target = (New) t;
5163 target.RequestedType = RequestedType.Clone (clonectx);
5164 if (Arguments != null){
5165 target.Arguments = new ArrayList ();
5166 foreach (Argument a in Arguments){
5167 target.Arguments.Add (a.Clone (clonectx));
5174 /// 14.5.10.2: Represents an array creation expression.
5178 /// There are two possible scenarios here: one is an array creation
5179 /// expression that specifies the dimensions and optionally the
5180 /// initialization data and the other which does not need dimensions
5181 /// specified but where initialization data is mandatory.
5183 public class ArrayCreation : Expression {
5184 Expression requested_base_type;
5185 ArrayList initializers;
5188 // The list of Argument types.
5189 // This is used to construct the `newarray' or constructor signature
5191 protected ArrayList arguments;
5193 protected Type array_element_type;
5194 bool expect_initializers = false;
5195 int num_arguments = 0;
5196 protected int dimensions;
5197 protected readonly string rank;
5199 protected ArrayList array_data;
5203 // The number of constants in array initializers
5204 int const_initializers_count;
5205 bool only_constant_initializers;
5207 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5209 this.requested_base_type = requested_base_type;
5210 this.initializers = initializers;
5214 arguments = new ArrayList ();
5216 foreach (Expression e in exprs) {
5217 arguments.Add (new Argument (e, Argument.AType.Expression));
5222 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5224 this.requested_base_type = requested_base_type;
5225 this.initializers = initializers;
5229 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5231 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5233 //dimensions = tmp.Length - 1;
5234 expect_initializers = true;
5237 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5239 StringBuilder sb = new StringBuilder (rank);
5242 for (int i = 1; i < idx_count; i++)
5247 return new ComposedCast (base_type, sb.ToString (), loc);
5250 void Error_IncorrectArrayInitializer ()
5252 Error (178, "Invalid rank specifier: expected `,' or `]'");
5255 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5257 if (specified_dims) {
5258 Argument a = (Argument) arguments [idx];
5260 if (!a.Resolve (ec, loc))
5263 Constant c = a.Expr as Constant;
5265 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5269 Report.Error (150, a.Expr.Location, "A constant value is expected");
5273 int value = (int) c.GetValue ();
5275 if (value != probe.Count) {
5276 Error_IncorrectArrayInitializer ();
5280 bounds [idx] = value;
5283 int child_bounds = -1;
5284 only_constant_initializers = true;
5285 for (int i = 0; i < probe.Count; ++i) {
5286 object o = probe [i];
5287 if (o is ArrayList) {
5288 ArrayList sub_probe = o as ArrayList;
5289 int current_bounds = sub_probe.Count;
5291 if (child_bounds == -1)
5292 child_bounds = current_bounds;
5294 else if (child_bounds != current_bounds){
5295 Error_IncorrectArrayInitializer ();
5298 if (idx + 1 >= dimensions){
5299 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5303 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5307 if (child_bounds != -1){
5308 Error_IncorrectArrayInitializer ();
5312 Expression element = ResolveArrayElement (ec, (Expression) o);
5313 if (element == null)
5316 // Initializers with the default values can be ignored
5317 Constant c = element as Constant;
5319 if (c.IsDefaultInitializer (array_element_type)) {
5323 ++const_initializers_count;
5326 only_constant_initializers = false;
5329 array_data.Add (element);
5336 public void UpdateIndices ()
5339 for (ArrayList probe = initializers; probe != null;) {
5340 if (probe.Count > 0 && probe [0] is ArrayList) {
5341 Expression e = new IntConstant (probe.Count, Location.Null);
5342 arguments.Add (new Argument (e, Argument.AType.Expression));
5344 bounds [i++] = probe.Count;
5346 probe = (ArrayList) probe [0];
5349 Expression e = new IntConstant (probe.Count, Location.Null);
5350 arguments.Add (new Argument (e, Argument.AType.Expression));
5352 bounds [i++] = probe.Count;
5359 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5361 element = element.Resolve (ec);
5362 if (element == null)
5365 return Convert.ImplicitConversionRequired (
5366 ec, element, array_element_type, loc);
5369 protected bool ResolveInitializers (EmitContext ec)
5371 if (initializers == null) {
5372 return !expect_initializers;
5376 // We use this to store all the date values in the order in which we
5377 // will need to store them in the byte blob later
5379 array_data = new ArrayList ();
5380 bounds = new System.Collections.Specialized.HybridDictionary ();
5382 if (arguments != null)
5383 return CheckIndices (ec, initializers, 0, true);
5385 arguments = new ArrayList ();
5387 if (!CheckIndices (ec, initializers, 0, false))
5396 // Resolved the type of the array
5398 bool ResolveArrayType (EmitContext ec)
5400 if (requested_base_type == null) {
5401 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5405 StringBuilder array_qualifier = new StringBuilder (rank);
5408 // `In the first form allocates an array instace of the type that results
5409 // from deleting each of the individual expression from the expression list'
5411 if (num_arguments > 0) {
5412 array_qualifier.Append ("[");
5413 for (int i = num_arguments-1; i > 0; i--)
5414 array_qualifier.Append (",");
5415 array_qualifier.Append ("]");
5421 TypeExpr array_type_expr;
5422 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5423 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5424 if (array_type_expr == null)
5427 type = array_type_expr.Type;
5428 array_element_type = TypeManager.GetElementType (type);
5429 dimensions = type.GetArrayRank ();
5434 public override Expression DoResolve (EmitContext ec)
5439 if (!ResolveArrayType (ec))
5442 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5443 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5444 TypeManager.CSharpName (array_element_type));
5448 // First step is to validate the initializers and fill
5449 // in any missing bits
5451 if (!ResolveInitializers (ec))
5454 if (arguments.Count != dimensions) {
5455 Error_IncorrectArrayInitializer ();
5458 foreach (Argument a in arguments){
5459 if (!a.Resolve (ec, loc))
5462 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5463 if (real_arg == null)
5469 eclass = ExprClass.Value;
5473 MethodInfo GetArrayMethod (int arguments)
5475 ModuleBuilder mb = CodeGen.Module.Builder;
5477 Type[] arg_types = new Type[arguments];
5478 for (int i = 0; i < arguments; i++)
5479 arg_types[i] = TypeManager.int32_type;
5481 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5485 Report.Error (-6, "New invocation: Can not find a constructor for " +
5486 "this argument list");
5493 byte [] MakeByteBlob ()
5498 int count = array_data.Count;
5500 if (array_element_type.IsEnum)
5501 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5503 factor = GetTypeSize (array_element_type);
5505 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5507 data = new byte [(count * factor + 3) & ~3];
5510 for (int i = 0; i < count; ++i) {
5511 object v = array_data [i];
5513 if (v is EnumConstant)
5514 v = ((EnumConstant) v).Child;
5516 if (v is Constant && !(v is StringConstant))
5517 v = ((Constant) v).GetValue ();
5523 if (array_element_type == TypeManager.int64_type){
5524 if (!(v is Expression)){
5525 long val = (long) v;
5527 for (int j = 0; j < factor; ++j) {
5528 data [idx + j] = (byte) (val & 0xFF);
5532 } else if (array_element_type == TypeManager.uint64_type){
5533 if (!(v is Expression)){
5534 ulong val = (ulong) v;
5536 for (int j = 0; j < factor; ++j) {
5537 data [idx + j] = (byte) (val & 0xFF);
5541 } else if (array_element_type == TypeManager.float_type) {
5542 if (!(v is Expression)){
5543 element = BitConverter.GetBytes ((float) v);
5545 for (int j = 0; j < factor; ++j)
5546 data [idx + j] = element [j];
5547 if (!BitConverter.IsLittleEndian)
5548 System.Array.Reverse (data, idx, 4);
5550 } else if (array_element_type == TypeManager.double_type) {
5551 if (!(v is Expression)){
5552 element = BitConverter.GetBytes ((double) v);
5554 for (int j = 0; j < factor; ++j)
5555 data [idx + j] = element [j];
5557 // FIXME: Handle the ARM float format.
5558 if (!BitConverter.IsLittleEndian)
5559 System.Array.Reverse (data, idx, 8);
5561 } else if (array_element_type == TypeManager.char_type){
5562 if (!(v is Expression)){
5563 int val = (int) ((char) v);
5565 data [idx] = (byte) (val & 0xff);
5566 data [idx+1] = (byte) (val >> 8);
5568 } else if (array_element_type == TypeManager.short_type){
5569 if (!(v is Expression)){
5570 int val = (int) ((short) v);
5572 data [idx] = (byte) (val & 0xff);
5573 data [idx+1] = (byte) (val >> 8);
5575 } else if (array_element_type == TypeManager.ushort_type){
5576 if (!(v is Expression)){
5577 int val = (int) ((ushort) v);
5579 data [idx] = (byte) (val & 0xff);
5580 data [idx+1] = (byte) (val >> 8);
5582 } else if (array_element_type == TypeManager.int32_type) {
5583 if (!(v is Expression)){
5586 data [idx] = (byte) (val & 0xff);
5587 data [idx+1] = (byte) ((val >> 8) & 0xff);
5588 data [idx+2] = (byte) ((val >> 16) & 0xff);
5589 data [idx+3] = (byte) (val >> 24);
5591 } else if (array_element_type == TypeManager.uint32_type) {
5592 if (!(v is Expression)){
5593 uint val = (uint) v;
5595 data [idx] = (byte) (val & 0xff);
5596 data [idx+1] = (byte) ((val >> 8) & 0xff);
5597 data [idx+2] = (byte) ((val >> 16) & 0xff);
5598 data [idx+3] = (byte) (val >> 24);
5600 } else if (array_element_type == TypeManager.sbyte_type) {
5601 if (!(v is Expression)){
5602 sbyte val = (sbyte) v;
5603 data [idx] = (byte) val;
5605 } else if (array_element_type == TypeManager.byte_type) {
5606 if (!(v is Expression)){
5607 byte val = (byte) v;
5608 data [idx] = (byte) val;
5610 } else if (array_element_type == TypeManager.bool_type) {
5611 if (!(v is Expression)){
5612 bool val = (bool) v;
5613 data [idx] = (byte) (val ? 1 : 0);
5615 } else if (array_element_type == TypeManager.decimal_type){
5616 if (!(v is Expression)){
5617 int [] bits = Decimal.GetBits ((decimal) v);
5620 // FIXME: For some reason, this doesn't work on the MS runtime.
5621 int [] nbits = new int [4];
5622 nbits [0] = bits [3];
5623 nbits [1] = bits [2];
5624 nbits [2] = bits [0];
5625 nbits [3] = bits [1];
5627 for (int j = 0; j < 4; j++){
5628 data [p++] = (byte) (nbits [j] & 0xff);
5629 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5630 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5631 data [p++] = (byte) (nbits [j] >> 24);
5635 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5644 // Emits the initializers for the array
5646 void EmitStaticInitializers (EmitContext ec)
5649 // First, the static data
5652 ILGenerator ig = ec.ig;
5654 byte [] data = MakeByteBlob ();
5656 fb = RootContext.MakeStaticData (data);
5658 ig.Emit (OpCodes.Dup);
5659 ig.Emit (OpCodes.Ldtoken, fb);
5660 ig.Emit (OpCodes.Call,
5661 TypeManager.void_initializearray_array_fieldhandle);
5665 // Emits pieces of the array that can not be computed at compile
5666 // time (variables and string locations).
5668 // This always expect the top value on the stack to be the array
5670 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5672 ILGenerator ig = ec.ig;
5673 int dims = bounds.Count;
5674 int [] current_pos = new int [dims];
5676 MethodInfo set = null;
5679 Type [] args = new Type [dims + 1];
5681 for (int j = 0; j < dims; j++)
5682 args [j] = TypeManager.int32_type;
5683 args [dims] = array_element_type;
5685 set = CodeGen.Module.Builder.GetArrayMethod (
5687 CallingConventions.HasThis | CallingConventions.Standard,
5688 TypeManager.void_type, args);
5691 for (int i = 0; i < array_data.Count; i++){
5693 Expression e = (Expression)array_data [i];
5695 // Constant can be initialized via StaticInitializer
5696 if (e != null && !(!emitConstants && e is Constant)) {
5697 Type etype = e.Type;
5699 ig.Emit (OpCodes.Dup);
5701 for (int idx = 0; idx < dims; idx++)
5702 IntConstant.EmitInt (ig, current_pos [idx]);
5705 // If we are dealing with a struct, get the
5706 // address of it, so we can store it.
5708 if ((dims == 1) && etype.IsValueType &&
5709 (!TypeManager.IsBuiltinOrEnum (etype) ||
5710 etype == TypeManager.decimal_type)) {
5715 // Let new know that we are providing
5716 // the address where to store the results
5718 n.DisableTemporaryValueType ();
5721 ig.Emit (OpCodes.Ldelema, etype);
5727 bool is_stobj, has_type_arg;
5728 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5730 ig.Emit (OpCodes.Stobj, etype);
5731 else if (has_type_arg)
5732 ig.Emit (op, etype);
5736 ig.Emit (OpCodes.Call, set);
5743 for (int j = dims - 1; j >= 0; j--){
5745 if (current_pos [j] < (int) bounds [j])
5747 current_pos [j] = 0;
5752 void EmitArrayArguments (EmitContext ec)
5754 foreach (Argument a in arguments)
5755 a.EmitArrayArgument (ec);
5758 public override void Emit (EmitContext ec)
5760 ILGenerator ig = ec.ig;
5762 EmitArrayArguments (ec);
5763 if (arguments.Count == 1)
5764 ig.Emit (OpCodes.Newarr, array_element_type);
5766 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5769 if (initializers == null)
5772 // Emit static initializer for arrays which have contain more than 4 items and
5773 // the static initializer will initialize at least 25% of array values.
5774 // NOTE: const_initializers_count does not contain default constant values.
5775 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5776 TypeManager.IsPrimitiveType (array_element_type)) {
5777 EmitStaticInitializers (ec);
5779 if (!only_constant_initializers)
5780 EmitDynamicInitializers (ec, false);
5782 EmitDynamicInitializers (ec, true);
5786 public override bool GetAttributableValue (Type valueType, out object value)
5788 if (arguments.Count != 1) {
5789 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
5790 return base.GetAttributableValue (null, out value);
5793 if (array_data == null) {
5794 Constant c = (Constant)((Argument)arguments [0]).Expr;
5795 if (c.IsDefaultValue) {
5796 value = Array.CreateInstance (array_element_type, 0);
5799 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
5800 return base.GetAttributableValue (null, out value);
5803 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
5804 object element_value;
5805 for (int i = 0; i < ret.Length; ++i)
5807 Expression e = (Expression)array_data [i];
5809 // Is null when an initializer is optimized (value == predefined value)
5813 if (!e.GetAttributableValue (array_element_type, out element_value)) {
5817 ret.SetValue (element_value, i);
5823 protected override void CloneTo (CloneContext clonectx, Expression t)
5825 ArrayCreation target = (ArrayCreation) t;
5827 if (requested_base_type != null)
5828 target.requested_base_type = requested_base_type.Clone (clonectx);
5830 if (arguments != null){
5831 target.arguments = new ArrayList (arguments.Count);
5832 foreach (Argument a in arguments)
5833 target.arguments.Add (a.Clone (clonectx));
5836 if (initializers != null){
5837 target.initializers = new ArrayList (initializers.Count);
5838 foreach (Expression initializer in initializers)
5839 target.initializers.Add (initializer.Clone (clonectx));
5845 // Represents an implicitly typed array epxression
5847 public class ImplicitlyTypedArrayCreation : ArrayCreation
5849 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
5850 : base (null, rank, initializers, loc)
5852 if (rank.Length > 2) {
5853 while (rank [++dimensions] == ',');
5859 public override Expression DoResolve (EmitContext ec)
5864 if (!ResolveInitializers (ec))
5867 if (array_element_type == null || array_element_type == TypeManager.null_type ||
5868 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
5869 arguments.Count != dimensions) {
5870 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
5875 // At this point we found common base type for all initializer elements
5876 // but we have to be sure that all static initializer elements are of
5879 UnifyInitializerElement (ec);
5881 type = TypeManager.GetConstructedType (array_element_type, rank);
5882 eclass = ExprClass.Value;
5887 // Converts static initializer only
5889 void UnifyInitializerElement (EmitContext ec)
5891 for (int i = 0; i < array_data.Count; ++i) {
5892 Expression e = (Expression)array_data[i];
5894 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
5898 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
5900 element = element.Resolve (ec);
5901 if (element == null)
5904 if (array_element_type == null) {
5905 array_element_type = element.Type;
5909 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
5913 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
5914 array_element_type = element.Type;
5918 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
5923 public sealed class CompilerGeneratedThis : This
5925 public static This Instance = new CompilerGeneratedThis ();
5927 private CompilerGeneratedThis ()
5928 : base (Location.Null)
5932 public override Expression DoResolve (EmitContext ec)
5934 eclass = ExprClass.Variable;
5935 type = ec.ContainerType;
5936 variable = new SimpleThis (type);
5942 /// Represents the `this' construct
5945 public class This : VariableReference, IVariable
5948 VariableInfo variable_info;
5949 protected Variable variable;
5952 public This (Block block, Location loc)
5958 public This (Location loc)
5963 public VariableInfo VariableInfo {
5964 get { return variable_info; }
5967 public bool VerifyFixed ()
5969 return !TypeManager.IsValueType (Type);
5972 public override bool IsRef {
5973 get { return is_struct; }
5976 public override Variable Variable {
5977 get { return variable; }
5980 public bool ResolveBase (EmitContext ec)
5982 eclass = ExprClass.Variable;
5984 if (ec.TypeContainer.CurrentType != null)
5985 type = ec.TypeContainer.CurrentType;
5987 type = ec.ContainerType;
5989 is_struct = ec.TypeContainer is Struct;
5992 Error (26, "Keyword `this' is not valid in a static property, " +
5993 "static method, or static field initializer");
5997 if (block != null) {
5998 if (block.Toplevel.ThisVariable != null)
5999 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6001 AnonymousContainer am = ec.CurrentAnonymousMethod;
6002 if (is_struct && (am != null) && !am.IsIterator) {
6003 Report.Error (1673, loc, "Anonymous methods inside structs " +
6004 "cannot access instance members of `this'. " +
6005 "Consider copying `this' to a local variable " +
6006 "outside the anonymous method and using the " +
6011 RootScopeInfo host = block.Toplevel.RootScope;
6012 if ((host != null) && !ec.IsConstructor &&
6013 (!is_struct || host.IsIterator)) {
6014 variable = host.CaptureThis ();
6015 type = variable.Type;
6020 if (variable == null)
6021 variable = new SimpleThis (type);
6027 // Called from Invocation to check if the invocation is correct
6029 public bool CheckThisUsage (EmitContext ec)
6031 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6032 !variable_info.IsAssigned (ec)) {
6033 Error (188, "The `this' object cannot be used before all of its " +
6034 "fields are assigned to");
6035 variable_info.SetAssigned (ec);
6042 public override Expression DoResolve (EmitContext ec)
6044 if (!ResolveBase (ec))
6048 if (ec.IsInFieldInitializer) {
6049 Error (27, "Keyword `this' is not available in the current context");
6056 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6058 if (!ResolveBase (ec))
6061 if (variable_info != null)
6062 variable_info.SetAssigned (ec);
6064 if (ec.TypeContainer is Class){
6065 Error (1604, "Cannot assign to 'this' because it is read-only");
6071 public override int GetHashCode()
6073 return block.GetHashCode ();
6076 public override bool Equals (object obj)
6078 This t = obj as This;
6082 return block == t.block;
6085 protected class SimpleThis : Variable
6089 public SimpleThis (Type type)
6094 public override Type Type {
6095 get { return type; }
6098 public override bool HasInstance {
6099 get { return false; }
6102 public override bool NeedsTemporary {
6103 get { return false; }
6106 public override void EmitInstance (EmitContext ec)
6111 public override void Emit (EmitContext ec)
6113 ec.ig.Emit (OpCodes.Ldarg_0);
6116 public override void EmitAssign (EmitContext ec)
6118 throw new InvalidOperationException ();
6121 public override void EmitAddressOf (EmitContext ec)
6123 ec.ig.Emit (OpCodes.Ldarg_0);
6127 protected override void CloneTo (CloneContext clonectx, Expression t)
6129 This target = (This) t;
6131 target.block = clonectx.LookupBlock (block);
6136 /// Represents the `__arglist' construct
6138 public class ArglistAccess : Expression
6140 public ArglistAccess (Location loc)
6145 public override Expression DoResolve (EmitContext ec)
6147 eclass = ExprClass.Variable;
6148 type = TypeManager.runtime_argument_handle_type;
6150 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6152 Error (190, "The __arglist construct is valid only within " +
6153 "a variable argument method");
6160 public override void Emit (EmitContext ec)
6162 ec.ig.Emit (OpCodes.Arglist);
6165 protected override void CloneTo (CloneContext clonectx, Expression target)
6172 /// Represents the `__arglist (....)' construct
6174 public class Arglist : Expression
6176 Argument[] Arguments;
6178 public Arglist (Location loc)
6179 : this (Argument.Empty, loc)
6183 public Arglist (Argument[] args, Location l)
6189 public Type[] ArgumentTypes {
6191 Type[] retval = new Type [Arguments.Length];
6192 for (int i = 0; i < Arguments.Length; i++)
6193 retval [i] = Arguments [i].Type;
6198 public override Expression DoResolve (EmitContext ec)
6200 eclass = ExprClass.Variable;
6201 type = TypeManager.runtime_argument_handle_type;
6203 foreach (Argument arg in Arguments) {
6204 if (!arg.Resolve (ec, loc))
6211 public override void Emit (EmitContext ec)
6213 foreach (Argument arg in Arguments)
6217 protected override void CloneTo (CloneContext clonectx, Expression t)
6219 Arglist target = (Arglist) t;
6221 target.Arguments = new Argument [Arguments.Length];
6222 for (int i = 0; i < Arguments.Length; i++)
6223 target.Arguments [i] = Arguments [i].Clone (clonectx);
6228 // This produces the value that renders an instance, used by the iterators code
6230 public class ProxyInstance : Expression, IMemoryLocation {
6231 public override Expression DoResolve (EmitContext ec)
6233 eclass = ExprClass.Variable;
6234 type = ec.ContainerType;
6238 public override void Emit (EmitContext ec)
6240 ec.ig.Emit (OpCodes.Ldarg_0);
6244 public void AddressOf (EmitContext ec, AddressOp mode)
6246 ec.ig.Emit (OpCodes.Ldarg_0);
6251 /// Implements the typeof operator
6253 public class TypeOf : Expression {
6254 Expression QueriedType;
6255 protected Type typearg;
6257 public TypeOf (Expression queried_type, Location l)
6259 QueriedType = queried_type;
6263 public override Expression DoResolve (EmitContext ec)
6265 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6269 typearg = texpr.Type;
6271 if (typearg == TypeManager.void_type) {
6272 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6276 if (typearg.IsPointer && !ec.InUnsafe){
6281 type = TypeManager.type_type;
6282 // Even though what is returned is a type object, it's treated as a value by the compiler.
6283 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6284 eclass = ExprClass.Value;
6288 public override void Emit (EmitContext ec)
6290 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6291 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6294 public override bool GetAttributableValue (Type valueType, out object value)
6296 if (TypeManager.ContainsGenericParameters (typearg) &&
6297 !TypeManager.IsGenericTypeDefinition (typearg)) {
6298 Report.SymbolRelatedToPreviousError (typearg);
6299 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6300 TypeManager.CSharpName (typearg));
6305 if (valueType == TypeManager.object_type) {
6306 value = (object)typearg;
6313 public Type TypeArgument
6321 protected override void CloneTo (CloneContext clonectx, Expression t)
6323 TypeOf target = (TypeOf) t;
6325 target.QueriedType = QueriedType.Clone (clonectx);
6330 /// Implements the `typeof (void)' operator
6332 public class TypeOfVoid : TypeOf {
6333 public TypeOfVoid (Location l) : base (null, l)
6338 public override Expression DoResolve (EmitContext ec)
6340 type = TypeManager.type_type;
6341 typearg = TypeManager.void_type;
6342 // See description in TypeOf.
6343 eclass = ExprClass.Value;
6349 /// Implements the sizeof expression
6351 public class SizeOf : Expression {
6352 readonly Expression QueriedType;
6355 public SizeOf (Expression queried_type, Location l)
6357 this.QueriedType = queried_type;
6361 public override Expression DoResolve (EmitContext ec)
6363 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6368 if (texpr is TypeParameterExpr){
6369 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6374 type_queried = texpr.Type;
6375 if (type_queried.IsEnum)
6376 type_queried = TypeManager.EnumToUnderlying (type_queried);
6378 if (type_queried == TypeManager.void_type) {
6379 Expression.Error_VoidInvalidInTheContext (loc);
6383 int size_of = GetTypeSize (type_queried);
6385 return new IntConstant (size_of, loc);
6389 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)",
6390 TypeManager.CSharpName (type_queried));
6394 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6398 type = TypeManager.int32_type;
6399 eclass = ExprClass.Value;
6403 public override void Emit (EmitContext ec)
6405 int size = GetTypeSize (type_queried);
6408 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6410 IntConstant.EmitInt (ec.ig, size);
6413 protected override void CloneTo (CloneContext clonectx, Expression t)
6419 /// Implements the qualified-alias-member (::) expression.
6421 public class QualifiedAliasMember : Expression
6423 string alias, identifier;
6425 public QualifiedAliasMember (string alias, string identifier, Location l)
6427 if (RootContext.Version == LanguageVersion.ISO_1)
6428 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6431 this.identifier = identifier;
6435 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6437 if (alias == "global")
6438 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6440 int errors = Report.Errors;
6441 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6443 if (errors == Report.Errors)
6444 Report.Error (432, loc, "Alias `{0}' not found", alias);
6447 if (fne.eclass != ExprClass.Namespace) {
6449 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6452 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6455 public override Expression DoResolve (EmitContext ec)
6457 FullNamedExpression fne;
6458 if (alias == "global") {
6459 fne = RootNamespace.Global;
6461 int errors = Report.Errors;
6462 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6464 if (errors == Report.Errors)
6465 Report.Error (432, loc, "Alias `{0}' not found", alias);
6470 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6474 if (!(retval is FullNamedExpression)) {
6475 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6479 // We defer this check till the end to match the behaviour of CSC
6480 if (fne.eclass != ExprClass.Namespace) {
6481 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6487 public override void Emit (EmitContext ec)
6489 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6493 public override string ToString ()
6495 return alias + "::" + identifier;
6498 public override string GetSignatureForError ()
6503 protected override void CloneTo (CloneContext clonectx, Expression t)
6510 /// Implements the member access expression
6512 public class MemberAccess : Expression {
6513 public readonly string Identifier;
6515 readonly TypeArguments args;
6517 public MemberAccess (Expression expr, string id)
6518 : this (expr, id, expr.Location)
6522 public MemberAccess (Expression expr, string identifier, Location loc)
6525 Identifier = identifier;
6529 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6530 : this (expr, identifier, loc)
6535 protected string LookupIdentifier {
6536 get { return MemberName.MakeName (Identifier, args); }
6539 // TODO: this method has very poor performace for Enum fields and
6540 // probably for other constants as well
6541 Expression DoResolve (EmitContext ec, Expression right_side)
6544 throw new Exception ();
6547 // Resolve the expression with flow analysis turned off, we'll do the definite
6548 // assignment checks later. This is because we don't know yet what the expression
6549 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6550 // definite assignment check on the actual field and not on the whole struct.
6553 SimpleName original = expr as SimpleName;
6554 Expression expr_resolved = expr.Resolve (ec,
6555 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6556 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6558 if (expr_resolved == null)
6561 if (expr_resolved is Namespace) {
6562 Namespace ns = (Namespace) expr_resolved;
6563 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6565 if ((retval != null) && (args != null))
6566 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6570 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6574 Type expr_type = expr_resolved.Type;
6575 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6576 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6579 if (expr_type == TypeManager.anonymous_method_type){
6580 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6584 Constant c = expr_resolved as Constant;
6585 if (c != null && c.GetValue () == null) {
6586 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6587 "System.NullReferenceException");
6590 Expression member_lookup;
6591 member_lookup = MemberLookup (
6592 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6594 if ((member_lookup == null) && (args != null)) {
6595 member_lookup = MemberLookup (
6596 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6599 if (member_lookup == null) {
6600 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
6601 if (ex_method_lookup != null) {
6602 ex_method_lookup.ExtensionExpression = expr_resolved;
6605 return ex_method_lookup.ResolveGeneric (ec, args);
6607 return ex_method_lookup.DoResolve (ec);
6610 if (!ec.IsInProbingMode)
6611 Error_MemberLookupFailed (
6612 ec.ContainerType, expr_type, expr_type, Identifier, null,
6613 AllMemberTypes, AllBindingFlags);
6617 TypeExpr texpr = member_lookup as TypeExpr;
6618 if (texpr != null) {
6619 if (!(expr_resolved is TypeExpr) &&
6620 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6621 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6622 Identifier, member_lookup.GetSignatureForError ());
6626 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6627 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6628 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6633 ConstructedType ct = expr_resolved as ConstructedType;
6636 // When looking up a nested type in a generic instance
6637 // via reflection, we always get a generic type definition
6638 // and not a generic instance - so we have to do this here.
6640 // See gtest-172-lib.cs and gtest-172.cs for an example.
6642 ct = new ConstructedType (
6643 member_lookup.Type, ct.TypeArguments, loc);
6645 return ct.ResolveAsTypeStep (ec, false);
6648 return member_lookup;
6651 MemberExpr me = (MemberExpr) member_lookup;
6652 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6653 if (member_lookup == null)
6657 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6659 throw new InternalErrorException ();
6661 return mg.ResolveGeneric (ec, args);
6664 if (original != null && !TypeManager.IsValueType (expr_type)) {
6665 me = member_lookup as MemberExpr;
6666 if (me != null && me.IsInstance) {
6667 LocalVariableReference var = expr_resolved as LocalVariableReference;
6668 if (var != null && !var.VerifyAssigned (ec))
6673 // The following DoResolve/DoResolveLValue will do the definite assignment
6676 if (right_side != null)
6677 return member_lookup.DoResolveLValue (ec, right_side);
6679 return member_lookup.DoResolve (ec);
6682 public override Expression DoResolve (EmitContext ec)
6684 return DoResolve (ec, null);
6687 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6689 return DoResolve (ec, right_side);
6692 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6694 return ResolveNamespaceOrType (ec, silent);
6697 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6699 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6701 if (new_expr == null)
6704 if (new_expr is Namespace) {
6705 Namespace ns = (Namespace) new_expr;
6706 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6708 if ((retval != null) && (args != null))
6709 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6711 if (!silent && retval == null)
6712 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6716 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6717 if (tnew_expr == null)
6720 Type expr_type = tnew_expr.Type;
6722 if (expr_type.IsPointer){
6723 Error (23, "The `.' operator can not be applied to pointer operands (" +
6724 TypeManager.CSharpName (expr_type) + ")");
6728 Expression member_lookup = MemberLookup (
6729 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6730 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6731 if (member_lookup == null) {
6735 member_lookup = MemberLookup(
6736 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6737 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6739 if (member_lookup == null) {
6740 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6741 Identifier, new_expr.GetSignatureForError ());
6743 // TODO: Report.SymbolRelatedToPreviousError
6744 member_lookup.Error_UnexpectedKind (null, "type", loc);
6749 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6754 TypeArguments the_args = args;
6755 if (TypeManager.HasGenericArguments (expr_type)) {
6756 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6758 TypeArguments new_args = new TypeArguments (loc);
6759 foreach (Type decl in decl_args)
6760 new_args.Add (new TypeExpression (decl, loc));
6763 new_args.Add (args);
6765 the_args = new_args;
6768 if (the_args != null) {
6769 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6770 return ctype.ResolveAsTypeStep (rc, false);
6777 public override void Emit (EmitContext ec)
6779 throw new Exception ("Should not happen");
6782 public override string ToString ()
6784 return expr + "." + MemberName.MakeName (Identifier, args);
6787 public override string GetSignatureForError ()
6789 return expr.GetSignatureForError () + "." + Identifier;
6792 protected override void CloneTo (CloneContext clonectx, Expression t)
6794 MemberAccess target = (MemberAccess) t;
6796 target.expr = expr.Clone (clonectx);
6801 /// Implements checked expressions
6803 public class CheckedExpr : Expression {
6805 public Expression Expr;
6807 public CheckedExpr (Expression e, Location l)
6813 public override Expression DoResolve (EmitContext ec)
6815 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6816 Expr = Expr.Resolve (ec);
6821 if (Expr is Constant)
6824 eclass = Expr.eclass;
6829 public override void Emit (EmitContext ec)
6831 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6835 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6837 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6838 Expr.EmitBranchable (ec, target, onTrue);
6841 protected override void CloneTo (CloneContext clonectx, Expression t)
6843 CheckedExpr target = (CheckedExpr) t;
6845 target.Expr = Expr.Clone (clonectx);
6850 /// Implements the unchecked expression
6852 public class UnCheckedExpr : Expression {
6854 public Expression Expr;
6856 public UnCheckedExpr (Expression e, Location l)
6862 public override Expression DoResolve (EmitContext ec)
6864 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6865 Expr = Expr.Resolve (ec);
6870 if (Expr is Constant)
6873 eclass = Expr.eclass;
6878 public override void Emit (EmitContext ec)
6880 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6884 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6886 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6887 Expr.EmitBranchable (ec, target, onTrue);
6890 protected override void CloneTo (CloneContext clonectx, Expression t)
6892 UnCheckedExpr target = (UnCheckedExpr) t;
6894 target.Expr = Expr.Clone (clonectx);
6899 /// An Element Access expression.
6901 /// During semantic analysis these are transformed into
6902 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
6904 public class ElementAccess : Expression {
6905 public ArrayList Arguments;
6906 public Expression Expr;
6908 public ElementAccess (Expression e, ArrayList e_list)
6917 Arguments = new ArrayList ();
6918 foreach (Expression tmp in e_list)
6919 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6923 bool CommonResolve (EmitContext ec)
6925 Expr = Expr.Resolve (ec);
6927 if (Arguments == null)
6930 foreach (Argument a in Arguments){
6931 if (!a.Resolve (ec, loc))
6935 return Expr != null;
6938 Expression MakePointerAccess (EmitContext ec, Type t)
6940 if (t == TypeManager.void_ptr_type){
6941 Error (242, "The array index operation is not valid on void pointers");
6944 if (Arguments.Count != 1){
6945 Error (196, "A pointer must be indexed by only one value");
6950 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
6953 return new Indirection (p, loc).Resolve (ec);
6956 public override Expression DoResolve (EmitContext ec)
6958 if (!CommonResolve (ec))
6962 // We perform some simple tests, and then to "split" the emit and store
6963 // code we create an instance of a different class, and return that.
6965 // I am experimenting with this pattern.
6969 if (t == TypeManager.array_type){
6970 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
6975 return (new ArrayAccess (this, loc)).Resolve (ec);
6977 return MakePointerAccess (ec, t);
6979 FieldExpr fe = Expr as FieldExpr;
6981 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
6983 return MakePointerAccess (ec, ff.ElementType);
6986 return (new IndexerAccess (this, loc)).Resolve (ec);
6989 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6991 if (!CommonResolve (ec))
6996 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
6999 return MakePointerAccess (ec, t);
7001 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7004 public override void Emit (EmitContext ec)
7006 throw new Exception ("Should never be reached");
7009 protected override void CloneTo (CloneContext clonectx, Expression t)
7011 ElementAccess target = (ElementAccess) t;
7013 target.Expr = Expr.Clone (clonectx);
7014 target.Arguments = new ArrayList (Arguments.Count);
7015 foreach (Argument a in Arguments)
7016 target.Arguments.Add (a.Clone (clonectx));
7021 /// Implements array access
7023 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7025 // Points to our "data" repository
7029 LocalTemporary temp;
7030 LocalTemporary prepared_value;
7034 public ArrayAccess (ElementAccess ea_data, Location l)
7037 eclass = ExprClass.Variable;
7041 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7043 return DoResolve (ec);
7046 public override Expression DoResolve (EmitContext ec)
7049 ExprClass eclass = ea.Expr.eclass;
7051 // As long as the type is valid
7052 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7053 eclass == ExprClass.Value)) {
7054 ea.Expr.Error_UnexpectedKind ("variable or value");
7059 Type t = ea.Expr.Type;
7060 if (t.GetArrayRank () != ea.Arguments.Count){
7061 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7062 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7066 type = TypeManager.GetElementType (t);
7067 if (type.IsPointer && !ec.InUnsafe){
7068 UnsafeError (ea.Location);
7072 foreach (Argument a in ea.Arguments){
7073 Type argtype = a.Type;
7075 if (argtype == TypeManager.int32_type ||
7076 argtype == TypeManager.uint32_type ||
7077 argtype == TypeManager.int64_type ||
7078 argtype == TypeManager.uint64_type) {
7079 Constant c = a.Expr as Constant;
7080 if (c != null && c.IsNegative) {
7081 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7087 // Mhm. This is strage, because the Argument.Type is not the same as
7088 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7090 // Wonder if I will run into trouble for this.
7092 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7097 eclass = ExprClass.Variable;
7103 /// Emits the right opcode to load an object of Type `t'
7104 /// from an array of T
7106 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7109 MethodInfo get = FetchGetMethod ();
7110 ig.Emit (OpCodes.Call, get);
7114 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7115 ig.Emit (OpCodes.Ldelem_U1);
7116 else if (type == TypeManager.sbyte_type)
7117 ig.Emit (OpCodes.Ldelem_I1);
7118 else if (type == TypeManager.short_type)
7119 ig.Emit (OpCodes.Ldelem_I2);
7120 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7121 ig.Emit (OpCodes.Ldelem_U2);
7122 else if (type == TypeManager.int32_type)
7123 ig.Emit (OpCodes.Ldelem_I4);
7124 else if (type == TypeManager.uint32_type)
7125 ig.Emit (OpCodes.Ldelem_U4);
7126 else if (type == TypeManager.uint64_type)
7127 ig.Emit (OpCodes.Ldelem_I8);
7128 else if (type == TypeManager.int64_type)
7129 ig.Emit (OpCodes.Ldelem_I8);
7130 else if (type == TypeManager.float_type)
7131 ig.Emit (OpCodes.Ldelem_R4);
7132 else if (type == TypeManager.double_type)
7133 ig.Emit (OpCodes.Ldelem_R8);
7134 else if (type == TypeManager.intptr_type)
7135 ig.Emit (OpCodes.Ldelem_I);
7136 else if (TypeManager.IsEnumType (type)){
7137 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
7138 } else if (type.IsValueType){
7139 ig.Emit (OpCodes.Ldelema, type);
7140 ig.Emit (OpCodes.Ldobj, type);
7142 } else if (type.IsGenericParameter) {
7143 ig.Emit (OpCodes.Ldelem, type);
7145 } else if (type.IsPointer)
7146 ig.Emit (OpCodes.Ldelem_I);
7148 ig.Emit (OpCodes.Ldelem_Ref);
7152 /// Returns the right opcode to store an object of Type `t'
7153 /// from an array of T.
7155 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7157 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7158 has_type_arg = false; is_stobj = false;
7159 t = TypeManager.TypeToCoreType (t);
7160 if (TypeManager.IsEnumType (t))
7161 t = TypeManager.EnumToUnderlying (t);
7162 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7163 t == TypeManager.bool_type)
7164 return OpCodes.Stelem_I1;
7165 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7166 t == TypeManager.char_type)
7167 return OpCodes.Stelem_I2;
7168 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7169 return OpCodes.Stelem_I4;
7170 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7171 return OpCodes.Stelem_I8;
7172 else if (t == TypeManager.float_type)
7173 return OpCodes.Stelem_R4;
7174 else if (t == TypeManager.double_type)
7175 return OpCodes.Stelem_R8;
7176 else if (t == TypeManager.intptr_type) {
7177 has_type_arg = true;
7179 return OpCodes.Stobj;
7180 } else if (t.IsValueType) {
7181 has_type_arg = true;
7183 return OpCodes.Stobj;
7185 } else if (t.IsGenericParameter) {
7186 has_type_arg = true;
7187 return OpCodes.Stelem;
7190 } else if (t.IsPointer)
7191 return OpCodes.Stelem_I;
7193 return OpCodes.Stelem_Ref;
7196 MethodInfo FetchGetMethod ()
7198 ModuleBuilder mb = CodeGen.Module.Builder;
7199 int arg_count = ea.Arguments.Count;
7200 Type [] args = new Type [arg_count];
7203 for (int i = 0; i < arg_count; i++){
7204 //args [i++] = a.Type;
7205 args [i] = TypeManager.int32_type;
7208 get = mb.GetArrayMethod (
7209 ea.Expr.Type, "Get",
7210 CallingConventions.HasThis |
7211 CallingConventions.Standard,
7217 MethodInfo FetchAddressMethod ()
7219 ModuleBuilder mb = CodeGen.Module.Builder;
7220 int arg_count = ea.Arguments.Count;
7221 Type [] args = new Type [arg_count];
7225 ret_type = TypeManager.GetReferenceType (type);
7227 for (int i = 0; i < arg_count; i++){
7228 //args [i++] = a.Type;
7229 args [i] = TypeManager.int32_type;
7232 address = mb.GetArrayMethod (
7233 ea.Expr.Type, "Address",
7234 CallingConventions.HasThis |
7235 CallingConventions.Standard,
7242 // Load the array arguments into the stack.
7244 // If we have been requested to cache the values (cached_locations array
7245 // initialized), then load the arguments the first time and store them
7246 // in locals. otherwise load from local variables.
7248 // prepareForLoad is used in compound assignments to cache original index
7249 // values ( label[idx++] += s )
7251 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepareForLoad)
7255 LocalTemporary[] indexes = null;
7256 if (prepareForLoad) {
7257 ec.ig.Emit (OpCodes.Dup);
7258 indexes = new LocalTemporary [ea.Arguments.Count];
7261 for (int i = 0; i < ea.Arguments.Count; ++i) {
7262 ((Argument)ea.Arguments [i]).EmitArrayArgument (ec);
7263 if (!prepareForLoad)
7266 // Keep original array index value on the stack
7267 ec.ig.Emit (OpCodes.Dup);
7269 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7270 indexes [i].Store (ec);
7276 public void Emit (EmitContext ec, bool leave_copy)
7278 int rank = ea.Expr.Type.GetArrayRank ();
7279 ILGenerator ig = ec.ig;
7281 if (prepared_value != null) {
7282 prepared_value.Emit (ec);
7283 } else if (prepared) {
7284 LoadFromPtr (ig, this.type);
7286 LoadArrayAndArguments (ec, false);
7287 EmitLoadOpcode (ig, type, rank);
7291 ig.Emit (OpCodes.Dup);
7292 temp = new LocalTemporary (this.type);
7297 public override void Emit (EmitContext ec)
7302 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7304 int rank = ea.Expr.Type.GetArrayRank ();
7305 ILGenerator ig = ec.ig;
7306 Type t = source.Type;
7307 prepared = prepare_for_load && !(source is StringConcat);
7310 AddressOf (ec, AddressOp.LoadStore);
7311 ec.ig.Emit (OpCodes.Dup);
7313 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7314 prepare_for_load && (source is StringConcat));
7316 if (original_indexes_values != null) {
7317 prepared_value = new LocalTemporary (type);
7318 EmitLoadOpcode (ig, type, rank);
7319 prepared_value.Store (ec);
7320 foreach (LocalTemporary lt in original_indexes_values) {
7328 bool is_stobj, has_type_arg;
7329 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7333 // The stobj opcode used by value types will need
7334 // an address on the stack, not really an array/array
7338 ig.Emit (OpCodes.Ldelema, t);
7343 ec.ig.Emit (OpCodes.Dup);
7344 temp = new LocalTemporary (this.type);
7349 StoreFromPtr (ig, t);
7351 ig.Emit (OpCodes.Stobj, t);
7352 else if (has_type_arg)
7359 ec.ig.Emit (OpCodes.Dup);
7360 temp = new LocalTemporary (this.type);
7365 StoreFromPtr (ig, t);
7367 int arg_count = ea.Arguments.Count;
7368 Type [] args = new Type [arg_count + 1];
7369 for (int i = 0; i < arg_count; i++) {
7370 //args [i++] = a.Type;
7371 args [i] = TypeManager.int32_type;
7373 args [arg_count] = type;
7375 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7376 ea.Expr.Type, "Set",
7377 CallingConventions.HasThis |
7378 CallingConventions.Standard,
7379 TypeManager.void_type, args);
7381 ig.Emit (OpCodes.Call, set);
7391 public void AddressOf (EmitContext ec, AddressOp mode)
7393 int rank = ea.Expr.Type.GetArrayRank ();
7394 ILGenerator ig = ec.ig;
7396 LoadArrayAndArguments (ec, false);
7399 ig.Emit (OpCodes.Ldelema, type);
7401 MethodInfo address = FetchAddressMethod ();
7402 ig.Emit (OpCodes.Call, address);
7406 public void EmitGetLength (EmitContext ec, int dim)
7408 int rank = ea.Expr.Type.GetArrayRank ();
7409 ILGenerator ig = ec.ig;
7413 ig.Emit (OpCodes.Ldlen);
7414 ig.Emit (OpCodes.Conv_I4);
7416 IntLiteral.EmitInt (ig, dim);
7417 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7423 /// Expressions that represent an indexer call.
7425 public class IndexerAccess : Expression, IAssignMethod
7427 class IndexerMethodGroupExpr : MethodGroupExpr
7429 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7432 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7435 public override string Name {
7441 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7444 // Here is the trick, decrease number of arguments by 1 when only
7445 // available property method is setter. This makes overload resolution
7446 // work correctly for indexers.
7449 if (method.Name [0] == 'g')
7450 return parameters.Count;
7452 return parameters.Count - 1;
7458 // Contains either property getter or setter
7459 public ArrayList Methods;
7460 public ArrayList Properties;
7466 void Append (Type caller_type, MemberInfo [] mi)
7471 foreach (PropertyInfo property in mi) {
7472 MethodInfo accessor = property.GetGetMethod (true);
7473 if (accessor == null)
7474 accessor = property.GetSetMethod (true);
7476 if (Methods == null) {
7477 Methods = new ArrayList ();
7478 Properties = new ArrayList ();
7481 Methods.Add (accessor);
7482 Properties.Add (property);
7486 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7488 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7490 return TypeManager.MemberLookup (
7491 caller_type, caller_type, lookup_type, MemberTypes.Property,
7492 BindingFlags.Public | BindingFlags.Instance |
7493 BindingFlags.DeclaredOnly, p_name, null);
7496 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7498 Indexers ix = new Indexers ();
7501 if (lookup_type.IsGenericParameter) {
7502 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7506 if (gc.HasClassConstraint)
7507 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7509 Type[] ifaces = gc.InterfaceConstraints;
7510 foreach (Type itype in ifaces)
7511 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7517 Type copy = lookup_type;
7518 while (copy != TypeManager.object_type && copy != null){
7519 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7520 copy = copy.BaseType;
7523 if (lookup_type.IsInterface) {
7524 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7525 if (ifaces != null) {
7526 foreach (Type itype in ifaces)
7527 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7542 // Points to our "data" repository
7544 MethodInfo get, set;
7545 bool is_base_indexer;
7547 LocalTemporary temp;
7548 LocalTemporary prepared_value;
7549 Expression set_expr;
7551 protected Type indexer_type;
7552 protected Type current_type;
7553 protected Expression instance_expr;
7554 protected ArrayList arguments;
7556 public IndexerAccess (ElementAccess ea, Location loc)
7557 : this (ea.Expr, false, loc)
7559 this.arguments = ea.Arguments;
7562 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7565 this.instance_expr = instance_expr;
7566 this.is_base_indexer = is_base_indexer;
7567 this.eclass = ExprClass.Value;
7571 static string GetAccessorName (AccessorType at)
7573 if (at == AccessorType.Set)
7576 if (at == AccessorType.Get)
7579 throw new NotImplementedException (at.ToString ());
7582 protected virtual bool CommonResolve (EmitContext ec)
7584 indexer_type = instance_expr.Type;
7585 current_type = ec.ContainerType;
7590 public override Expression DoResolve (EmitContext ec)
7592 return ResolveAccessor (ec, AccessorType.Get);
7595 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7597 if (right_side == EmptyExpression.OutAccess) {
7598 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7599 GetSignatureForError ());
7603 // if the indexer returns a value type, and we try to set a field in it
7604 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7605 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7606 GetSignatureForError ());
7610 Expression e = ResolveAccessor (ec, AccessorType.Set);
7614 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
7618 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
7620 if (!CommonResolve (ec))
7623 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7624 if (ilist.Methods == null) {
7625 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7626 TypeManager.CSharpName (indexer_type));
7630 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
7631 mg = mg.OverloadResolve (ec, arguments, false, loc);
7635 MethodInfo mi = (MethodInfo) mg;
7636 PropertyInfo pi = null;
7637 for (int i = 0; i < ilist.Methods.Count; ++i) {
7638 if (ilist.Methods [i] == mi) {
7639 pi = (PropertyInfo) ilist.Properties [i];
7644 type = pi.PropertyType;
7645 if (type.IsPointer && !ec.InUnsafe)
7648 MethodInfo accessor;
7649 if (accessorType == AccessorType.Get) {
7650 accessor = get = pi.GetGetMethod (true);
7652 accessor = set = pi.GetSetMethod (true);
7653 if (accessor == null && pi.GetGetMethod (true) != null) {
7654 Report.SymbolRelatedToPreviousError (pi);
7655 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
7656 TypeManager.GetFullNameSignature (pi));
7661 if (accessor == null) {
7662 Report.SymbolRelatedToPreviousError (pi);
7663 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
7664 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7669 // Only base will allow this invocation to happen.
7671 if (accessor.IsAbstract && this is BaseIndexerAccess) {
7672 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
7675 bool must_do_cs1540_check;
7676 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
7678 set = pi.GetSetMethod (true);
7680 get = pi.GetGetMethod (true);
7682 if (set != null && get != null &&
7683 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
7684 Report.SymbolRelatedToPreviousError (accessor);
7685 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
7686 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7688 Report.SymbolRelatedToPreviousError (pi);
7689 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
7693 instance_expr.CheckMarshalByRefAccess ();
7694 eclass = ExprClass.IndexerAccess;
7698 public void Emit (EmitContext ec, bool leave_copy)
7701 prepared_value.Emit (ec);
7703 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7704 arguments, loc, false, false);
7708 ec.ig.Emit (OpCodes.Dup);
7709 temp = new LocalTemporary (Type);
7715 // source is ignored, because we already have a copy of it from the
7716 // LValue resolution and we have already constructed a pre-cached
7717 // version of the arguments (ea.set_arguments);
7719 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7721 prepared = prepare_for_load;
7724 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7725 arguments, loc, true, false);
7727 prepared_value = new LocalTemporary (type);
7728 prepared_value.Store (ec);
7730 prepared_value.Release (ec);
7733 ec.ig.Emit (OpCodes.Dup);
7734 temp = new LocalTemporary (Type);
7737 } else if (leave_copy) {
7738 temp = new LocalTemporary (Type);
7742 Argument a = (Argument) arguments [arguments.Count - 1];
7746 arguments.Add (new Argument (set_expr, Argument.AType.Expression));
7747 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
7755 public override void Emit (EmitContext ec)
7760 public override string GetSignatureForError ()
7762 // FIXME: print the argument list of the indexer
7763 return instance_expr.GetSignatureForError () + ".this[...]";
7766 protected override void CloneTo (CloneContext clonectx, Expression t)
7768 IndexerAccess target = (IndexerAccess) t;
7770 if (arguments != null){
7771 target.arguments = new ArrayList ();
7772 foreach (Argument a in arguments)
7773 target.arguments.Add (a.Clone (clonectx));
7775 if (instance_expr != null)
7776 target.instance_expr = instance_expr.Clone (clonectx);
7781 /// The base operator for method names
7783 public class BaseAccess : Expression {
7784 public readonly string Identifier;
7787 public BaseAccess (string member, Location l)
7789 this.Identifier = member;
7793 public BaseAccess (string member, TypeArguments args, Location l)
7799 public override Expression DoResolve (EmitContext ec)
7801 Expression c = CommonResolve (ec);
7807 // MethodGroups use this opportunity to flag an error on lacking ()
7809 if (!(c is MethodGroupExpr))
7810 return c.Resolve (ec);
7814 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7816 Expression c = CommonResolve (ec);
7822 // MethodGroups use this opportunity to flag an error on lacking ()
7824 if (! (c is MethodGroupExpr))
7825 return c.DoResolveLValue (ec, right_side);
7830 Expression CommonResolve (EmitContext ec)
7832 Expression member_lookup;
7833 Type current_type = ec.ContainerType;
7834 Type base_type = current_type.BaseType;
7837 Error (1511, "Keyword `base' is not available in a static method");
7841 if (ec.IsInFieldInitializer){
7842 Error (1512, "Keyword `base' is not available in the current context");
7846 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
7847 AllMemberTypes, AllBindingFlags, loc);
7848 if (member_lookup == null) {
7849 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
7850 null, AllMemberTypes, AllBindingFlags);
7857 left = new TypeExpression (base_type, loc);
7859 left = ec.GetThis (loc);
7861 MemberExpr me = (MemberExpr) member_lookup;
7863 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
7865 if (e is PropertyExpr) {
7866 PropertyExpr pe = (PropertyExpr) e;
7868 } else if (e is EventExpr) {
7869 EventExpr ee = (EventExpr) e;
7873 MethodGroupExpr mg = e as MethodGroupExpr;
7879 return mg.ResolveGeneric (ec, args);
7881 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
7889 public override void Emit (EmitContext ec)
7891 throw new Exception ("Should never be called");
7894 protected override void CloneTo (CloneContext clonectx, Expression t)
7896 BaseAccess target = (BaseAccess) t;
7898 target.args = args.Clone ();
7903 /// The base indexer operator
7905 public class BaseIndexerAccess : IndexerAccess {
7906 public BaseIndexerAccess (ArrayList args, Location loc)
7907 : base (null, true, loc)
7909 arguments = new ArrayList ();
7910 foreach (Expression tmp in args)
7911 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7914 protected override bool CommonResolve (EmitContext ec)
7916 instance_expr = ec.GetThis (loc);
7918 current_type = ec.ContainerType.BaseType;
7919 indexer_type = current_type;
7921 foreach (Argument a in arguments){
7922 if (!a.Resolve (ec, loc))
7931 /// This class exists solely to pass the Type around and to be a dummy
7932 /// that can be passed to the conversion functions (this is used by
7933 /// foreach implementation to typecast the object return value from
7934 /// get_Current into the proper type. All code has been generated and
7935 /// we only care about the side effect conversions to be performed
7937 /// This is also now used as a placeholder where a no-action expression
7938 /// is needed (the `New' class).
7940 public class EmptyExpression : Expression {
7941 public static readonly EmptyExpression Null = new EmptyExpression ();
7943 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
7944 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
7945 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
7947 static EmptyExpression temp = new EmptyExpression ();
7948 public static EmptyExpression Grab ()
7950 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
7955 public static void Release (EmptyExpression e)
7960 // TODO: should be protected
7961 public EmptyExpression ()
7963 type = TypeManager.object_type;
7964 eclass = ExprClass.Value;
7965 loc = Location.Null;
7968 public EmptyExpression (Type t)
7971 eclass = ExprClass.Value;
7972 loc = Location.Null;
7975 public override Expression DoResolve (EmitContext ec)
7980 public override void Emit (EmitContext ec)
7982 // nothing, as we only exist to not do anything.
7986 // This is just because we might want to reuse this bad boy
7987 // instead of creating gazillions of EmptyExpressions.
7988 // (CanImplicitConversion uses it)
7990 public void SetType (Type t)
7997 // Empty statement expression
7999 public sealed class EmptyExpressionStatement : ExpressionStatement
8001 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8003 private EmptyExpressionStatement ()
8005 type = TypeManager.object_type;
8006 eclass = ExprClass.Value;
8007 loc = Location.Null;
8010 public override void EmitStatement (EmitContext ec)
8015 public override Expression DoResolve (EmitContext ec)
8020 public override void Emit (EmitContext ec)
8026 public class UserCast : Expression {
8030 public UserCast (MethodInfo method, Expression source, Location l)
8032 this.method = method;
8033 this.source = source;
8034 type = method.ReturnType;
8035 eclass = ExprClass.Value;
8039 public Expression Source {
8045 public override Expression DoResolve (EmitContext ec)
8048 // We are born fully resolved
8053 public override void Emit (EmitContext ec)
8055 ILGenerator ig = ec.ig;
8059 if (method is MethodInfo)
8060 ig.Emit (OpCodes.Call, (MethodInfo) method);
8062 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8068 // This class is used to "construct" the type during a typecast
8069 // operation. Since the Type.GetType class in .NET can parse
8070 // the type specification, we just use this to construct the type
8071 // one bit at a time.
8073 public class ComposedCast : TypeExpr {
8077 public ComposedCast (Expression left, string dim)
8078 : this (left, dim, left.Location)
8082 public ComposedCast (Expression left, string dim, Location l)
8090 public Expression RemoveNullable ()
8092 if (dim.EndsWith ("?")) {
8093 dim = dim.Substring (0, dim.Length - 1);
8102 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8104 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8108 Type ltype = lexpr.Type;
8109 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8110 Error_VoidInvalidInTheContext (loc);
8115 if ((dim.Length > 0) && (dim [0] == '?')) {
8116 TypeExpr nullable = new NullableType (left, loc);
8118 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8119 return nullable.ResolveAsTypeTerminal (ec, false);
8123 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8126 if (dim != "" && dim [0] == '[' &&
8127 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8128 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8133 type = TypeManager.GetConstructedType (ltype, dim);
8138 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8140 if (type.IsPointer && !ec.IsInUnsafeScope){
8145 eclass = ExprClass.Type;
8149 public override string Name {
8150 get { return left + dim; }
8153 public override string FullName {
8154 get { return type.FullName; }
8157 public override string GetSignatureForError ()
8159 return left.GetSignatureForError () + dim;
8162 protected override void CloneTo (CloneContext clonectx, Expression t)
8164 ComposedCast target = (ComposedCast) t;
8166 target.left = left.Clone (clonectx);
8170 public class FixedBufferPtr : Expression {
8173 public FixedBufferPtr (Expression array, Type array_type, Location l)
8178 type = TypeManager.GetPointerType (array_type);
8179 eclass = ExprClass.Value;
8182 public override void Emit(EmitContext ec)
8187 public override Expression DoResolve (EmitContext ec)
8190 // We are born fully resolved
8198 // This class is used to represent the address of an array, used
8199 // only by the Fixed statement, this generates "&a [0]" construct
8200 // for fixed (char *pa = a)
8202 public class ArrayPtr : FixedBufferPtr {
8205 public ArrayPtr (Expression array, Type array_type, Location l):
8206 base (array, array_type, l)
8208 this.array_type = array_type;
8211 public override void Emit (EmitContext ec)
8215 ILGenerator ig = ec.ig;
8216 IntLiteral.EmitInt (ig, 0);
8217 ig.Emit (OpCodes.Ldelema, array_type);
8222 // Used by the fixed statement
8224 public class StringPtr : Expression {
8227 public StringPtr (LocalBuilder b, Location l)
8230 eclass = ExprClass.Value;
8231 type = TypeManager.char_ptr_type;
8235 public override Expression DoResolve (EmitContext ec)
8237 // This should never be invoked, we are born in fully
8238 // initialized state.
8243 public override void Emit (EmitContext ec)
8245 ILGenerator ig = ec.ig;
8247 ig.Emit (OpCodes.Ldloc, b);
8248 ig.Emit (OpCodes.Conv_I);
8249 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8250 ig.Emit (OpCodes.Add);
8255 // Implements the `stackalloc' keyword
8257 public class StackAlloc : Expression {
8262 public StackAlloc (Expression type, Expression count, Location l)
8269 public override Expression DoResolve (EmitContext ec)
8271 count = count.Resolve (ec);
8275 if (count.Type != TypeManager.int32_type){
8276 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8281 Constant c = count as Constant;
8282 if (c != null && c.IsNegative) {
8283 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8287 if (ec.InCatch || ec.InFinally) {
8288 Error (255, "Cannot use stackalloc in finally or catch");
8292 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8298 if (!TypeManager.VerifyUnManaged (otype, loc))
8301 type = TypeManager.GetPointerType (otype);
8302 eclass = ExprClass.Value;
8307 public override void Emit (EmitContext ec)
8309 int size = GetTypeSize (otype);
8310 ILGenerator ig = ec.ig;
8313 ig.Emit (OpCodes.Sizeof, otype);
8315 IntConstant.EmitInt (ig, size);
8317 ig.Emit (OpCodes.Mul);
8318 ig.Emit (OpCodes.Localloc);
8321 protected override void CloneTo (CloneContext clonectx, Expression t)
8323 StackAlloc target = (StackAlloc) t;
8324 target.count = count.Clone (clonectx);
8325 target.t = t.Clone (clonectx);
8330 // An object initializer expression
8332 public class ElementInitializer : Expression
8334 Expression initializer;
8335 public readonly string Name;
8337 public ElementInitializer (string name, Expression initializer, Location loc)
8340 this.initializer = initializer;
8344 protected override void CloneTo (CloneContext clonectx, Expression t)
8346 if (initializer == null)
8349 ElementInitializer target = (ElementInitializer) t;
8350 target.initializer = initializer.Clone (clonectx);
8353 public override Expression DoResolve (EmitContext ec)
8355 if (initializer == null)
8356 return EmptyExpressionStatement.Instance;
8358 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8359 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8361 if (element_member == null)
8364 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8366 if (initializer is CollectionOrObjectInitializers) {
8367 Expression previous = ec.CurrentInitializerVariable;
8368 ec.CurrentInitializerVariable = element_member;
8369 initializer = initializer.Resolve (ec);
8370 ec.CurrentInitializerVariable = previous;
8374 return new Assign (element_member, initializer, loc).Resolve (ec);
8377 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8379 MemberInfo member = members [0];
8380 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8381 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8382 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8384 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8385 TypeManager.GetFullNameSignature (member));
8390 public override void Emit (EmitContext ec)
8392 throw new NotSupportedException ("Should not be reached");
8397 // A collection initializer expression
8399 public class CollectionElementInitializer : Expression
8401 public class ElementInitializerArgument : Argument
8403 public ElementInitializerArgument (Expression e)
8409 ArrayList arguments;
8411 public CollectionElementInitializer (Expression argument)
8413 arguments = new ArrayList (1);
8414 arguments.Add (argument);
8415 this.loc = argument.Location;
8418 public CollectionElementInitializer (ArrayList arguments, Location loc)
8420 this.arguments = arguments;
8424 protected override void CloneTo (CloneContext clonectx, Expression t)
8426 CollectionElementInitializer target = (CollectionElementInitializer) t;
8427 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8428 foreach (Expression e in arguments)
8429 t_arguments.Add (e.Clone (clonectx));
8432 public override Expression DoResolve (EmitContext ec)
8434 // TODO: We should call a constructor which takes element counts argument,
8435 // for know types like List<T>, Dictionary<T, U>
8437 for (int i = 0; i < arguments.Count; ++i)
8438 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8440 Expression add_method = new Invocation (
8441 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8444 add_method = add_method.Resolve (ec);
8449 public override void Emit (EmitContext ec)
8451 throw new NotSupportedException ("Should not be reached");
8456 // A block of object or collection initializers
8458 public class CollectionOrObjectInitializers : ExpressionStatement
8460 ArrayList initializers;
8462 public static readonly CollectionOrObjectInitializers Empty =
8463 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8465 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8467 this.initializers = initializers;
8471 public bool IsEmpty {
8473 return initializers.Count == 0;
8477 protected override void CloneTo (CloneContext clonectx, Expression target)
8479 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8481 t.initializers = new ArrayList (initializers.Count);
8482 foreach (Expression e in initializers)
8483 t.initializers.Add (e.Clone (clonectx));
8486 public override Expression DoResolve (EmitContext ec)
8488 bool is_elements_initialization = false;
8489 ArrayList element_names = null;
8490 for (int i = 0; i < initializers.Count; ++i) {
8491 Expression initializer = (Expression) initializers [i];
8492 ElementInitializer element_initializer = initializer as ElementInitializer;
8495 if (element_initializer != null) {
8496 is_elements_initialization = true;
8497 element_names = new ArrayList (initializers.Count);
8498 element_names.Add (element_initializer.Name);
8500 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8501 TypeManager.ienumerable_type)) {
8502 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8503 "object initializer because type `{1}' does not implement `{2}' interface",
8504 ec.CurrentInitializerVariable.GetSignatureForError (),
8505 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8506 TypeManager.CSharpName (TypeManager.ienumerable_type));
8511 if (is_elements_initialization == (element_initializer == null)) {
8512 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8513 is_elements_initialization ? "object initializer" : "collection initializer");
8517 if (is_elements_initialization) {
8518 if (element_names.Contains (element_initializer.Name)) {
8519 Report.Error (1912, element_initializer.Location,
8520 "An object initializer includes more than one member `{0}' initialization",
8521 element_initializer.Name);
8523 element_names.Add (element_initializer.Name);
8528 initializers [i] = initializer.Resolve (ec);
8531 type = typeof (CollectionOrObjectInitializers);
8532 eclass = ExprClass.Variable;
8536 public override void Emit (EmitContext ec)
8541 public override void EmitStatement (EmitContext ec)
8543 foreach (ExpressionStatement e in initializers)
8544 e.EmitStatement (ec);
8549 // New expression with element/object initializers
8551 public class NewInitialize : New
8553 CollectionOrObjectInitializers initializers;
8554 TemporaryVariable type_instance;
8556 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8557 : base (requested_type, arguments, l)
8559 this.initializers = initializers;
8562 protected override void CloneTo (CloneContext clonectx, Expression t)
8564 base.CloneTo (clonectx, t);
8566 NewInitialize target = (NewInitialize) t;
8567 target.initializers = (CollectionOrObjectInitializers)initializers.Clone (clonectx);
8570 public override Expression DoResolve (EmitContext ec)
8572 Expression e = base.DoResolve (ec);
8576 // Empty initializer can be optimized to simple new
8577 if (initializers.IsEmpty)
8580 type_instance = new TemporaryVariable (type, loc);
8581 type_instance = (TemporaryVariable)type_instance.Resolve (ec);
8583 Expression previous = ec.CurrentInitializerVariable;
8584 ec.CurrentInitializerVariable = type_instance;
8585 initializers.Resolve (ec);
8586 ec.CurrentInitializerVariable = previous;
8590 public override void Emit (EmitContext ec)
8594 type_instance.EmitStore (ec);
8595 initializers.Emit (ec);
8596 type_instance.Emit (ec);
8600 public class AnonymousTypeDeclaration : Expression
8602 ArrayList parameters;
8603 readonly TypeContainer parent;
8604 static readonly ArrayList EmptyParameters = new ArrayList (0);
8606 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8608 this.parameters = parameters;
8609 this.parent = parent;
8613 protected override void CloneTo (CloneContext clonectx, Expression target)
8615 if (parameters == null)
8618 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
8619 t.parameters = new ArrayList (parameters.Count);
8620 foreach (AnonymousTypeParameter atp in parameters)
8621 t.parameters.Add (atp.Clone (clonectx));
8624 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
8626 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8630 type = AnonymousTypeClass.Create (parent, parameters, loc);
8635 type.DefineMembers ();
8639 RootContext.ToplevelTypes.AddAnonymousType (type);
8643 public override Expression DoResolve (EmitContext ec)
8645 AnonymousTypeClass anonymous_type;
8647 if (parameters == null) {
8648 anonymous_type = CreateAnonymousType (EmptyParameters);
8649 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
8650 null, loc).Resolve (ec);
8654 ArrayList arguments = new ArrayList (parameters.Count);
8655 TypeExpression [] t_args = new TypeExpression [parameters.Count];
8656 for (int i = 0; i < parameters.Count; ++i) {
8657 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
8663 arguments.Add (new Argument (e));
8664 t_args [i] = new TypeExpression (e.Type, e.Location);
8670 anonymous_type = CreateAnonymousType (parameters);
8671 if (anonymous_type == null)
8674 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8675 new TypeArguments (loc, t_args), loc);
8677 return new New (te, arguments, loc).Resolve (ec);
8680 public override void Emit (EmitContext ec)
8682 throw new InternalErrorException ("Should not be reached");
8686 public class AnonymousTypeParameter : Expression
8688 public readonly string Name;
8689 Expression initializer;
8691 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8695 this.initializer = initializer;
8698 public AnonymousTypeParameter (Parameter parameter)
8700 this.Name = parameter.Name;
8701 this.loc = parameter.Location;
8702 this.initializer = new SimpleName (Name, loc);
8705 protected override void CloneTo (CloneContext clonectx, Expression target)
8707 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
8708 t.initializer = initializer.Clone (clonectx);
8711 public override bool Equals (object o)
8713 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8714 return other != null && Name == other.Name;
8717 public override int GetHashCode ()
8719 return Name.GetHashCode ();
8722 public override Expression DoResolve (EmitContext ec)
8724 Expression e = initializer.Resolve (ec);
8729 if (type == TypeManager.void_type || type == TypeManager.null_type ||
8730 type == TypeManager.anonymous_method_type || type.IsPointer) {
8731 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8732 Name, e.GetSignatureForError ());
8739 public override void Emit (EmitContext ec)
8741 throw new InternalErrorException ("Should not be reached");