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 new EmptyCast (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 new EmptyCast (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 new EmptyCast (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 if (expr.eclass == ExprClass.Value) {
895 Error_ValueAssignment (loc);
897 expr.Error_UnexpectedKind (ec.DeclContainer, "variable, indexer or property access", loc);
905 public override Expression DoResolve (EmitContext ec)
907 expr = expr.Resolve (ec);
912 eclass = ExprClass.Value;
915 if (TypeManager.IsNullableValueType (expr.Type))
916 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
919 return ResolveOperator (ec);
922 static int PtrTypeSize (Type t)
924 return GetTypeSize (TypeManager.GetElementType (t));
928 // Loads the proper "1" into the stack based on the type, then it emits the
929 // opcode for the operation requested
931 void LoadOneAndEmitOp (EmitContext ec, Type t)
934 // Measure if getting the typecode and using that is more/less efficient
935 // that comparing types. t.GetTypeCode() is an internal call.
937 ILGenerator ig = ec.ig;
939 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
940 LongConstant.EmitLong (ig, 1);
941 else if (t == TypeManager.double_type)
942 ig.Emit (OpCodes.Ldc_R8, 1.0);
943 else if (t == TypeManager.float_type)
944 ig.Emit (OpCodes.Ldc_R4, 1.0F);
945 else if (t.IsPointer){
946 int n = PtrTypeSize (t);
949 ig.Emit (OpCodes.Sizeof, t);
951 IntConstant.EmitInt (ig, n);
953 ig.Emit (OpCodes.Ldc_I4_1);
956 // Now emit the operation
959 if (t == TypeManager.int32_type ||
960 t == TypeManager.int64_type){
961 if ((mode & Mode.IsDecrement) != 0)
962 ig.Emit (OpCodes.Sub_Ovf);
964 ig.Emit (OpCodes.Add_Ovf);
965 } else if (t == TypeManager.uint32_type ||
966 t == TypeManager.uint64_type){
967 if ((mode & Mode.IsDecrement) != 0)
968 ig.Emit (OpCodes.Sub_Ovf_Un);
970 ig.Emit (OpCodes.Add_Ovf_Un);
972 if ((mode & Mode.IsDecrement) != 0)
973 ig.Emit (OpCodes.Sub_Ovf);
975 ig.Emit (OpCodes.Add_Ovf);
978 if ((mode & Mode.IsDecrement) != 0)
979 ig.Emit (OpCodes.Sub);
981 ig.Emit (OpCodes.Add);
984 if (t == TypeManager.sbyte_type){
986 ig.Emit (OpCodes.Conv_Ovf_I1);
988 ig.Emit (OpCodes.Conv_I1);
989 } else if (t == TypeManager.byte_type){
991 ig.Emit (OpCodes.Conv_Ovf_U1);
993 ig.Emit (OpCodes.Conv_U1);
994 } else if (t == TypeManager.short_type){
996 ig.Emit (OpCodes.Conv_Ovf_I2);
998 ig.Emit (OpCodes.Conv_I2);
999 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1001 ig.Emit (OpCodes.Conv_Ovf_U2);
1003 ig.Emit (OpCodes.Conv_U2);
1008 void EmitCode (EmitContext ec, bool is_expr)
1011 this.is_expr = is_expr;
1012 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1015 public override void Emit (EmitContext ec)
1018 // We use recurse to allow ourselfs to be the source
1019 // of an assignment. This little hack prevents us from
1020 // having to allocate another expression
1023 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1025 LoadOneAndEmitOp (ec, expr.Type);
1027 ec.ig.Emit (OpCodes.Call, method.Method);
1032 EmitCode (ec, true);
1035 public override void EmitStatement (EmitContext ec)
1037 EmitCode (ec, false);
1040 protected override void CloneTo (CloneContext clonectx, Expression t)
1042 UnaryMutator target = (UnaryMutator) t;
1044 target.expr = expr.Clone (clonectx);
1049 /// Base class for the `Is' and `As' classes.
1053 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1056 public abstract class Probe : Expression {
1057 public Expression ProbeType;
1058 protected Expression expr;
1059 protected TypeExpr probe_type_expr;
1061 public Probe (Expression expr, Expression probe_type, Location l)
1063 ProbeType = probe_type;
1068 public Expression Expr {
1074 public override Expression DoResolve (EmitContext ec)
1076 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1077 if (probe_type_expr == null)
1080 expr = expr.Resolve (ec);
1084 if (expr.Type.IsPointer) {
1085 Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types");
1091 protected override void CloneTo (CloneContext clonectx, Expression t)
1093 Probe target = (Probe) t;
1095 target.expr = expr.Clone (clonectx);
1096 target.ProbeType = ProbeType.Clone (clonectx);
1102 /// Implementation of the `is' operator.
1104 public class Is : Probe {
1105 public Is (Expression expr, Expression probe_type, Location l)
1106 : base (expr, probe_type, l)
1111 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1116 public override void Emit (EmitContext ec)
1118 ILGenerator ig = ec.ig;
1123 case Action.AlwaysFalse:
1124 ig.Emit (OpCodes.Pop);
1125 IntConstant.EmitInt (ig, 0);
1127 case Action.AlwaysTrue:
1128 ig.Emit (OpCodes.Pop);
1129 IntConstant.EmitInt (ig, 1);
1131 case Action.LeaveOnStack:
1132 // the `e != null' rule.
1133 ig.Emit (OpCodes.Ldnull);
1134 ig.Emit (OpCodes.Ceq);
1135 ig.Emit (OpCodes.Ldc_I4_0);
1136 ig.Emit (OpCodes.Ceq);
1139 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1140 ig.Emit (OpCodes.Ldnull);
1141 ig.Emit (OpCodes.Cgt_Un);
1144 throw new Exception ("never reached");
1147 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
1149 ILGenerator ig = ec.ig;
1152 case Action.AlwaysFalse:
1154 ig.Emit (OpCodes.Br, target);
1157 case Action.AlwaysTrue:
1159 ig.Emit (OpCodes.Br, target);
1162 case Action.LeaveOnStack:
1163 // the `e != null' rule.
1165 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1169 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1170 ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1173 throw new Exception ("never reached");
1176 public override Expression DoResolve (EmitContext ec)
1178 Expression e = base.DoResolve (ec);
1180 if ((e == null) || (expr == null))
1183 Type etype = expr.Type;
1184 type = TypeManager.bool_type;
1185 eclass = ExprClass.Value;
1188 // First case, if at compile time, there is an implicit conversion
1189 // then e != null (objects) or true (value types)
1191 Type probe_type = probe_type_expr.Type;
1192 e = Convert.ImplicitConversionStandard (ec, expr, probe_type, loc);
1195 if (etype.IsValueType)
1196 action = Action.AlwaysTrue;
1198 action = Action.LeaveOnStack;
1200 Constant c = e as Constant;
1201 if (c != null && c.GetValue () == null) {
1202 action = Action.AlwaysFalse;
1203 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1204 TypeManager.CSharpName (probe_type));
1205 } else if (etype.IsValueType) {
1206 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1207 TypeManager.CSharpName (probe_type));
1212 if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){
1213 if (TypeManager.IsGenericParameter (etype))
1214 expr = new BoxedCast (expr, etype);
1217 // Second case: explicit reference convresion
1219 if (expr is NullLiteral)
1220 action = Action.AlwaysFalse;
1222 action = Action.Probe;
1223 } else if (TypeManager.ContainsGenericParameters (etype) ||
1224 TypeManager.ContainsGenericParameters (probe_type)) {
1225 expr = new BoxedCast (expr, etype);
1226 action = Action.Probe;
1228 action = Action.AlwaysFalse;
1229 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1230 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type", TypeManager.CSharpName (probe_type));
1238 /// Implementation of the `as' operator.
1240 public class As : Probe {
1241 public As (Expression expr, Expression probe_type, Location l)
1242 : base (expr, probe_type, l)
1246 bool do_isinst = false;
1247 Expression resolved_type;
1249 public override void Emit (EmitContext ec)
1251 ILGenerator ig = ec.ig;
1256 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1259 if (TypeManager.IsNullableType (type))
1260 ig.Emit (OpCodes.Unbox_Any, type);
1264 static void Error_CannotConvertType (Type source, Type target, Location loc)
1266 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1267 TypeManager.CSharpName (source),
1268 TypeManager.CSharpName (target));
1271 public override Expression DoResolve (EmitContext ec)
1273 if (resolved_type == null) {
1274 resolved_type = base.DoResolve (ec);
1276 if (resolved_type == null)
1280 type = probe_type_expr.Type;
1281 eclass = ExprClass.Value;
1282 Type etype = expr.Type;
1284 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1285 Report.Error (77, loc, "The as operator must be used with a reference type (`" +
1286 TypeManager.CSharpName (type) + "' is a value type)");
1293 // If the type is a type parameter, ensure
1294 // that it is constrained by a class
1296 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1298 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1301 if (constraints == null)
1304 if (!constraints.HasClassConstraint)
1305 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1309 Report.Error (413, loc,
1310 "The as operator requires that the `{0}' type parameter be constrained by a class",
1311 probe_type_expr.GetSignatureForError ());
1317 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1324 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1325 if (TypeManager.IsGenericParameter (etype))
1326 expr = new BoxedCast (expr, etype);
1332 if (TypeManager.ContainsGenericParameters (etype) ||
1333 TypeManager.ContainsGenericParameters (type)) {
1334 expr = new BoxedCast (expr, etype);
1339 Error_CannotConvertType (etype, type, loc);
1343 public override bool GetAttributableValue (Type valueType, out object value)
1345 return expr.GetAttributableValue (valueType, out value);
1350 /// This represents a typecast in the source language.
1352 /// FIXME: Cast expressions have an unusual set of parsing
1353 /// rules, we need to figure those out.
1355 public class Cast : Expression {
1356 Expression target_type;
1359 public Cast (Expression cast_type, Expression expr)
1360 : this (cast_type, expr, cast_type.Location)
1364 public Cast (Expression cast_type, Expression expr, Location loc)
1366 this.target_type = cast_type;
1370 if (target_type == TypeManager.system_void_expr)
1371 Error_VoidInvalidInTheContext (loc);
1374 public Expression TargetType {
1375 get { return target_type; }
1378 public Expression Expr {
1379 get { return expr; }
1382 public override Expression DoResolve (EmitContext ec)
1384 expr = expr.Resolve (ec);
1388 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1394 if (type.IsAbstract && type.IsSealed) {
1395 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1399 eclass = ExprClass.Value;
1401 Constant c = expr as Constant;
1403 c = c.TryReduce (ec, type, loc);
1408 if (type.IsPointer && !ec.InUnsafe) {
1412 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1416 public override void Emit (EmitContext ec)
1418 throw new Exception ("Should not happen");
1421 protected override void CloneTo (CloneContext clonectx, Expression t)
1423 Cast target = (Cast) t;
1425 target.target_type = target_type.Clone (clonectx);
1426 target.expr = expr.Clone (clonectx);
1431 /// Binary operators
1433 public class Binary : Expression {
1434 public enum Operator : byte {
1435 Multiply, Division, Modulus,
1436 Addition, Subtraction,
1437 LeftShift, RightShift,
1438 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1439 Equality, Inequality,
1448 readonly Operator oper;
1449 Expression left, right;
1451 // This must be kept in sync with Operator!!!
1452 public static readonly string [] oper_names;
1456 oper_names = new string [(int) Operator.TOP];
1458 oper_names [(int) Operator.Multiply] = "op_Multiply";
1459 oper_names [(int) Operator.Division] = "op_Division";
1460 oper_names [(int) Operator.Modulus] = "op_Modulus";
1461 oper_names [(int) Operator.Addition] = "op_Addition";
1462 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1463 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1464 oper_names [(int) Operator.RightShift] = "op_RightShift";
1465 oper_names [(int) Operator.LessThan] = "op_LessThan";
1466 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1467 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1468 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1469 oper_names [(int) Operator.Equality] = "op_Equality";
1470 oper_names [(int) Operator.Inequality] = "op_Inequality";
1471 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1472 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1473 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1474 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1475 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1478 public Binary (Operator oper, Expression left, Expression right)
1483 this.loc = left.Location;
1486 public Operator Oper {
1493 /// Returns a stringified representation of the Operator
1495 public static string OperName (Operator oper)
1498 case Operator.Multiply:
1500 case Operator.Division:
1502 case Operator.Modulus:
1504 case Operator.Addition:
1506 case Operator.Subtraction:
1508 case Operator.LeftShift:
1510 case Operator.RightShift:
1512 case Operator.LessThan:
1514 case Operator.GreaterThan:
1516 case Operator.LessThanOrEqual:
1518 case Operator.GreaterThanOrEqual:
1520 case Operator.Equality:
1522 case Operator.Inequality:
1524 case Operator.BitwiseAnd:
1526 case Operator.BitwiseOr:
1528 case Operator.ExclusiveOr:
1530 case Operator.LogicalOr:
1532 case Operator.LogicalAnd:
1536 return oper.ToString ();
1539 public override string ToString ()
1541 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1542 right.ToString () + ")";
1545 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1547 if (expr.Type == target_type)
1550 return Convert.ImplicitConversion (ec, expr, target_type, loc);
1553 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1556 34, loc, "Operator `" + OperName (oper)
1557 + "' is ambiguous on operands of type `"
1558 + TypeManager.CSharpName (l) + "' "
1559 + "and `" + TypeManager.CSharpName (r)
1563 bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
1565 return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
1568 bool VerifyApplicable_Predefined (EmitContext ec, Type t)
1570 if (!IsConvertible (ec, left, right, t))
1572 left = ForceConversion (ec, left, t);
1573 right = ForceConversion (ec, right, t);
1578 bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
1580 bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
1581 bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
1583 if (oper == Operator.Equality || oper == Operator.Inequality)
1585 if (oper == Operator.Addition)
1590 bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
1592 if (!IsApplicable_String (ec, left, right, oper))
1594 Type t = TypeManager.string_type;
1595 if (Convert.ImplicitConversionExists (ec, left, t))
1596 left = ForceConversion (ec, left, t);
1597 if (Convert.ImplicitConversionExists (ec, right, t))
1598 right = ForceConversion (ec, right, t);
1603 bool OverloadResolve_PredefinedIntegral (EmitContext ec)
1605 return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
1606 VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
1607 VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
1608 VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
1612 bool OverloadResolve_PredefinedFloating (EmitContext ec)
1614 return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
1615 VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
1619 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1621 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1624 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1626 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1630 void Error_OperatorCannotBeApplied ()
1632 Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
1633 TypeManager.CSharpName(right.Type));
1636 static bool is_unsigned (Type t)
1638 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1639 t == TypeManager.short_type || t == TypeManager.byte_type);
1642 Expression Make32or64 (EmitContext ec, Expression e)
1646 if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1647 t == TypeManager.int64_type || t == TypeManager.uint64_type)
1649 Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
1652 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
1655 ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
1658 ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
1664 Expression CheckShiftArguments (EmitContext ec)
1666 Expression new_left = Make32or64 (ec, left);
1667 Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
1668 if (new_left == null || new_right == null) {
1669 Error_OperatorCannotBeApplied ();
1672 type = new_left.Type;
1673 int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
1675 right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
1680 // This is used to check if a test 'x == null' can be optimized to a reference equals,
1681 // i.e., not invoke op_Equality.
1683 static bool EqualsNullIsReferenceEquals (Type t)
1685 return t == TypeManager.object_type || t == TypeManager.string_type ||
1686 t == TypeManager.delegate_type || t.IsSubclassOf (TypeManager.delegate_type);
1689 static void Warning_UnintendedReferenceComparison (Location loc, string side, Type type)
1691 Report.Warning ((side == "left" ? 252 : 253), 2, loc,
1692 "Possible unintended reference comparison; to get a value comparison, " +
1693 "cast the {0} hand side to type `{1}'.", side, TypeManager.CSharpName (type));
1696 static void Warning_Constant_Result (Location loc, bool result, Type type)
1698 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
1699 "This operation is undocumented and it is temporary supported for compatibility reasons only",
1700 TypeManager.CSharpName (type), result ? "true" : "false");
1703 Expression ResolveOperator (EmitContext ec)
1706 Type r = right.Type;
1708 if (oper == Operator.Equality || oper == Operator.Inequality){
1709 if (right is NullLiteral){
1710 if (TypeManager.IsGenericParameter (l)){
1711 if (l.BaseType == TypeManager.value_type) {
1712 Error_OperatorCannotBeApplied ();
1716 left = new BoxedCast (left, TypeManager.object_type);
1717 Type = TypeManager.bool_type;
1722 // CSC 2 has this behavior, it allows structs to be compared
1723 // with the null literal *outside* of a generics context and
1724 // inlines that as true or false.
1726 // This is, in my opinion, completely wrong.
1728 if (RootContext.Version != LanguageVersion.ISO_1 && l.IsValueType){
1729 Warning_Constant_Result (loc, oper == Operator.Inequality, l);
1730 return new BoolLiteral (oper == Operator.Inequality, loc);
1734 if (left is NullLiteral){
1735 if (TypeManager.IsGenericParameter (r)){
1736 if (r.BaseType == TypeManager.value_type) {
1737 Error_OperatorCannotBeApplied ();
1741 right = new BoxedCast (right, TypeManager.object_type);
1742 Type = TypeManager.bool_type;
1747 // CSC 2 has this behavior, it allows structs to be compared
1748 // with the null literal *outside* of a generics context and
1749 // inlines that as true or false.
1751 // This is, in my opinion, completely wrong.
1753 if (RootContext.Version != LanguageVersion.ISO_1 && r.IsValueType){
1754 Warning_Constant_Result (loc, oper == Operator.Inequality, r);
1755 return new BoolLiteral (oper == Operator.Inequality, loc);
1760 // Optimize out call to op_Equality in a few cases.
1762 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
1763 (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
1764 Type = TypeManager.bool_type;
1769 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
1770 Type = TypeManager.bool_type;
1776 // Delegate equality
1778 MethodGroupExpr mg = null;
1779 Type delegate_type = null;
1780 if (left.eclass == ExprClass.MethodGroup) {
1781 if (!TypeManager.IsDelegateType(r)) {
1782 Error_OperatorCannotBeApplied(Location, OperName(oper),
1783 left.ExprClassName, right.ExprClassName);
1786 mg = (MethodGroupExpr)left;
1788 } else if (right.eclass == ExprClass.MethodGroup) {
1789 if (!TypeManager.IsDelegateType(l)) {
1790 Error_OperatorCannotBeApplied(Location, OperName(oper),
1791 left.ExprClassName, right.ExprClassName);
1794 mg = (MethodGroupExpr)right;
1799 Expression e = ImplicitDelegateCreation.Create (ec, mg, delegate_type, loc);
1803 // Find operator method
1804 string op = oper_names[(int)oper];
1805 MemberInfo[] mi = TypeManager.MemberLookup(ec.ContainerType, null,
1806 TypeManager.delegate_type, MemberTypes.Method, AllBindingFlags, op, null);
1808 ArrayList args = new ArrayList(2);
1809 args.Add(new Argument(e, Argument.AType.Expression));
1810 if (delegate_type == l)
1811 args.Insert(0, new Argument(left, Argument.AType.Expression));
1813 args.Add(new Argument(right, Argument.AType.Expression));
1815 return new BinaryMethod (TypeManager.bool_type, (MethodInfo)mi [0], args);
1818 if (l == TypeManager.anonymous_method_type || r == TypeManager.anonymous_method_type) {
1819 Error_OperatorCannotBeApplied(Location, OperName(oper),
1820 left.ExprClassName, right.ExprClassName);
1827 // Do not perform operator overload resolution when both sides are
1830 MethodGroupExpr left_operators = null, right_operators = null;
1831 if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
1833 // Step 1: Perform Operator Overload location
1835 string op = oper_names [(int) oper];
1837 MethodGroupExpr union;
1838 left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1840 right_operators = MemberLookup (
1841 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1842 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
1844 union = left_operators;
1846 if (union != null) {
1847 ArrayList args = new ArrayList (2);
1848 args.Add (new Argument (left, Argument.AType.Expression));
1849 args.Add (new Argument (right, Argument.AType.Expression));
1851 union = union.OverloadResolve (ec, args, true, Location.Null);
1853 if (union != null) {
1854 MethodInfo mi = (MethodInfo) union;
1855 return new BinaryMethod (mi.ReturnType, mi, args);
1861 // Step 0: String concatenation (because overloading will get this wrong)
1863 if (oper == Operator.Addition){
1865 // If any of the arguments is a string, cast to string
1868 // Simple constant folding
1869 if (left is StringConstant && right is StringConstant)
1870 return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value, left.Location);
1872 if (l == TypeManager.string_type || r == TypeManager.string_type) {
1874 if (r == TypeManager.void_type || l == TypeManager.void_type) {
1875 Error_OperatorCannotBeApplied ();
1879 // try to fold it in on the left
1880 if (left is StringConcat) {
1883 // We have to test here for not-null, since we can be doubly-resolved
1884 // take care of not appending twice
1887 type = TypeManager.string_type;
1888 ((StringConcat) left).Append (ec, right);
1889 return left.Resolve (ec);
1895 // Otherwise, start a new concat expression
1896 return new StringConcat (ec, loc, left, right).Resolve (ec);
1900 // Transform a + ( - b) into a - b
1902 if (right is Unary){
1903 Unary right_unary = (Unary) right;
1905 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1906 return new Binary (Operator.Subtraction, left, right_unary.Expr).Resolve (ec);
1911 if (oper == Operator.Equality || oper == Operator.Inequality){
1912 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1913 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1914 Error_OperatorCannotBeApplied ();
1918 type = TypeManager.bool_type;
1922 if (l.IsPointer || r.IsPointer) {
1923 if (l.IsPointer && r.IsPointer) {
1924 type = TypeManager.bool_type;
1928 if (l.IsPointer && r == TypeManager.null_type) {
1929 right = new EmptyCast (NullPointer.Null, l);
1930 type = TypeManager.bool_type;
1934 if (r.IsPointer && l == TypeManager.null_type) {
1935 left = new EmptyCast (NullPointer.Null, r);
1936 type = TypeManager.bool_type;
1942 if (l.IsGenericParameter && r.IsGenericParameter) {
1943 GenericConstraints l_gc, r_gc;
1945 l_gc = TypeManager.GetTypeParameterConstraints (l);
1946 r_gc = TypeManager.GetTypeParameterConstraints (r);
1948 if ((l_gc == null) || (r_gc == null) ||
1949 !(l_gc.HasReferenceTypeConstraint || l_gc.HasClassConstraint) ||
1950 !(r_gc.HasReferenceTypeConstraint || r_gc.HasClassConstraint)) {
1951 Error_OperatorCannotBeApplied ();
1959 // operator != (object a, object b)
1960 // operator == (object a, object b)
1962 // For this to be used, both arguments have to be reference-types.
1963 // Read the rationale on the spec (14.9.6)
1965 if (!(l.IsValueType || r.IsValueType)){
1966 type = TypeManager.bool_type;
1972 // Also, a standard conversion must exist from either one
1974 bool left_to_right =
1975 Convert.ImplicitStandardConversionExists (left, r);
1976 bool right_to_left = !left_to_right &&
1977 Convert.ImplicitStandardConversionExists (right, l);
1979 if (!left_to_right && !right_to_left) {
1980 Error_OperatorCannotBeApplied ();
1984 if (left_to_right && left_operators != null &&
1985 Report.WarningLevel >= 2) {
1986 ArrayList args = new ArrayList (2);
1987 args.Add (new Argument (left, Argument.AType.Expression));
1988 args.Add (new Argument (left, Argument.AType.Expression));
1989 if (left_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1990 Warning_UnintendedReferenceComparison (loc, "right", l);
1993 if (right_to_left && right_operators != null &&
1994 Report.WarningLevel >= 2) {
1995 ArrayList args = new ArrayList (2);
1996 args.Add (new Argument (right, Argument.AType.Expression));
1997 args.Add (new Argument (right, Argument.AType.Expression));
1998 if (right_operators.OverloadResolve (ec, args, true, Location.Null) != null)
1999 Warning_UnintendedReferenceComparison (loc, "left", r);
2003 // We are going to have to convert to an object to compare
2005 if (l != TypeManager.object_type)
2006 left = new EmptyCast (left, TypeManager.object_type);
2007 if (r != TypeManager.object_type)
2008 right = new EmptyCast (right, TypeManager.object_type);
2014 // Only perform numeric promotions on:
2015 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2017 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2018 if (TypeManager.IsDelegateType (l)){
2019 if (((right.eclass == ExprClass.MethodGroup) ||
2020 (r == TypeManager.anonymous_method_type))){
2021 if ((RootContext.Version != LanguageVersion.ISO_1)){
2022 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2030 if (TypeManager.IsDelegateType (r) || right is NullLiteral){
2032 ArrayList args = new ArrayList (2);
2034 args = new ArrayList (2);
2035 args.Add (new Argument (left, Argument.AType.Expression));
2036 args.Add (new Argument (right, Argument.AType.Expression));
2038 if (oper == Operator.Addition)
2039 method = TypeManager.delegate_combine_delegate_delegate;
2041 method = TypeManager.delegate_remove_delegate_delegate;
2043 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
2044 Error_OperatorCannotBeApplied ();
2048 return new BinaryDelegate (l, method, args);
2053 // Pointer arithmetic:
2055 // T* operator + (T* x, int y);
2056 // T* operator + (T* x, uint y);
2057 // T* operator + (T* x, long y);
2058 // T* operator + (T* x, ulong y);
2060 // T* operator + (int y, T* x);
2061 // T* operator + (uint y, T *x);
2062 // T* operator + (long y, T *x);
2063 // T* operator + (ulong y, T *x);
2065 // T* operator - (T* x, int y);
2066 // T* operator - (T* x, uint y);
2067 // T* operator - (T* x, long y);
2068 // T* operator - (T* x, ulong y);
2070 // long operator - (T* x, T *y)
2073 if (r.IsPointer && oper == Operator.Subtraction){
2075 return new PointerArithmetic (
2076 false, left, right, TypeManager.int64_type,
2079 Expression t = Make32or64 (ec, right);
2081 return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2083 } else if (r.IsPointer && oper == Operator.Addition){
2084 Expression t = Make32or64 (ec, left);
2086 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2091 // Enumeration operators
2093 bool lie = TypeManager.IsEnumType (l);
2094 bool rie = TypeManager.IsEnumType (r);
2098 // U operator - (E e, E f)
2100 if (oper == Operator.Subtraction){
2102 type = TypeManager.EnumToUnderlying (l);
2105 Error_OperatorCannotBeApplied ();
2111 // operator + (E e, U x)
2112 // operator - (E e, U x)
2114 if (oper == Operator.Addition || oper == Operator.Subtraction){
2115 Type enum_type = lie ? l : r;
2116 Type other_type = lie ? r : l;
2117 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2119 if (underlying_type != other_type){
2120 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2130 Error_OperatorCannotBeApplied ();
2139 temp = Convert.ImplicitConversion (ec, right, l, loc);
2143 Error_OperatorCannotBeApplied ();
2147 temp = Convert.ImplicitConversion (ec, left, r, loc);
2152 Error_OperatorCannotBeApplied ();
2157 if (oper == Operator.Equality || oper == Operator.Inequality ||
2158 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2159 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2160 if (left.Type != right.Type){
2161 Error_OperatorCannotBeApplied ();
2164 type = TypeManager.bool_type;
2168 if (oper == Operator.BitwiseAnd ||
2169 oper == Operator.BitwiseOr ||
2170 oper == Operator.ExclusiveOr){
2171 if (left.Type != right.Type){
2172 Error_OperatorCannotBeApplied ();
2178 Error_OperatorCannotBeApplied ();
2182 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2183 return CheckShiftArguments (ec);
2185 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2186 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2187 type = TypeManager.bool_type;
2191 Expression left_operators_e = l == TypeManager.bool_type ?
2192 left : Convert.ImplicitUserConversion (ec, left, TypeManager.bool_type, loc);
2193 Expression right_operators_e = r == TypeManager.bool_type ?
2194 right : Convert.ImplicitUserConversion (ec, right, TypeManager.bool_type, loc);
2196 if (left_operators_e != null && right_operators_e != null) {
2197 left = left_operators_e;
2198 right = right_operators_e;
2199 type = TypeManager.bool_type;
2203 Expression e = new ConditionalLogicalOperator (
2204 oper == Operator.LogicalAnd, left, right, l, loc);
2205 return e.Resolve (ec);
2208 Expression orig_left = left;
2209 Expression orig_right = right;
2212 // operator & (bool x, bool y)
2213 // operator | (bool x, bool y)
2214 // operator ^ (bool x, bool y)
2216 if (oper == Operator.BitwiseAnd ||
2217 oper == Operator.BitwiseOr ||
2218 oper == Operator.ExclusiveOr) {
2219 if (OverloadResolve_PredefinedIntegral (ec)) {
2220 if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
2221 Error_OperatorAmbiguous (loc, oper, l, r);
2225 if (oper == Operator.BitwiseOr && l != r && !(orig_right is Constant) && right is OpcodeCast &&
2226 (r == TypeManager.sbyte_type || r == TypeManager.short_type ||
2227 r == TypeManager.int32_type || r == TypeManager.int64_type)) {
2228 Report.Warning (675, 3, loc, "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2229 TypeManager.CSharpName (r));
2232 } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
2233 Error_OperatorCannotBeApplied ();
2240 // Pointer comparison
2242 if (l.IsPointer && r.IsPointer){
2243 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2244 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2245 type = TypeManager.bool_type;
2250 if (OverloadResolve_PredefinedIntegral (ec)) {
2251 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2252 Error_OperatorAmbiguous (loc, oper, l, r);
2255 } else if (OverloadResolve_PredefinedFloating (ec)) {
2256 if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
2257 IsApplicable_String (ec, orig_left, orig_right, oper)) {
2258 Error_OperatorAmbiguous (loc, oper, l, r);
2261 } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
2262 if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
2263 Error_OperatorAmbiguous (loc, oper, l, r);
2266 } else if (!OverloadResolve_PredefinedString (ec, oper)) {
2267 Error_OperatorCannotBeApplied ();
2271 if (oper == Operator.Equality ||
2272 oper == Operator.Inequality ||
2273 oper == Operator.LessThanOrEqual ||
2274 oper == Operator.LessThan ||
2275 oper == Operator.GreaterThanOrEqual ||
2276 oper == Operator.GreaterThan)
2277 type = TypeManager.bool_type;
2282 if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
2284 if (r == TypeManager.string_type)
2286 MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
2287 ec.ContainerType, lookup, oper_names [(int) oper],
2288 MemberTypes.Method, AllBindingFlags, loc);
2289 ArrayList args = new ArrayList (2);
2290 args.Add (new Argument (left, Argument.AType.Expression));
2291 args.Add (new Argument (right, Argument.AType.Expression));
2292 ops = ops.OverloadResolve (ec, args, true, Location.Null);
2293 return new BinaryMethod (type, (MethodInfo)ops, args);
2299 Constant EnumLiftUp (Constant left, Constant right)
2302 case Operator.BitwiseOr:
2303 case Operator.BitwiseAnd:
2304 case Operator.ExclusiveOr:
2305 case Operator.Equality:
2306 case Operator.Inequality:
2307 case Operator.LessThan:
2308 case Operator.LessThanOrEqual:
2309 case Operator.GreaterThan:
2310 case Operator.GreaterThanOrEqual:
2311 if (left is EnumConstant)
2314 if (left.IsZeroInteger)
2315 return new EnumConstant (left, right.Type);
2319 case Operator.Addition:
2320 case Operator.Subtraction:
2323 case Operator.Multiply:
2324 case Operator.Division:
2325 case Operator.Modulus:
2326 case Operator.LeftShift:
2327 case Operator.RightShift:
2328 if (right is EnumConstant || left is EnumConstant)
2332 Error_OperatorCannotBeApplied (loc, Binary.OperName (oper), left.Type, right.Type);
2336 public override Expression DoResolve (EmitContext ec)
2341 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2342 left = ((ParenthesizedExpression) left).Expr;
2343 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2347 if (left.eclass == ExprClass.Type) {
2348 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2352 left = left.Resolve (ec);
2357 Constant lc = left as Constant;
2358 if (lc != null && lc.Type == TypeManager.bool_type &&
2359 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2360 (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2362 // TODO: make a sense to resolve unreachable expression as we do for statement
2363 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2367 right = right.Resolve (ec);
2371 eclass = ExprClass.Value;
2372 Constant rc = right as Constant;
2374 // The conversion rules are ignored in enum context but why
2375 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2376 left = lc = EnumLiftUp (lc, rc);
2380 right = rc = EnumLiftUp (rc, lc);
2385 if (oper == Operator.BitwiseAnd) {
2386 if (rc != null && rc.IsZeroInteger) {
2387 return lc is EnumConstant ?
2388 new EnumConstant (rc, lc.Type):
2392 if (lc != null && lc.IsZeroInteger) {
2393 return rc is EnumConstant ?
2394 new EnumConstant (lc, rc.Type):
2398 else if (oper == Operator.BitwiseOr) {
2399 if (lc is EnumConstant &&
2400 rc != null && rc.IsZeroInteger)
2402 if (rc is EnumConstant &&
2403 lc != null && lc.IsZeroInteger)
2405 } else if (oper == Operator.LogicalAnd) {
2406 if (rc != null && rc.IsDefaultValue && rc.Type == TypeManager.bool_type)
2408 if (lc != null && lc.IsDefaultValue && lc.Type == TypeManager.bool_type)
2412 if (rc != null && lc != null){
2413 int prev_e = Report.Errors;
2414 Expression e = ConstantFold.BinaryFold (
2415 ec, oper, lc, rc, loc);
2416 if (e != null || Report.Errors != prev_e)
2421 if ((left is NullLiteral || left.Type.IsValueType) &&
2422 (right is NullLiteral || right.Type.IsValueType) &&
2423 !(left is NullLiteral && right is NullLiteral) &&
2424 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)))
2425 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2428 // Comparison warnings
2429 if (oper == Operator.Equality || oper == Operator.Inequality ||
2430 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2431 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2432 if (left.Equals (right)) {
2433 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2435 CheckUselessComparison (lc, right.Type);
2436 CheckUselessComparison (rc, left.Type);
2439 return ResolveOperator (ec);
2442 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2447 private void CheckUselessComparison (Constant c, Type type)
2449 if (c == null || !IsTypeIntegral (type)
2450 || c is StringConstant
2451 || c is BoolConstant
2452 || c is FloatConstant
2453 || c is DoubleConstant
2454 || c is DecimalConstant
2460 if (c is ULongConstant) {
2461 ulong uvalue = ((ULongConstant) c).Value;
2462 if (uvalue > long.MaxValue) {
2463 if (type == TypeManager.byte_type ||
2464 type == TypeManager.sbyte_type ||
2465 type == TypeManager.short_type ||
2466 type == TypeManager.ushort_type ||
2467 type == TypeManager.int32_type ||
2468 type == TypeManager.uint32_type ||
2469 type == TypeManager.int64_type ||
2470 type == TypeManager.char_type)
2471 WarnUselessComparison (type);
2474 value = (long) uvalue;
2476 else if (c is ByteConstant)
2477 value = ((ByteConstant) c).Value;
2478 else if (c is SByteConstant)
2479 value = ((SByteConstant) c).Value;
2480 else if (c is ShortConstant)
2481 value = ((ShortConstant) c).Value;
2482 else if (c is UShortConstant)
2483 value = ((UShortConstant) c).Value;
2484 else if (c is IntConstant)
2485 value = ((IntConstant) c).Value;
2486 else if (c is UIntConstant)
2487 value = ((UIntConstant) c).Value;
2488 else if (c is LongConstant)
2489 value = ((LongConstant) c).Value;
2490 else if (c is CharConstant)
2491 value = ((CharConstant)c).Value;
2496 if (IsValueOutOfRange (value, type))
2497 WarnUselessComparison (type);
2500 private bool IsValueOutOfRange (long value, Type type)
2502 if (IsTypeUnsigned (type) && value < 0)
2504 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2505 type == TypeManager.byte_type && value >= 0x100 ||
2506 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2507 type == TypeManager.ushort_type && value >= 0x10000 ||
2508 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2509 type == TypeManager.uint32_type && value >= 0x100000000;
2512 private static bool IsTypeIntegral (Type type)
2514 return type == TypeManager.uint64_type ||
2515 type == TypeManager.int64_type ||
2516 type == TypeManager.uint32_type ||
2517 type == TypeManager.int32_type ||
2518 type == TypeManager.ushort_type ||
2519 type == TypeManager.short_type ||
2520 type == TypeManager.sbyte_type ||
2521 type == TypeManager.byte_type ||
2522 type == TypeManager.char_type;
2525 private static bool IsTypeUnsigned (Type type)
2527 return type == TypeManager.uint64_type ||
2528 type == TypeManager.uint32_type ||
2529 type == TypeManager.ushort_type ||
2530 type == TypeManager.byte_type ||
2531 type == TypeManager.char_type;
2534 private void WarnUselessComparison (Type type)
2536 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}'",
2537 TypeManager.CSharpName (type));
2541 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2542 /// context of a conditional bool expression. This function will return
2543 /// false if it is was possible to use EmitBranchable, or true if it was.
2545 /// The expression's code is generated, and we will generate a branch to `target'
2546 /// if the resulting expression value is equal to isTrue
2548 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2550 ILGenerator ig = ec.ig;
2553 // This is more complicated than it looks, but its just to avoid
2554 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2555 // but on top of that we want for == and != to use a special path
2556 // if we are comparing against null
2558 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2559 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2562 // put the constant on the rhs, for simplicity
2564 if (left is Constant) {
2565 Expression swap = right;
2570 if (((Constant) right).IsZeroInteger) {
2573 ig.Emit (OpCodes.Brtrue, target);
2575 ig.Emit (OpCodes.Brfalse, target);
2578 } else if (right is BoolConstant) {
2580 if (my_on_true != ((BoolConstant) right).Value)
2581 ig.Emit (OpCodes.Brtrue, target);
2583 ig.Emit (OpCodes.Brfalse, target);
2588 } else if (oper == Operator.LogicalAnd) {
2591 Label tests_end = ig.DefineLabel ();
2593 left.EmitBranchable (ec, tests_end, false);
2594 right.EmitBranchable (ec, target, true);
2595 ig.MarkLabel (tests_end);
2598 // This optimizes code like this
2599 // if (true && i > 4)
2601 if (!(left is Constant))
2602 left.EmitBranchable (ec, target, false);
2604 if (!(right is Constant))
2605 right.EmitBranchable (ec, target, false);
2610 } else if (oper == Operator.LogicalOr){
2612 left.EmitBranchable (ec, target, true);
2613 right.EmitBranchable (ec, target, true);
2616 Label tests_end = ig.DefineLabel ();
2617 left.EmitBranchable (ec, tests_end, true);
2618 right.EmitBranchable (ec, target, false);
2619 ig.MarkLabel (tests_end);
2624 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
2625 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2626 oper == Operator.Equality || oper == Operator.Inequality)) {
2627 base.EmitBranchable (ec, target, onTrue);
2635 bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2638 case Operator.Equality:
2640 ig.Emit (OpCodes.Beq, target);
2642 ig.Emit (OpCodes.Bne_Un, target);
2645 case Operator.Inequality:
2647 ig.Emit (OpCodes.Bne_Un, target);
2649 ig.Emit (OpCodes.Beq, target);
2652 case Operator.LessThan:
2655 ig.Emit (OpCodes.Blt_Un, target);
2657 ig.Emit (OpCodes.Blt, target);
2660 ig.Emit (OpCodes.Bge_Un, target);
2662 ig.Emit (OpCodes.Bge, target);
2665 case Operator.GreaterThan:
2668 ig.Emit (OpCodes.Bgt_Un, target);
2670 ig.Emit (OpCodes.Bgt, target);
2673 ig.Emit (OpCodes.Ble_Un, target);
2675 ig.Emit (OpCodes.Ble, target);
2678 case Operator.LessThanOrEqual:
2681 ig.Emit (OpCodes.Ble_Un, target);
2683 ig.Emit (OpCodes.Ble, target);
2686 ig.Emit (OpCodes.Bgt_Un, target);
2688 ig.Emit (OpCodes.Bgt, target);
2692 case Operator.GreaterThanOrEqual:
2695 ig.Emit (OpCodes.Bge_Un, target);
2697 ig.Emit (OpCodes.Bge, target);
2700 ig.Emit (OpCodes.Blt_Un, target);
2702 ig.Emit (OpCodes.Blt, target);
2705 Console.WriteLine (oper);
2706 throw new Exception ("what is THAT");
2710 public override void Emit (EmitContext ec)
2712 ILGenerator ig = ec.ig;
2717 // Handle short-circuit operators differently
2720 if (oper == Operator.LogicalAnd) {
2721 Label load_zero = ig.DefineLabel ();
2722 Label end = ig.DefineLabel ();
2724 left.EmitBranchable (ec, load_zero, false);
2726 ig.Emit (OpCodes.Br, end);
2728 ig.MarkLabel (load_zero);
2729 ig.Emit (OpCodes.Ldc_I4_0);
2732 } else if (oper == Operator.LogicalOr) {
2733 Label load_one = ig.DefineLabel ();
2734 Label end = ig.DefineLabel ();
2736 left.EmitBranchable (ec, load_one, true);
2738 ig.Emit (OpCodes.Br, end);
2740 ig.MarkLabel (load_one);
2741 ig.Emit (OpCodes.Ldc_I4_1);
2749 bool isUnsigned = is_unsigned (left.Type);
2752 case Operator.Multiply:
2754 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2755 opcode = OpCodes.Mul_Ovf;
2756 else if (isUnsigned)
2757 opcode = OpCodes.Mul_Ovf_Un;
2759 opcode = OpCodes.Mul;
2761 opcode = OpCodes.Mul;
2765 case Operator.Division:
2767 opcode = OpCodes.Div_Un;
2769 opcode = OpCodes.Div;
2772 case Operator.Modulus:
2774 opcode = OpCodes.Rem_Un;
2776 opcode = OpCodes.Rem;
2779 case Operator.Addition:
2781 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2782 opcode = OpCodes.Add_Ovf;
2783 else if (isUnsigned)
2784 opcode = OpCodes.Add_Ovf_Un;
2786 opcode = OpCodes.Add;
2788 opcode = OpCodes.Add;
2791 case Operator.Subtraction:
2793 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2794 opcode = OpCodes.Sub_Ovf;
2795 else if (isUnsigned)
2796 opcode = OpCodes.Sub_Ovf_Un;
2798 opcode = OpCodes.Sub;
2800 opcode = OpCodes.Sub;
2803 case Operator.RightShift:
2805 opcode = OpCodes.Shr_Un;
2807 opcode = OpCodes.Shr;
2810 case Operator.LeftShift:
2811 opcode = OpCodes.Shl;
2814 case Operator.Equality:
2815 opcode = OpCodes.Ceq;
2818 case Operator.Inequality:
2819 ig.Emit (OpCodes.Ceq);
2820 ig.Emit (OpCodes.Ldc_I4_0);
2822 opcode = OpCodes.Ceq;
2825 case Operator.LessThan:
2827 opcode = OpCodes.Clt_Un;
2829 opcode = OpCodes.Clt;
2832 case Operator.GreaterThan:
2834 opcode = OpCodes.Cgt_Un;
2836 opcode = OpCodes.Cgt;
2839 case Operator.LessThanOrEqual:
2840 Type lt = left.Type;
2842 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2843 ig.Emit (OpCodes.Cgt_Un);
2845 ig.Emit (OpCodes.Cgt);
2846 ig.Emit (OpCodes.Ldc_I4_0);
2848 opcode = OpCodes.Ceq;
2851 case Operator.GreaterThanOrEqual:
2852 Type le = left.Type;
2854 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2855 ig.Emit (OpCodes.Clt_Un);
2857 ig.Emit (OpCodes.Clt);
2859 ig.Emit (OpCodes.Ldc_I4_0);
2861 opcode = OpCodes.Ceq;
2864 case Operator.BitwiseOr:
2865 opcode = OpCodes.Or;
2868 case Operator.BitwiseAnd:
2869 opcode = OpCodes.And;
2872 case Operator.ExclusiveOr:
2873 opcode = OpCodes.Xor;
2877 throw new Exception ("This should not happen: Operator = "
2878 + oper.ToString ());
2884 protected override void CloneTo (CloneContext clonectx, Expression t)
2886 Binary target = (Binary) t;
2888 target.left = left.Clone (clonectx);
2889 target.right = right.Clone (clonectx);
2894 // Object created by Binary when the binary operator uses an method instead of being
2895 // a binary operation that maps to a CIL binary operation.
2897 public class BinaryMethod : Expression {
2898 public MethodBase method;
2899 public ArrayList Arguments;
2901 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2906 eclass = ExprClass.Value;
2909 public override Expression DoResolve (EmitContext ec)
2914 public override void Emit (EmitContext ec)
2916 ILGenerator ig = ec.ig;
2918 if (Arguments != null)
2919 Invocation.EmitArguments (ec, method, Arguments, false, null);
2921 if (method is MethodInfo)
2922 ig.Emit (OpCodes.Call, (MethodInfo) method);
2924 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2929 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2930 // b, c, d... may be strings or objects.
2932 public class StringConcat : Expression {
2934 bool invalid = false;
2935 bool emit_conv_done = false;
2937 // Are we also concating objects?
2939 bool is_strings_only = true;
2941 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2944 type = TypeManager.string_type;
2945 eclass = ExprClass.Value;
2947 operands = new ArrayList (2);
2952 public override Expression DoResolve (EmitContext ec)
2960 public void Append (EmitContext ec, Expression operand)
2965 StringConstant sc = operand as StringConstant;
2967 // TODO: it will be better to do this silently as an optimalization
2969 // string s = "" + i;
2970 // because this code has poor performace
2971 // if (sc.Value.Length == 0)
2972 // Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2974 if (operands.Count != 0) {
2975 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2976 if (last_operand != null) {
2977 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2984 // Conversion to object
2986 if (operand.Type != TypeManager.string_type) {
2987 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2990 Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2996 operands.Add (operand);
2999 public override void Emit (EmitContext ec)
3001 MethodInfo concat_method = null;
3004 // Do conversion to arguments; check for strings only
3007 // This can get called multiple times, so we have to deal with that.
3008 if (!emit_conv_done) {
3009 emit_conv_done = true;
3010 for (int i = 0; i < operands.Count; i ++) {
3011 Expression e = (Expression) operands [i];
3012 is_strings_only &= e.Type == TypeManager.string_type;
3015 for (int i = 0; i < operands.Count; i ++) {
3016 Expression e = (Expression) operands [i];
3018 if (! is_strings_only && e.Type == TypeManager.string_type) {
3019 // need to make sure this is an object, because the EmitParams
3020 // method might look at the type of this expression, see it is a
3021 // string and emit a string [] when we want an object [];
3023 e = new EmptyCast (e, TypeManager.object_type);
3025 operands [i] = new Argument (e, Argument.AType.Expression);
3030 // Find the right method
3032 switch (operands.Count) {
3035 // This should not be possible, because simple constant folding
3036 // is taken care of in the Binary code.
3038 throw new Exception ("how did you get here?");
3041 concat_method = is_strings_only ?
3042 TypeManager.string_concat_string_string :
3043 TypeManager.string_concat_object_object ;
3046 concat_method = is_strings_only ?
3047 TypeManager.string_concat_string_string_string :
3048 TypeManager.string_concat_object_object_object ;
3052 // There is not a 4 param overlaod for object (the one that there is
3053 // is actually a varargs methods, and is only in corlib because it was
3054 // introduced there before.).
3056 if (!is_strings_only)
3059 concat_method = TypeManager.string_concat_string_string_string_string;
3062 concat_method = is_strings_only ?
3063 TypeManager.string_concat_string_dot_dot_dot :
3064 TypeManager.string_concat_object_dot_dot_dot ;
3068 Invocation.EmitArguments (ec, concat_method, operands, false, null);
3069 ec.ig.Emit (OpCodes.Call, concat_method);
3074 // Object created with +/= on delegates
3076 public class BinaryDelegate : Expression {
3080 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3085 eclass = ExprClass.Value;
3088 public override Expression DoResolve (EmitContext ec)
3093 public override void Emit (EmitContext ec)
3095 ILGenerator ig = ec.ig;
3097 Invocation.EmitArguments (ec, method, args, false, null);
3099 ig.Emit (OpCodes.Call, (MethodInfo) method);
3100 ig.Emit (OpCodes.Castclass, type);
3103 public Expression Right {
3105 Argument arg = (Argument) args [1];
3110 public bool IsAddition {
3112 return method == TypeManager.delegate_combine_delegate_delegate;
3118 // User-defined conditional logical operator
3119 public class ConditionalLogicalOperator : Expression {
3120 Expression left, right;
3123 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3126 eclass = ExprClass.Value;
3130 this.is_and = is_and;
3133 protected void Error19 ()
3135 Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3138 protected void Error218 ()
3140 Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3141 "declarations of operator true and operator false");
3144 Expression op_true, op_false, op;
3145 LocalTemporary left_temp;
3147 public override Expression DoResolve (EmitContext ec)
3149 MethodGroupExpr operator_group;
3151 operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3152 if (operator_group == null) {
3157 left_temp = new LocalTemporary (type);
3159 ArrayList arguments = new ArrayList (2);
3160 arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3161 arguments.Add (new Argument (right, Argument.AType.Expression));
3162 operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3163 if (operator_group == null) {
3168 MethodInfo method = (MethodInfo)operator_group;
3169 if (method.ReturnType != type) {
3170 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3171 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3175 op = new StaticCallExpr (method, arguments, loc);
3177 op_true = GetOperatorTrue (ec, left_temp, loc);
3178 op_false = GetOperatorFalse (ec, left_temp, loc);
3179 if ((op_true == null) || (op_false == null)) {
3187 public override void Emit (EmitContext ec)
3189 ILGenerator ig = ec.ig;
3190 Label false_target = ig.DefineLabel ();
3191 Label end_target = ig.DefineLabel ();
3194 left_temp.Store (ec);
3196 (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3197 left_temp.Emit (ec);
3198 ig.Emit (OpCodes.Br, end_target);
3199 ig.MarkLabel (false_target);
3201 ig.MarkLabel (end_target);
3203 // We release 'left_temp' here since 'op' may refer to it too
3204 left_temp.Release (ec);
3208 public class PointerArithmetic : Expression {
3209 Expression left, right;
3213 // We assume that `l' is always a pointer
3215 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3221 is_add = is_addition;
3224 public override Expression DoResolve (EmitContext ec)
3226 eclass = ExprClass.Variable;
3228 if (left.Type == TypeManager.void_ptr_type) {
3229 Error (242, "The operation in question is undefined on void pointers");
3236 public override void Emit (EmitContext ec)
3238 Type op_type = left.Type;
3239 ILGenerator ig = ec.ig;
3241 // It must be either array or fixed buffer
3242 Type element = TypeManager.HasElementType (op_type) ?
3243 element = TypeManager.GetElementType (op_type) :
3244 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3246 int size = GetTypeSize (element);
3247 Type rtype = right.Type;
3249 if (rtype.IsPointer){
3251 // handle (pointer - pointer)
3255 ig.Emit (OpCodes.Sub);
3259 ig.Emit (OpCodes.Sizeof, element);
3261 IntLiteral.EmitInt (ig, size);
3262 ig.Emit (OpCodes.Div);
3264 ig.Emit (OpCodes.Conv_I8);
3267 // handle + and - on (pointer op int)
3270 ig.Emit (OpCodes.Conv_I);
3272 Constant right_const = right as Constant;
3273 if (right_const != null && size != 0) {
3274 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3282 ig.Emit (OpCodes.Sizeof, element);
3284 IntLiteral.EmitInt (ig, size);
3285 if (rtype == TypeManager.int64_type)
3286 ig.Emit (OpCodes.Conv_I8);
3287 else if (rtype == TypeManager.uint64_type)
3288 ig.Emit (OpCodes.Conv_U8);
3289 ig.Emit (OpCodes.Mul);
3293 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3294 ig.Emit (OpCodes.Conv_I);
3297 ig.Emit (OpCodes.Add);
3299 ig.Emit (OpCodes.Sub);
3305 /// Implements the ternary conditional operator (?:)
3307 public class Conditional : Expression {
3308 Expression expr, trueExpr, falseExpr;
3310 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3313 this.trueExpr = trueExpr;
3314 this.falseExpr = falseExpr;
3315 this.loc = expr.Location;
3318 public Expression Expr {
3324 public Expression TrueExpr {
3330 public Expression FalseExpr {
3336 public override Expression DoResolve (EmitContext ec)
3338 expr = expr.Resolve (ec);
3344 if (TypeManager.IsNullableValueType (expr.Type))
3345 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3348 if (expr.Type != TypeManager.bool_type){
3349 expr = Expression.ResolveBoolean (
3356 Assign ass = expr as Assign;
3357 if (ass != null && ass.Source is Constant) {
3358 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3361 trueExpr = trueExpr.Resolve (ec);
3362 falseExpr = falseExpr.Resolve (ec);
3364 if (trueExpr == null || falseExpr == null)
3367 eclass = ExprClass.Value;
3368 if (trueExpr.Type == falseExpr.Type) {
3369 type = trueExpr.Type;
3370 if (type == TypeManager.null_type) {
3371 // TODO: probably will have to implement ConditionalConstant
3372 // to call method without return constant as well
3373 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3378 Type true_type = trueExpr.Type;
3379 Type false_type = falseExpr.Type;
3382 // First, if an implicit conversion exists from trueExpr
3383 // to falseExpr, then the result type is of type falseExpr.Type
3385 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3388 // Check if both can convert implicitl to each other's type
3390 if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3392 "Can not compute type of conditional expression " +
3393 "as `" + TypeManager.CSharpName (trueExpr.Type) +
3394 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3395 "' convert implicitly to each other");
3400 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3404 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3405 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3410 // Dead code optimalization
3411 if (expr is BoolConstant){
3412 BoolConstant bc = (BoolConstant) expr;
3414 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3415 return bc.Value ? trueExpr : falseExpr;
3421 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3426 public override void Emit (EmitContext ec)
3428 ILGenerator ig = ec.ig;
3429 Label false_target = ig.DefineLabel ();
3430 Label end_target = ig.DefineLabel ();
3432 expr.EmitBranchable (ec, false_target, false);
3434 ig.Emit (OpCodes.Br, end_target);
3435 ig.MarkLabel (false_target);
3436 falseExpr.Emit (ec);
3437 ig.MarkLabel (end_target);
3440 protected override void CloneTo (CloneContext clonectx, Expression t)
3442 Conditional target = (Conditional) t;
3444 target.expr = expr.Clone (clonectx);
3445 target.trueExpr = trueExpr.Clone (clonectx);
3446 target.falseExpr = falseExpr.Clone (clonectx);
3450 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3452 LocalTemporary temp;
3454 public abstract Variable Variable {
3458 public abstract bool IsRef {
3462 public override void Emit (EmitContext ec)
3468 // This method is used by parameters that are references, that are
3469 // being passed as references: we only want to pass the pointer (that
3470 // is already stored in the parameter, not the address of the pointer,
3471 // and not the value of the variable).
3473 public void EmitLoad (EmitContext ec)
3475 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3477 Variable.EmitInstance (ec);
3481 public void Emit (EmitContext ec, bool leave_copy)
3483 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3489 ec.ig.Emit (OpCodes.Dup);
3492 // If we are a reference, we loaded on the stack a pointer
3493 // Now lets load the real value
3495 LoadFromPtr (ec.ig, type);
3499 ec.ig.Emit (OpCodes.Dup);
3501 if (IsRef || Variable.NeedsTemporary) {
3502 temp = new LocalTemporary (Type);
3508 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3509 bool prepare_for_load)
3511 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3514 ILGenerator ig = ec.ig;
3515 prepared = prepare_for_load;
3517 Variable.EmitInstance (ec);
3518 if (prepare_for_load && Variable.HasInstance)
3519 ig.Emit (OpCodes.Dup);
3520 else if (IsRef && !prepared)
3526 ig.Emit (OpCodes.Dup);
3527 if (IsRef || Variable.NeedsTemporary) {
3528 temp = new LocalTemporary (Type);
3534 StoreFromPtr (ig, type);
3536 Variable.EmitAssign (ec);
3544 public void AddressOf (EmitContext ec, AddressOp mode)
3546 Variable.EmitInstance (ec);
3547 Variable.EmitAddressOf (ec);
3554 public class LocalVariableReference : VariableReference, IVariable {
3555 public readonly string Name;
3557 public LocalInfo local_info;
3561 public LocalVariableReference (Block block, string name, Location l)
3566 eclass = ExprClass.Variable;
3570 // Setting `is_readonly' to false will allow you to create a writable
3571 // reference to a read-only variable. This is used by foreach and using.
3573 public LocalVariableReference (Block block, string name, Location l,
3574 LocalInfo local_info, bool is_readonly)
3575 : this (block, name, l)
3577 this.local_info = local_info;
3578 this.is_readonly = is_readonly;
3581 public VariableInfo VariableInfo {
3582 get { return local_info.VariableInfo; }
3585 public override bool IsRef {
3586 get { return false; }
3589 public bool IsReadOnly {
3590 get { return is_readonly; }
3593 public bool VerifyAssigned (EmitContext ec)
3595 VariableInfo variable_info = local_info.VariableInfo;
3596 return variable_info == null || variable_info.IsAssigned (ec, loc);
3599 void ResolveLocalInfo ()
3601 if (local_info == null) {
3602 local_info = Block.GetLocalInfo (Name);
3603 type = local_info.VariableType;
3604 is_readonly = local_info.ReadOnly;
3608 protected Expression DoResolveBase (EmitContext ec)
3610 type = local_info.VariableType;
3612 Expression e = Block.GetConstantExpression (Name);
3614 return e.Resolve (ec);
3616 if (!VerifyAssigned (ec))
3620 // If we are referencing a variable from the external block
3621 // flag it for capturing
3623 if (ec.MustCaptureVariable (local_info)) {
3624 if (local_info.AddressTaken){
3625 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3629 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3630 variable = scope.AddLocal (local_info);
3631 type = variable.Type;
3637 public override Expression DoResolve (EmitContext ec)
3639 ResolveLocalInfo ();
3640 local_info.Used = true;
3642 if (type == null && local_info.Type is VarExpr) {
3643 local_info.VariableType = TypeManager.object_type;
3644 Error_VariableIsUsedBeforeItIsDeclared (Name);
3648 return DoResolveBase (ec);
3651 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3653 ResolveLocalInfo ();
3656 if (right_side == EmptyExpression.OutAccess)
3657 local_info.Used = true;
3659 // Infer implicitly typed local variable
3661 VarExpr ve = local_info.Type as VarExpr;
3663 ve.DoResolveLValue (ec, right_side);
3664 type = local_info.VariableType = ve.Type;
3671 if (right_side == EmptyExpression.OutAccess) {
3672 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3673 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3674 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3675 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3676 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3678 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3680 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3684 if (VariableInfo != null)
3685 VariableInfo.SetAssigned (ec);
3687 return DoResolveBase (ec);
3690 public bool VerifyFixed ()
3692 // A local Variable is always fixed.
3696 public override int GetHashCode ()
3698 return Name.GetHashCode ();
3701 public override bool Equals (object obj)
3703 LocalVariableReference lvr = obj as LocalVariableReference;
3707 return Name == lvr.Name && Block == lvr.Block;
3710 public override Variable Variable {
3711 get { return variable != null ? variable : local_info.Variable; }
3714 public override string ToString ()
3716 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3719 protected override void CloneTo (CloneContext clonectx, Expression t)
3721 LocalVariableReference target = (LocalVariableReference) t;
3723 target.Block = clonectx.LookupBlock (Block);
3724 if (local_info != null)
3725 target.local_info = clonectx.LookupVariable (local_info);
3730 /// This represents a reference to a parameter in the intermediate
3733 public class ParameterReference : VariableReference, IVariable {
3734 readonly ToplevelParameterInfo pi;
3735 readonly ToplevelBlock referenced;
3738 public bool is_ref, is_out;
3741 get { return is_out; }
3744 public override bool IsRef {
3745 get { return is_ref; }
3748 public string Name {
3749 get { return Parameter.Name; }
3752 public Parameter Parameter {
3753 get { return pi.Parameter; }
3756 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3759 this.referenced = referenced;
3761 eclass = ExprClass.Variable;
3764 public VariableInfo VariableInfo {
3765 get { return pi.VariableInfo; }
3768 public override Variable Variable {
3769 get { return variable != null ? variable : Parameter.Variable; }
3772 public bool VerifyFixed ()
3774 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3775 return Parameter.ModFlags == Parameter.Modifier.NONE;
3778 public bool IsAssigned (EmitContext ec, Location loc)
3780 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3783 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3787 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3789 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3792 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3796 public void SetAssigned (EmitContext ec)
3798 if (is_out && ec.DoFlowAnalysis)
3799 ec.CurrentBranching.SetAssigned (VariableInfo);
3802 public void SetFieldAssigned (EmitContext ec, string field_name)
3804 if (is_out && ec.DoFlowAnalysis)
3805 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3808 protected bool DoResolveBase (EmitContext ec)
3810 Parameter par = Parameter;
3811 if (!par.Resolve (ec)) {
3815 type = par.ParameterType;
3816 Parameter.Modifier mod = par.ModFlags;
3817 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3818 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3819 eclass = ExprClass.Variable;
3821 AnonymousContainer am = ec.CurrentAnonymousMethod;
3825 ToplevelBlock declared = pi.Block;
3826 if (is_ref && declared != referenced) {
3827 Report.Error (1628, Location,
3828 "Cannot use ref or out parameter `{0}' inside an " +
3829 "anonymous method block", par.Name);
3833 if (!am.IsIterator && declared == referenced)
3836 // Don't capture aruments when the probing is on
3837 if (!ec.IsInProbingMode) {
3838 ScopeInfo scope = declared.CreateScopeInfo ();
3839 variable = scope.AddParameter (par, pi.Index);
3840 type = variable.Type;
3845 public override int GetHashCode ()
3847 return Name.GetHashCode ();
3850 public override bool Equals (object obj)
3852 ParameterReference pr = obj as ParameterReference;
3856 return Name == pr.Name && referenced == pr.referenced;
3860 // Notice that for ref/out parameters, the type exposed is not the
3861 // same type exposed externally.
3864 // externally we expose "int&"
3865 // here we expose "int".
3867 // We record this in "is_ref". This means that the type system can treat
3868 // the type as it is expected, but when we generate the code, we generate
3869 // the alternate kind of code.
3871 public override Expression DoResolve (EmitContext ec)
3873 if (!DoResolveBase (ec))
3876 if (is_out && ec.DoFlowAnalysis &&
3877 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3883 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3885 if (!DoResolveBase (ec))
3888 // HACK: parameters are not captured when probing is on
3889 if (!ec.IsInProbingMode)
3895 static public void EmitLdArg (ILGenerator ig, int x)
3899 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3900 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3901 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3902 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3903 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3906 ig.Emit (OpCodes.Ldarg, x);
3909 public override string ToString ()
3911 return "ParameterReference[" + Name + "]";
3916 /// Used for arguments to New(), Invocation()
3918 public class Argument {
3919 public enum AType : byte {
3926 public static readonly Argument[] Empty = new Argument [0];
3928 public readonly AType ArgType;
3929 public Expression Expr;
3931 public Argument (Expression expr, AType type)
3934 this.ArgType = type;
3937 public Argument (Expression expr)
3940 this.ArgType = AType.Expression;
3945 if (ArgType == AType.Ref || ArgType == AType.Out)
3946 return TypeManager.GetReferenceType (Expr.Type);
3952 public Parameter.Modifier Modifier
3957 return Parameter.Modifier.OUT;
3960 return Parameter.Modifier.REF;
3963 return Parameter.Modifier.NONE;
3968 public static string FullDesc (Argument a)
3970 if (a.ArgType == AType.ArgList)
3973 return (a.ArgType == AType.Ref ? "ref " :
3974 (a.ArgType == AType.Out ? "out " : "")) +
3975 TypeManager.CSharpName (a.Expr.Type);
3978 public bool ResolveMethodGroup (EmitContext ec)
3980 SimpleName sn = Expr as SimpleName;
3982 Expr = sn.GetMethodGroup ();
3984 // FIXME: csc doesn't report any error if you try to use `ref' or
3985 // `out' in a delegate creation expression.
3986 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3993 public bool Resolve (EmitContext ec, Location loc)
3995 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3996 // Verify that the argument is readable
3997 if (ArgType != AType.Out)
3998 Expr = Expr.Resolve (ec);
4000 // Verify that the argument is writeable
4001 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4002 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4004 return Expr != null;
4008 public void Emit (EmitContext ec)
4010 if (ArgType != AType.Ref && ArgType != AType.Out) {
4015 AddressOp mode = AddressOp.Store;
4016 if (ArgType == AType.Ref)
4017 mode |= AddressOp.Load;
4019 IMemoryLocation ml = (IMemoryLocation) Expr;
4020 ParameterReference pr = ml as ParameterReference;
4023 // ParameterReferences might already be references, so we want
4024 // to pass just the value
4026 if (pr != null && pr.IsRef)
4029 ml.AddressOf (ec, mode);
4032 public Argument Clone (CloneContext clonectx)
4034 return new Argument (Expr.Clone (clonectx), ArgType);
4039 /// Invocation of methods or delegates.
4041 public class Invocation : ExpressionStatement {
4042 ArrayList Arguments;
4047 // arguments is an ArrayList, but we do not want to typecast,
4048 // as it might be null.
4050 public Invocation (Expression expr, ArrayList arguments)
4052 SimpleName sn = expr as SimpleName;
4054 this.expr = sn.GetMethodGroup ();
4058 Arguments = arguments;
4059 loc = expr.Location;
4062 public static string FullMethodDesc (MethodBase mb)
4068 if (mb is MethodInfo) {
4069 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4073 sb = new StringBuilder ();
4075 sb.Append (TypeManager.CSharpSignature (mb));
4076 return sb.ToString ();
4079 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4080 ArrayList arguments, int arg_count,
4081 ref MethodBase candidate)
4083 return IsParamsMethodApplicable (
4084 ec, me, arguments, arg_count, false, ref candidate) ||
4085 IsParamsMethodApplicable (
4086 ec, me, arguments, arg_count, true, ref candidate);
4091 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4092 ArrayList arguments, int arg_count,
4093 bool do_varargs, ref MethodBase candidate)
4096 if (!me.HasTypeArguments &&
4097 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4100 if (TypeManager.IsGenericMethodDefinition (candidate))
4101 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4104 return IsParamsMethodApplicable (
4105 ec, arguments, arg_count, candidate, do_varargs);
4109 /// Determines if the candidate method, if a params method, is applicable
4110 /// in its expanded form to the given set of arguments
4112 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4113 int arg_count, MethodBase candidate,
4116 ParameterData pd = TypeManager.GetParameterData (candidate);
4118 int pd_count = pd.Count;
4122 int count = pd_count - 1;
4124 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4126 if (pd_count != arg_count)
4129 if (!(((Argument) arguments [count]).Expr is Arglist))
4137 if (count > arg_count)
4140 if (pd_count == 1 && arg_count == 0)
4144 // If we have come this far, the case which
4145 // remains is when the number of parameters is
4146 // less than or equal to the argument count.
4148 int argument_index = 0;
4150 for (int i = 0; i < pd_count; ++i) {
4152 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4153 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4154 int params_args_count = arg_count - pd_count;
4155 if (params_args_count < 0)
4159 a = (Argument) arguments [argument_index++];
4161 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4163 } while (params_args_count-- > 0);
4167 a = (Argument) arguments [argument_index++];
4169 Parameter.Modifier a_mod = a.Modifier &
4170 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4171 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4172 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4174 if (a_mod == p_mod) {
4176 if (a_mod == Parameter.Modifier.NONE)
4177 if (!Convert.ImplicitConversionExists (ec,
4179 pd.ParameterType (i)))
4182 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4183 Type pt = pd.ParameterType (i);
4186 pt = TypeManager.GetReferenceType (pt);
4199 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4200 ArrayList arguments, int arg_count,
4201 ref MethodBase method)
4203 MethodBase candidate = method;
4206 if (!me.HasTypeArguments &&
4207 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4210 if (TypeManager.IsGenericMethodDefinition (candidate))
4211 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4214 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4223 /// Determines if the candidate method is applicable (section 14.4.2.1)
4224 /// to the given set of arguments
4226 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4227 MethodBase candidate)
4229 ParameterData pd = TypeManager.GetParameterData (candidate);
4231 if (arg_count != pd.Count)
4234 for (int i = arg_count; i > 0; ) {
4237 Argument a = (Argument) arguments [i];
4239 Parameter.Modifier a_mod = a.Modifier &
4240 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4242 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4243 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4248 Type pt = pd.ParameterType (i);
4250 if (TypeManager.IsEqual (pt, a.Type))
4253 if (a_mod != Parameter.Modifier.NONE)
4256 // FIXME: Kill this abomination (EmitContext.TempEc)
4257 EmitContext prevec = EmitContext.TempEc;
4258 EmitContext.TempEc = ec;
4260 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4263 EmitContext.TempEc = prevec;
4270 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4272 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4273 name, arg_count.ToString ());
4276 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4277 Type delegate_type, Argument a, ParameterData expected_par)
4279 if (delegate_type == null)
4280 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4281 TypeManager.CSharpSignature (method));
4283 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4284 TypeManager.CSharpName (delegate_type));
4286 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4288 string index = (idx + 1).ToString ();
4289 if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4290 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4291 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4292 index, Parameter.GetModifierSignature (a.Modifier));
4294 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4295 index, Parameter.GetModifierSignature (mod));
4297 string p1 = Argument.FullDesc (a);
4298 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4301 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4302 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4303 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4305 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4309 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4310 int arg_count, MethodBase method,
4311 bool chose_params_expanded,
4312 Type delegate_type, bool may_fail,
4315 ParameterData pd = TypeManager.GetParameterData (method);
4319 for (j = 0; j < pd.Count; j++) {
4320 Type parameter_type = pd.ParameterType (j);
4321 Parameter.Modifier pm = pd.ParameterModifier (j);
4323 if (pm == Parameter.Modifier.ARGLIST) {
4324 a = (Argument) Arguments [a_idx];
4325 if (!(a.Expr is Arglist))
4331 int params_arg_count = 1;
4332 if (pm == Parameter.Modifier.PARAMS) {
4333 pm = Parameter.Modifier.NONE;
4334 params_arg_count = arg_count - pd.Count + 1;
4335 if (chose_params_expanded)
4336 parameter_type = TypeManager.GetElementType (parameter_type);
4339 while (params_arg_count > 0) {
4340 a = (Argument) Arguments [a_idx];
4341 if (pm != a.Modifier)
4344 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4345 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4348 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4352 // Update the argument with the implicit conversion
4360 if (params_arg_count > 0)
4363 if (parameter_type.IsPointer && !ec.InUnsafe) {
4370 if (a_idx == arg_count)
4374 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4378 public override Expression DoResolve (EmitContext ec)
4380 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4381 if (expr_resolved == null)
4384 mg = expr_resolved as MethodGroupExpr;
4386 Type expr_type = expr_resolved.Type;
4388 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4389 return (new DelegateInvocation (
4390 expr_resolved, Arguments, loc)).Resolve (ec);
4392 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4397 // Next, evaluate all the expressions in the argument list
4399 if (Arguments != null){
4400 foreach (Argument a in Arguments){
4401 if (!a.Resolve (ec, loc))
4406 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4410 MethodInfo method = (MethodInfo)mg;
4411 if (method != null) {
4412 type = TypeManager.TypeToCoreType (method.ReturnType);
4413 Expression iexpr = mg.InstanceExpression;
4414 if (method.IsStatic) {
4415 if (iexpr == null ||
4416 iexpr is This || iexpr is EmptyExpression ||
4417 mg.IdenticalTypeName) {
4418 mg.InstanceExpression = null;
4420 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4424 if (iexpr == null || iexpr is EmptyExpression) {
4425 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4431 if (type.IsPointer){
4439 // Only base will allow this invocation to happen.
4441 if (mg.IsBase && method.IsAbstract){
4442 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4446 if (Arguments == null && method.Name == "Finalize") {
4448 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4450 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4454 if (IsSpecialMethodInvocation (method)) {
4458 if (mg.InstanceExpression != null){
4459 mg.InstanceExpression.CheckMarshalByRefAccess ();
4462 // This is used to check that no methods are called in struct
4463 // constructors before all the fields on the struct have been
4466 if (!method.IsStatic){
4467 This mgthis = mg.InstanceExpression as This;
4468 if (mgthis != null){
4469 if (!mgthis.CheckThisUsage (ec))
4475 eclass = ExprClass.Value;
4479 bool IsSpecialMethodInvocation (MethodBase method)
4481 if (!TypeManager.IsSpecialMethod (method))
4484 Report.SymbolRelatedToPreviousError (method);
4485 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4486 TypeManager.CSharpSignature (method, true));
4492 // Emits the list of arguments as an array
4494 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4496 ILGenerator ig = ec.ig;
4498 for (int j = 0; j < count; j++){
4499 Argument a = (Argument) arguments [j + idx];
4502 IntConstant.EmitInt (ig, count);
4503 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4506 ig.Emit (OpCodes.Dup);
4507 IntConstant.EmitInt (ig, j);
4509 bool is_stobj, has_type_arg;
4510 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4512 ig.Emit (OpCodes.Ldelema, t);
4524 /// Emits a list of resolved Arguments that are in the arguments
4527 /// The MethodBase argument might be null if the
4528 /// emission of the arguments is known not to contain
4529 /// a `params' field (for example in constructors or other routines
4530 /// that keep their arguments in this structure)
4532 /// if `dup_args' is true, a copy of the arguments will be left
4533 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4534 /// which will be duplicated before any other args. Only EmitCall
4535 /// should be using this interface.
4537 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4539 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4541 LocalTemporary [] temps = null;
4543 if (dup_args && top != 0)
4544 temps = new LocalTemporary [top];
4546 int argument_index = 0;
4548 for (int i = 0; i < top; i++){
4550 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4551 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4552 int params_args_count = arguments == null ?
4553 0 : arguments.Count - top + 1;
4555 // Fill not provided argument
4556 if (params_args_count <= 0) {
4557 ILGenerator ig = ec.ig;
4558 IntConstant.EmitInt (ig, 0);
4559 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4564 // Special case if we are passing the same data as the
4565 // params argument, we do not need to recreate an array.
4567 a = (Argument) arguments [argument_index];
4568 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4574 EmitParams (ec, arguments, i, params_args_count);
4575 argument_index += params_args_count;
4580 a = (Argument) arguments [argument_index++];
4583 ec.ig.Emit (OpCodes.Dup);
4584 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4589 if (this_arg != null)
4592 for (int i = 0; i < top; i ++) {
4593 temps [i].Emit (ec);
4594 temps [i].Release (ec);
4599 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4601 ParameterData pd = TypeManager.GetParameterData (mb);
4603 if (arguments == null)
4604 return new Type [0];
4606 Argument a = (Argument) arguments [pd.Count - 1];
4607 Arglist list = (Arglist) a.Expr;
4609 return list.ArgumentTypes;
4613 /// This checks the ConditionalAttribute on the method
4615 static bool IsMethodExcluded (MethodBase method)
4617 if (method.IsConstructor)
4620 IMethodData md = TypeManager.GetMethod (method);
4622 return md.IsExcluded ();
4624 // For some methods (generated by delegate class) GetMethod returns null
4625 // because they are not included in builder_to_method table
4626 if (method.DeclaringType is TypeBuilder)
4629 return AttributeTester.IsConditionalMethodExcluded (method);
4633 /// is_base tells whether we want to force the use of the `call'
4634 /// opcode instead of using callvirt. Call is required to call
4635 /// a specific method, while callvirt will always use the most
4636 /// recent method in the vtable.
4638 /// is_static tells whether this is an invocation on a static method
4640 /// instance_expr is an expression that represents the instance
4641 /// it must be non-null if is_static is false.
4643 /// method is the method to invoke.
4645 /// Arguments is the list of arguments to pass to the method or constructor.
4647 public static void EmitCall (EmitContext ec, bool is_base,
4648 Expression instance_expr,
4649 MethodBase method, ArrayList Arguments, Location loc)
4651 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4654 // `dup_args' leaves an extra copy of the arguments on the stack
4655 // `omit_args' does not leave any arguments at all.
4656 // So, basically, you could make one call with `dup_args' set to true,
4657 // and then another with `omit_args' set to true, and the two calls
4658 // would have the same set of arguments. However, each argument would
4659 // only have been evaluated once.
4660 public static void EmitCall (EmitContext ec, bool is_base,
4661 Expression instance_expr,
4662 MethodBase method, ArrayList Arguments, Location loc,
4663 bool dup_args, bool omit_args)
4665 ILGenerator ig = ec.ig;
4666 bool struct_call = false;
4667 bool this_call = false;
4668 LocalTemporary this_arg = null;
4670 Type decl_type = method.DeclaringType;
4672 if (!RootContext.StdLib) {
4673 // Replace any calls to the system's System.Array type with calls to
4674 // the newly created one.
4675 if (method == TypeManager.system_int_array_get_length)
4676 method = TypeManager.int_array_get_length;
4677 else if (method == TypeManager.system_int_array_get_rank)
4678 method = TypeManager.int_array_get_rank;
4679 else if (method == TypeManager.system_object_array_clone)
4680 method = TypeManager.object_array_clone;
4681 else if (method == TypeManager.system_int_array_get_length_int)
4682 method = TypeManager.int_array_get_length_int;
4683 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4684 method = TypeManager.int_array_get_lower_bound_int;
4685 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4686 method = TypeManager.int_array_get_upper_bound_int;
4687 else if (method == TypeManager.system_void_array_copyto_array_int)
4688 method = TypeManager.void_array_copyto_array_int;
4691 if (!ec.IsInObsoleteScope) {
4693 // This checks ObsoleteAttribute on the method and on the declaring type
4695 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4697 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4699 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4701 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4705 if (IsMethodExcluded (method))
4708 bool is_static = method.IsStatic;
4710 if (instance_expr == EmptyExpression.Null) {
4711 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4715 this_call = instance_expr is This;
4716 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4720 // If this is ourselves, push "this"
4724 Type iexpr_type = instance_expr.Type;
4727 // Push the instance expression
4729 if (TypeManager.IsValueType (iexpr_type)) {
4731 // Special case: calls to a function declared in a
4732 // reference-type with a value-type argument need
4733 // to have their value boxed.
4734 if (decl_type.IsValueType ||
4735 TypeManager.IsGenericParameter (iexpr_type)) {
4737 // If the expression implements IMemoryLocation, then
4738 // we can optimize and use AddressOf on the
4741 // If not we have to use some temporary storage for
4743 if (instance_expr is IMemoryLocation) {
4744 ((IMemoryLocation)instance_expr).
4745 AddressOf (ec, AddressOp.LoadStore);
4747 LocalTemporary temp = new LocalTemporary (iexpr_type);
4748 instance_expr.Emit (ec);
4750 temp.AddressOf (ec, AddressOp.Load);
4753 // avoid the overhead of doing this all the time.
4755 t = TypeManager.GetReferenceType (iexpr_type);
4757 instance_expr.Emit (ec);
4758 ig.Emit (OpCodes.Box, instance_expr.Type);
4759 t = TypeManager.object_type;
4762 instance_expr.Emit (ec);
4763 t = instance_expr.Type;
4767 ig.Emit (OpCodes.Dup);
4768 if (Arguments != null && Arguments.Count != 0) {
4769 this_arg = new LocalTemporary (t);
4770 this_arg.Store (ec);
4777 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4780 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4781 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4785 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4786 call_op = OpCodes.Call;
4788 call_op = OpCodes.Callvirt;
4790 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4791 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4792 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4799 // and DoFoo is not virtual, you can omit the callvirt,
4800 // because you don't need the null checking behavior.
4802 if (method is MethodInfo)
4803 ig.Emit (call_op, (MethodInfo) method);
4805 ig.Emit (call_op, (ConstructorInfo) method);
4808 public override void Emit (EmitContext ec)
4810 mg.EmitCall (ec, Arguments);
4813 public override void EmitStatement (EmitContext ec)
4818 // Pop the return value if there is one
4820 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4821 ec.ig.Emit (OpCodes.Pop);
4824 protected override void CloneTo (CloneContext clonectx, Expression t)
4826 Invocation target = (Invocation) t;
4828 if (Arguments != null) {
4829 target.Arguments = new ArrayList (Arguments.Count);
4830 foreach (Argument a in Arguments)
4831 target.Arguments.Add (a.Clone (clonectx));
4834 target.expr = expr.Clone (clonectx);
4838 public class InvocationOrCast : ExpressionStatement
4841 Expression argument;
4843 public InvocationOrCast (Expression expr, Expression argument)
4846 this.argument = argument;
4847 this.loc = expr.Location;
4850 public override Expression DoResolve (EmitContext ec)
4853 // First try to resolve it as a cast.
4855 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4856 if ((te != null) && (te.eclass == ExprClass.Type)) {
4857 Cast cast = new Cast (te, argument, loc);
4858 return cast.Resolve (ec);
4862 // This can either be a type or a delegate invocation.
4863 // Let's just resolve it and see what we'll get.
4865 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4870 // Ok, so it's a Cast.
4872 if (expr.eclass == ExprClass.Type) {
4873 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4874 return cast.Resolve (ec);
4878 // It's a delegate invocation.
4880 if (!TypeManager.IsDelegateType (expr.Type)) {
4881 Error (149, "Method name expected");
4885 ArrayList args = new ArrayList ();
4886 args.Add (new Argument (argument, Argument.AType.Expression));
4887 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4888 return invocation.Resolve (ec);
4891 public override ExpressionStatement ResolveStatement (EmitContext ec)
4894 // First try to resolve it as a cast.
4896 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4897 if ((te != null) && (te.eclass == ExprClass.Type)) {
4898 Error_InvalidExpressionStatement ();
4903 // This can either be a type or a delegate invocation.
4904 // Let's just resolve it and see what we'll get.
4906 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4907 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4908 Error_InvalidExpressionStatement ();
4913 // It's a delegate invocation.
4915 if (!TypeManager.IsDelegateType (expr.Type)) {
4916 Error (149, "Method name expected");
4920 ArrayList args = new ArrayList ();
4921 args.Add (new Argument (argument, Argument.AType.Expression));
4922 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4923 return invocation.ResolveStatement (ec);
4926 public override void Emit (EmitContext ec)
4928 throw new Exception ("Cannot happen");
4931 public override void EmitStatement (EmitContext ec)
4933 throw new Exception ("Cannot happen");
4936 protected override void CloneTo (CloneContext clonectx, Expression t)
4938 InvocationOrCast target = (InvocationOrCast) t;
4940 target.expr = expr.Clone (clonectx);
4941 target.argument = argument.Clone (clonectx);
4946 // This class is used to "disable" the code generation for the
4947 // temporary variable when initializing value types.
4949 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4950 public void AddressOf (EmitContext ec, AddressOp Mode)
4957 /// Implements the new expression
4959 public class New : ExpressionStatement, IMemoryLocation {
4960 ArrayList Arguments;
4963 // During bootstrap, it contains the RequestedType,
4964 // but if `type' is not null, it *might* contain a NewDelegate
4965 // (because of field multi-initialization)
4967 public Expression RequestedType;
4969 MethodGroupExpr method;
4972 // If set, the new expression is for a value_target, and
4973 // we will not leave anything on the stack.
4975 Expression value_target;
4976 bool value_target_set = false;
4977 bool is_type_parameter = false;
4979 public New (Expression requested_type, ArrayList arguments, Location l)
4981 RequestedType = requested_type;
4982 Arguments = arguments;
4986 public bool SetValueTypeVariable (Expression value)
4988 value_target = value;
4989 value_target_set = true;
4990 if (!(value_target is IMemoryLocation)){
4991 Error_UnexpectedKind (null, "variable", loc);
4998 // This function is used to disable the following code sequence for
4999 // value type initialization:
5001 // AddressOf (temporary)
5005 // Instead the provide will have provided us with the address on the
5006 // stack to store the results.
5008 static Expression MyEmptyExpression;
5010 public void DisableTemporaryValueType ()
5012 if (MyEmptyExpression == null)
5013 MyEmptyExpression = new EmptyAddressOf ();
5016 // To enable this, look into:
5017 // test-34 and test-89 and self bootstrapping.
5019 // For instance, we can avoid a copy by using `newobj'
5020 // instead of Call + Push-temp on value types.
5021 // value_target = MyEmptyExpression;
5026 /// Converts complex core type syntax like 'new int ()' to simple constant
5028 public static Constant Constantify (Type t)
5030 if (t == TypeManager.int32_type)
5031 return new IntConstant (0, Location.Null);
5032 if (t == TypeManager.uint32_type)
5033 return new UIntConstant (0, Location.Null);
5034 if (t == TypeManager.int64_type)
5035 return new LongConstant (0, Location.Null);
5036 if (t == TypeManager.uint64_type)
5037 return new ULongConstant (0, Location.Null);
5038 if (t == TypeManager.float_type)
5039 return new FloatConstant (0, Location.Null);
5040 if (t == TypeManager.double_type)
5041 return new DoubleConstant (0, Location.Null);
5042 if (t == TypeManager.short_type)
5043 return new ShortConstant (0, Location.Null);
5044 if (t == TypeManager.ushort_type)
5045 return new UShortConstant (0, Location.Null);
5046 if (t == TypeManager.sbyte_type)
5047 return new SByteConstant (0, Location.Null);
5048 if (t == TypeManager.byte_type)
5049 return new ByteConstant (0, Location.Null);
5050 if (t == TypeManager.char_type)
5051 return new CharConstant ('\0', Location.Null);
5052 if (t == TypeManager.bool_type)
5053 return new BoolConstant (false, Location.Null);
5054 if (t == TypeManager.decimal_type)
5055 return new DecimalConstant (0, Location.Null);
5056 if (TypeManager.IsEnumType (t))
5057 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5063 // Checks whether the type is an interface that has the
5064 // [ComImport, CoClass] attributes and must be treated
5067 public Expression CheckComImport (EmitContext ec)
5069 if (!type.IsInterface)
5073 // Turn the call into:
5074 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5076 Type real_class = AttributeTester.GetCoClassAttribute (type);
5077 if (real_class == null)
5080 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5081 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5082 return cast.Resolve (ec);
5085 public override Expression DoResolve (EmitContext ec)
5088 // The New DoResolve might be called twice when initializing field
5089 // expressions (see EmitFieldInitializers, the call to
5090 // GetInitializerExpression will perform a resolve on the expression,
5091 // and later the assign will trigger another resolution
5093 // This leads to bugs (#37014)
5096 if (RequestedType is NewDelegate)
5097 return RequestedType;
5101 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5107 if (type == TypeManager.void_type) {
5108 Error_VoidInvalidInTheContext (loc);
5112 if (Arguments == null) {
5113 Expression c = Constantify (type);
5118 if (TypeManager.IsDelegateType (type)) {
5119 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5120 if (RequestedType != null)
5121 if (!(RequestedType is DelegateCreation))
5122 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5123 return RequestedType;
5127 if (type.IsGenericParameter) {
5128 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5130 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5131 Error (304, String.Format (
5132 "Cannot create an instance of the " +
5133 "variable type '{0}' because it " +
5134 "doesn't have the new() constraint",
5139 if ((Arguments != null) && (Arguments.Count != 0)) {
5140 Error (417, String.Format (
5141 "`{0}': cannot provide arguments " +
5142 "when creating an instance of a " +
5143 "variable type.", type));
5147 is_type_parameter = true;
5148 eclass = ExprClass.Value;
5153 if (type.IsAbstract && type.IsSealed) {
5154 Report.SymbolRelatedToPreviousError (type);
5155 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5159 if (type.IsInterface || type.IsAbstract){
5160 if (!TypeManager.IsGenericType (type)) {
5161 RequestedType = CheckComImport (ec);
5162 if (RequestedType != null)
5163 return RequestedType;
5166 Report.SymbolRelatedToPreviousError (type);
5167 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5171 bool is_struct = type.IsValueType;
5172 eclass = ExprClass.Value;
5175 // SRE returns a match for .ctor () on structs (the object constructor),
5176 // so we have to manually ignore it.
5178 if (is_struct && Arguments == null)
5181 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5182 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5183 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5188 method = ml as MethodGroupExpr;
5190 if (method == null) {
5191 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5195 if (Arguments != null){
5196 foreach (Argument a in Arguments){
5197 if (!a.Resolve (ec, loc))
5202 method = method.OverloadResolve (ec, Arguments, false, loc);
5203 if (method == null) {
5204 if (almostMatchedMembers.Count != 0)
5205 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5212 bool DoEmitTypeParameter (EmitContext ec)
5215 ILGenerator ig = ec.ig;
5216 // IMemoryLocation ml;
5218 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5219 new Type [] { type });
5221 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5222 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5223 ig.Emit (OpCodes.Call, ci);
5227 // Allow DoEmit() to be called multiple times.
5228 // We need to create a new LocalTemporary each time since
5229 // you can't share LocalBuilders among ILGeneators.
5230 LocalTemporary temp = new LocalTemporary (type);
5232 Label label_activator = ig.DefineLabel ();
5233 Label label_end = ig.DefineLabel ();
5235 temp.AddressOf (ec, AddressOp.Store);
5236 ig.Emit (OpCodes.Initobj, type);
5239 ig.Emit (OpCodes.Box, type);
5240 ig.Emit (OpCodes.Brfalse, label_activator);
5242 temp.AddressOf (ec, AddressOp.Store);
5243 ig.Emit (OpCodes.Initobj, type);
5245 ig.Emit (OpCodes.Br, label_end);
5247 ig.MarkLabel (label_activator);
5249 ig.Emit (OpCodes.Call, ci);
5250 ig.MarkLabel (label_end);
5253 throw new InternalErrorException ();
5258 // This DoEmit can be invoked in two contexts:
5259 // * As a mechanism that will leave a value on the stack (new object)
5260 // * As one that wont (init struct)
5262 // You can control whether a value is required on the stack by passing
5263 // need_value_on_stack. The code *might* leave a value on the stack
5264 // so it must be popped manually
5266 // If we are dealing with a ValueType, we have a few
5267 // situations to deal with:
5269 // * The target is a ValueType, and we have been provided
5270 // the instance (this is easy, we are being assigned).
5272 // * The target of New is being passed as an argument,
5273 // to a boxing operation or a function that takes a
5276 // In this case, we need to create a temporary variable
5277 // that is the argument of New.
5279 // Returns whether a value is left on the stack
5281 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5283 bool is_value_type = TypeManager.IsValueType (type);
5284 ILGenerator ig = ec.ig;
5289 // Allow DoEmit() to be called multiple times.
5290 // We need to create a new LocalTemporary each time since
5291 // you can't share LocalBuilders among ILGeneators.
5292 if (!value_target_set)
5293 value_target = new LocalTemporary (type);
5295 ml = (IMemoryLocation) value_target;
5296 ml.AddressOf (ec, AddressOp.Store);
5300 method.EmitArguments (ec, Arguments);
5304 ig.Emit (OpCodes.Initobj, type);
5306 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5307 if (need_value_on_stack){
5308 value_target.Emit (ec);
5313 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5318 public override void Emit (EmitContext ec)
5320 if (is_type_parameter)
5321 DoEmitTypeParameter (ec);
5326 public override void EmitStatement (EmitContext ec)
5328 bool value_on_stack;
5330 if (is_type_parameter)
5331 value_on_stack = DoEmitTypeParameter (ec);
5333 value_on_stack = DoEmit (ec, false);
5336 ec.ig.Emit (OpCodes.Pop);
5340 public void AddressOf (EmitContext ec, AddressOp Mode)
5342 if (is_type_parameter) {
5343 LocalTemporary temp = new LocalTemporary (type);
5344 DoEmitTypeParameter (ec);
5346 temp.AddressOf (ec, Mode);
5350 if (!type.IsValueType){
5352 // We throw an exception. So far, I believe we only need to support
5354 // foreach (int j in new StructType ())
5357 throw new Exception ("AddressOf should not be used for classes");
5360 if (!value_target_set)
5361 value_target = new LocalTemporary (type);
5362 IMemoryLocation ml = (IMemoryLocation) value_target;
5364 ml.AddressOf (ec, AddressOp.Store);
5365 if (method == null) {
5366 ec.ig.Emit (OpCodes.Initobj, type);
5368 method.EmitArguments (ec, Arguments);
5369 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5372 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5375 protected override void CloneTo (CloneContext clonectx, Expression t)
5377 New target = (New) t;
5379 target.RequestedType = RequestedType.Clone (clonectx);
5380 if (Arguments != null){
5381 target.Arguments = new ArrayList ();
5382 foreach (Argument a in Arguments){
5383 target.Arguments.Add (a.Clone (clonectx));
5390 /// 14.5.10.2: Represents an array creation expression.
5394 /// There are two possible scenarios here: one is an array creation
5395 /// expression that specifies the dimensions and optionally the
5396 /// initialization data and the other which does not need dimensions
5397 /// specified but where initialization data is mandatory.
5399 public class ArrayCreation : Expression {
5400 Expression requested_base_type;
5401 ArrayList initializers;
5404 // The list of Argument types.
5405 // This is used to construct the `newarray' or constructor signature
5407 protected ArrayList arguments;
5409 protected Type array_element_type;
5410 bool expect_initializers = false;
5411 int num_arguments = 0;
5412 protected int dimensions;
5413 protected readonly string rank;
5415 protected ArrayList array_data;
5419 // The number of constants in array initializers
5420 int const_initializers_count;
5421 bool only_constant_initializers;
5423 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5425 this.requested_base_type = requested_base_type;
5426 this.initializers = initializers;
5430 arguments = new ArrayList ();
5432 foreach (Expression e in exprs) {
5433 arguments.Add (new Argument (e, Argument.AType.Expression));
5438 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5440 this.requested_base_type = requested_base_type;
5441 this.initializers = initializers;
5445 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5447 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5449 //dimensions = tmp.Length - 1;
5450 expect_initializers = true;
5453 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5455 StringBuilder sb = new StringBuilder (rank);
5458 for (int i = 1; i < idx_count; i++)
5463 return new ComposedCast (base_type, sb.ToString (), loc);
5466 void Error_IncorrectArrayInitializer ()
5468 Error (178, "Invalid rank specifier: expected `,' or `]'");
5471 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5473 if (specified_dims) {
5474 Argument a = (Argument) arguments [idx];
5476 if (!a.Resolve (ec, loc))
5479 Constant c = a.Expr as Constant;
5481 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5485 Report.Error (150, a.Expr.Location, "A constant value is expected");
5489 int value = (int) c.GetValue ();
5491 if (value != probe.Count) {
5492 Error_IncorrectArrayInitializer ();
5496 bounds [idx] = value;
5499 int child_bounds = -1;
5500 only_constant_initializers = true;
5501 for (int i = 0; i < probe.Count; ++i) {
5502 object o = probe [i];
5503 if (o is ArrayList) {
5504 ArrayList sub_probe = o as ArrayList;
5505 int current_bounds = sub_probe.Count;
5507 if (child_bounds == -1)
5508 child_bounds = current_bounds;
5510 else if (child_bounds != current_bounds){
5511 Error_IncorrectArrayInitializer ();
5514 if (idx + 1 >= dimensions){
5515 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5519 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5523 if (child_bounds != -1){
5524 Error_IncorrectArrayInitializer ();
5528 Expression element = ResolveArrayElement (ec, (Expression) o);
5529 if (element == null)
5532 // Initializers with the default values can be ignored
5533 Constant c = element as Constant;
5535 if (c.IsDefaultInitializer (array_element_type)) {
5539 ++const_initializers_count;
5542 only_constant_initializers = false;
5545 array_data.Add (element);
5552 public void UpdateIndices ()
5555 for (ArrayList probe = initializers; probe != null;) {
5556 if (probe.Count > 0 && probe [0] is ArrayList) {
5557 Expression e = new IntConstant (probe.Count, Location.Null);
5558 arguments.Add (new Argument (e, Argument.AType.Expression));
5560 bounds [i++] = probe.Count;
5562 probe = (ArrayList) probe [0];
5565 Expression e = new IntConstant (probe.Count, Location.Null);
5566 arguments.Add (new Argument (e, Argument.AType.Expression));
5568 bounds [i++] = probe.Count;
5575 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5577 element = element.Resolve (ec);
5578 if (element == null)
5581 return Convert.ImplicitConversionRequired (
5582 ec, element, array_element_type, loc);
5585 protected bool ResolveInitializers (EmitContext ec)
5587 if (initializers == null) {
5588 return !expect_initializers;
5592 // We use this to store all the date values in the order in which we
5593 // will need to store them in the byte blob later
5595 array_data = new ArrayList ();
5596 bounds = new System.Collections.Specialized.HybridDictionary ();
5598 if (arguments != null)
5599 return CheckIndices (ec, initializers, 0, true);
5601 arguments = new ArrayList ();
5603 if (!CheckIndices (ec, initializers, 0, false))
5612 // Resolved the type of the array
5614 bool ResolveArrayType (EmitContext ec)
5616 if (requested_base_type == null) {
5617 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5621 StringBuilder array_qualifier = new StringBuilder (rank);
5624 // `In the first form allocates an array instace of the type that results
5625 // from deleting each of the individual expression from the expression list'
5627 if (num_arguments > 0) {
5628 array_qualifier.Append ("[");
5629 for (int i = num_arguments-1; i > 0; i--)
5630 array_qualifier.Append (",");
5631 array_qualifier.Append ("]");
5637 TypeExpr array_type_expr;
5638 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5639 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5640 if (array_type_expr == null)
5643 type = array_type_expr.Type;
5644 array_element_type = TypeManager.GetElementType (type);
5645 dimensions = type.GetArrayRank ();
5650 public override Expression DoResolve (EmitContext ec)
5655 if (!ResolveArrayType (ec))
5658 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5659 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5660 TypeManager.CSharpName (array_element_type));
5664 // First step is to validate the initializers and fill
5665 // in any missing bits
5667 if (!ResolveInitializers (ec))
5670 if (arguments.Count != dimensions) {
5671 Error_IncorrectArrayInitializer ();
5674 foreach (Argument a in arguments){
5675 if (!a.Resolve (ec, loc))
5678 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5679 if (real_arg == null)
5685 eclass = ExprClass.Value;
5689 MethodInfo GetArrayMethod (int arguments)
5691 ModuleBuilder mb = CodeGen.Module.Builder;
5693 Type[] arg_types = new Type[arguments];
5694 for (int i = 0; i < arguments; i++)
5695 arg_types[i] = TypeManager.int32_type;
5697 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5701 Report.Error (-6, "New invocation: Can not find a constructor for " +
5702 "this argument list");
5709 byte [] MakeByteBlob ()
5714 int count = array_data.Count;
5716 if (array_element_type.IsEnum)
5717 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5719 factor = GetTypeSize (array_element_type);
5721 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5723 data = new byte [(count * factor + 4) & ~3];
5726 for (int i = 0; i < count; ++i) {
5727 object v = array_data [i];
5729 if (v is EnumConstant)
5730 v = ((EnumConstant) v).Child;
5732 if (v is Constant && !(v is StringConstant))
5733 v = ((Constant) v).GetValue ();
5739 if (array_element_type == TypeManager.int64_type){
5740 if (!(v is Expression)){
5741 long val = (long) v;
5743 for (int j = 0; j < factor; ++j) {
5744 data [idx + j] = (byte) (val & 0xFF);
5748 } else if (array_element_type == TypeManager.uint64_type){
5749 if (!(v is Expression)){
5750 ulong val = (ulong) v;
5752 for (int j = 0; j < factor; ++j) {
5753 data [idx + j] = (byte) (val & 0xFF);
5757 } else if (array_element_type == TypeManager.float_type) {
5758 if (!(v is Expression)){
5759 element = BitConverter.GetBytes ((float) v);
5761 for (int j = 0; j < factor; ++j)
5762 data [idx + j] = element [j];
5763 if (!BitConverter.IsLittleEndian)
5764 System.Array.Reverse (data, idx, 4);
5766 } else if (array_element_type == TypeManager.double_type) {
5767 if (!(v is Expression)){
5768 element = BitConverter.GetBytes ((double) v);
5770 for (int j = 0; j < factor; ++j)
5771 data [idx + j] = element [j];
5773 // FIXME: Handle the ARM float format.
5774 if (!BitConverter.IsLittleEndian)
5775 System.Array.Reverse (data, idx, 8);
5777 } else if (array_element_type == TypeManager.char_type){
5778 if (!(v is Expression)){
5779 int val = (int) ((char) v);
5781 data [idx] = (byte) (val & 0xff);
5782 data [idx+1] = (byte) (val >> 8);
5784 } else if (array_element_type == TypeManager.short_type){
5785 if (!(v is Expression)){
5786 int val = (int) ((short) v);
5788 data [idx] = (byte) (val & 0xff);
5789 data [idx+1] = (byte) (val >> 8);
5791 } else if (array_element_type == TypeManager.ushort_type){
5792 if (!(v is Expression)){
5793 int val = (int) ((ushort) v);
5795 data [idx] = (byte) (val & 0xff);
5796 data [idx+1] = (byte) (val >> 8);
5798 } else if (array_element_type == TypeManager.int32_type) {
5799 if (!(v is Expression)){
5802 data [idx] = (byte) (val & 0xff);
5803 data [idx+1] = (byte) ((val >> 8) & 0xff);
5804 data [idx+2] = (byte) ((val >> 16) & 0xff);
5805 data [idx+3] = (byte) (val >> 24);
5807 } else if (array_element_type == TypeManager.uint32_type) {
5808 if (!(v is Expression)){
5809 uint val = (uint) v;
5811 data [idx] = (byte) (val & 0xff);
5812 data [idx+1] = (byte) ((val >> 8) & 0xff);
5813 data [idx+2] = (byte) ((val >> 16) & 0xff);
5814 data [idx+3] = (byte) (val >> 24);
5816 } else if (array_element_type == TypeManager.sbyte_type) {
5817 if (!(v is Expression)){
5818 sbyte val = (sbyte) v;
5819 data [idx] = (byte) val;
5821 } else if (array_element_type == TypeManager.byte_type) {
5822 if (!(v is Expression)){
5823 byte val = (byte) v;
5824 data [idx] = (byte) val;
5826 } else if (array_element_type == TypeManager.bool_type) {
5827 if (!(v is Expression)){
5828 bool val = (bool) v;
5829 data [idx] = (byte) (val ? 1 : 0);
5831 } else if (array_element_type == TypeManager.decimal_type){
5832 if (!(v is Expression)){
5833 int [] bits = Decimal.GetBits ((decimal) v);
5836 // FIXME: For some reason, this doesn't work on the MS runtime.
5837 int [] nbits = new int [4];
5838 nbits [0] = bits [3];
5839 nbits [1] = bits [2];
5840 nbits [2] = bits [0];
5841 nbits [3] = bits [1];
5843 for (int j = 0; j < 4; j++){
5844 data [p++] = (byte) (nbits [j] & 0xff);
5845 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5846 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5847 data [p++] = (byte) (nbits [j] >> 24);
5851 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5860 // Emits the initializers for the array
5862 void EmitStaticInitializers (EmitContext ec)
5865 // First, the static data
5868 ILGenerator ig = ec.ig;
5870 byte [] data = MakeByteBlob ();
5872 fb = RootContext.MakeStaticData (data);
5874 ig.Emit (OpCodes.Dup);
5875 ig.Emit (OpCodes.Ldtoken, fb);
5876 ig.Emit (OpCodes.Call,
5877 TypeManager.void_initializearray_array_fieldhandle);
5881 // Emits pieces of the array that can not be computed at compile
5882 // time (variables and string locations).
5884 // This always expect the top value on the stack to be the array
5886 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5888 ILGenerator ig = ec.ig;
5889 int dims = bounds.Count;
5890 int [] current_pos = new int [dims];
5892 MethodInfo set = null;
5895 Type [] args = new Type [dims + 1];
5897 for (int j = 0; j < dims; j++)
5898 args [j] = TypeManager.int32_type;
5899 args [dims] = array_element_type;
5901 set = CodeGen.Module.Builder.GetArrayMethod (
5903 CallingConventions.HasThis | CallingConventions.Standard,
5904 TypeManager.void_type, args);
5907 for (int i = 0; i < array_data.Count; i++){
5909 Expression e = (Expression)array_data [i];
5911 // Constant can be initialized via StaticInitializer
5912 if (e != null && !(!emitConstants && e is Constant)) {
5913 Type etype = e.Type;
5915 ig.Emit (OpCodes.Dup);
5917 for (int idx = 0; idx < dims; idx++)
5918 IntConstant.EmitInt (ig, current_pos [idx]);
5921 // If we are dealing with a struct, get the
5922 // address of it, so we can store it.
5924 if ((dims == 1) && etype.IsValueType &&
5925 (!TypeManager.IsBuiltinOrEnum (etype) ||
5926 etype == TypeManager.decimal_type)) {
5931 // Let new know that we are providing
5932 // the address where to store the results
5934 n.DisableTemporaryValueType ();
5937 ig.Emit (OpCodes.Ldelema, etype);
5943 bool is_stobj, has_type_arg;
5944 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5946 ig.Emit (OpCodes.Stobj, etype);
5947 else if (has_type_arg)
5948 ig.Emit (op, etype);
5952 ig.Emit (OpCodes.Call, set);
5959 for (int j = dims - 1; j >= 0; j--){
5961 if (current_pos [j] < (int) bounds [j])
5963 current_pos [j] = 0;
5968 void EmitArrayArguments (EmitContext ec)
5970 ILGenerator ig = ec.ig;
5972 foreach (Argument a in arguments) {
5973 Type atype = a.Type;
5976 if (atype == TypeManager.uint64_type)
5977 ig.Emit (OpCodes.Conv_Ovf_U4);
5978 else if (atype == TypeManager.int64_type)
5979 ig.Emit (OpCodes.Conv_Ovf_I4);
5983 public override void Emit (EmitContext ec)
5985 ILGenerator ig = ec.ig;
5987 EmitArrayArguments (ec);
5988 if (arguments.Count == 1)
5989 ig.Emit (OpCodes.Newarr, array_element_type);
5991 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5994 if (initializers == null)
5997 // Emit static initializer for arrays which have contain more than 4 items and
5998 // the static initializer will initialize at least 25% of array values.
5999 // NOTE: const_initializers_count does not contain default constant values.
6000 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6001 TypeManager.IsPrimitiveType (array_element_type)) {
6002 EmitStaticInitializers (ec);
6004 if (!only_constant_initializers)
6005 EmitDynamicInitializers (ec, false);
6007 EmitDynamicInitializers (ec, true);
6011 public override bool GetAttributableValue (Type valueType, out object value)
6013 if (arguments.Count != 1) {
6014 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6015 return base.GetAttributableValue (null, out value);
6018 if (array_data == null) {
6019 Constant c = (Constant)((Argument)arguments [0]).Expr;
6020 if (c.IsDefaultValue) {
6021 value = Array.CreateInstance (array_element_type, 0);
6024 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6025 return base.GetAttributableValue (null, out value);
6028 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6029 object element_value;
6030 for (int i = 0; i < ret.Length; ++i)
6032 Expression e = (Expression)array_data [i];
6034 // Is null when an initializer is optimized (value == predefined value)
6038 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6042 ret.SetValue (element_value, i);
6048 protected override void CloneTo (CloneContext clonectx, Expression t)
6050 ArrayCreation target = (ArrayCreation) t;
6052 target.requested_base_type = requested_base_type.Clone (clonectx);
6054 if (arguments != null){
6055 target.arguments = new ArrayList ();
6056 foreach (Argument a in arguments)
6057 target.arguments.Add (a.Clone (clonectx));
6060 if (initializers != null){
6061 target.initializers = new ArrayList ();
6062 foreach (Expression initializer in initializers)
6063 target.initializers.Add (initializer.Clone (clonectx));
6069 // Represents an implicitly typed array epxression
6071 public class ImplicitlyTypedArrayCreation : ArrayCreation
6073 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6074 : base (null, rank, initializers, loc)
6076 if (rank.Length > 2) {
6077 while (rank [++dimensions] == ',');
6083 public override Expression DoResolve (EmitContext ec)
6088 if (!ResolveInitializers (ec))
6091 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6092 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6093 arguments.Count != dimensions) {
6094 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6099 // At this point we found common base type for all initializer elements
6100 // but we have to be sure that all static initializer elements are of
6103 UnifyInitializerElement (ec);
6105 type = TypeManager.GetConstructedType (array_element_type, rank);
6106 eclass = ExprClass.Value;
6111 // Converts static initializer only
6113 void UnifyInitializerElement (EmitContext ec)
6115 for (int i = 0; i < array_data.Count; ++i) {
6116 Expression e = (Expression)array_data[i];
6118 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6122 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6124 element = element.Resolve (ec);
6125 if (element == null)
6128 if (array_element_type == null) {
6129 array_element_type = element.Type;
6133 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6137 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6138 array_element_type = element.Type;
6142 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6147 public sealed class CompilerGeneratedThis : This
6149 public static This Instance = new CompilerGeneratedThis ();
6151 private CompilerGeneratedThis ()
6152 : base (Location.Null)
6156 public override Expression DoResolve (EmitContext ec)
6158 eclass = ExprClass.Variable;
6159 type = ec.ContainerType;
6160 variable = new SimpleThis (type);
6166 /// Represents the `this' construct
6169 public class This : VariableReference, IVariable
6172 VariableInfo variable_info;
6173 protected Variable variable;
6176 public This (Block block, Location loc)
6182 public This (Location loc)
6187 public VariableInfo VariableInfo {
6188 get { return variable_info; }
6191 public bool VerifyFixed ()
6193 return !TypeManager.IsValueType (Type);
6196 public override bool IsRef {
6197 get { return is_struct; }
6200 public override Variable Variable {
6201 get { return variable; }
6204 public bool ResolveBase (EmitContext ec)
6206 eclass = ExprClass.Variable;
6208 if (ec.TypeContainer.CurrentType != null)
6209 type = ec.TypeContainer.CurrentType;
6211 type = ec.ContainerType;
6213 is_struct = ec.TypeContainer is Struct;
6216 Error (26, "Keyword `this' is not valid in a static property, " +
6217 "static method, or static field initializer");
6221 if (block != null) {
6222 if (block.Toplevel.ThisVariable != null)
6223 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6225 AnonymousContainer am = ec.CurrentAnonymousMethod;
6226 if (is_struct && (am != null) && !am.IsIterator) {
6227 Report.Error (1673, loc, "Anonymous methods inside structs " +
6228 "cannot access instance members of `this'. " +
6229 "Consider copying `this' to a local variable " +
6230 "outside the anonymous method and using the " +
6235 RootScopeInfo host = block.Toplevel.RootScope;
6236 if ((host != null) && !ec.IsConstructor &&
6237 (!is_struct || host.IsIterator)) {
6238 variable = host.CaptureThis ();
6239 type = variable.Type;
6244 if (variable == null)
6245 variable = new SimpleThis (type);
6251 // Called from Invocation to check if the invocation is correct
6253 public bool CheckThisUsage (EmitContext ec)
6255 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6256 !variable_info.IsAssigned (ec)) {
6257 Error (188, "The `this' object cannot be used before all of its " +
6258 "fields are assigned to");
6259 variable_info.SetAssigned (ec);
6266 public override Expression DoResolve (EmitContext ec)
6268 if (!ResolveBase (ec))
6272 if (ec.IsFieldInitializer) {
6273 Error (27, "Keyword `this' is not available in the current context");
6280 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6282 if (!ResolveBase (ec))
6285 if (variable_info != null)
6286 variable_info.SetAssigned (ec);
6288 if (ec.TypeContainer is Class){
6289 Error (1604, "Cannot assign to 'this' because it is read-only");
6295 public override int GetHashCode()
6297 return block.GetHashCode ();
6300 public override bool Equals (object obj)
6302 This t = obj as This;
6306 return block == t.block;
6309 protected class SimpleThis : Variable
6313 public SimpleThis (Type type)
6318 public override Type Type {
6319 get { return type; }
6322 public override bool HasInstance {
6323 get { return false; }
6326 public override bool NeedsTemporary {
6327 get { return false; }
6330 public override void EmitInstance (EmitContext ec)
6335 public override void Emit (EmitContext ec)
6337 ec.ig.Emit (OpCodes.Ldarg_0);
6340 public override void EmitAssign (EmitContext ec)
6342 throw new InvalidOperationException ();
6345 public override void EmitAddressOf (EmitContext ec)
6347 ec.ig.Emit (OpCodes.Ldarg_0);
6351 protected override void CloneTo (CloneContext clonectx, Expression t)
6353 This target = (This) t;
6355 target.block = clonectx.LookupBlock (block);
6360 /// Represents the `__arglist' construct
6362 public class ArglistAccess : Expression
6364 public ArglistAccess (Location loc)
6369 public override Expression DoResolve (EmitContext ec)
6371 eclass = ExprClass.Variable;
6372 type = TypeManager.runtime_argument_handle_type;
6374 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6376 Error (190, "The __arglist construct is valid only within " +
6377 "a variable argument method");
6384 public override void Emit (EmitContext ec)
6386 ec.ig.Emit (OpCodes.Arglist);
6389 protected override void CloneTo (CloneContext clonectx, Expression target)
6396 /// Represents the `__arglist (....)' construct
6398 public class Arglist : Expression
6400 Argument[] Arguments;
6402 public Arglist (Location loc)
6403 : this (Argument.Empty, loc)
6407 public Arglist (Argument[] args, Location l)
6413 public Type[] ArgumentTypes {
6415 Type[] retval = new Type [Arguments.Length];
6416 for (int i = 0; i < Arguments.Length; i++)
6417 retval [i] = Arguments [i].Type;
6422 public override Expression DoResolve (EmitContext ec)
6424 eclass = ExprClass.Variable;
6425 type = TypeManager.runtime_argument_handle_type;
6427 foreach (Argument arg in Arguments) {
6428 if (!arg.Resolve (ec, loc))
6435 public override void Emit (EmitContext ec)
6437 foreach (Argument arg in Arguments)
6441 protected override void CloneTo (CloneContext clonectx, Expression t)
6443 Arglist target = (Arglist) t;
6445 target.Arguments = new Argument [Arguments.Length];
6446 for (int i = 0; i < Arguments.Length; i++)
6447 target.Arguments [i] = Arguments [i].Clone (clonectx);
6452 // This produces the value that renders an instance, used by the iterators code
6454 public class ProxyInstance : Expression, IMemoryLocation {
6455 public override Expression DoResolve (EmitContext ec)
6457 eclass = ExprClass.Variable;
6458 type = ec.ContainerType;
6462 public override void Emit (EmitContext ec)
6464 ec.ig.Emit (OpCodes.Ldarg_0);
6468 public void AddressOf (EmitContext ec, AddressOp mode)
6470 ec.ig.Emit (OpCodes.Ldarg_0);
6475 /// Implements the typeof operator
6477 public class TypeOf : Expression {
6478 Expression QueriedType;
6479 protected Type typearg;
6481 public TypeOf (Expression queried_type, Location l)
6483 QueriedType = queried_type;
6487 public override Expression DoResolve (EmitContext ec)
6489 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6493 typearg = texpr.Type;
6495 if (typearg == TypeManager.void_type) {
6496 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6500 if (typearg.IsPointer && !ec.InUnsafe){
6505 type = TypeManager.type_type;
6506 // Even though what is returned is a type object, it's treated as a value by the compiler.
6507 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6508 eclass = ExprClass.Value;
6512 public override void Emit (EmitContext ec)
6514 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6515 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6518 public override bool GetAttributableValue (Type valueType, out object value)
6520 if (TypeManager.ContainsGenericParameters (typearg) &&
6521 !TypeManager.IsGenericTypeDefinition (typearg)) {
6522 Report.SymbolRelatedToPreviousError (typearg);
6523 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6524 TypeManager.CSharpName (typearg));
6529 if (valueType == TypeManager.object_type) {
6530 value = (object)typearg;
6537 public Type TypeArgument
6545 protected override void CloneTo (CloneContext clonectx, Expression t)
6547 TypeOf target = (TypeOf) t;
6549 target.QueriedType = QueriedType.Clone (clonectx);
6554 /// Implements the `typeof (void)' operator
6556 public class TypeOfVoid : TypeOf {
6557 public TypeOfVoid (Location l) : base (null, l)
6562 public override Expression DoResolve (EmitContext ec)
6564 type = TypeManager.type_type;
6565 typearg = TypeManager.void_type;
6566 // See description in TypeOf.
6567 eclass = ExprClass.Value;
6573 /// Implements the sizeof expression
6575 public class SizeOf : Expression {
6576 readonly Expression QueriedType;
6579 public SizeOf (Expression queried_type, Location l)
6581 this.QueriedType = queried_type;
6585 public override Expression DoResolve (EmitContext ec)
6587 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6592 if (texpr is TypeParameterExpr){
6593 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6598 type_queried = texpr.Type;
6599 if (type_queried.IsEnum)
6600 type_queried = TypeManager.EnumToUnderlying (type_queried);
6602 if (type_queried == TypeManager.void_type) {
6603 Expression.Error_VoidInvalidInTheContext (loc);
6607 int size_of = GetTypeSize (type_queried);
6609 return new IntConstant (size_of, loc);
6613 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)",
6614 TypeManager.CSharpName (type_queried));
6618 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6622 type = TypeManager.int32_type;
6623 eclass = ExprClass.Value;
6627 public override void Emit (EmitContext ec)
6629 int size = GetTypeSize (type_queried);
6632 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6634 IntConstant.EmitInt (ec.ig, size);
6637 protected override void CloneTo (CloneContext clonectx, Expression t)
6643 /// Implements the qualified-alias-member (::) expression.
6645 public class QualifiedAliasMember : Expression
6647 string alias, identifier;
6649 public QualifiedAliasMember (string alias, string identifier, Location l)
6651 if (RootContext.Version == LanguageVersion.ISO_1)
6652 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6655 this.identifier = identifier;
6659 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6661 if (alias == "global")
6662 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6664 int errors = Report.Errors;
6665 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6667 if (errors == Report.Errors)
6668 Report.Error (432, loc, "Alias `{0}' not found", alias);
6671 if (fne.eclass != ExprClass.Namespace) {
6673 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6676 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6679 public override Expression DoResolve (EmitContext ec)
6681 FullNamedExpression fne;
6682 if (alias == "global") {
6683 fne = RootNamespace.Global;
6685 int errors = Report.Errors;
6686 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6688 if (errors == Report.Errors)
6689 Report.Error (432, loc, "Alias `{0}' not found", alias);
6694 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6698 if (!(retval is FullNamedExpression)) {
6699 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6703 // We defer this check till the end to match the behaviour of CSC
6704 if (fne.eclass != ExprClass.Namespace) {
6705 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6711 public override void Emit (EmitContext ec)
6713 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6717 public override string ToString ()
6719 return alias + "::" + identifier;
6722 public override string GetSignatureForError ()
6727 protected override void CloneTo (CloneContext clonectx, Expression t)
6734 /// Implements the member access expression
6736 public class MemberAccess : Expression {
6737 public readonly string Identifier;
6739 readonly TypeArguments args;
6741 public MemberAccess (Expression expr, string id)
6742 : this (expr, id, expr.Location)
6746 public MemberAccess (Expression expr, string identifier, Location loc)
6749 Identifier = identifier;
6753 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6754 : this (expr, identifier, loc)
6759 protected string LookupIdentifier {
6760 get { return MemberName.MakeName (Identifier, args); }
6763 // TODO: this method has very poor performace for Enum fields and
6764 // probably for other constants as well
6765 Expression DoResolve (EmitContext ec, Expression right_side)
6768 throw new Exception ();
6771 // Resolve the expression with flow analysis turned off, we'll do the definite
6772 // assignment checks later. This is because we don't know yet what the expression
6773 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6774 // definite assignment check on the actual field and not on the whole struct.
6777 SimpleName original = expr as SimpleName;
6778 Expression expr_resolved = expr.Resolve (ec,
6779 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6780 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6782 if (expr_resolved == null)
6785 if (expr_resolved is Namespace) {
6786 Namespace ns = (Namespace) expr_resolved;
6787 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6789 if ((retval != null) && (args != null))
6790 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6794 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6798 Type expr_type = expr_resolved.Type;
6799 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6800 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6803 if (expr_type == TypeManager.anonymous_method_type){
6804 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6808 Constant c = expr_resolved as Constant;
6809 if (c != null && c.GetValue () == null) {
6810 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6811 "System.NullReferenceException");
6814 Expression member_lookup;
6815 member_lookup = MemberLookup (
6816 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6818 if ((member_lookup == null) && (args != null)) {
6819 member_lookup = MemberLookup (
6820 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6823 if (member_lookup == null) {
6824 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6825 if (ex_method_lookup != null) {
6826 ex_method_lookup.ExtensionExpression = expr_resolved;
6827 return ex_method_lookup.DoResolve (ec);
6830 if (!ec.IsInProbingMode)
6831 MemberLookupFailed (
6832 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6836 TypeExpr texpr = member_lookup as TypeExpr;
6837 if (texpr != null) {
6838 if (!(expr_resolved is TypeExpr) &&
6839 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6840 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6841 Identifier, member_lookup.GetSignatureForError ());
6845 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6846 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6847 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6852 ConstructedType ct = expr_resolved as ConstructedType;
6855 // When looking up a nested type in a generic instance
6856 // via reflection, we always get a generic type definition
6857 // and not a generic instance - so we have to do this here.
6859 // See gtest-172-lib.cs and gtest-172.cs for an example.
6861 ct = new ConstructedType (
6862 member_lookup.Type, ct.TypeArguments, loc);
6864 return ct.ResolveAsTypeStep (ec, false);
6867 return member_lookup;
6870 MemberExpr me = (MemberExpr) member_lookup;
6871 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6872 if (member_lookup == null)
6876 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6878 throw new InternalErrorException ();
6880 return mg.ResolveGeneric (ec, args);
6883 if (original != null && !TypeManager.IsValueType (expr_type)) {
6884 me = member_lookup as MemberExpr;
6885 if (me != null && me.IsInstance) {
6886 LocalVariableReference var = expr_resolved as LocalVariableReference;
6887 if (var != null && !var.VerifyAssigned (ec))
6892 // The following DoResolve/DoResolveLValue will do the definite assignment
6895 if (right_side != null)
6896 return member_lookup.DoResolveLValue (ec, right_side);
6898 return member_lookup.DoResolve (ec);
6901 public override Expression DoResolve (EmitContext ec)
6903 return DoResolve (ec, null);
6906 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6908 return DoResolve (ec, right_side);
6911 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6913 return ResolveNamespaceOrType (ec, silent);
6916 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6918 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6920 if (new_expr == null)
6923 if (new_expr is Namespace) {
6924 Namespace ns = (Namespace) new_expr;
6925 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6927 if ((retval != null) && (args != null))
6928 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6930 if (!silent && retval == null)
6931 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6935 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6936 if (tnew_expr == null)
6939 Type expr_type = tnew_expr.Type;
6941 if (expr_type.IsPointer){
6942 Error (23, "The `.' operator can not be applied to pointer operands (" +
6943 TypeManager.CSharpName (expr_type) + ")");
6947 Expression member_lookup = MemberLookup (
6948 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6949 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6950 if (member_lookup == null) {
6954 member_lookup = MemberLookup(
6955 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6956 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6958 if (member_lookup == null) {
6959 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6960 Identifier, new_expr.GetSignatureForError ());
6962 // TODO: Report.SymbolRelatedToPreviousError
6963 member_lookup.Error_UnexpectedKind (null, "type", loc);
6968 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6973 TypeArguments the_args = args;
6974 if (TypeManager.HasGenericArguments (expr_type)) {
6975 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6977 TypeArguments new_args = new TypeArguments (loc);
6978 foreach (Type decl in decl_args)
6979 new_args.Add (new TypeExpression (decl, loc));
6982 new_args.Add (args);
6984 the_args = new_args;
6987 if (the_args != null) {
6988 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6989 return ctype.ResolveAsTypeStep (rc, false);
6996 public override void Emit (EmitContext ec)
6998 throw new Exception ("Should not happen");
7001 public override string ToString ()
7003 return expr + "." + MemberName.MakeName (Identifier, args);
7006 public override string GetSignatureForError ()
7008 return expr.GetSignatureForError () + "." + Identifier;
7011 protected override void CloneTo (CloneContext clonectx, Expression t)
7013 MemberAccess target = (MemberAccess) t;
7015 target.expr = expr.Clone (clonectx);
7020 /// Implements checked expressions
7022 public class CheckedExpr : Expression {
7024 public Expression Expr;
7026 public CheckedExpr (Expression e, Location l)
7032 public override Expression DoResolve (EmitContext ec)
7034 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7035 Expr = Expr.Resolve (ec);
7040 if (Expr is Constant)
7043 eclass = Expr.eclass;
7048 public override void Emit (EmitContext ec)
7050 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7054 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7056 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7057 Expr.EmitBranchable (ec, target, onTrue);
7060 protected override void CloneTo (CloneContext clonectx, Expression t)
7062 CheckedExpr target = (CheckedExpr) t;
7064 target.Expr = Expr.Clone (clonectx);
7069 /// Implements the unchecked expression
7071 public class UnCheckedExpr : Expression {
7073 public Expression Expr;
7075 public UnCheckedExpr (Expression e, Location l)
7081 public override Expression DoResolve (EmitContext ec)
7083 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7084 Expr = Expr.Resolve (ec);
7089 if (Expr is Constant)
7092 eclass = Expr.eclass;
7097 public override void Emit (EmitContext ec)
7099 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7103 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7105 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7106 Expr.EmitBranchable (ec, target, onTrue);
7109 protected override void CloneTo (CloneContext clonectx, Expression t)
7111 UnCheckedExpr target = (UnCheckedExpr) t;
7113 target.Expr = Expr.Clone (clonectx);
7118 /// An Element Access expression.
7120 /// During semantic analysis these are transformed into
7121 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7123 public class ElementAccess : Expression {
7124 public ArrayList Arguments;
7125 public Expression Expr;
7127 public ElementAccess (Expression e, ArrayList e_list)
7136 Arguments = new ArrayList ();
7137 foreach (Expression tmp in e_list)
7138 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7142 bool CommonResolve (EmitContext ec)
7144 Expr = Expr.Resolve (ec);
7146 if (Arguments == null)
7149 foreach (Argument a in Arguments){
7150 if (!a.Resolve (ec, loc))
7154 return Expr != null;
7157 Expression MakePointerAccess (EmitContext ec, Type t)
7159 if (t == TypeManager.void_ptr_type){
7160 Error (242, "The array index operation is not valid on void pointers");
7163 if (Arguments.Count != 1){
7164 Error (196, "A pointer must be indexed by only one value");
7169 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7172 return new Indirection (p, loc).Resolve (ec);
7175 public override Expression DoResolve (EmitContext ec)
7177 if (!CommonResolve (ec))
7181 // We perform some simple tests, and then to "split" the emit and store
7182 // code we create an instance of a different class, and return that.
7184 // I am experimenting with this pattern.
7188 if (t == TypeManager.array_type){
7189 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7194 return (new ArrayAccess (this, loc)).Resolve (ec);
7196 return MakePointerAccess (ec, t);
7198 FieldExpr fe = Expr as FieldExpr;
7200 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7202 return MakePointerAccess (ec, ff.ElementType);
7205 return (new IndexerAccess (this, loc)).Resolve (ec);
7208 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7210 if (!CommonResolve (ec))
7215 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7218 return MakePointerAccess (ec, t);
7220 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7223 public override void Emit (EmitContext ec)
7225 throw new Exception ("Should never be reached");
7228 protected override void CloneTo (CloneContext clonectx, Expression t)
7230 ElementAccess target = (ElementAccess) t;
7232 target.Expr = Expr.Clone (clonectx);
7233 target.Arguments = new ArrayList (Arguments.Count);
7234 foreach (Argument a in Arguments)
7235 target.Arguments.Add (a.Clone (clonectx));
7240 /// Implements array access
7242 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7244 // Points to our "data" repository
7248 LocalTemporary temp;
7251 public ArrayAccess (ElementAccess ea_data, Location l)
7254 eclass = ExprClass.Variable;
7258 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7260 return DoResolve (ec);
7263 public override Expression DoResolve (EmitContext ec)
7266 ExprClass eclass = ea.Expr.eclass;
7268 // As long as the type is valid
7269 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7270 eclass == ExprClass.Value)) {
7271 ea.Expr.Error_UnexpectedKind ("variable or value");
7276 Type t = ea.Expr.Type;
7277 if (t.GetArrayRank () != ea.Arguments.Count){
7278 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7279 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7283 type = TypeManager.GetElementType (t);
7284 if (type.IsPointer && !ec.InUnsafe){
7285 UnsafeError (ea.Location);
7289 foreach (Argument a in ea.Arguments){
7290 Type argtype = a.Type;
7292 if (argtype == TypeManager.int32_type ||
7293 argtype == TypeManager.uint32_type ||
7294 argtype == TypeManager.int64_type ||
7295 argtype == TypeManager.uint64_type) {
7296 Constant c = a.Expr as Constant;
7297 if (c != null && c.IsNegative) {
7298 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7304 // Mhm. This is strage, because the Argument.Type is not the same as
7305 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7307 // Wonder if I will run into trouble for this.
7309 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7314 eclass = ExprClass.Variable;
7320 /// Emits the right opcode to load an object of Type `t'
7321 /// from an array of T
7323 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7325 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7326 ig.Emit (OpCodes.Ldelem_U1);
7327 else if (type == TypeManager.sbyte_type)
7328 ig.Emit (OpCodes.Ldelem_I1);
7329 else if (type == TypeManager.short_type)
7330 ig.Emit (OpCodes.Ldelem_I2);
7331 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7332 ig.Emit (OpCodes.Ldelem_U2);
7333 else if (type == TypeManager.int32_type)
7334 ig.Emit (OpCodes.Ldelem_I4);
7335 else if (type == TypeManager.uint32_type)
7336 ig.Emit (OpCodes.Ldelem_U4);
7337 else if (type == TypeManager.uint64_type)
7338 ig.Emit (OpCodes.Ldelem_I8);
7339 else if (type == TypeManager.int64_type)
7340 ig.Emit (OpCodes.Ldelem_I8);
7341 else if (type == TypeManager.float_type)
7342 ig.Emit (OpCodes.Ldelem_R4);
7343 else if (type == TypeManager.double_type)
7344 ig.Emit (OpCodes.Ldelem_R8);
7345 else if (type == TypeManager.intptr_type)
7346 ig.Emit (OpCodes.Ldelem_I);
7347 else if (TypeManager.IsEnumType (type)){
7348 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7349 } else if (type.IsValueType){
7350 ig.Emit (OpCodes.Ldelema, type);
7351 ig.Emit (OpCodes.Ldobj, type);
7353 } else if (type.IsGenericParameter) {
7354 ig.Emit (OpCodes.Ldelem, type);
7356 } else if (type.IsPointer)
7357 ig.Emit (OpCodes.Ldelem_I);
7359 ig.Emit (OpCodes.Ldelem_Ref);
7363 /// Returns the right opcode to store an object of Type `t'
7364 /// from an array of T.
7366 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7368 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7369 has_type_arg = false; is_stobj = false;
7370 t = TypeManager.TypeToCoreType (t);
7371 if (TypeManager.IsEnumType (t))
7372 t = TypeManager.EnumToUnderlying (t);
7373 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7374 t == TypeManager.bool_type)
7375 return OpCodes.Stelem_I1;
7376 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7377 t == TypeManager.char_type)
7378 return OpCodes.Stelem_I2;
7379 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7380 return OpCodes.Stelem_I4;
7381 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7382 return OpCodes.Stelem_I8;
7383 else if (t == TypeManager.float_type)
7384 return OpCodes.Stelem_R4;
7385 else if (t == TypeManager.double_type)
7386 return OpCodes.Stelem_R8;
7387 else if (t == TypeManager.intptr_type) {
7388 has_type_arg = true;
7390 return OpCodes.Stobj;
7391 } else if (t.IsValueType) {
7392 has_type_arg = true;
7394 return OpCodes.Stobj;
7396 } else if (t.IsGenericParameter) {
7397 has_type_arg = true;
7398 return OpCodes.Stelem;
7401 } else if (t.IsPointer)
7402 return OpCodes.Stelem_I;
7404 return OpCodes.Stelem_Ref;
7407 MethodInfo FetchGetMethod ()
7409 ModuleBuilder mb = CodeGen.Module.Builder;
7410 int arg_count = ea.Arguments.Count;
7411 Type [] args = new Type [arg_count];
7414 for (int i = 0; i < arg_count; i++){
7415 //args [i++] = a.Type;
7416 args [i] = TypeManager.int32_type;
7419 get = mb.GetArrayMethod (
7420 ea.Expr.Type, "Get",
7421 CallingConventions.HasThis |
7422 CallingConventions.Standard,
7428 MethodInfo FetchAddressMethod ()
7430 ModuleBuilder mb = CodeGen.Module.Builder;
7431 int arg_count = ea.Arguments.Count;
7432 Type [] args = new Type [arg_count];
7436 ret_type = TypeManager.GetReferenceType (type);
7438 for (int i = 0; i < arg_count; i++){
7439 //args [i++] = a.Type;
7440 args [i] = TypeManager.int32_type;
7443 address = mb.GetArrayMethod (
7444 ea.Expr.Type, "Address",
7445 CallingConventions.HasThis |
7446 CallingConventions.Standard,
7453 // Load the array arguments into the stack.
7455 // If we have been requested to cache the values (cached_locations array
7456 // initialized), then load the arguments the first time and store them
7457 // in locals. otherwise load from local variables.
7459 void LoadArrayAndArguments (EmitContext ec)
7461 ILGenerator ig = ec.ig;
7464 foreach (Argument a in ea.Arguments){
7465 Type argtype = a.Expr.Type;
7469 if (argtype == TypeManager.int64_type)
7470 ig.Emit (OpCodes.Conv_Ovf_I);
7471 else if (argtype == TypeManager.uint64_type)
7472 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7476 public void Emit (EmitContext ec, bool leave_copy)
7478 int rank = ea.Expr.Type.GetArrayRank ();
7479 ILGenerator ig = ec.ig;
7482 LoadArrayAndArguments (ec);
7485 EmitLoadOpcode (ig, type);
7489 method = FetchGetMethod ();
7490 ig.Emit (OpCodes.Call, method);
7493 LoadFromPtr (ec.ig, this.type);
7496 ec.ig.Emit (OpCodes.Dup);
7497 temp = new LocalTemporary (this.type);
7502 public override void Emit (EmitContext ec)
7507 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7509 int rank = ea.Expr.Type.GetArrayRank ();
7510 ILGenerator ig = ec.ig;
7511 Type t = source.Type;
7512 prepared = prepare_for_load;
7514 if (prepare_for_load) {
7515 AddressOf (ec, AddressOp.LoadStore);
7516 ec.ig.Emit (OpCodes.Dup);
7519 ec.ig.Emit (OpCodes.Dup);
7520 temp = new LocalTemporary (this.type);
7523 StoreFromPtr (ec.ig, t);
7533 LoadArrayAndArguments (ec);
7536 bool is_stobj, has_type_arg;
7537 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7539 // The stobj opcode used by value types will need
7540 // an address on the stack, not really an array/array
7544 ig.Emit (OpCodes.Ldelema, t);
7548 ec.ig.Emit (OpCodes.Dup);
7549 temp = new LocalTemporary (this.type);
7554 ig.Emit (OpCodes.Stobj, t);
7555 else if (has_type_arg)
7560 ModuleBuilder mb = CodeGen.Module.Builder;
7561 int arg_count = ea.Arguments.Count;
7562 Type [] args = new Type [arg_count + 1];
7567 ec.ig.Emit (OpCodes.Dup);
7568 temp = new LocalTemporary (this.type);
7572 for (int i = 0; i < arg_count; i++){
7573 //args [i++] = a.Type;
7574 args [i] = TypeManager.int32_type;
7577 args [arg_count] = type;
7579 set = mb.GetArrayMethod (
7580 ea.Expr.Type, "Set",
7581 CallingConventions.HasThis |
7582 CallingConventions.Standard,
7583 TypeManager.void_type, args);
7585 ig.Emit (OpCodes.Call, set);
7594 public void AddressOf (EmitContext ec, AddressOp mode)
7596 int rank = ea.Expr.Type.GetArrayRank ();
7597 ILGenerator ig = ec.ig;
7599 LoadArrayAndArguments (ec);
7602 ig.Emit (OpCodes.Ldelema, type);
7604 MethodInfo address = FetchAddressMethod ();
7605 ig.Emit (OpCodes.Call, address);
7609 public void EmitGetLength (EmitContext ec, int dim)
7611 int rank = ea.Expr.Type.GetArrayRank ();
7612 ILGenerator ig = ec.ig;
7616 ig.Emit (OpCodes.Ldlen);
7617 ig.Emit (OpCodes.Conv_I4);
7619 IntLiteral.EmitInt (ig, dim);
7620 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7626 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7627 public readonly ArrayList Properties;
7628 static Indexers empty;
7630 public struct Indexer {
7631 public readonly PropertyInfo PropertyInfo;
7632 public readonly MethodInfo Getter, Setter;
7634 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7636 this.PropertyInfo = property_info;
7644 empty = new Indexers (null);
7647 Indexers (ArrayList array)
7652 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7657 foreach (PropertyInfo property in mi){
7658 MethodInfo get, set;
7660 get = property.GetGetMethod (true);
7661 set = property.GetSetMethod (true);
7662 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7664 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7666 if (get != null || set != null) {
7668 ix = new Indexers (new ArrayList ());
7669 ix.Properties.Add (new Indexer (property, get, set));
7674 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7676 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7678 return TypeManager.MemberLookup (
7679 caller_type, caller_type, lookup_type, MemberTypes.Property,
7680 BindingFlags.Public | BindingFlags.Instance |
7681 BindingFlags.DeclaredOnly, p_name, null);
7684 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7686 Indexers ix = empty;
7689 if (lookup_type.IsGenericParameter) {
7690 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7694 if (gc.HasClassConstraint)
7695 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7697 Type[] ifaces = gc.InterfaceConstraints;
7698 foreach (Type itype in ifaces)
7699 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7705 Type copy = lookup_type;
7706 while (copy != TypeManager.object_type && copy != null){
7707 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7708 copy = copy.BaseType;
7711 if (lookup_type.IsInterface) {
7712 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7713 if (ifaces != null) {
7714 foreach (Type itype in ifaces)
7715 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7724 /// Expressions that represent an indexer call.
7726 public class IndexerAccess : Expression, IAssignMethod {
7728 // Points to our "data" repository
7730 MethodInfo get, set;
7731 ArrayList set_arguments;
7732 bool is_base_indexer;
7734 protected Type indexer_type;
7735 protected Type current_type;
7736 protected Expression instance_expr;
7737 protected ArrayList arguments;
7739 public IndexerAccess (ElementAccess ea, Location loc)
7740 : this (ea.Expr, false, loc)
7742 this.arguments = ea.Arguments;
7745 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7748 this.instance_expr = instance_expr;
7749 this.is_base_indexer = is_base_indexer;
7750 this.eclass = ExprClass.Value;
7754 protected virtual bool CommonResolve (EmitContext ec)
7756 indexer_type = instance_expr.Type;
7757 current_type = ec.ContainerType;
7762 public override Expression DoResolve (EmitContext ec)
7764 if (!CommonResolve (ec))
7768 // Step 1: Query for all `Item' *properties*. Notice
7769 // that the actual methods are pointed from here.
7771 // This is a group of properties, piles of them.
7773 ArrayList AllGetters = null;
7775 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7776 if (ilist.Properties != null) {
7777 AllGetters = new ArrayList(ilist.Properties.Count);
7778 foreach (Indexers.Indexer ix in ilist.Properties) {
7779 if (ix.Getter != null)
7780 AllGetters.Add (ix.Getter);
7784 if (AllGetters == null) {
7785 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7786 TypeManager.CSharpName (indexer_type));
7790 if (AllGetters.Count == 0) {
7791 // FIXME: we cannot simply select first one as the error message is missleading when
7792 // multiple indexers exist
7793 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7794 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7795 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7799 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7800 arguments, false, loc);
7803 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7808 // Only base will allow this invocation to happen.
7810 if (get.IsAbstract && this is BaseIndexerAccess){
7811 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7815 type = get.ReturnType;
7816 if (type.IsPointer && !ec.InUnsafe){
7821 instance_expr.CheckMarshalByRefAccess ();
7823 eclass = ExprClass.IndexerAccess;
7827 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7829 if (right_side == EmptyExpression.OutAccess) {
7830 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7831 GetSignatureForError ());
7835 // if the indexer returns a value type, and we try to set a field in it
7836 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7837 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7838 GetSignatureForError ());
7842 ArrayList AllSetters = new ArrayList();
7843 if (!CommonResolve (ec))
7846 bool found_any = false, found_any_setters = false;
7848 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7849 if (ilist.Properties != null) {
7851 foreach (Indexers.Indexer ix in ilist.Properties) {
7852 if (ix.Setter != null)
7853 AllSetters.Add (ix.Setter);
7856 if (AllSetters.Count > 0) {
7857 found_any_setters = true;
7858 set_arguments = (ArrayList) arguments.Clone ();
7859 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7860 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7862 set_arguments, false, loc);
7866 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7867 TypeManager.CSharpName (indexer_type));
7871 if (!found_any_setters) {
7872 Error (154, "indexer can not be used in this context, because " +
7873 "it lacks a `set' accessor");
7878 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7883 // Only base will allow this invocation to happen.
7885 if (set.IsAbstract && this is BaseIndexerAccess){
7886 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7891 // Now look for the actual match in the list of indexers to set our "return" type
7893 type = TypeManager.void_type; // default value
7894 foreach (Indexers.Indexer ix in ilist.Properties){
7895 if (ix.Setter == set){
7896 type = ix.PropertyInfo.PropertyType;
7901 instance_expr.CheckMarshalByRefAccess ();
7903 eclass = ExprClass.IndexerAccess;
7907 bool prepared = false;
7908 LocalTemporary temp;
7910 public void Emit (EmitContext ec, bool leave_copy)
7912 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7914 ec.ig.Emit (OpCodes.Dup);
7915 temp = new LocalTemporary (Type);
7921 // source is ignored, because we already have a copy of it from the
7922 // LValue resolution and we have already constructed a pre-cached
7923 // version of the arguments (ea.set_arguments);
7925 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7927 prepared = prepare_for_load;
7928 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7933 ec.ig.Emit (OpCodes.Dup);
7934 temp = new LocalTemporary (Type);
7937 } else if (leave_copy) {
7938 temp = new LocalTemporary (Type);
7944 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7953 public override void Emit (EmitContext ec)
7958 public override string GetSignatureForError ()
7960 // FIXME: print the argument list of the indexer
7961 return instance_expr.GetSignatureForError () + ".this[...]";
7964 protected override void CloneTo (CloneContext clonectx, Expression t)
7966 IndexerAccess target = (IndexerAccess) t;
7968 if (arguments != null){
7969 target.arguments = new ArrayList ();
7970 foreach (Argument a in arguments)
7971 target.arguments.Add (a.Clone (clonectx));
7973 if (instance_expr != null)
7974 target.instance_expr = instance_expr.Clone (clonectx);
7979 /// The base operator for method names
7981 public class BaseAccess : Expression {
7982 public readonly string Identifier;
7985 public BaseAccess (string member, Location l)
7987 this.Identifier = member;
7991 public BaseAccess (string member, TypeArguments args, Location l)
7997 public override Expression DoResolve (EmitContext ec)
7999 Expression c = CommonResolve (ec);
8005 // MethodGroups use this opportunity to flag an error on lacking ()
8007 if (!(c is MethodGroupExpr))
8008 return c.Resolve (ec);
8012 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8014 Expression c = CommonResolve (ec);
8020 // MethodGroups use this opportunity to flag an error on lacking ()
8022 if (! (c is MethodGroupExpr))
8023 return c.DoResolveLValue (ec, right_side);
8028 Expression CommonResolve (EmitContext ec)
8030 Expression member_lookup;
8031 Type current_type = ec.ContainerType;
8032 Type base_type = current_type.BaseType;
8035 Error (1511, "Keyword `base' is not available in a static method");
8039 if (ec.IsFieldInitializer){
8040 Error (1512, "Keyword `base' is not available in the current context");
8044 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8045 AllMemberTypes, AllBindingFlags, loc);
8046 if (member_lookup == null) {
8047 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8054 left = new TypeExpression (base_type, loc);
8056 left = ec.GetThis (loc);
8058 MemberExpr me = (MemberExpr) member_lookup;
8060 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8062 if (e is PropertyExpr) {
8063 PropertyExpr pe = (PropertyExpr) e;
8065 } else if (e is EventExpr) {
8066 EventExpr ee = (EventExpr) e;
8070 MethodGroupExpr mg = e as MethodGroupExpr;
8076 return mg.ResolveGeneric (ec, args);
8078 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8086 public override void Emit (EmitContext ec)
8088 throw new Exception ("Should never be called");
8091 protected override void CloneTo (CloneContext clonectx, Expression t)
8093 BaseAccess target = (BaseAccess) t;
8095 target.args = args.Clone ();
8100 /// The base indexer operator
8102 public class BaseIndexerAccess : IndexerAccess {
8103 public BaseIndexerAccess (ArrayList args, Location loc)
8104 : base (null, true, loc)
8106 arguments = new ArrayList ();
8107 foreach (Expression tmp in args)
8108 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8111 protected override bool CommonResolve (EmitContext ec)
8113 instance_expr = ec.GetThis (loc);
8115 current_type = ec.ContainerType.BaseType;
8116 indexer_type = current_type;
8118 foreach (Argument a in arguments){
8119 if (!a.Resolve (ec, loc))
8128 /// This class exists solely to pass the Type around and to be a dummy
8129 /// that can be passed to the conversion functions (this is used by
8130 /// foreach implementation to typecast the object return value from
8131 /// get_Current into the proper type. All code has been generated and
8132 /// we only care about the side effect conversions to be performed
8134 /// This is also now used as a placeholder where a no-action expression
8135 /// is needed (the `New' class).
8137 public class EmptyExpression : Expression {
8138 public static readonly EmptyExpression Null = new EmptyExpression ();
8140 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8141 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8142 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8144 static EmptyExpression temp = new EmptyExpression ();
8145 public static EmptyExpression Grab ()
8147 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8152 public static void Release (EmptyExpression e)
8157 // TODO: should be protected
8158 public EmptyExpression ()
8160 type = TypeManager.object_type;
8161 eclass = ExprClass.Value;
8162 loc = Location.Null;
8165 public EmptyExpression (Type t)
8168 eclass = ExprClass.Value;
8169 loc = Location.Null;
8172 public override Expression DoResolve (EmitContext ec)
8177 public override void Emit (EmitContext ec)
8179 // nothing, as we only exist to not do anything.
8183 // This is just because we might want to reuse this bad boy
8184 // instead of creating gazillions of EmptyExpressions.
8185 // (CanImplicitConversion uses it)
8187 public void SetType (Type t)
8193 public class UserCast : Expression {
8197 public UserCast (MethodInfo method, Expression source, Location l)
8199 this.method = method;
8200 this.source = source;
8201 type = method.ReturnType;
8202 eclass = ExprClass.Value;
8206 public Expression Source {
8212 public override Expression DoResolve (EmitContext ec)
8215 // We are born fully resolved
8220 public override void Emit (EmitContext ec)
8222 ILGenerator ig = ec.ig;
8226 if (method is MethodInfo)
8227 ig.Emit (OpCodes.Call, (MethodInfo) method);
8229 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8235 // This class is used to "construct" the type during a typecast
8236 // operation. Since the Type.GetType class in .NET can parse
8237 // the type specification, we just use this to construct the type
8238 // one bit at a time.
8240 public class ComposedCast : TypeExpr {
8244 public ComposedCast (Expression left, string dim)
8245 : this (left, dim, left.Location)
8249 public ComposedCast (Expression left, string dim, Location l)
8257 public Expression RemoveNullable ()
8259 if (dim.EndsWith ("?")) {
8260 dim = dim.Substring (0, dim.Length - 1);
8269 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8271 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8275 Type ltype = lexpr.Type;
8276 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8277 Error_VoidInvalidInTheContext (loc);
8282 if ((dim.Length > 0) && (dim [0] == '?')) {
8283 TypeExpr nullable = new NullableType (left, loc);
8285 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8286 return nullable.ResolveAsTypeTerminal (ec, false);
8290 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8293 if (dim != "" && dim [0] == '[' &&
8294 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8295 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8300 type = TypeManager.GetConstructedType (ltype, dim);
8305 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8307 if (type.IsPointer && !ec.IsInUnsafeScope){
8312 eclass = ExprClass.Type;
8316 public override string Name {
8317 get { return left + dim; }
8320 public override string FullName {
8321 get { return type.FullName; }
8324 public override string GetSignatureForError ()
8326 return left.GetSignatureForError () + dim;
8329 protected override void CloneTo (CloneContext clonectx, Expression t)
8331 ComposedCast target = (ComposedCast) t;
8333 target.left = left.Clone (clonectx);
8337 public class FixedBufferPtr : Expression {
8340 public FixedBufferPtr (Expression array, Type array_type, Location l)
8345 type = TypeManager.GetPointerType (array_type);
8346 eclass = ExprClass.Value;
8349 public override void Emit(EmitContext ec)
8354 public override Expression DoResolve (EmitContext ec)
8357 // We are born fully resolved
8365 // This class is used to represent the address of an array, used
8366 // only by the Fixed statement, this generates "&a [0]" construct
8367 // for fixed (char *pa = a)
8369 public class ArrayPtr : FixedBufferPtr {
8372 public ArrayPtr (Expression array, Type array_type, Location l):
8373 base (array, array_type, l)
8375 this.array_type = array_type;
8378 public override void Emit (EmitContext ec)
8382 ILGenerator ig = ec.ig;
8383 IntLiteral.EmitInt (ig, 0);
8384 ig.Emit (OpCodes.Ldelema, array_type);
8389 // Used by the fixed statement
8391 public class StringPtr : Expression {
8394 public StringPtr (LocalBuilder b, Location l)
8397 eclass = ExprClass.Value;
8398 type = TypeManager.char_ptr_type;
8402 public override Expression DoResolve (EmitContext ec)
8404 // This should never be invoked, we are born in fully
8405 // initialized state.
8410 public override void Emit (EmitContext ec)
8412 ILGenerator ig = ec.ig;
8414 ig.Emit (OpCodes.Ldloc, b);
8415 ig.Emit (OpCodes.Conv_I);
8416 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8417 ig.Emit (OpCodes.Add);
8422 // Implements the `stackalloc' keyword
8424 public class StackAlloc : Expression {
8429 public StackAlloc (Expression type, Expression count, Location l)
8436 public override Expression DoResolve (EmitContext ec)
8438 count = count.Resolve (ec);
8442 if (count.Type != TypeManager.int32_type){
8443 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8448 Constant c = count as Constant;
8449 if (c != null && c.IsNegative) {
8450 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8454 if (ec.InCatch || ec.InFinally) {
8455 Error (255, "Cannot use stackalloc in finally or catch");
8459 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8465 if (!TypeManager.VerifyUnManaged (otype, loc))
8468 type = TypeManager.GetPointerType (otype);
8469 eclass = ExprClass.Value;
8474 public override void Emit (EmitContext ec)
8476 int size = GetTypeSize (otype);
8477 ILGenerator ig = ec.ig;
8480 ig.Emit (OpCodes.Sizeof, otype);
8482 IntConstant.EmitInt (ig, size);
8484 ig.Emit (OpCodes.Mul);
8485 ig.Emit (OpCodes.Localloc);
8488 protected override void CloneTo (CloneContext clonectx, Expression t)
8490 StackAlloc target = (StackAlloc) t;
8491 target.count = count.Clone (clonectx);
8492 target.t = t.Clone (clonectx);
8496 public interface IInitializable
8498 bool Initialize (EmitContext ec, Expression target);
8501 public class Initializer
8503 public readonly string Name;
8504 public readonly object Value;
8506 public Initializer (string name, Expression value)
8512 public Initializer (string name, IInitializable value)
8519 public class ObjectInitializer : IInitializable
8521 readonly ArrayList initializers;
8522 public ObjectInitializer (ArrayList initializers)
8524 this.initializers = initializers;
8527 public bool Initialize (EmitContext ec, Expression target)
8529 ArrayList initialized = new ArrayList (initializers.Count);
8530 for (int i = initializers.Count - 1; i >= 0; i--) {
8531 Initializer initializer = initializers[i] as Initializer;
8532 if (initialized.Contains (initializer.Name)) {
8533 //FIXME proper error
8534 Console.WriteLine ("Object member can only be initialized once");
8538 MemberAccess ma = new MemberAccess (target, initializer.Name);
8539 Expression expr = initializer.Value as Expression;
8540 // If it's an expresison, append the assign.
8542 Assign a = new Assign (ma, expr);
8543 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8545 // If it's another initializer (object or collection), initialize it.
8546 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8549 initialized.Add (initializer.Name);
8555 public class CollectionInitializer : IInitializable
8557 readonly ArrayList items;
8558 public CollectionInitializer (ArrayList items)
8563 bool CheckCollection (EmitContext ec, Expression e)
8565 if (e == null || e.Type == null)
8567 bool is_ienumerable = false;
8568 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8569 if (t == typeof (IEnumerable)) {
8570 is_ienumerable = true;
8574 if (!is_ienumerable)
8577 MethodGroupExpr mg = Expression.MemberLookup (
8578 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8579 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8584 foreach (MethodInfo mi in mg.Methods) {
8585 if (TypeManager.GetParameterData (mi).Count != 1)
8587 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8594 public bool Initialize (EmitContext ec, Expression target)
8596 if (!CheckCollection (ec, target.Resolve (ec))) {
8597 // FIXME throw proper error
8598 Console.WriteLine ("Error: This is not a collection");
8602 for (int i = items.Count - 1; i >= 0; i--) {
8603 MemberAccess ma = new MemberAccess (target, "Add");
8604 ArrayList array = new ArrayList ();
8605 array.Add (new Argument ((Expression)items[i]));
8606 Invocation invoke = new Invocation (ma, array);
8607 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8613 public class AnonymousTypeInitializer : IInitializable
8615 readonly ArrayList initializers;
8616 public AnonymousTypeInitializer (ArrayList initializers)
8618 this.initializers = initializers;
8621 public bool Initialize (EmitContext ec, Expression target)
8623 foreach (AnonymousTypeParameter p in initializers) {
8624 MemberAccess ma = new MemberAccess (target, p.Name);
8625 Assign a = p.Expression as Assign;
8626 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8627 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8633 public class NewInitialize : New, IInitializable
8635 IInitializable initializer;
8637 public bool Initialize (EmitContext ec, Expression target)
8639 return initializer.Initialize (ec, target);
8642 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8643 : base (requested_type, arguments, l)
8645 this.initializer = initializer;
8649 public class AnonymousType : Expression
8651 ArrayList parameters;
8652 TypeContainer parent;
8653 TypeContainer anonymous_type;
8655 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8657 this.parameters = parameters;
8658 this.parent = parent;
8662 public override Expression DoResolve (EmitContext ec)
8664 foreach (AnonymousTypeParameter p in parameters)
8667 anonymous_type = GetAnonymousType (ec);
8669 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8670 AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8671 return new NewInitialize (te, null, ati, loc).Resolve (ec);
8674 TypeContainer GetAnonymousType (EmitContext ec)
8676 // See if we already have an anonymous type with the right fields.
8677 // If not, create one.
8679 // Look through all availible pre-existing anonymous types:
8680 foreach (DictionaryEntry d in parent.AnonymousTypes) {
8681 ArrayList p = d.Key as ArrayList;
8682 if (p.Count != parameters.Count)
8685 // And for each of the fields we need...
8686 foreach (AnonymousTypeParameter atp in parameters) {
8687 // ... check each of the pre-existing A-type's fields.
8689 foreach (AnonymousTypeParameter a in p)
8690 if (atp.Equals(a)) {
8694 // If the pre-existing A-type doesn't have one of our fields, try the next one
8700 // If it's a match, return it.
8702 return d.Value as TypeContainer;
8704 // Otherwise, create a new type.
8705 return CreateAnonymousType (ec);
8708 TypeContainer CreateAnonymousType (EmitContext ec)
8710 TypeContainer type = new AnonymousClass (parent, loc);
8711 foreach (AnonymousTypeParameter p in parameters) {
8712 TypeExpression te = new TypeExpression (p.Type, loc);
8713 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8714 type.AddField (field);
8717 type.DefineMembers ();
8718 parent.AnonymousTypes.Add (parameters, type);
8722 public override void Emit (EmitContext ec)
8724 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8725 new New (te, null, loc).Emit(ec);
8729 public class AnonymousTypeParameter : Expression
8733 Expression expression;
8735 public LocatedToken Token {
8736 get { return token; }
8739 public string Name {
8740 get { return name; }
8743 public Expression Expression {
8744 get { return expression; }
8747 public override bool Equals (object o)
8749 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8750 return other != null && Name == other.Name && Type == other.Type;
8753 public override int GetHashCode ()
8755 return name.GetHashCode ();
8758 public override Expression DoResolve (EmitContext ec)
8760 Expression e = expression.Resolve(ec);
8765 public override void Emit (EmitContext ec)
8767 expression.Emit(ec);
8770 public AnonymousTypeParameter (Expression expression, string name)
8773 this.expression = expression;
8774 type = expression.Type;