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 (RootContext.Version <= LanguageVersion.ISO_2)
5853 Report.FeatureIsNotISO1 (loc, "implicitly typed arrays");
5855 if (rank.Length > 2) {
5856 while (rank [++dimensions] == ',');
5862 public override Expression DoResolve (EmitContext ec)
5867 if (!ResolveInitializers (ec))
5870 if (array_element_type == null || array_element_type == TypeManager.null_type ||
5871 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
5872 arguments.Count != dimensions) {
5873 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
5878 // At this point we found common base type for all initializer elements
5879 // but we have to be sure that all static initializer elements are of
5882 UnifyInitializerElement (ec);
5884 type = TypeManager.GetConstructedType (array_element_type, rank);
5885 eclass = ExprClass.Value;
5890 // Converts static initializer only
5892 void UnifyInitializerElement (EmitContext ec)
5894 for (int i = 0; i < array_data.Count; ++i) {
5895 Expression e = (Expression)array_data[i];
5897 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
5901 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
5903 element = element.Resolve (ec);
5904 if (element == null)
5907 if (array_element_type == null) {
5908 array_element_type = element.Type;
5912 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
5916 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
5917 array_element_type = element.Type;
5921 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
5926 public sealed class CompilerGeneratedThis : This
5928 public static This Instance = new CompilerGeneratedThis ();
5930 private CompilerGeneratedThis ()
5931 : base (Location.Null)
5935 public override Expression DoResolve (EmitContext ec)
5937 eclass = ExprClass.Variable;
5938 type = ec.ContainerType;
5939 variable = new SimpleThis (type);
5945 /// Represents the `this' construct
5948 public class This : VariableReference, IVariable
5951 VariableInfo variable_info;
5952 protected Variable variable;
5955 public This (Block block, Location loc)
5961 public This (Location loc)
5966 public VariableInfo VariableInfo {
5967 get { return variable_info; }
5970 public bool VerifyFixed ()
5972 return !TypeManager.IsValueType (Type);
5975 public override bool IsRef {
5976 get { return is_struct; }
5979 public override Variable Variable {
5980 get { return variable; }
5983 public bool ResolveBase (EmitContext ec)
5985 eclass = ExprClass.Variable;
5987 if (ec.TypeContainer.CurrentType != null)
5988 type = ec.TypeContainer.CurrentType;
5990 type = ec.ContainerType;
5992 is_struct = ec.TypeContainer is Struct;
5995 Error (26, "Keyword `this' is not valid in a static property, " +
5996 "static method, or static field initializer");
6000 if (block != null) {
6001 if (block.Toplevel.ThisVariable != null)
6002 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6004 AnonymousContainer am = ec.CurrentAnonymousMethod;
6005 if (is_struct && (am != null) && !am.IsIterator) {
6006 Report.Error (1673, loc, "Anonymous methods inside structs " +
6007 "cannot access instance members of `this'. " +
6008 "Consider copying `this' to a local variable " +
6009 "outside the anonymous method and using the " +
6014 RootScopeInfo host = block.Toplevel.RootScope;
6015 if ((host != null) && !ec.IsConstructor &&
6016 (!is_struct || host.IsIterator)) {
6017 variable = host.CaptureThis ();
6018 type = variable.Type;
6023 if (variable == null)
6024 variable = new SimpleThis (type);
6030 // Called from Invocation to check if the invocation is correct
6032 public bool CheckThisUsage (EmitContext ec)
6034 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6035 !variable_info.IsAssigned (ec)) {
6036 Error (188, "The `this' object cannot be used before all of its " +
6037 "fields are assigned to");
6038 variable_info.SetAssigned (ec);
6045 public override Expression DoResolve (EmitContext ec)
6047 if (!ResolveBase (ec))
6051 if (ec.IsInFieldInitializer) {
6052 Error (27, "Keyword `this' is not available in the current context");
6059 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6061 if (!ResolveBase (ec))
6064 if (variable_info != null)
6065 variable_info.SetAssigned (ec);
6067 if (ec.TypeContainer is Class){
6068 Error (1604, "Cannot assign to 'this' because it is read-only");
6074 public override int GetHashCode()
6076 return block.GetHashCode ();
6079 public override bool Equals (object obj)
6081 This t = obj as This;
6085 return block == t.block;
6088 protected class SimpleThis : Variable
6092 public SimpleThis (Type type)
6097 public override Type Type {
6098 get { return type; }
6101 public override bool HasInstance {
6102 get { return false; }
6105 public override bool NeedsTemporary {
6106 get { return false; }
6109 public override void EmitInstance (EmitContext ec)
6114 public override void Emit (EmitContext ec)
6116 ec.ig.Emit (OpCodes.Ldarg_0);
6119 public override void EmitAssign (EmitContext ec)
6121 throw new InvalidOperationException ();
6124 public override void EmitAddressOf (EmitContext ec)
6126 ec.ig.Emit (OpCodes.Ldarg_0);
6130 protected override void CloneTo (CloneContext clonectx, Expression t)
6132 This target = (This) t;
6134 target.block = clonectx.LookupBlock (block);
6139 /// Represents the `__arglist' construct
6141 public class ArglistAccess : Expression
6143 public ArglistAccess (Location loc)
6148 public override Expression DoResolve (EmitContext ec)
6150 eclass = ExprClass.Variable;
6151 type = TypeManager.runtime_argument_handle_type;
6153 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6155 Error (190, "The __arglist construct is valid only within " +
6156 "a variable argument method");
6163 public override void Emit (EmitContext ec)
6165 ec.ig.Emit (OpCodes.Arglist);
6168 protected override void CloneTo (CloneContext clonectx, Expression target)
6175 /// Represents the `__arglist (....)' construct
6177 public class Arglist : Expression
6179 Argument[] Arguments;
6181 public Arglist (Location loc)
6182 : this (Argument.Empty, loc)
6186 public Arglist (Argument[] args, Location l)
6192 public Type[] ArgumentTypes {
6194 Type[] retval = new Type [Arguments.Length];
6195 for (int i = 0; i < Arguments.Length; i++)
6196 retval [i] = Arguments [i].Type;
6201 public override Expression DoResolve (EmitContext ec)
6203 eclass = ExprClass.Variable;
6204 type = TypeManager.runtime_argument_handle_type;
6206 foreach (Argument arg in Arguments) {
6207 if (!arg.Resolve (ec, loc))
6214 public override void Emit (EmitContext ec)
6216 foreach (Argument arg in Arguments)
6220 protected override void CloneTo (CloneContext clonectx, Expression t)
6222 Arglist target = (Arglist) t;
6224 target.Arguments = new Argument [Arguments.Length];
6225 for (int i = 0; i < Arguments.Length; i++)
6226 target.Arguments [i] = Arguments [i].Clone (clonectx);
6231 // This produces the value that renders an instance, used by the iterators code
6233 public class ProxyInstance : Expression, IMemoryLocation {
6234 public override Expression DoResolve (EmitContext ec)
6236 eclass = ExprClass.Variable;
6237 type = ec.ContainerType;
6241 public override void Emit (EmitContext ec)
6243 ec.ig.Emit (OpCodes.Ldarg_0);
6247 public void AddressOf (EmitContext ec, AddressOp mode)
6249 ec.ig.Emit (OpCodes.Ldarg_0);
6254 /// Implements the typeof operator
6256 public class TypeOf : Expression {
6257 Expression QueriedType;
6258 protected Type typearg;
6260 public TypeOf (Expression queried_type, Location l)
6262 QueriedType = queried_type;
6266 public override Expression DoResolve (EmitContext ec)
6268 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6272 typearg = texpr.Type;
6274 if (typearg == TypeManager.void_type) {
6275 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6279 if (typearg.IsPointer && !ec.InUnsafe){
6284 type = TypeManager.type_type;
6285 // Even though what is returned is a type object, it's treated as a value by the compiler.
6286 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6287 eclass = ExprClass.Value;
6291 public override void Emit (EmitContext ec)
6293 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6294 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6297 public override bool GetAttributableValue (Type valueType, out object value)
6299 if (TypeManager.ContainsGenericParameters (typearg) &&
6300 !TypeManager.IsGenericTypeDefinition (typearg)) {
6301 Report.SymbolRelatedToPreviousError (typearg);
6302 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6303 TypeManager.CSharpName (typearg));
6308 if (valueType == TypeManager.object_type) {
6309 value = (object)typearg;
6316 public Type TypeArgument
6324 protected override void CloneTo (CloneContext clonectx, Expression t)
6326 TypeOf target = (TypeOf) t;
6328 target.QueriedType = QueriedType.Clone (clonectx);
6333 /// Implements the `typeof (void)' operator
6335 public class TypeOfVoid : TypeOf {
6336 public TypeOfVoid (Location l) : base (null, l)
6341 public override Expression DoResolve (EmitContext ec)
6343 type = TypeManager.type_type;
6344 typearg = TypeManager.void_type;
6345 // See description in TypeOf.
6346 eclass = ExprClass.Value;
6352 /// Implements the sizeof expression
6354 public class SizeOf : Expression {
6355 readonly Expression QueriedType;
6358 public SizeOf (Expression queried_type, Location l)
6360 this.QueriedType = queried_type;
6364 public override Expression DoResolve (EmitContext ec)
6366 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6371 if (texpr is TypeParameterExpr){
6372 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6377 type_queried = texpr.Type;
6378 if (type_queried.IsEnum)
6379 type_queried = TypeManager.EnumToUnderlying (type_queried);
6381 if (type_queried == TypeManager.void_type) {
6382 Expression.Error_VoidInvalidInTheContext (loc);
6386 int size_of = GetTypeSize (type_queried);
6388 return new IntConstant (size_of, loc);
6392 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)",
6393 TypeManager.CSharpName (type_queried));
6397 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6401 type = TypeManager.int32_type;
6402 eclass = ExprClass.Value;
6406 public override void Emit (EmitContext ec)
6408 int size = GetTypeSize (type_queried);
6411 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6413 IntConstant.EmitInt (ec.ig, size);
6416 protected override void CloneTo (CloneContext clonectx, Expression t)
6422 /// Implements the qualified-alias-member (::) expression.
6424 public class QualifiedAliasMember : Expression
6426 string alias, identifier;
6428 public QualifiedAliasMember (string alias, string identifier, Location l)
6430 if (RootContext.Version == LanguageVersion.ISO_1)
6431 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6434 this.identifier = identifier;
6438 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6440 if (alias == "global")
6441 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6443 int errors = Report.Errors;
6444 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6446 if (errors == Report.Errors)
6447 Report.Error (432, loc, "Alias `{0}' not found", alias);
6450 if (fne.eclass != ExprClass.Namespace) {
6452 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6455 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6458 public override Expression DoResolve (EmitContext ec)
6460 FullNamedExpression fne;
6461 if (alias == "global") {
6462 fne = RootNamespace.Global;
6464 int errors = Report.Errors;
6465 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6467 if (errors == Report.Errors)
6468 Report.Error (432, loc, "Alias `{0}' not found", alias);
6473 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6477 if (!(retval is FullNamedExpression)) {
6478 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6482 // We defer this check till the end to match the behaviour of CSC
6483 if (fne.eclass != ExprClass.Namespace) {
6484 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6490 public override void Emit (EmitContext ec)
6492 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6496 public override string ToString ()
6498 return alias + "::" + identifier;
6501 public override string GetSignatureForError ()
6506 protected override void CloneTo (CloneContext clonectx, Expression t)
6513 /// Implements the member access expression
6515 public class MemberAccess : Expression {
6516 public readonly string Identifier;
6518 readonly TypeArguments args;
6520 public MemberAccess (Expression expr, string id)
6521 : this (expr, id, expr.Location)
6525 public MemberAccess (Expression expr, string identifier, Location loc)
6528 Identifier = identifier;
6532 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6533 : this (expr, identifier, loc)
6538 protected string LookupIdentifier {
6539 get { return MemberName.MakeName (Identifier, args); }
6542 // TODO: this method has very poor performace for Enum fields and
6543 // probably for other constants as well
6544 Expression DoResolve (EmitContext ec, Expression right_side)
6547 throw new Exception ();
6550 // Resolve the expression with flow analysis turned off, we'll do the definite
6551 // assignment checks later. This is because we don't know yet what the expression
6552 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6553 // definite assignment check on the actual field and not on the whole struct.
6556 SimpleName original = expr as SimpleName;
6557 Expression expr_resolved = expr.Resolve (ec,
6558 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6559 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6561 if (expr_resolved == null)
6564 if (expr_resolved is Namespace) {
6565 Namespace ns = (Namespace) expr_resolved;
6566 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6568 if ((retval != null) && (args != null))
6569 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6573 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6577 Type expr_type = expr_resolved.Type;
6578 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6579 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6582 if (expr_type == TypeManager.anonymous_method_type){
6583 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6587 Constant c = expr_resolved as Constant;
6588 if (c != null && c.GetValue () == null) {
6589 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6590 "System.NullReferenceException");
6593 Expression member_lookup;
6594 member_lookup = MemberLookup (
6595 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6597 if ((member_lookup == null) && (args != null)) {
6598 member_lookup = MemberLookup (
6599 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6602 if (member_lookup == null) {
6603 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Identifier);
6604 if (ex_method_lookup != null) {
6605 ex_method_lookup.ExtensionExpression = expr_resolved;
6608 return ex_method_lookup.ResolveGeneric (ec, args);
6610 return ex_method_lookup.DoResolve (ec);
6613 expr = expr_resolved;
6614 Error_MemberLookupFailed (
6615 ec.ContainerType, expr_type, expr_type, Identifier, null,
6616 AllMemberTypes, AllBindingFlags);
6620 TypeExpr texpr = member_lookup as TypeExpr;
6621 if (texpr != null) {
6622 if (!(expr_resolved is TypeExpr) &&
6623 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6624 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6625 Identifier, member_lookup.GetSignatureForError ());
6629 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6630 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6631 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6636 ConstructedType ct = expr_resolved as ConstructedType;
6639 // When looking up a nested type in a generic instance
6640 // via reflection, we always get a generic type definition
6641 // and not a generic instance - so we have to do this here.
6643 // See gtest-172-lib.cs and gtest-172.cs for an example.
6645 ct = new ConstructedType (
6646 member_lookup.Type, ct.TypeArguments, loc);
6648 return ct.ResolveAsTypeStep (ec, false);
6651 return member_lookup;
6654 MemberExpr me = (MemberExpr) member_lookup;
6655 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6656 if (member_lookup == null)
6660 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6662 throw new InternalErrorException ();
6664 return mg.ResolveGeneric (ec, args);
6667 if (original != null && !TypeManager.IsValueType (expr_type)) {
6668 me = member_lookup as MemberExpr;
6669 if (me != null && me.IsInstance) {
6670 LocalVariableReference var = expr_resolved as LocalVariableReference;
6671 if (var != null && !var.VerifyAssigned (ec))
6676 // The following DoResolve/DoResolveLValue will do the definite assignment
6679 if (right_side != null)
6680 return member_lookup.DoResolveLValue (ec, right_side);
6682 return member_lookup.DoResolve (ec);
6685 public override Expression DoResolve (EmitContext ec)
6687 return DoResolve (ec, null);
6690 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6692 return DoResolve (ec, right_side);
6695 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6697 return ResolveNamespaceOrType (ec, silent);
6700 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6702 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6704 if (new_expr == null)
6707 if (new_expr is Namespace) {
6708 Namespace ns = (Namespace) new_expr;
6709 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6711 if ((retval != null) && (args != null))
6712 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6714 if (!silent && retval == null)
6715 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6719 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6720 if (tnew_expr == null)
6723 Type expr_type = tnew_expr.Type;
6725 if (expr_type.IsPointer){
6726 Error (23, "The `.' operator can not be applied to pointer operands (" +
6727 TypeManager.CSharpName (expr_type) + ")");
6731 Expression member_lookup = MemberLookup (
6732 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6733 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6734 if (member_lookup == null) {
6738 member_lookup = MemberLookup(
6739 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6740 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6742 if (member_lookup == null) {
6743 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6744 Identifier, new_expr.GetSignatureForError ());
6746 // TODO: Report.SymbolRelatedToPreviousError
6747 member_lookup.Error_UnexpectedKind (null, "type", loc);
6752 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6757 TypeArguments the_args = args;
6758 if (TypeManager.HasGenericArguments (expr_type)) {
6759 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6761 TypeArguments new_args = new TypeArguments (loc);
6762 foreach (Type decl in decl_args)
6763 new_args.Add (new TypeExpression (decl, loc));
6766 new_args.Add (args);
6768 the_args = new_args;
6771 if (the_args != null) {
6772 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6773 return ctype.ResolveAsTypeStep (rc, false);
6780 public override void Emit (EmitContext ec)
6782 throw new Exception ("Should not happen");
6785 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
6787 if (RootContext.Version > LanguageVersion.ISO_2 &&
6788 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
6789 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
6790 "extension method `{1}' of type `{0}' could be found " +
6791 "(are you missing a using directive or an assembly reference?)",
6792 TypeManager.CSharpName (type), name);
6796 base.Error_TypeDoesNotContainDefinition (type, name);
6799 public override string ToString ()
6801 return expr + "." + MemberName.MakeName (Identifier, args);
6804 public override string GetSignatureForError ()
6806 return expr.GetSignatureForError () + "." + Identifier;
6809 protected override void CloneTo (CloneContext clonectx, Expression t)
6811 MemberAccess target = (MemberAccess) t;
6813 target.expr = expr.Clone (clonectx);
6818 /// Implements checked expressions
6820 public class CheckedExpr : Expression {
6822 public Expression Expr;
6824 public CheckedExpr (Expression e, Location l)
6830 public override Expression DoResolve (EmitContext ec)
6832 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6833 Expr = Expr.Resolve (ec);
6838 if (Expr is Constant)
6841 eclass = Expr.eclass;
6846 public override void Emit (EmitContext ec)
6848 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6852 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6854 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6855 Expr.EmitBranchable (ec, target, onTrue);
6858 protected override void CloneTo (CloneContext clonectx, Expression t)
6860 CheckedExpr target = (CheckedExpr) t;
6862 target.Expr = Expr.Clone (clonectx);
6867 /// Implements the unchecked expression
6869 public class UnCheckedExpr : Expression {
6871 public Expression Expr;
6873 public UnCheckedExpr (Expression e, Location l)
6879 public override Expression DoResolve (EmitContext ec)
6881 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6882 Expr = Expr.Resolve (ec);
6887 if (Expr is Constant)
6890 eclass = Expr.eclass;
6895 public override void Emit (EmitContext ec)
6897 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6901 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6903 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
6904 Expr.EmitBranchable (ec, target, onTrue);
6907 protected override void CloneTo (CloneContext clonectx, Expression t)
6909 UnCheckedExpr target = (UnCheckedExpr) t;
6911 target.Expr = Expr.Clone (clonectx);
6916 /// An Element Access expression.
6918 /// During semantic analysis these are transformed into
6919 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
6921 public class ElementAccess : Expression {
6922 public ArrayList Arguments;
6923 public Expression Expr;
6925 public ElementAccess (Expression e, ArrayList e_list)
6934 Arguments = new ArrayList ();
6935 foreach (Expression tmp in e_list)
6936 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6940 bool CommonResolve (EmitContext ec)
6942 Expr = Expr.Resolve (ec);
6944 if (Arguments == null)
6947 foreach (Argument a in Arguments){
6948 if (!a.Resolve (ec, loc))
6952 return Expr != null;
6955 Expression MakePointerAccess (EmitContext ec, Type t)
6957 if (t == TypeManager.void_ptr_type){
6958 Error (242, "The array index operation is not valid on void pointers");
6961 if (Arguments.Count != 1){
6962 Error (196, "A pointer must be indexed by only one value");
6967 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
6970 return new Indirection (p, loc).Resolve (ec);
6973 public override Expression DoResolve (EmitContext ec)
6975 if (!CommonResolve (ec))
6979 // We perform some simple tests, and then to "split" the emit and store
6980 // code we create an instance of a different class, and return that.
6982 // I am experimenting with this pattern.
6986 if (t == TypeManager.array_type){
6987 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
6992 return (new ArrayAccess (this, loc)).Resolve (ec);
6994 return MakePointerAccess (ec, t);
6996 FieldExpr fe = Expr as FieldExpr;
6998 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7000 return MakePointerAccess (ec, ff.ElementType);
7003 return (new IndexerAccess (this, loc)).Resolve (ec);
7006 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7008 if (!CommonResolve (ec))
7013 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7016 return MakePointerAccess (ec, t);
7018 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7021 public override void Emit (EmitContext ec)
7023 throw new Exception ("Should never be reached");
7026 protected override void CloneTo (CloneContext clonectx, Expression t)
7028 ElementAccess target = (ElementAccess) t;
7030 target.Expr = Expr.Clone (clonectx);
7031 target.Arguments = new ArrayList (Arguments.Count);
7032 foreach (Argument a in Arguments)
7033 target.Arguments.Add (a.Clone (clonectx));
7038 /// Implements array access
7040 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7042 // Points to our "data" repository
7046 LocalTemporary temp;
7047 LocalTemporary prepared_value;
7051 public ArrayAccess (ElementAccess ea_data, Location l)
7054 eclass = ExprClass.Variable;
7058 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7060 return DoResolve (ec);
7063 public override Expression DoResolve (EmitContext ec)
7066 ExprClass eclass = ea.Expr.eclass;
7068 // As long as the type is valid
7069 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7070 eclass == ExprClass.Value)) {
7071 ea.Expr.Error_UnexpectedKind ("variable or value");
7076 Type t = ea.Expr.Type;
7077 if (t.GetArrayRank () != ea.Arguments.Count){
7078 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7079 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7083 type = TypeManager.GetElementType (t);
7084 if (type.IsPointer && !ec.InUnsafe){
7085 UnsafeError (ea.Location);
7089 foreach (Argument a in ea.Arguments){
7090 Type argtype = a.Type;
7092 if (argtype == TypeManager.int32_type ||
7093 argtype == TypeManager.uint32_type ||
7094 argtype == TypeManager.int64_type ||
7095 argtype == TypeManager.uint64_type) {
7096 Constant c = a.Expr as Constant;
7097 if (c != null && c.IsNegative) {
7098 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7104 // Mhm. This is strage, because the Argument.Type is not the same as
7105 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7107 // Wonder if I will run into trouble for this.
7109 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7114 eclass = ExprClass.Variable;
7120 /// Emits the right opcode to load an object of Type `t'
7121 /// from an array of T
7123 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7126 MethodInfo get = FetchGetMethod ();
7127 ig.Emit (OpCodes.Call, get);
7131 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7132 ig.Emit (OpCodes.Ldelem_U1);
7133 else if (type == TypeManager.sbyte_type)
7134 ig.Emit (OpCodes.Ldelem_I1);
7135 else if (type == TypeManager.short_type)
7136 ig.Emit (OpCodes.Ldelem_I2);
7137 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7138 ig.Emit (OpCodes.Ldelem_U2);
7139 else if (type == TypeManager.int32_type)
7140 ig.Emit (OpCodes.Ldelem_I4);
7141 else if (type == TypeManager.uint32_type)
7142 ig.Emit (OpCodes.Ldelem_U4);
7143 else if (type == TypeManager.uint64_type)
7144 ig.Emit (OpCodes.Ldelem_I8);
7145 else if (type == TypeManager.int64_type)
7146 ig.Emit (OpCodes.Ldelem_I8);
7147 else if (type == TypeManager.float_type)
7148 ig.Emit (OpCodes.Ldelem_R4);
7149 else if (type == TypeManager.double_type)
7150 ig.Emit (OpCodes.Ldelem_R8);
7151 else if (type == TypeManager.intptr_type)
7152 ig.Emit (OpCodes.Ldelem_I);
7153 else if (TypeManager.IsEnumType (type)){
7154 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type), rank);
7155 } else if (type.IsValueType){
7156 ig.Emit (OpCodes.Ldelema, type);
7157 ig.Emit (OpCodes.Ldobj, type);
7159 } else if (type.IsGenericParameter) {
7160 ig.Emit (OpCodes.Ldelem, type);
7162 } else if (type.IsPointer)
7163 ig.Emit (OpCodes.Ldelem_I);
7165 ig.Emit (OpCodes.Ldelem_Ref);
7169 /// Returns the right opcode to store an object of Type `t'
7170 /// from an array of T.
7172 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7174 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7175 has_type_arg = false; is_stobj = false;
7176 t = TypeManager.TypeToCoreType (t);
7177 if (TypeManager.IsEnumType (t))
7178 t = TypeManager.EnumToUnderlying (t);
7179 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7180 t == TypeManager.bool_type)
7181 return OpCodes.Stelem_I1;
7182 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7183 t == TypeManager.char_type)
7184 return OpCodes.Stelem_I2;
7185 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7186 return OpCodes.Stelem_I4;
7187 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7188 return OpCodes.Stelem_I8;
7189 else if (t == TypeManager.float_type)
7190 return OpCodes.Stelem_R4;
7191 else if (t == TypeManager.double_type)
7192 return OpCodes.Stelem_R8;
7193 else if (t == TypeManager.intptr_type) {
7194 has_type_arg = true;
7196 return OpCodes.Stobj;
7197 } else if (t.IsValueType) {
7198 has_type_arg = true;
7200 return OpCodes.Stobj;
7202 } else if (t.IsGenericParameter) {
7203 has_type_arg = true;
7204 return OpCodes.Stelem;
7207 } else if (t.IsPointer)
7208 return OpCodes.Stelem_I;
7210 return OpCodes.Stelem_Ref;
7213 MethodInfo FetchGetMethod ()
7215 ModuleBuilder mb = CodeGen.Module.Builder;
7216 int arg_count = ea.Arguments.Count;
7217 Type [] args = new Type [arg_count];
7220 for (int i = 0; i < arg_count; i++){
7221 //args [i++] = a.Type;
7222 args [i] = TypeManager.int32_type;
7225 get = mb.GetArrayMethod (
7226 ea.Expr.Type, "Get",
7227 CallingConventions.HasThis |
7228 CallingConventions.Standard,
7234 MethodInfo FetchAddressMethod ()
7236 ModuleBuilder mb = CodeGen.Module.Builder;
7237 int arg_count = ea.Arguments.Count;
7238 Type [] args = new Type [arg_count];
7242 ret_type = TypeManager.GetReferenceType (type);
7244 for (int i = 0; i < arg_count; i++){
7245 //args [i++] = a.Type;
7246 args [i] = TypeManager.int32_type;
7249 address = mb.GetArrayMethod (
7250 ea.Expr.Type, "Address",
7251 CallingConventions.HasThis |
7252 CallingConventions.Standard,
7259 // Load the array arguments into the stack.
7261 // If we have been requested to cache the values (cached_locations array
7262 // initialized), then load the arguments the first time and store them
7263 // in locals. otherwise load from local variables.
7265 // prepareForLoad is used in compound assignments to cache original index
7266 // values ( label[idx++] += s )
7268 LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepareForLoad)
7272 LocalTemporary[] indexes = null;
7273 if (prepareForLoad) {
7274 ec.ig.Emit (OpCodes.Dup);
7275 indexes = new LocalTemporary [ea.Arguments.Count];
7278 for (int i = 0; i < ea.Arguments.Count; ++i) {
7279 ((Argument)ea.Arguments [i]).EmitArrayArgument (ec);
7280 if (!prepareForLoad)
7283 // Keep original array index value on the stack
7284 ec.ig.Emit (OpCodes.Dup);
7286 indexes [i] = new LocalTemporary (TypeManager.intptr_type);
7287 indexes [i].Store (ec);
7293 public void Emit (EmitContext ec, bool leave_copy)
7295 int rank = ea.Expr.Type.GetArrayRank ();
7296 ILGenerator ig = ec.ig;
7298 if (prepared_value != null) {
7299 prepared_value.Emit (ec);
7300 } else if (prepared) {
7301 LoadFromPtr (ig, this.type);
7303 LoadArrayAndArguments (ec, false);
7304 EmitLoadOpcode (ig, type, rank);
7308 ig.Emit (OpCodes.Dup);
7309 temp = new LocalTemporary (this.type);
7314 public override void Emit (EmitContext ec)
7319 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7321 int rank = ea.Expr.Type.GetArrayRank ();
7322 ILGenerator ig = ec.ig;
7323 Type t = source.Type;
7324 prepared = prepare_for_load && !(source is StringConcat);
7327 AddressOf (ec, AddressOp.LoadStore);
7328 ec.ig.Emit (OpCodes.Dup);
7330 LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
7331 prepare_for_load && (source is StringConcat));
7333 if (original_indexes_values != null) {
7334 prepared_value = new LocalTemporary (type);
7335 EmitLoadOpcode (ig, type, rank);
7336 prepared_value.Store (ec);
7337 foreach (LocalTemporary lt in original_indexes_values) {
7345 bool is_stobj, has_type_arg;
7346 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7350 // The stobj opcode used by value types will need
7351 // an address on the stack, not really an array/array
7355 ig.Emit (OpCodes.Ldelema, t);
7360 ec.ig.Emit (OpCodes.Dup);
7361 temp = new LocalTemporary (this.type);
7366 StoreFromPtr (ig, t);
7368 ig.Emit (OpCodes.Stobj, t);
7369 else if (has_type_arg)
7376 ec.ig.Emit (OpCodes.Dup);
7377 temp = new LocalTemporary (this.type);
7382 StoreFromPtr (ig, t);
7384 int arg_count = ea.Arguments.Count;
7385 Type [] args = new Type [arg_count + 1];
7386 for (int i = 0; i < arg_count; i++) {
7387 //args [i++] = a.Type;
7388 args [i] = TypeManager.int32_type;
7390 args [arg_count] = type;
7392 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
7393 ea.Expr.Type, "Set",
7394 CallingConventions.HasThis |
7395 CallingConventions.Standard,
7396 TypeManager.void_type, args);
7398 ig.Emit (OpCodes.Call, set);
7408 public void AddressOf (EmitContext ec, AddressOp mode)
7410 int rank = ea.Expr.Type.GetArrayRank ();
7411 ILGenerator ig = ec.ig;
7413 LoadArrayAndArguments (ec, false);
7416 ig.Emit (OpCodes.Ldelema, type);
7418 MethodInfo address = FetchAddressMethod ();
7419 ig.Emit (OpCodes.Call, address);
7423 public void EmitGetLength (EmitContext ec, int dim)
7425 int rank = ea.Expr.Type.GetArrayRank ();
7426 ILGenerator ig = ec.ig;
7430 ig.Emit (OpCodes.Ldlen);
7431 ig.Emit (OpCodes.Conv_I4);
7433 IntLiteral.EmitInt (ig, dim);
7434 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7440 /// Expressions that represent an indexer call.
7442 public class IndexerAccess : Expression, IAssignMethod
7444 class IndexerMethodGroupExpr : MethodGroupExpr
7446 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
7449 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
7452 public override string Name {
7458 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
7461 // Here is the trick, decrease number of arguments by 1 when only
7462 // available property method is setter. This makes overload resolution
7463 // work correctly for indexers.
7466 if (method.Name [0] == 'g')
7467 return parameters.Count;
7469 return parameters.Count - 1;
7475 // Contains either property getter or setter
7476 public ArrayList Methods;
7477 public ArrayList Properties;
7483 void Append (Type caller_type, MemberInfo [] mi)
7488 foreach (PropertyInfo property in mi) {
7489 MethodInfo accessor = property.GetGetMethod (true);
7490 if (accessor == null)
7491 accessor = property.GetSetMethod (true);
7493 if (Methods == null) {
7494 Methods = new ArrayList ();
7495 Properties = new ArrayList ();
7498 Methods.Add (accessor);
7499 Properties.Add (property);
7503 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7505 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7507 return TypeManager.MemberLookup (
7508 caller_type, caller_type, lookup_type, MemberTypes.Property,
7509 BindingFlags.Public | BindingFlags.Instance |
7510 BindingFlags.DeclaredOnly, p_name, null);
7513 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7515 Indexers ix = new Indexers ();
7518 if (lookup_type.IsGenericParameter) {
7519 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7523 if (gc.HasClassConstraint)
7524 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7526 Type[] ifaces = gc.InterfaceConstraints;
7527 foreach (Type itype in ifaces)
7528 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7534 Type copy = lookup_type;
7535 while (copy != TypeManager.object_type && copy != null){
7536 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7537 copy = copy.BaseType;
7540 if (lookup_type.IsInterface) {
7541 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7542 if (ifaces != null) {
7543 foreach (Type itype in ifaces)
7544 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7559 // Points to our "data" repository
7561 MethodInfo get, set;
7562 bool is_base_indexer;
7564 LocalTemporary temp;
7565 LocalTemporary prepared_value;
7566 Expression set_expr;
7568 protected Type indexer_type;
7569 protected Type current_type;
7570 protected Expression instance_expr;
7571 protected ArrayList arguments;
7573 public IndexerAccess (ElementAccess ea, Location loc)
7574 : this (ea.Expr, false, loc)
7576 this.arguments = ea.Arguments;
7579 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7582 this.instance_expr = instance_expr;
7583 this.is_base_indexer = is_base_indexer;
7584 this.eclass = ExprClass.Value;
7588 static string GetAccessorName (AccessorType at)
7590 if (at == AccessorType.Set)
7593 if (at == AccessorType.Get)
7596 throw new NotImplementedException (at.ToString ());
7599 protected virtual bool CommonResolve (EmitContext ec)
7601 indexer_type = instance_expr.Type;
7602 current_type = ec.ContainerType;
7607 public override Expression DoResolve (EmitContext ec)
7609 return ResolveAccessor (ec, AccessorType.Get);
7612 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7614 if (right_side == EmptyExpression.OutAccess) {
7615 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7616 GetSignatureForError ());
7620 // if the indexer returns a value type, and we try to set a field in it
7621 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7622 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7623 GetSignatureForError ());
7627 Expression e = ResolveAccessor (ec, AccessorType.Set);
7631 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
7635 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
7637 if (!CommonResolve (ec))
7640 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7641 if (ilist.Methods == null) {
7642 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7643 TypeManager.CSharpName (indexer_type));
7647 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
7648 mg = mg.OverloadResolve (ec, arguments, false, loc);
7652 MethodInfo mi = (MethodInfo) mg;
7653 PropertyInfo pi = null;
7654 for (int i = 0; i < ilist.Methods.Count; ++i) {
7655 if (ilist.Methods [i] == mi) {
7656 pi = (PropertyInfo) ilist.Properties [i];
7661 type = pi.PropertyType;
7662 if (type.IsPointer && !ec.InUnsafe)
7665 MethodInfo accessor;
7666 if (accessorType == AccessorType.Get) {
7667 accessor = get = pi.GetGetMethod (true);
7669 accessor = set = pi.GetSetMethod (true);
7670 if (accessor == null && pi.GetGetMethod (true) != null) {
7671 Report.SymbolRelatedToPreviousError (pi);
7672 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
7673 TypeManager.GetFullNameSignature (pi));
7678 if (accessor == null) {
7679 Report.SymbolRelatedToPreviousError (pi);
7680 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
7681 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7686 // Only base will allow this invocation to happen.
7688 if (accessor.IsAbstract && this is BaseIndexerAccess) {
7689 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
7692 bool must_do_cs1540_check;
7693 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
7695 set = pi.GetSetMethod (true);
7697 get = pi.GetGetMethod (true);
7699 if (set != null && get != null &&
7700 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
7701 Report.SymbolRelatedToPreviousError (accessor);
7702 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
7703 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
7705 Report.SymbolRelatedToPreviousError (pi);
7706 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
7710 instance_expr.CheckMarshalByRefAccess ();
7711 eclass = ExprClass.IndexerAccess;
7715 public void Emit (EmitContext ec, bool leave_copy)
7718 prepared_value.Emit (ec);
7720 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7721 arguments, loc, false, false);
7725 ec.ig.Emit (OpCodes.Dup);
7726 temp = new LocalTemporary (Type);
7732 // source is ignored, because we already have a copy of it from the
7733 // LValue resolution and we have already constructed a pre-cached
7734 // version of the arguments (ea.set_arguments);
7736 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7738 prepared = prepare_for_load;
7741 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
7742 arguments, loc, true, false);
7744 prepared_value = new LocalTemporary (type);
7745 prepared_value.Store (ec);
7747 prepared_value.Release (ec);
7750 ec.ig.Emit (OpCodes.Dup);
7751 temp = new LocalTemporary (Type);
7754 } else if (leave_copy) {
7755 temp = new LocalTemporary (Type);
7759 Argument a = (Argument) arguments [arguments.Count - 1];
7763 arguments.Add (new Argument (set_expr, Argument.AType.Expression));
7764 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
7772 public override void Emit (EmitContext ec)
7777 public override string GetSignatureForError ()
7779 // FIXME: print the argument list of the indexer
7780 return instance_expr.GetSignatureForError () + ".this[...]";
7783 protected override void CloneTo (CloneContext clonectx, Expression t)
7785 IndexerAccess target = (IndexerAccess) t;
7787 if (arguments != null){
7788 target.arguments = new ArrayList ();
7789 foreach (Argument a in arguments)
7790 target.arguments.Add (a.Clone (clonectx));
7792 if (instance_expr != null)
7793 target.instance_expr = instance_expr.Clone (clonectx);
7798 /// The base operator for method names
7800 public class BaseAccess : Expression {
7801 public readonly string Identifier;
7804 public BaseAccess (string member, Location l)
7806 this.Identifier = member;
7810 public BaseAccess (string member, TypeArguments args, Location l)
7816 public override Expression DoResolve (EmitContext ec)
7818 Expression c = CommonResolve (ec);
7824 // MethodGroups use this opportunity to flag an error on lacking ()
7826 if (!(c is MethodGroupExpr))
7827 return c.Resolve (ec);
7831 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7833 Expression c = CommonResolve (ec);
7839 // MethodGroups use this opportunity to flag an error on lacking ()
7841 if (! (c is MethodGroupExpr))
7842 return c.DoResolveLValue (ec, right_side);
7847 Expression CommonResolve (EmitContext ec)
7849 Expression member_lookup;
7850 Type current_type = ec.ContainerType;
7851 Type base_type = current_type.BaseType;
7854 Error (1511, "Keyword `base' is not available in a static method");
7858 if (ec.IsInFieldInitializer){
7859 Error (1512, "Keyword `base' is not available in the current context");
7863 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
7864 AllMemberTypes, AllBindingFlags, loc);
7865 if (member_lookup == null) {
7866 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
7867 null, AllMemberTypes, AllBindingFlags);
7874 left = new TypeExpression (base_type, loc);
7876 left = ec.GetThis (loc);
7878 MemberExpr me = (MemberExpr) member_lookup;
7880 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
7882 if (e is PropertyExpr) {
7883 PropertyExpr pe = (PropertyExpr) e;
7885 } else if (e is EventExpr) {
7886 EventExpr ee = (EventExpr) e;
7890 MethodGroupExpr mg = e as MethodGroupExpr;
7896 return mg.ResolveGeneric (ec, args);
7898 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
7906 public override void Emit (EmitContext ec)
7908 throw new Exception ("Should never be called");
7911 protected override void CloneTo (CloneContext clonectx, Expression t)
7913 BaseAccess target = (BaseAccess) t;
7915 target.args = args.Clone ();
7920 /// The base indexer operator
7922 public class BaseIndexerAccess : IndexerAccess {
7923 public BaseIndexerAccess (ArrayList args, Location loc)
7924 : base (null, true, loc)
7926 arguments = new ArrayList ();
7927 foreach (Expression tmp in args)
7928 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7931 protected override bool CommonResolve (EmitContext ec)
7933 instance_expr = ec.GetThis (loc);
7935 current_type = ec.ContainerType.BaseType;
7936 indexer_type = current_type;
7938 foreach (Argument a in arguments){
7939 if (!a.Resolve (ec, loc))
7948 /// This class exists solely to pass the Type around and to be a dummy
7949 /// that can be passed to the conversion functions (this is used by
7950 /// foreach implementation to typecast the object return value from
7951 /// get_Current into the proper type. All code has been generated and
7952 /// we only care about the side effect conversions to be performed
7954 /// This is also now used as a placeholder where a no-action expression
7955 /// is needed (the `New' class).
7957 public class EmptyExpression : Expression {
7958 public static readonly EmptyExpression Null = new EmptyExpression ();
7960 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
7961 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
7962 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
7964 static EmptyExpression temp = new EmptyExpression ();
7965 public static EmptyExpression Grab ()
7967 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
7972 public static void Release (EmptyExpression e)
7977 // TODO: should be protected
7978 public EmptyExpression ()
7980 type = TypeManager.object_type;
7981 eclass = ExprClass.Value;
7982 loc = Location.Null;
7985 public EmptyExpression (Type t)
7988 eclass = ExprClass.Value;
7989 loc = Location.Null;
7992 public override Expression DoResolve (EmitContext ec)
7997 public override void Emit (EmitContext ec)
7999 // nothing, as we only exist to not do anything.
8003 // This is just because we might want to reuse this bad boy
8004 // instead of creating gazillions of EmptyExpressions.
8005 // (CanImplicitConversion uses it)
8007 public void SetType (Type t)
8014 // Empty statement expression
8016 public sealed class EmptyExpressionStatement : ExpressionStatement
8018 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8020 private EmptyExpressionStatement ()
8022 type = TypeManager.object_type;
8023 eclass = ExprClass.Value;
8024 loc = Location.Null;
8027 public override void EmitStatement (EmitContext ec)
8032 public override Expression DoResolve (EmitContext ec)
8037 public override void Emit (EmitContext ec)
8043 public class UserCast : Expression {
8047 public UserCast (MethodInfo method, Expression source, Location l)
8049 this.method = method;
8050 this.source = source;
8051 type = method.ReturnType;
8052 eclass = ExprClass.Value;
8056 public Expression Source {
8062 public override Expression DoResolve (EmitContext ec)
8065 // We are born fully resolved
8070 public override void Emit (EmitContext ec)
8072 ILGenerator ig = ec.ig;
8076 if (method is MethodInfo)
8077 ig.Emit (OpCodes.Call, (MethodInfo) method);
8079 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8085 // This class is used to "construct" the type during a typecast
8086 // operation. Since the Type.GetType class in .NET can parse
8087 // the type specification, we just use this to construct the type
8088 // one bit at a time.
8090 public class ComposedCast : TypeExpr {
8094 public ComposedCast (Expression left, string dim)
8095 : this (left, dim, left.Location)
8099 public ComposedCast (Expression left, string dim, Location l)
8107 public Expression RemoveNullable ()
8109 if (dim.EndsWith ("?")) {
8110 dim = dim.Substring (0, dim.Length - 1);
8119 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8121 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8125 Type ltype = lexpr.Type;
8126 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8127 Error_VoidInvalidInTheContext (loc);
8132 if ((dim.Length > 0) && (dim [0] == '?')) {
8133 TypeExpr nullable = new NullableType (left, loc);
8135 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8136 return nullable.ResolveAsTypeTerminal (ec, false);
8140 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8143 if (dim != "" && dim [0] == '[' &&
8144 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8145 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8150 type = TypeManager.GetConstructedType (ltype, dim);
8155 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8157 if (type.IsPointer && !ec.IsInUnsafeScope){
8162 eclass = ExprClass.Type;
8166 public override string Name {
8167 get { return left + dim; }
8170 public override string FullName {
8171 get { return type.FullName; }
8174 public override string GetSignatureForError ()
8176 return left.GetSignatureForError () + dim;
8179 protected override void CloneTo (CloneContext clonectx, Expression t)
8181 ComposedCast target = (ComposedCast) t;
8183 target.left = left.Clone (clonectx);
8187 public class FixedBufferPtr : Expression {
8190 public FixedBufferPtr (Expression array, Type array_type, Location l)
8195 type = TypeManager.GetPointerType (array_type);
8196 eclass = ExprClass.Value;
8199 public override void Emit(EmitContext ec)
8204 public override Expression DoResolve (EmitContext ec)
8207 // We are born fully resolved
8215 // This class is used to represent the address of an array, used
8216 // only by the Fixed statement, this generates "&a [0]" construct
8217 // for fixed (char *pa = a)
8219 public class ArrayPtr : FixedBufferPtr {
8222 public ArrayPtr (Expression array, Type array_type, Location l):
8223 base (array, array_type, l)
8225 this.array_type = array_type;
8228 public override void Emit (EmitContext ec)
8232 ILGenerator ig = ec.ig;
8233 IntLiteral.EmitInt (ig, 0);
8234 ig.Emit (OpCodes.Ldelema, array_type);
8239 // Used by the fixed statement
8241 public class StringPtr : Expression {
8244 public StringPtr (LocalBuilder b, Location l)
8247 eclass = ExprClass.Value;
8248 type = TypeManager.char_ptr_type;
8252 public override Expression DoResolve (EmitContext ec)
8254 // This should never be invoked, we are born in fully
8255 // initialized state.
8260 public override void Emit (EmitContext ec)
8262 ILGenerator ig = ec.ig;
8264 ig.Emit (OpCodes.Ldloc, b);
8265 ig.Emit (OpCodes.Conv_I);
8266 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8267 ig.Emit (OpCodes.Add);
8272 // Implements the `stackalloc' keyword
8274 public class StackAlloc : Expression {
8279 public StackAlloc (Expression type, Expression count, Location l)
8286 public override Expression DoResolve (EmitContext ec)
8288 count = count.Resolve (ec);
8292 if (count.Type != TypeManager.int32_type){
8293 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8298 Constant c = count as Constant;
8299 if (c != null && c.IsNegative) {
8300 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8304 if (ec.InCatch || ec.InFinally) {
8305 Error (255, "Cannot use stackalloc in finally or catch");
8309 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8315 if (!TypeManager.VerifyUnManaged (otype, loc))
8318 type = TypeManager.GetPointerType (otype);
8319 eclass = ExprClass.Value;
8324 public override void Emit (EmitContext ec)
8326 int size = GetTypeSize (otype);
8327 ILGenerator ig = ec.ig;
8330 ig.Emit (OpCodes.Sizeof, otype);
8332 IntConstant.EmitInt (ig, size);
8334 ig.Emit (OpCodes.Mul);
8335 ig.Emit (OpCodes.Localloc);
8338 protected override void CloneTo (CloneContext clonectx, Expression t)
8340 StackAlloc target = (StackAlloc) t;
8341 target.count = count.Clone (clonectx);
8342 target.t = t.Clone (clonectx);
8347 // An object initializer expression
8349 public class ElementInitializer : Expression
8351 Expression initializer;
8352 public readonly string Name;
8354 public ElementInitializer (string name, Expression initializer, Location loc)
8357 this.initializer = initializer;
8361 protected override void CloneTo (CloneContext clonectx, Expression t)
8363 if (initializer == null)
8366 ElementInitializer target = (ElementInitializer) t;
8367 target.initializer = initializer.Clone (clonectx);
8370 public override Expression DoResolve (EmitContext ec)
8372 if (initializer == null)
8373 return EmptyExpressionStatement.Instance;
8375 MemberExpr element_member = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8376 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8378 if (element_member == null)
8381 element_member.InstanceExpression = ec.CurrentInitializerVariable;
8383 if (initializer is CollectionOrObjectInitializers) {
8384 Expression previous = ec.CurrentInitializerVariable;
8385 ec.CurrentInitializerVariable = element_member;
8386 initializer = initializer.Resolve (ec);
8387 ec.CurrentInitializerVariable = previous;
8391 return new Assign (element_member, initializer, loc).Resolve (ec);
8394 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
8396 MemberInfo member = members [0];
8397 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
8398 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
8399 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
8401 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
8402 TypeManager.GetFullNameSignature (member));
8407 public override void Emit (EmitContext ec)
8409 throw new NotSupportedException ("Should not be reached");
8414 // A collection initializer expression
8416 public class CollectionElementInitializer : Expression
8418 public class ElementInitializerArgument : Argument
8420 public ElementInitializerArgument (Expression e)
8426 ArrayList arguments;
8428 public CollectionElementInitializer (Expression argument)
8430 arguments = new ArrayList (1);
8431 arguments.Add (argument);
8432 this.loc = argument.Location;
8435 public CollectionElementInitializer (ArrayList arguments, Location loc)
8437 this.arguments = arguments;
8441 protected override void CloneTo (CloneContext clonectx, Expression t)
8443 CollectionElementInitializer target = (CollectionElementInitializer) t;
8444 ArrayList t_arguments = target.arguments = new ArrayList (arguments.Count);
8445 foreach (Expression e in arguments)
8446 t_arguments.Add (e.Clone (clonectx));
8449 public override Expression DoResolve (EmitContext ec)
8451 // TODO: We should call a constructor which takes element counts argument,
8452 // for know types like List<T>, Dictionary<T, U>
8454 for (int i = 0; i < arguments.Count; ++i)
8455 arguments [i] = new ElementInitializerArgument ((Expression)arguments [i]);
8457 Expression add_method = new Invocation (
8458 new MemberAccess (ec.CurrentInitializerVariable, "Add", loc),
8461 add_method = add_method.Resolve (ec);
8466 public override void Emit (EmitContext ec)
8468 throw new NotSupportedException ("Should not be reached");
8473 // A block of object or collection initializers
8475 public class CollectionOrObjectInitializers : ExpressionStatement
8477 ArrayList initializers;
8479 public static readonly CollectionOrObjectInitializers Empty =
8480 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
8482 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
8484 this.initializers = initializers;
8488 public bool IsEmpty {
8490 return initializers.Count == 0;
8494 protected override void CloneTo (CloneContext clonectx, Expression target)
8496 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
8498 t.initializers = new ArrayList (initializers.Count);
8499 foreach (Expression e in initializers)
8500 t.initializers.Add (e.Clone (clonectx));
8503 public override Expression DoResolve (EmitContext ec)
8505 bool is_elements_initialization = false;
8506 ArrayList element_names = null;
8507 for (int i = 0; i < initializers.Count; ++i) {
8508 Expression initializer = (Expression) initializers [i];
8509 ElementInitializer element_initializer = initializer as ElementInitializer;
8512 if (element_initializer != null) {
8513 is_elements_initialization = true;
8514 element_names = new ArrayList (initializers.Count);
8515 element_names.Add (element_initializer.Name);
8517 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
8518 TypeManager.ienumerable_type)) {
8519 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
8520 "object initializer because type `{1}' does not implement `{2}' interface",
8521 ec.CurrentInitializerVariable.GetSignatureForError (),
8522 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
8523 TypeManager.CSharpName (TypeManager.ienumerable_type));
8528 if (is_elements_initialization == (element_initializer == null)) {
8529 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
8530 is_elements_initialization ? "object initializer" : "collection initializer");
8534 if (is_elements_initialization) {
8535 if (element_names.Contains (element_initializer.Name)) {
8536 Report.Error (1912, element_initializer.Location,
8537 "An object initializer includes more than one member `{0}' initialization",
8538 element_initializer.Name);
8540 element_names.Add (element_initializer.Name);
8545 initializers [i] = initializer.Resolve (ec);
8548 type = typeof (CollectionOrObjectInitializers);
8549 eclass = ExprClass.Variable;
8553 public override void Emit (EmitContext ec)
8558 public override void EmitStatement (EmitContext ec)
8560 foreach (ExpressionStatement e in initializers)
8561 e.EmitStatement (ec);
8566 // New expression with element/object initializers
8568 public class NewInitialize : New
8570 CollectionOrObjectInitializers initializers;
8571 TemporaryVariable type_instance;
8573 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
8574 : base (requested_type, arguments, l)
8576 this.initializers = initializers;
8579 protected override void CloneTo (CloneContext clonectx, Expression t)
8581 base.CloneTo (clonectx, t);
8583 NewInitialize target = (NewInitialize) t;
8584 target.initializers = (CollectionOrObjectInitializers)initializers.Clone (clonectx);
8587 public override Expression DoResolve (EmitContext ec)
8589 Expression e = base.DoResolve (ec);
8593 // Empty initializer can be optimized to simple new
8594 if (initializers.IsEmpty)
8597 type_instance = new TemporaryVariable (type, loc);
8598 type_instance = (TemporaryVariable)type_instance.Resolve (ec);
8600 Expression previous = ec.CurrentInitializerVariable;
8601 ec.CurrentInitializerVariable = type_instance;
8602 initializers.Resolve (ec);
8603 ec.CurrentInitializerVariable = previous;
8607 public override void Emit (EmitContext ec)
8611 type_instance.EmitStore (ec);
8612 initializers.Emit (ec);
8613 type_instance.Emit (ec);
8617 public class AnonymousTypeDeclaration : Expression
8619 ArrayList parameters;
8620 readonly TypeContainer parent;
8621 static readonly ArrayList EmptyParameters = new ArrayList (0);
8623 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8625 this.parameters = parameters;
8626 this.parent = parent;
8630 protected override void CloneTo (CloneContext clonectx, Expression target)
8632 if (parameters == null)
8635 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
8636 t.parameters = new ArrayList (parameters.Count);
8637 foreach (AnonymousTypeParameter atp in parameters)
8638 t.parameters.Add (atp.Clone (clonectx));
8641 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
8643 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8647 type = AnonymousTypeClass.Create (parent, parameters, loc);
8652 type.DefineMembers ();
8656 RootContext.ToplevelTypes.AddAnonymousType (type);
8660 public override Expression DoResolve (EmitContext ec)
8662 AnonymousTypeClass anonymous_type;
8664 if (parameters == null) {
8665 anonymous_type = CreateAnonymousType (EmptyParameters);
8666 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
8667 null, loc).Resolve (ec);
8671 ArrayList arguments = new ArrayList (parameters.Count);
8672 TypeExpression [] t_args = new TypeExpression [parameters.Count];
8673 for (int i = 0; i < parameters.Count; ++i) {
8674 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
8680 arguments.Add (new Argument (e));
8681 t_args [i] = new TypeExpression (e.Type, e.Location);
8687 anonymous_type = CreateAnonymousType (parameters);
8688 if (anonymous_type == null)
8691 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8692 new TypeArguments (loc, t_args), loc);
8694 return new New (te, arguments, loc).Resolve (ec);
8697 public override void Emit (EmitContext ec)
8699 throw new InternalErrorException ("Should not be reached");
8703 public class AnonymousTypeParameter : Expression
8705 public readonly string Name;
8706 Expression initializer;
8708 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8712 this.initializer = initializer;
8715 public AnonymousTypeParameter (Parameter parameter)
8717 this.Name = parameter.Name;
8718 this.loc = parameter.Location;
8719 this.initializer = new SimpleName (Name, loc);
8722 protected override void CloneTo (CloneContext clonectx, Expression target)
8724 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
8725 t.initializer = initializer.Clone (clonectx);
8728 public override bool Equals (object o)
8730 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8731 return other != null && Name == other.Name;
8734 public override int GetHashCode ()
8736 return Name.GetHashCode ();
8739 public override Expression DoResolve (EmitContext ec)
8741 Expression e = initializer.Resolve (ec);
8746 if (type == TypeManager.void_type || type == TypeManager.null_type ||
8747 type == TypeManager.anonymous_method_type || type.IsPointer) {
8748 Error_InvalidInitializer (e);
8755 protected virtual void Error_InvalidInitializer (Expression initializer)
8757 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8758 Name, initializer.GetSignatureForError ());
8761 public override void Emit (EmitContext ec)
8763 throw new InternalErrorException ("Should not be reached");