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);
3728 /// This represents a reference to a parameter in the intermediate
3731 public class ParameterReference : VariableReference, IVariable {
3732 readonly ToplevelParameterInfo pi;
3733 readonly ToplevelBlock referenced;
3736 public bool is_ref, is_out;
3739 get { return is_out; }
3742 public override bool IsRef {
3743 get { return is_ref; }
3746 public string Name {
3747 get { return Parameter.Name; }
3750 public Parameter Parameter {
3751 get { return pi.Parameter; }
3754 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3757 this.referenced = referenced;
3759 eclass = ExprClass.Variable;
3762 public VariableInfo VariableInfo {
3763 get { return pi.VariableInfo; }
3766 public override Variable Variable {
3767 get { return variable != null ? variable : Parameter.Variable; }
3770 public bool VerifyFixed ()
3772 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3773 return Parameter.ModFlags == Parameter.Modifier.NONE;
3776 public bool IsAssigned (EmitContext ec, Location loc)
3778 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3781 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3785 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3787 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3790 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3794 public void SetAssigned (EmitContext ec)
3796 if (is_out && ec.DoFlowAnalysis)
3797 ec.CurrentBranching.SetAssigned (VariableInfo);
3800 public void SetFieldAssigned (EmitContext ec, string field_name)
3802 if (is_out && ec.DoFlowAnalysis)
3803 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3806 protected bool DoResolveBase (EmitContext ec)
3808 Parameter par = Parameter;
3809 if (!par.Resolve (ec)) {
3813 type = par.ParameterType;
3814 Parameter.Modifier mod = par.ModFlags;
3815 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3816 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3817 eclass = ExprClass.Variable;
3819 AnonymousContainer am = ec.CurrentAnonymousMethod;
3823 ToplevelBlock declared = pi.Block;
3824 if (is_ref && declared != referenced) {
3825 Report.Error (1628, Location,
3826 "Cannot use ref or out parameter `{0}' inside an " +
3827 "anonymous method block", par.Name);
3831 if (!am.IsIterator && declared == referenced)
3834 // Don't capture aruments when the probing is on
3835 if (!ec.IsInProbingMode) {
3836 ScopeInfo scope = declared.CreateScopeInfo ();
3837 variable = scope.AddParameter (par, pi.Index);
3838 type = variable.Type;
3843 public override int GetHashCode ()
3845 return Name.GetHashCode ();
3848 public override bool Equals (object obj)
3850 ParameterReference pr = obj as ParameterReference;
3854 return Name == pr.Name && referenced == pr.referenced;
3858 // Notice that for ref/out parameters, the type exposed is not the
3859 // same type exposed externally.
3862 // externally we expose "int&"
3863 // here we expose "int".
3865 // We record this in "is_ref". This means that the type system can treat
3866 // the type as it is expected, but when we generate the code, we generate
3867 // the alternate kind of code.
3869 public override Expression DoResolve (EmitContext ec)
3871 if (!DoResolveBase (ec))
3874 if (is_out && ec.DoFlowAnalysis &&
3875 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3881 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3883 if (!DoResolveBase (ec))
3886 // HACK: parameters are not captured when probing is on
3887 if (!ec.IsInProbingMode)
3893 static public void EmitLdArg (ILGenerator ig, int x)
3897 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3898 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3899 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3900 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3901 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3904 ig.Emit (OpCodes.Ldarg, x);
3907 public override string ToString ()
3909 return "ParameterReference[" + Name + "]";
3914 /// Used for arguments to New(), Invocation()
3916 public class Argument {
3917 public enum AType : byte {
3924 public static readonly Argument[] Empty = new Argument [0];
3926 public readonly AType ArgType;
3927 public Expression Expr;
3929 public Argument (Expression expr, AType type)
3932 this.ArgType = type;
3935 public Argument (Expression expr)
3938 this.ArgType = AType.Expression;
3943 if (ArgType == AType.Ref || ArgType == AType.Out)
3944 return TypeManager.GetReferenceType (Expr.Type);
3950 public Parameter.Modifier Modifier
3955 return Parameter.Modifier.OUT;
3958 return Parameter.Modifier.REF;
3961 return Parameter.Modifier.NONE;
3966 public static string FullDesc (Argument a)
3968 if (a.ArgType == AType.ArgList)
3971 return (a.ArgType == AType.Ref ? "ref " :
3972 (a.ArgType == AType.Out ? "out " : "")) +
3973 TypeManager.CSharpName (a.Expr.Type);
3976 public bool ResolveMethodGroup (EmitContext ec)
3978 SimpleName sn = Expr as SimpleName;
3980 Expr = sn.GetMethodGroup ();
3982 // FIXME: csc doesn't report any error if you try to use `ref' or
3983 // `out' in a delegate creation expression.
3984 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3991 public bool Resolve (EmitContext ec, Location loc)
3993 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3994 // Verify that the argument is readable
3995 if (ArgType != AType.Out)
3996 Expr = Expr.Resolve (ec);
3998 // Verify that the argument is writeable
3999 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4000 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4002 return Expr != null;
4006 public void Emit (EmitContext ec)
4008 if (ArgType != AType.Ref && ArgType != AType.Out) {
4013 AddressOp mode = AddressOp.Store;
4014 if (ArgType == AType.Ref)
4015 mode |= AddressOp.Load;
4017 IMemoryLocation ml = (IMemoryLocation) Expr;
4018 ParameterReference pr = ml as ParameterReference;
4021 // ParameterReferences might already be references, so we want
4022 // to pass just the value
4024 if (pr != null && pr.IsRef)
4027 ml.AddressOf (ec, mode);
4030 public Argument Clone (CloneContext clonectx)
4032 return new Argument (Expr.Clone (clonectx), ArgType);
4037 /// Invocation of methods or delegates.
4039 public class Invocation : ExpressionStatement {
4040 ArrayList Arguments;
4045 // arguments is an ArrayList, but we do not want to typecast,
4046 // as it might be null.
4048 public Invocation (Expression expr, ArrayList arguments)
4050 SimpleName sn = expr as SimpleName;
4052 this.expr = sn.GetMethodGroup ();
4056 Arguments = arguments;
4057 loc = expr.Location;
4060 public static string FullMethodDesc (MethodBase mb)
4066 if (mb is MethodInfo) {
4067 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4071 sb = new StringBuilder ();
4073 sb.Append (TypeManager.CSharpSignature (mb));
4074 return sb.ToString ();
4077 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4078 ArrayList arguments, int arg_count,
4079 ref MethodBase candidate)
4081 return IsParamsMethodApplicable (
4082 ec, me, arguments, arg_count, false, ref candidate) ||
4083 IsParamsMethodApplicable (
4084 ec, me, arguments, arg_count, true, ref candidate);
4089 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4090 ArrayList arguments, int arg_count,
4091 bool do_varargs, ref MethodBase candidate)
4094 if (!me.HasTypeArguments &&
4095 !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4098 if (TypeManager.IsGenericMethodDefinition (candidate))
4099 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4102 return IsParamsMethodApplicable (
4103 ec, arguments, arg_count, candidate, do_varargs);
4107 /// Determines if the candidate method, if a params method, is applicable
4108 /// in its expanded form to the given set of arguments
4110 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4111 int arg_count, MethodBase candidate,
4114 ParameterData pd = TypeManager.GetParameterData (candidate);
4116 int pd_count = pd.Count;
4120 int count = pd_count - 1;
4122 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4124 if (pd_count != arg_count)
4127 if (!(((Argument) arguments [count]).Expr is Arglist))
4135 if (count > arg_count)
4138 if (pd_count == 1 && arg_count == 0)
4142 // If we have come this far, the case which
4143 // remains is when the number of parameters is
4144 // less than or equal to the argument count.
4146 int argument_index = 0;
4148 for (int i = 0; i < pd_count; ++i) {
4150 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4151 Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4152 int params_args_count = arg_count - pd_count;
4153 if (params_args_count < 0)
4157 a = (Argument) arguments [argument_index++];
4159 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4161 } while (params_args_count-- > 0);
4165 a = (Argument) arguments [argument_index++];
4167 Parameter.Modifier a_mod = a.Modifier &
4168 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4169 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4170 (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4172 if (a_mod == p_mod) {
4174 if (a_mod == Parameter.Modifier.NONE)
4175 if (!Convert.ImplicitConversionExists (ec,
4177 pd.ParameterType (i)))
4180 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4181 Type pt = pd.ParameterType (i);
4184 pt = TypeManager.GetReferenceType (pt);
4197 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4198 ArrayList arguments, int arg_count,
4199 ref MethodBase method)
4201 MethodBase candidate = method;
4204 if (!me.HasTypeArguments &&
4205 !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4208 if (TypeManager.IsGenericMethodDefinition (candidate))
4209 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4212 if (IsApplicable (ec, arguments, arg_count, candidate)) {
4221 /// Determines if the candidate method is applicable (section 14.4.2.1)
4222 /// to the given set of arguments
4224 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4225 MethodBase candidate)
4227 ParameterData pd = TypeManager.GetParameterData (candidate);
4229 if (arg_count != pd.Count)
4232 for (int i = arg_count; i > 0; ) {
4235 Argument a = (Argument) arguments [i];
4237 Parameter.Modifier a_mod = a.Modifier &
4238 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4240 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4241 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4246 Type pt = pd.ParameterType (i);
4248 if (TypeManager.IsEqual (pt, a.Type))
4251 if (a_mod != Parameter.Modifier.NONE)
4254 // FIXME: Kill this abomination (EmitContext.TempEc)
4255 EmitContext prevec = EmitContext.TempEc;
4256 EmitContext.TempEc = ec;
4258 if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4261 EmitContext.TempEc = prevec;
4268 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4270 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4271 name, arg_count.ToString ());
4274 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4275 Type delegate_type, Argument a, ParameterData expected_par)
4277 if (delegate_type == null)
4278 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4279 TypeManager.CSharpSignature (method));
4281 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4282 TypeManager.CSharpName (delegate_type));
4284 Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4286 string index = (idx + 1).ToString ();
4287 if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4288 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4289 Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4290 index, Parameter.GetModifierSignature (a.Modifier));
4292 Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4293 index, Parameter.GetModifierSignature (mod));
4295 string p1 = Argument.FullDesc (a);
4296 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4299 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4300 Report.SymbolRelatedToPreviousError (a.Expr.Type);
4301 Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4303 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4307 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4308 int arg_count, MethodBase method,
4309 bool chose_params_expanded,
4310 Type delegate_type, bool may_fail,
4313 ParameterData pd = TypeManager.GetParameterData (method);
4317 for (j = 0; j < pd.Count; j++) {
4318 Type parameter_type = pd.ParameterType (j);
4319 Parameter.Modifier pm = pd.ParameterModifier (j);
4321 if (pm == Parameter.Modifier.ARGLIST) {
4322 a = (Argument) Arguments [a_idx];
4323 if (!(a.Expr is Arglist))
4329 int params_arg_count = 1;
4330 if (pm == Parameter.Modifier.PARAMS) {
4331 pm = Parameter.Modifier.NONE;
4332 params_arg_count = arg_count - pd.Count + 1;
4333 if (chose_params_expanded)
4334 parameter_type = TypeManager.GetElementType (parameter_type);
4337 while (params_arg_count > 0) {
4338 a = (Argument) Arguments [a_idx];
4339 if (pm != a.Modifier)
4342 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4343 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4346 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4350 // Update the argument with the implicit conversion
4358 if (params_arg_count > 0)
4361 if (parameter_type.IsPointer && !ec.InUnsafe) {
4368 if (a_idx == arg_count)
4372 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4376 public override Expression DoResolve (EmitContext ec)
4378 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4379 if (expr_resolved == null)
4382 mg = expr_resolved as MethodGroupExpr;
4384 Type expr_type = expr_resolved.Type;
4386 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4387 return (new DelegateInvocation (
4388 expr_resolved, Arguments, loc)).Resolve (ec);
4390 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4395 // Next, evaluate all the expressions in the argument list
4397 if (Arguments != null){
4398 foreach (Argument a in Arguments){
4399 if (!a.Resolve (ec, loc))
4404 mg = mg.OverloadResolve (ec, Arguments, false, loc);
4408 MethodInfo method = (MethodInfo)mg;
4409 if (method != null) {
4410 type = TypeManager.TypeToCoreType (method.ReturnType);
4411 Expression iexpr = mg.InstanceExpression;
4412 if (method.IsStatic) {
4413 if (iexpr == null ||
4414 iexpr is This || iexpr is EmptyExpression ||
4415 mg.IdenticalTypeName) {
4416 mg.InstanceExpression = null;
4418 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4422 if (iexpr == null || iexpr is EmptyExpression) {
4423 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4429 if (type.IsPointer){
4437 // Only base will allow this invocation to happen.
4439 if (mg.IsBase && method.IsAbstract){
4440 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4444 if (Arguments == null && method.Name == "Finalize") {
4446 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4448 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4452 if (IsSpecialMethodInvocation (method)) {
4456 if (mg.InstanceExpression != null){
4457 mg.InstanceExpression.CheckMarshalByRefAccess ();
4460 // This is used to check that no methods are called in struct
4461 // constructors before all the fields on the struct have been
4464 if (!method.IsStatic){
4465 This mgthis = mg.InstanceExpression as This;
4466 if (mgthis != null){
4467 if (!mgthis.CheckThisUsage (ec))
4473 eclass = ExprClass.Value;
4477 bool IsSpecialMethodInvocation (MethodBase method)
4479 if (!TypeManager.IsSpecialMethod (method))
4482 Report.SymbolRelatedToPreviousError (method);
4483 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4484 TypeManager.CSharpSignature (method, true));
4490 // Emits the list of arguments as an array
4492 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4494 ILGenerator ig = ec.ig;
4496 for (int j = 0; j < count; j++){
4497 Argument a = (Argument) arguments [j + idx];
4500 IntConstant.EmitInt (ig, count);
4501 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4504 ig.Emit (OpCodes.Dup);
4505 IntConstant.EmitInt (ig, j);
4507 bool is_stobj, has_type_arg;
4508 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4510 ig.Emit (OpCodes.Ldelema, t);
4522 /// Emits a list of resolved Arguments that are in the arguments
4525 /// The MethodBase argument might be null if the
4526 /// emission of the arguments is known not to contain
4527 /// a `params' field (for example in constructors or other routines
4528 /// that keep their arguments in this structure)
4530 /// if `dup_args' is true, a copy of the arguments will be left
4531 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4532 /// which will be duplicated before any other args. Only EmitCall
4533 /// should be using this interface.
4535 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4537 ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4539 LocalTemporary [] temps = null;
4541 if (dup_args && top != 0)
4542 temps = new LocalTemporary [top];
4544 int argument_index = 0;
4546 for (int i = 0; i < top; i++){
4548 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4549 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4550 int params_args_count = arguments == null ?
4551 0 : arguments.Count - top + 1;
4553 // Fill not provided argument
4554 if (params_args_count <= 0) {
4555 ILGenerator ig = ec.ig;
4556 IntConstant.EmitInt (ig, 0);
4557 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4562 // Special case if we are passing the same data as the
4563 // params argument, we do not need to recreate an array.
4565 a = (Argument) arguments [argument_index];
4566 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4572 EmitParams (ec, arguments, i, params_args_count);
4573 argument_index += params_args_count;
4578 a = (Argument) arguments [argument_index++];
4581 ec.ig.Emit (OpCodes.Dup);
4582 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4587 if (this_arg != null)
4590 for (int i = 0; i < top; i ++) {
4591 temps [i].Emit (ec);
4592 temps [i].Release (ec);
4597 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4599 ParameterData pd = TypeManager.GetParameterData (mb);
4601 if (arguments == null)
4602 return new Type [0];
4604 Argument a = (Argument) arguments [pd.Count - 1];
4605 Arglist list = (Arglist) a.Expr;
4607 return list.ArgumentTypes;
4611 /// This checks the ConditionalAttribute on the method
4613 static bool IsMethodExcluded (MethodBase method)
4615 if (method.IsConstructor)
4618 IMethodData md = TypeManager.GetMethod (method);
4620 return md.IsExcluded ();
4622 // For some methods (generated by delegate class) GetMethod returns null
4623 // because they are not included in builder_to_method table
4624 if (method.DeclaringType is TypeBuilder)
4627 return AttributeTester.IsConditionalMethodExcluded (method);
4631 /// is_base tells whether we want to force the use of the `call'
4632 /// opcode instead of using callvirt. Call is required to call
4633 /// a specific method, while callvirt will always use the most
4634 /// recent method in the vtable.
4636 /// is_static tells whether this is an invocation on a static method
4638 /// instance_expr is an expression that represents the instance
4639 /// it must be non-null if is_static is false.
4641 /// method is the method to invoke.
4643 /// Arguments is the list of arguments to pass to the method or constructor.
4645 public static void EmitCall (EmitContext ec, bool is_base,
4646 Expression instance_expr,
4647 MethodBase method, ArrayList Arguments, Location loc)
4649 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4652 // `dup_args' leaves an extra copy of the arguments on the stack
4653 // `omit_args' does not leave any arguments at all.
4654 // So, basically, you could make one call with `dup_args' set to true,
4655 // and then another with `omit_args' set to true, and the two calls
4656 // would have the same set of arguments. However, each argument would
4657 // only have been evaluated once.
4658 public static void EmitCall (EmitContext ec, bool is_base,
4659 Expression instance_expr,
4660 MethodBase method, ArrayList Arguments, Location loc,
4661 bool dup_args, bool omit_args)
4663 ILGenerator ig = ec.ig;
4664 bool struct_call = false;
4665 bool this_call = false;
4666 LocalTemporary this_arg = null;
4668 Type decl_type = method.DeclaringType;
4670 if (!RootContext.StdLib) {
4671 // Replace any calls to the system's System.Array type with calls to
4672 // the newly created one.
4673 if (method == TypeManager.system_int_array_get_length)
4674 method = TypeManager.int_array_get_length;
4675 else if (method == TypeManager.system_int_array_get_rank)
4676 method = TypeManager.int_array_get_rank;
4677 else if (method == TypeManager.system_object_array_clone)
4678 method = TypeManager.object_array_clone;
4679 else if (method == TypeManager.system_int_array_get_length_int)
4680 method = TypeManager.int_array_get_length_int;
4681 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4682 method = TypeManager.int_array_get_lower_bound_int;
4683 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4684 method = TypeManager.int_array_get_upper_bound_int;
4685 else if (method == TypeManager.system_void_array_copyto_array_int)
4686 method = TypeManager.void_array_copyto_array_int;
4689 if (!ec.IsInObsoleteScope) {
4691 // This checks ObsoleteAttribute on the method and on the declaring type
4693 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4695 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4697 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4699 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4703 if (IsMethodExcluded (method))
4706 bool is_static = method.IsStatic;
4708 if (instance_expr == EmptyExpression.Null) {
4709 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4713 this_call = instance_expr is This;
4714 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4718 // If this is ourselves, push "this"
4722 Type iexpr_type = instance_expr.Type;
4725 // Push the instance expression
4727 if (TypeManager.IsValueType (iexpr_type)) {
4729 // Special case: calls to a function declared in a
4730 // reference-type with a value-type argument need
4731 // to have their value boxed.
4732 if (decl_type.IsValueType ||
4733 TypeManager.IsGenericParameter (iexpr_type)) {
4735 // If the expression implements IMemoryLocation, then
4736 // we can optimize and use AddressOf on the
4739 // If not we have to use some temporary storage for
4741 if (instance_expr is IMemoryLocation) {
4742 ((IMemoryLocation)instance_expr).
4743 AddressOf (ec, AddressOp.LoadStore);
4745 LocalTemporary temp = new LocalTemporary (iexpr_type);
4746 instance_expr.Emit (ec);
4748 temp.AddressOf (ec, AddressOp.Load);
4751 // avoid the overhead of doing this all the time.
4753 t = TypeManager.GetReferenceType (iexpr_type);
4755 instance_expr.Emit (ec);
4756 ig.Emit (OpCodes.Box, instance_expr.Type);
4757 t = TypeManager.object_type;
4760 instance_expr.Emit (ec);
4761 t = instance_expr.Type;
4765 ig.Emit (OpCodes.Dup);
4766 if (Arguments != null && Arguments.Count != 0) {
4767 this_arg = new LocalTemporary (t);
4768 this_arg.Store (ec);
4775 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4778 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4779 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4783 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4784 call_op = OpCodes.Call;
4786 call_op = OpCodes.Callvirt;
4788 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4789 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4790 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4797 // and DoFoo is not virtual, you can omit the callvirt,
4798 // because you don't need the null checking behavior.
4800 if (method is MethodInfo)
4801 ig.Emit (call_op, (MethodInfo) method);
4803 ig.Emit (call_op, (ConstructorInfo) method);
4806 public override void Emit (EmitContext ec)
4808 mg.EmitCall (ec, Arguments);
4811 public override void EmitStatement (EmitContext ec)
4816 // Pop the return value if there is one
4818 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4819 ec.ig.Emit (OpCodes.Pop);
4822 protected override void CloneTo (CloneContext clonectx, Expression t)
4824 Invocation target = (Invocation) t;
4826 if (Arguments != null) {
4827 target.Arguments = new ArrayList (Arguments.Count);
4828 foreach (Argument a in Arguments)
4829 target.Arguments.Add (a.Clone (clonectx));
4832 target.expr = expr.Clone (clonectx);
4836 public class InvocationOrCast : ExpressionStatement
4839 Expression argument;
4841 public InvocationOrCast (Expression expr, Expression argument)
4844 this.argument = argument;
4845 this.loc = expr.Location;
4848 public override Expression DoResolve (EmitContext ec)
4851 // First try to resolve it as a cast.
4853 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4854 if ((te != null) && (te.eclass == ExprClass.Type)) {
4855 Cast cast = new Cast (te, argument, loc);
4856 return cast.Resolve (ec);
4860 // This can either be a type or a delegate invocation.
4861 // Let's just resolve it and see what we'll get.
4863 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4868 // Ok, so it's a Cast.
4870 if (expr.eclass == ExprClass.Type) {
4871 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4872 return cast.Resolve (ec);
4876 // It's a delegate invocation.
4878 if (!TypeManager.IsDelegateType (expr.Type)) {
4879 Error (149, "Method name expected");
4883 ArrayList args = new ArrayList ();
4884 args.Add (new Argument (argument, Argument.AType.Expression));
4885 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4886 return invocation.Resolve (ec);
4889 public override ExpressionStatement ResolveStatement (EmitContext ec)
4892 // First try to resolve it as a cast.
4894 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4895 if ((te != null) && (te.eclass == ExprClass.Type)) {
4896 Error_InvalidExpressionStatement ();
4901 // This can either be a type or a delegate invocation.
4902 // Let's just resolve it and see what we'll get.
4904 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4905 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4906 Error_InvalidExpressionStatement ();
4911 // It's a delegate invocation.
4913 if (!TypeManager.IsDelegateType (expr.Type)) {
4914 Error (149, "Method name expected");
4918 ArrayList args = new ArrayList ();
4919 args.Add (new Argument (argument, Argument.AType.Expression));
4920 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4921 return invocation.ResolveStatement (ec);
4924 public override void Emit (EmitContext ec)
4926 throw new Exception ("Cannot happen");
4929 public override void EmitStatement (EmitContext ec)
4931 throw new Exception ("Cannot happen");
4934 protected override void CloneTo (CloneContext clonectx, Expression t)
4936 InvocationOrCast target = (InvocationOrCast) t;
4938 target.expr = expr.Clone (clonectx);
4939 target.argument = argument.Clone (clonectx);
4944 // This class is used to "disable" the code generation for the
4945 // temporary variable when initializing value types.
4947 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4948 public void AddressOf (EmitContext ec, AddressOp Mode)
4955 /// Implements the new expression
4957 public class New : ExpressionStatement, IMemoryLocation {
4958 ArrayList Arguments;
4961 // During bootstrap, it contains the RequestedType,
4962 // but if `type' is not null, it *might* contain a NewDelegate
4963 // (because of field multi-initialization)
4965 public Expression RequestedType;
4967 MethodGroupExpr method;
4970 // If set, the new expression is for a value_target, and
4971 // we will not leave anything on the stack.
4973 Expression value_target;
4974 bool value_target_set = false;
4975 bool is_type_parameter = false;
4977 public New (Expression requested_type, ArrayList arguments, Location l)
4979 RequestedType = requested_type;
4980 Arguments = arguments;
4984 public bool SetValueTypeVariable (Expression value)
4986 value_target = value;
4987 value_target_set = true;
4988 if (!(value_target is IMemoryLocation)){
4989 Error_UnexpectedKind (null, "variable", loc);
4996 // This function is used to disable the following code sequence for
4997 // value type initialization:
4999 // AddressOf (temporary)
5003 // Instead the provide will have provided us with the address on the
5004 // stack to store the results.
5006 static Expression MyEmptyExpression;
5008 public void DisableTemporaryValueType ()
5010 if (MyEmptyExpression == null)
5011 MyEmptyExpression = new EmptyAddressOf ();
5014 // To enable this, look into:
5015 // test-34 and test-89 and self bootstrapping.
5017 // For instance, we can avoid a copy by using `newobj'
5018 // instead of Call + Push-temp on value types.
5019 // value_target = MyEmptyExpression;
5024 /// Converts complex core type syntax like 'new int ()' to simple constant
5026 public static Constant Constantify (Type t)
5028 if (t == TypeManager.int32_type)
5029 return new IntConstant (0, Location.Null);
5030 if (t == TypeManager.uint32_type)
5031 return new UIntConstant (0, Location.Null);
5032 if (t == TypeManager.int64_type)
5033 return new LongConstant (0, Location.Null);
5034 if (t == TypeManager.uint64_type)
5035 return new ULongConstant (0, Location.Null);
5036 if (t == TypeManager.float_type)
5037 return new FloatConstant (0, Location.Null);
5038 if (t == TypeManager.double_type)
5039 return new DoubleConstant (0, Location.Null);
5040 if (t == TypeManager.short_type)
5041 return new ShortConstant (0, Location.Null);
5042 if (t == TypeManager.ushort_type)
5043 return new UShortConstant (0, Location.Null);
5044 if (t == TypeManager.sbyte_type)
5045 return new SByteConstant (0, Location.Null);
5046 if (t == TypeManager.byte_type)
5047 return new ByteConstant (0, Location.Null);
5048 if (t == TypeManager.char_type)
5049 return new CharConstant ('\0', Location.Null);
5050 if (t == TypeManager.bool_type)
5051 return new BoolConstant (false, Location.Null);
5052 if (t == TypeManager.decimal_type)
5053 return new DecimalConstant (0, Location.Null);
5054 if (TypeManager.IsEnumType (t))
5055 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5061 // Checks whether the type is an interface that has the
5062 // [ComImport, CoClass] attributes and must be treated
5065 public Expression CheckComImport (EmitContext ec)
5067 if (!type.IsInterface)
5071 // Turn the call into:
5072 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5074 Type real_class = AttributeTester.GetCoClassAttribute (type);
5075 if (real_class == null)
5078 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5079 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5080 return cast.Resolve (ec);
5083 public override Expression DoResolve (EmitContext ec)
5086 // The New DoResolve might be called twice when initializing field
5087 // expressions (see EmitFieldInitializers, the call to
5088 // GetInitializerExpression will perform a resolve on the expression,
5089 // and later the assign will trigger another resolution
5091 // This leads to bugs (#37014)
5094 if (RequestedType is NewDelegate)
5095 return RequestedType;
5099 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5105 if (type == TypeManager.void_type) {
5106 Error_VoidInvalidInTheContext (loc);
5110 if (Arguments == null) {
5111 Expression c = Constantify (type);
5116 if (TypeManager.IsDelegateType (type)) {
5117 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5118 if (RequestedType != null)
5119 if (!(RequestedType is DelegateCreation))
5120 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5121 return RequestedType;
5125 if (type.IsGenericParameter) {
5126 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5128 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5129 Error (304, String.Format (
5130 "Cannot create an instance of the " +
5131 "variable type '{0}' because it " +
5132 "doesn't have the new() constraint",
5137 if ((Arguments != null) && (Arguments.Count != 0)) {
5138 Error (417, String.Format (
5139 "`{0}': cannot provide arguments " +
5140 "when creating an instance of a " +
5141 "variable type.", type));
5145 is_type_parameter = true;
5146 eclass = ExprClass.Value;
5151 if (type.IsAbstract && type.IsSealed) {
5152 Report.SymbolRelatedToPreviousError (type);
5153 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5157 if (type.IsInterface || type.IsAbstract){
5158 if (!TypeManager.IsGenericType (type)) {
5159 RequestedType = CheckComImport (ec);
5160 if (RequestedType != null)
5161 return RequestedType;
5164 Report.SymbolRelatedToPreviousError (type);
5165 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5169 bool is_struct = type.IsValueType;
5170 eclass = ExprClass.Value;
5173 // SRE returns a match for .ctor () on structs (the object constructor),
5174 // so we have to manually ignore it.
5176 if (is_struct && Arguments == null)
5179 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5180 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5181 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5186 method = ml as MethodGroupExpr;
5188 if (method == null) {
5189 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5193 if (Arguments != null){
5194 foreach (Argument a in Arguments){
5195 if (!a.Resolve (ec, loc))
5200 method = method.OverloadResolve (ec, Arguments, false, loc);
5201 if (method == null) {
5202 if (almostMatchedMembers.Count != 0)
5203 MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5210 bool DoEmitTypeParameter (EmitContext ec)
5213 ILGenerator ig = ec.ig;
5214 // IMemoryLocation ml;
5216 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5217 new Type [] { type });
5219 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5220 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5221 ig.Emit (OpCodes.Call, ci);
5225 // Allow DoEmit() to be called multiple times.
5226 // We need to create a new LocalTemporary each time since
5227 // you can't share LocalBuilders among ILGeneators.
5228 LocalTemporary temp = new LocalTemporary (type);
5230 Label label_activator = ig.DefineLabel ();
5231 Label label_end = ig.DefineLabel ();
5233 temp.AddressOf (ec, AddressOp.Store);
5234 ig.Emit (OpCodes.Initobj, type);
5237 ig.Emit (OpCodes.Box, type);
5238 ig.Emit (OpCodes.Brfalse, label_activator);
5240 temp.AddressOf (ec, AddressOp.Store);
5241 ig.Emit (OpCodes.Initobj, type);
5243 ig.Emit (OpCodes.Br, label_end);
5245 ig.MarkLabel (label_activator);
5247 ig.Emit (OpCodes.Call, ci);
5248 ig.MarkLabel (label_end);
5251 throw new InternalErrorException ();
5256 // This DoEmit can be invoked in two contexts:
5257 // * As a mechanism that will leave a value on the stack (new object)
5258 // * As one that wont (init struct)
5260 // You can control whether a value is required on the stack by passing
5261 // need_value_on_stack. The code *might* leave a value on the stack
5262 // so it must be popped manually
5264 // If we are dealing with a ValueType, we have a few
5265 // situations to deal with:
5267 // * The target is a ValueType, and we have been provided
5268 // the instance (this is easy, we are being assigned).
5270 // * The target of New is being passed as an argument,
5271 // to a boxing operation or a function that takes a
5274 // In this case, we need to create a temporary variable
5275 // that is the argument of New.
5277 // Returns whether a value is left on the stack
5279 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5281 bool is_value_type = TypeManager.IsValueType (type);
5282 ILGenerator ig = ec.ig;
5287 // Allow DoEmit() to be called multiple times.
5288 // We need to create a new LocalTemporary each time since
5289 // you can't share LocalBuilders among ILGeneators.
5290 if (!value_target_set)
5291 value_target = new LocalTemporary (type);
5293 ml = (IMemoryLocation) value_target;
5294 ml.AddressOf (ec, AddressOp.Store);
5298 method.EmitArguments (ec, Arguments);
5302 ig.Emit (OpCodes.Initobj, type);
5304 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5305 if (need_value_on_stack){
5306 value_target.Emit (ec);
5311 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5316 public override void Emit (EmitContext ec)
5318 if (is_type_parameter)
5319 DoEmitTypeParameter (ec);
5324 public override void EmitStatement (EmitContext ec)
5326 bool value_on_stack;
5328 if (is_type_parameter)
5329 value_on_stack = DoEmitTypeParameter (ec);
5331 value_on_stack = DoEmit (ec, false);
5334 ec.ig.Emit (OpCodes.Pop);
5338 public void AddressOf (EmitContext ec, AddressOp Mode)
5340 if (is_type_parameter) {
5341 LocalTemporary temp = new LocalTemporary (type);
5342 DoEmitTypeParameter (ec);
5344 temp.AddressOf (ec, Mode);
5348 if (!type.IsValueType){
5350 // We throw an exception. So far, I believe we only need to support
5352 // foreach (int j in new StructType ())
5355 throw new Exception ("AddressOf should not be used for classes");
5358 if (!value_target_set)
5359 value_target = new LocalTemporary (type);
5360 IMemoryLocation ml = (IMemoryLocation) value_target;
5362 ml.AddressOf (ec, AddressOp.Store);
5363 if (method == null) {
5364 ec.ig.Emit (OpCodes.Initobj, type);
5366 method.EmitArguments (ec, Arguments);
5367 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5370 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5373 protected override void CloneTo (CloneContext clonectx, Expression t)
5375 New target = (New) t;
5377 target.RequestedType = RequestedType.Clone (clonectx);
5378 if (Arguments != null){
5379 target.Arguments = new ArrayList ();
5380 foreach (Argument a in Arguments){
5381 target.Arguments.Add (a.Clone (clonectx));
5388 /// 14.5.10.2: Represents an array creation expression.
5392 /// There are two possible scenarios here: one is an array creation
5393 /// expression that specifies the dimensions and optionally the
5394 /// initialization data and the other which does not need dimensions
5395 /// specified but where initialization data is mandatory.
5397 public class ArrayCreation : Expression {
5398 Expression requested_base_type;
5399 ArrayList initializers;
5402 // The list of Argument types.
5403 // This is used to construct the `newarray' or constructor signature
5405 protected ArrayList arguments;
5407 protected Type array_element_type;
5408 bool expect_initializers = false;
5409 int num_arguments = 0;
5410 protected int dimensions;
5411 protected readonly string rank;
5413 protected ArrayList array_data;
5417 // The number of constants in array initializers
5418 int const_initializers_count;
5419 bool only_constant_initializers;
5421 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5423 this.requested_base_type = requested_base_type;
5424 this.initializers = initializers;
5428 arguments = new ArrayList ();
5430 foreach (Expression e in exprs) {
5431 arguments.Add (new Argument (e, Argument.AType.Expression));
5436 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5438 this.requested_base_type = requested_base_type;
5439 this.initializers = initializers;
5443 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5445 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5447 //dimensions = tmp.Length - 1;
5448 expect_initializers = true;
5451 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5453 StringBuilder sb = new StringBuilder (rank);
5456 for (int i = 1; i < idx_count; i++)
5461 return new ComposedCast (base_type, sb.ToString (), loc);
5464 void Error_IncorrectArrayInitializer ()
5466 Error (178, "Invalid rank specifier: expected `,' or `]'");
5469 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5471 if (specified_dims) {
5472 Argument a = (Argument) arguments [idx];
5474 if (!a.Resolve (ec, loc))
5477 Constant c = a.Expr as Constant;
5479 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5483 Report.Error (150, a.Expr.Location, "A constant value is expected");
5487 int value = (int) c.GetValue ();
5489 if (value != probe.Count) {
5490 Error_IncorrectArrayInitializer ();
5494 bounds [idx] = value;
5497 int child_bounds = -1;
5498 only_constant_initializers = true;
5499 for (int i = 0; i < probe.Count; ++i) {
5500 object o = probe [i];
5501 if (o is ArrayList) {
5502 ArrayList sub_probe = o as ArrayList;
5503 int current_bounds = sub_probe.Count;
5505 if (child_bounds == -1)
5506 child_bounds = current_bounds;
5508 else if (child_bounds != current_bounds){
5509 Error_IncorrectArrayInitializer ();
5512 if (idx + 1 >= dimensions){
5513 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5517 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5521 if (child_bounds != -1){
5522 Error_IncorrectArrayInitializer ();
5526 Expression element = ResolveArrayElement (ec, (Expression) o);
5527 if (element == null)
5530 // Initializers with the default values can be ignored
5531 Constant c = element as Constant;
5533 if (c.IsDefaultInitializer (array_element_type)) {
5537 ++const_initializers_count;
5540 only_constant_initializers = false;
5543 array_data.Add (element);
5550 public void UpdateIndices ()
5553 for (ArrayList probe = initializers; probe != null;) {
5554 if (probe.Count > 0 && probe [0] is ArrayList) {
5555 Expression e = new IntConstant (probe.Count, Location.Null);
5556 arguments.Add (new Argument (e, Argument.AType.Expression));
5558 bounds [i++] = probe.Count;
5560 probe = (ArrayList) probe [0];
5563 Expression e = new IntConstant (probe.Count, Location.Null);
5564 arguments.Add (new Argument (e, Argument.AType.Expression));
5566 bounds [i++] = probe.Count;
5573 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5575 element = element.Resolve (ec);
5576 if (element == null)
5579 return Convert.ImplicitConversionRequired (
5580 ec, element, array_element_type, loc);
5583 protected bool ResolveInitializers (EmitContext ec)
5585 if (initializers == null) {
5586 return !expect_initializers;
5590 // We use this to store all the date values in the order in which we
5591 // will need to store them in the byte blob later
5593 array_data = new ArrayList ();
5594 bounds = new System.Collections.Specialized.HybridDictionary ();
5596 if (arguments != null)
5597 return CheckIndices (ec, initializers, 0, true);
5599 arguments = new ArrayList ();
5601 if (!CheckIndices (ec, initializers, 0, false))
5610 // Resolved the type of the array
5612 bool ResolveArrayType (EmitContext ec)
5614 if (requested_base_type == null) {
5615 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5619 StringBuilder array_qualifier = new StringBuilder (rank);
5622 // `In the first form allocates an array instace of the type that results
5623 // from deleting each of the individual expression from the expression list'
5625 if (num_arguments > 0) {
5626 array_qualifier.Append ("[");
5627 for (int i = num_arguments-1; i > 0; i--)
5628 array_qualifier.Append (",");
5629 array_qualifier.Append ("]");
5635 TypeExpr array_type_expr;
5636 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5637 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5638 if (array_type_expr == null)
5641 type = array_type_expr.Type;
5642 array_element_type = TypeManager.GetElementType (type);
5643 dimensions = type.GetArrayRank ();
5648 public override Expression DoResolve (EmitContext ec)
5653 if (!ResolveArrayType (ec))
5656 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5657 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5658 TypeManager.CSharpName (array_element_type));
5662 // First step is to validate the initializers and fill
5663 // in any missing bits
5665 if (!ResolveInitializers (ec))
5668 if (arguments.Count != dimensions) {
5669 Error_IncorrectArrayInitializer ();
5672 foreach (Argument a in arguments){
5673 if (!a.Resolve (ec, loc))
5676 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5677 if (real_arg == null)
5683 eclass = ExprClass.Value;
5687 MethodInfo GetArrayMethod (int arguments)
5689 ModuleBuilder mb = CodeGen.Module.Builder;
5691 Type[] arg_types = new Type[arguments];
5692 for (int i = 0; i < arguments; i++)
5693 arg_types[i] = TypeManager.int32_type;
5695 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5699 Report.Error (-6, "New invocation: Can not find a constructor for " +
5700 "this argument list");
5707 byte [] MakeByteBlob ()
5712 int count = array_data.Count;
5714 if (array_element_type.IsEnum)
5715 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5717 factor = GetTypeSize (array_element_type);
5719 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5721 data = new byte [(count * factor + 4) & ~3];
5724 for (int i = 0; i < count; ++i) {
5725 object v = array_data [i];
5727 if (v is EnumConstant)
5728 v = ((EnumConstant) v).Child;
5730 if (v is Constant && !(v is StringConstant))
5731 v = ((Constant) v).GetValue ();
5737 if (array_element_type == TypeManager.int64_type){
5738 if (!(v is Expression)){
5739 long val = (long) v;
5741 for (int j = 0; j < factor; ++j) {
5742 data [idx + j] = (byte) (val & 0xFF);
5746 } else if (array_element_type == TypeManager.uint64_type){
5747 if (!(v is Expression)){
5748 ulong val = (ulong) v;
5750 for (int j = 0; j < factor; ++j) {
5751 data [idx + j] = (byte) (val & 0xFF);
5755 } else if (array_element_type == TypeManager.float_type) {
5756 if (!(v is Expression)){
5757 element = BitConverter.GetBytes ((float) v);
5759 for (int j = 0; j < factor; ++j)
5760 data [idx + j] = element [j];
5761 if (!BitConverter.IsLittleEndian)
5762 System.Array.Reverse (data, idx, 4);
5764 } else if (array_element_type == TypeManager.double_type) {
5765 if (!(v is Expression)){
5766 element = BitConverter.GetBytes ((double) v);
5768 for (int j = 0; j < factor; ++j)
5769 data [idx + j] = element [j];
5771 // FIXME: Handle the ARM float format.
5772 if (!BitConverter.IsLittleEndian)
5773 System.Array.Reverse (data, idx, 8);
5775 } else if (array_element_type == TypeManager.char_type){
5776 if (!(v is Expression)){
5777 int val = (int) ((char) v);
5779 data [idx] = (byte) (val & 0xff);
5780 data [idx+1] = (byte) (val >> 8);
5782 } else if (array_element_type == TypeManager.short_type){
5783 if (!(v is Expression)){
5784 int val = (int) ((short) v);
5786 data [idx] = (byte) (val & 0xff);
5787 data [idx+1] = (byte) (val >> 8);
5789 } else if (array_element_type == TypeManager.ushort_type){
5790 if (!(v is Expression)){
5791 int val = (int) ((ushort) v);
5793 data [idx] = (byte) (val & 0xff);
5794 data [idx+1] = (byte) (val >> 8);
5796 } else if (array_element_type == TypeManager.int32_type) {
5797 if (!(v is Expression)){
5800 data [idx] = (byte) (val & 0xff);
5801 data [idx+1] = (byte) ((val >> 8) & 0xff);
5802 data [idx+2] = (byte) ((val >> 16) & 0xff);
5803 data [idx+3] = (byte) (val >> 24);
5805 } else if (array_element_type == TypeManager.uint32_type) {
5806 if (!(v is Expression)){
5807 uint val = (uint) v;
5809 data [idx] = (byte) (val & 0xff);
5810 data [idx+1] = (byte) ((val >> 8) & 0xff);
5811 data [idx+2] = (byte) ((val >> 16) & 0xff);
5812 data [idx+3] = (byte) (val >> 24);
5814 } else if (array_element_type == TypeManager.sbyte_type) {
5815 if (!(v is Expression)){
5816 sbyte val = (sbyte) v;
5817 data [idx] = (byte) val;
5819 } else if (array_element_type == TypeManager.byte_type) {
5820 if (!(v is Expression)){
5821 byte val = (byte) v;
5822 data [idx] = (byte) val;
5824 } else if (array_element_type == TypeManager.bool_type) {
5825 if (!(v is Expression)){
5826 bool val = (bool) v;
5827 data [idx] = (byte) (val ? 1 : 0);
5829 } else if (array_element_type == TypeManager.decimal_type){
5830 if (!(v is Expression)){
5831 int [] bits = Decimal.GetBits ((decimal) v);
5834 // FIXME: For some reason, this doesn't work on the MS runtime.
5835 int [] nbits = new int [4];
5836 nbits [0] = bits [3];
5837 nbits [1] = bits [2];
5838 nbits [2] = bits [0];
5839 nbits [3] = bits [1];
5841 for (int j = 0; j < 4; j++){
5842 data [p++] = (byte) (nbits [j] & 0xff);
5843 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5844 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5845 data [p++] = (byte) (nbits [j] >> 24);
5849 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5858 // Emits the initializers for the array
5860 void EmitStaticInitializers (EmitContext ec)
5863 // First, the static data
5866 ILGenerator ig = ec.ig;
5868 byte [] data = MakeByteBlob ();
5870 fb = RootContext.MakeStaticData (data);
5872 ig.Emit (OpCodes.Dup);
5873 ig.Emit (OpCodes.Ldtoken, fb);
5874 ig.Emit (OpCodes.Call,
5875 TypeManager.void_initializearray_array_fieldhandle);
5879 // Emits pieces of the array that can not be computed at compile
5880 // time (variables and string locations).
5882 // This always expect the top value on the stack to be the array
5884 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5886 ILGenerator ig = ec.ig;
5887 int dims = bounds.Count;
5888 int [] current_pos = new int [dims];
5890 MethodInfo set = null;
5893 Type [] args = new Type [dims + 1];
5895 for (int j = 0; j < dims; j++)
5896 args [j] = TypeManager.int32_type;
5897 args [dims] = array_element_type;
5899 set = CodeGen.Module.Builder.GetArrayMethod (
5901 CallingConventions.HasThis | CallingConventions.Standard,
5902 TypeManager.void_type, args);
5905 for (int i = 0; i < array_data.Count; i++){
5907 Expression e = (Expression)array_data [i];
5909 // Constant can be initialized via StaticInitializer
5910 if (e != null && !(!emitConstants && e is Constant)) {
5911 Type etype = e.Type;
5913 ig.Emit (OpCodes.Dup);
5915 for (int idx = 0; idx < dims; idx++)
5916 IntConstant.EmitInt (ig, current_pos [idx]);
5919 // If we are dealing with a struct, get the
5920 // address of it, so we can store it.
5922 if ((dims == 1) && etype.IsValueType &&
5923 (!TypeManager.IsBuiltinOrEnum (etype) ||
5924 etype == TypeManager.decimal_type)) {
5929 // Let new know that we are providing
5930 // the address where to store the results
5932 n.DisableTemporaryValueType ();
5935 ig.Emit (OpCodes.Ldelema, etype);
5941 bool is_stobj, has_type_arg;
5942 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5944 ig.Emit (OpCodes.Stobj, etype);
5945 else if (has_type_arg)
5946 ig.Emit (op, etype);
5950 ig.Emit (OpCodes.Call, set);
5957 for (int j = dims - 1; j >= 0; j--){
5959 if (current_pos [j] < (int) bounds [j])
5961 current_pos [j] = 0;
5966 void EmitArrayArguments (EmitContext ec)
5968 ILGenerator ig = ec.ig;
5970 foreach (Argument a in arguments) {
5971 Type atype = a.Type;
5974 if (atype == TypeManager.uint64_type)
5975 ig.Emit (OpCodes.Conv_Ovf_U4);
5976 else if (atype == TypeManager.int64_type)
5977 ig.Emit (OpCodes.Conv_Ovf_I4);
5981 public override void Emit (EmitContext ec)
5983 ILGenerator ig = ec.ig;
5985 EmitArrayArguments (ec);
5986 if (arguments.Count == 1)
5987 ig.Emit (OpCodes.Newarr, array_element_type);
5989 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5992 if (initializers == null)
5995 // Emit static initializer for arrays which have contain more than 4 items and
5996 // the static initializer will initialize at least 25% of array values.
5997 // NOTE: const_initializers_count does not contain default constant values.
5998 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5999 TypeManager.IsPrimitiveType (array_element_type)) {
6000 EmitStaticInitializers (ec);
6002 if (!only_constant_initializers)
6003 EmitDynamicInitializers (ec, false);
6005 EmitDynamicInitializers (ec, true);
6009 public override bool GetAttributableValue (Type valueType, out object value)
6011 if (arguments.Count != 1) {
6012 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6013 return base.GetAttributableValue (null, out value);
6016 if (array_data == null) {
6017 Constant c = (Constant)((Argument)arguments [0]).Expr;
6018 if (c.IsDefaultValue) {
6019 value = Array.CreateInstance (array_element_type, 0);
6022 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6023 return base.GetAttributableValue (null, out value);
6026 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6027 object element_value;
6028 for (int i = 0; i < ret.Length; ++i)
6030 Expression e = (Expression)array_data [i];
6032 // Is null when an initializer is optimized (value == predefined value)
6036 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6040 ret.SetValue (element_value, i);
6046 protected override void CloneTo (CloneContext clonectx, Expression t)
6048 ArrayCreation target = (ArrayCreation) t;
6050 target.requested_base_type = requested_base_type.Clone (clonectx);
6051 target.arguments = new ArrayList ();
6052 foreach (Argument a in arguments)
6053 target.arguments.Add (a.Clone (clonectx));
6055 if (initializers != null){
6056 target.initializers = new ArrayList ();
6057 foreach (Expression initializer in initializers)
6058 target.initializers.Add (initializer.Clone (clonectx));
6064 // Represents an implicitly typed array epxression
6066 public class ImplicitlyTypedArrayCreation : ArrayCreation
6068 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6069 : base (null, rank, initializers, loc)
6071 if (rank.Length > 2) {
6072 while (rank [++dimensions] == ',');
6078 public override Expression DoResolve (EmitContext ec)
6083 if (!ResolveInitializers (ec))
6086 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6087 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6088 arguments.Count != dimensions) {
6089 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6094 // At this point we found common base type for all initializer elements
6095 // but we have to be sure that all static initializer elements are of
6098 UnifyInitializerElement (ec);
6100 type = TypeManager.GetConstructedType (array_element_type, rank);
6101 eclass = ExprClass.Value;
6106 // Converts static initializer only
6108 void UnifyInitializerElement (EmitContext ec)
6110 for (int i = 0; i < array_data.Count; ++i) {
6111 Expression e = (Expression)array_data[i];
6113 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6117 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6119 element = element.Resolve (ec);
6120 if (element == null)
6123 if (array_element_type == null) {
6124 array_element_type = element.Type;
6128 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6132 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6133 array_element_type = element.Type;
6137 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6142 public sealed class CompilerGeneratedThis : This
6144 public static This Instance = new CompilerGeneratedThis ();
6146 private CompilerGeneratedThis ()
6147 : base (Location.Null)
6151 public override Expression DoResolve (EmitContext ec)
6153 eclass = ExprClass.Variable;
6154 type = ec.ContainerType;
6155 variable = new SimpleThis (type);
6161 /// Represents the `this' construct
6164 public class This : VariableReference, IVariable
6167 VariableInfo variable_info;
6168 protected Variable variable;
6171 public This (Block block, Location loc)
6177 public This (Location loc)
6182 public VariableInfo VariableInfo {
6183 get { return variable_info; }
6186 public bool VerifyFixed ()
6188 return !TypeManager.IsValueType (Type);
6191 public override bool IsRef {
6192 get { return is_struct; }
6195 public override Variable Variable {
6196 get { return variable; }
6199 public bool ResolveBase (EmitContext ec)
6201 eclass = ExprClass.Variable;
6203 if (ec.TypeContainer.CurrentType != null)
6204 type = ec.TypeContainer.CurrentType;
6206 type = ec.ContainerType;
6208 is_struct = ec.TypeContainer is Struct;
6211 Error (26, "Keyword `this' is not valid in a static property, " +
6212 "static method, or static field initializer");
6216 if (block != null) {
6217 if (block.Toplevel.ThisVariable != null)
6218 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6220 AnonymousContainer am = ec.CurrentAnonymousMethod;
6221 if (is_struct && (am != null) && !am.IsIterator) {
6222 Report.Error (1673, loc, "Anonymous methods inside structs " +
6223 "cannot access instance members of `this'. " +
6224 "Consider copying `this' to a local variable " +
6225 "outside the anonymous method and using the " +
6230 RootScopeInfo host = block.Toplevel.RootScope;
6231 if ((host != null) && !ec.IsConstructor &&
6232 (!is_struct || host.IsIterator)) {
6233 variable = host.CaptureThis ();
6234 type = variable.Type;
6239 if (variable == null)
6240 variable = new SimpleThis (type);
6246 // Called from Invocation to check if the invocation is correct
6248 public bool CheckThisUsage (EmitContext ec)
6250 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6251 !variable_info.IsAssigned (ec)) {
6252 Error (188, "The `this' object cannot be used before all of its " +
6253 "fields are assigned to");
6254 variable_info.SetAssigned (ec);
6261 public override Expression DoResolve (EmitContext ec)
6263 if (!ResolveBase (ec))
6267 if (ec.IsFieldInitializer) {
6268 Error (27, "Keyword `this' is not available in the current context");
6275 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6277 if (!ResolveBase (ec))
6280 if (variable_info != null)
6281 variable_info.SetAssigned (ec);
6283 if (ec.TypeContainer is Class){
6284 Error (1604, "Cannot assign to 'this' because it is read-only");
6290 public override int GetHashCode()
6292 return block.GetHashCode ();
6295 public override bool Equals (object obj)
6297 This t = obj as This;
6301 return block == t.block;
6304 protected class SimpleThis : Variable
6308 public SimpleThis (Type type)
6313 public override Type Type {
6314 get { return type; }
6317 public override bool HasInstance {
6318 get { return false; }
6321 public override bool NeedsTemporary {
6322 get { return false; }
6325 public override void EmitInstance (EmitContext ec)
6330 public override void Emit (EmitContext ec)
6332 ec.ig.Emit (OpCodes.Ldarg_0);
6335 public override void EmitAssign (EmitContext ec)
6337 throw new InvalidOperationException ();
6340 public override void EmitAddressOf (EmitContext ec)
6342 ec.ig.Emit (OpCodes.Ldarg_0);
6346 protected override void CloneTo (CloneContext clonectx, Expression t)
6348 This target = (This) t;
6350 target.block = clonectx.LookupBlock (block);
6355 /// Represents the `__arglist' construct
6357 public class ArglistAccess : Expression
6359 public ArglistAccess (Location loc)
6364 public override Expression DoResolve (EmitContext ec)
6366 eclass = ExprClass.Variable;
6367 type = TypeManager.runtime_argument_handle_type;
6369 if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6371 Error (190, "The __arglist construct is valid only within " +
6372 "a variable argument method");
6379 public override void Emit (EmitContext ec)
6381 ec.ig.Emit (OpCodes.Arglist);
6384 protected override void CloneTo (CloneContext clonectx, Expression target)
6391 /// Represents the `__arglist (....)' construct
6393 public class Arglist : Expression
6395 Argument[] Arguments;
6397 public Arglist (Location loc)
6398 : this (Argument.Empty, loc)
6402 public Arglist (Argument[] args, Location l)
6408 public Type[] ArgumentTypes {
6410 Type[] retval = new Type [Arguments.Length];
6411 for (int i = 0; i < Arguments.Length; i++)
6412 retval [i] = Arguments [i].Type;
6417 public override Expression DoResolve (EmitContext ec)
6419 eclass = ExprClass.Variable;
6420 type = TypeManager.runtime_argument_handle_type;
6422 foreach (Argument arg in Arguments) {
6423 if (!arg.Resolve (ec, loc))
6430 public override void Emit (EmitContext ec)
6432 foreach (Argument arg in Arguments)
6436 protected override void CloneTo (CloneContext clonectx, Expression t)
6438 Arglist target = (Arglist) t;
6440 target.Arguments = new Argument [Arguments.Length];
6441 for (int i = 0; i < Arguments.Length; i++)
6442 target.Arguments [i] = Arguments [i].Clone (clonectx);
6447 // This produces the value that renders an instance, used by the iterators code
6449 public class ProxyInstance : Expression, IMemoryLocation {
6450 public override Expression DoResolve (EmitContext ec)
6452 eclass = ExprClass.Variable;
6453 type = ec.ContainerType;
6457 public override void Emit (EmitContext ec)
6459 ec.ig.Emit (OpCodes.Ldarg_0);
6463 public void AddressOf (EmitContext ec, AddressOp mode)
6465 ec.ig.Emit (OpCodes.Ldarg_0);
6470 /// Implements the typeof operator
6472 public class TypeOf : Expression {
6473 Expression QueriedType;
6474 protected Type typearg;
6476 public TypeOf (Expression queried_type, Location l)
6478 QueriedType = queried_type;
6482 public override Expression DoResolve (EmitContext ec)
6484 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6488 typearg = texpr.Type;
6490 if (typearg == TypeManager.void_type) {
6491 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6495 if (typearg.IsPointer && !ec.InUnsafe){
6500 type = TypeManager.type_type;
6501 // Even though what is returned is a type object, it's treated as a value by the compiler.
6502 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6503 eclass = ExprClass.Value;
6507 public override void Emit (EmitContext ec)
6509 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6510 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6513 public override bool GetAttributableValue (Type valueType, out object value)
6515 if (TypeManager.ContainsGenericParameters (typearg)) {
6516 Report.SymbolRelatedToPreviousError(typearg);
6517 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6518 TypeManager.CSharpName(typearg));
6523 if (valueType == TypeManager.object_type) {
6524 value = (object)typearg;
6531 public Type TypeArgument
6539 protected override void CloneTo (CloneContext clonectx, Expression t)
6541 TypeOf target = (TypeOf) t;
6543 target.QueriedType = QueriedType.Clone (clonectx);
6548 /// Implements the `typeof (void)' operator
6550 public class TypeOfVoid : TypeOf {
6551 public TypeOfVoid (Location l) : base (null, l)
6556 public override Expression DoResolve (EmitContext ec)
6558 type = TypeManager.type_type;
6559 typearg = TypeManager.void_type;
6560 // See description in TypeOf.
6561 eclass = ExprClass.Value;
6567 /// Implements the sizeof expression
6569 public class SizeOf : Expression {
6570 readonly Expression QueriedType;
6573 public SizeOf (Expression queried_type, Location l)
6575 this.QueriedType = queried_type;
6579 public override Expression DoResolve (EmitContext ec)
6581 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6586 if (texpr is TypeParameterExpr){
6587 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6592 type_queried = texpr.Type;
6593 if (type_queried.IsEnum)
6594 type_queried = TypeManager.EnumToUnderlying (type_queried);
6596 if (type_queried == TypeManager.void_type) {
6597 Expression.Error_VoidInvalidInTheContext (loc);
6601 int size_of = GetTypeSize (type_queried);
6603 return new IntConstant (size_of, loc);
6607 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)",
6608 TypeManager.CSharpName (type_queried));
6612 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6616 type = TypeManager.int32_type;
6617 eclass = ExprClass.Value;
6621 public override void Emit (EmitContext ec)
6623 int size = GetTypeSize (type_queried);
6626 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6628 IntConstant.EmitInt (ec.ig, size);
6631 protected override void CloneTo (CloneContext clonectx, Expression t)
6637 /// Implements the qualified-alias-member (::) expression.
6639 public class QualifiedAliasMember : Expression
6641 string alias, identifier;
6643 public QualifiedAliasMember (string alias, string identifier, Location l)
6645 if (RootContext.Version == LanguageVersion.ISO_1)
6646 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6649 this.identifier = identifier;
6653 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6655 if (alias == "global")
6656 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6658 int errors = Report.Errors;
6659 FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6661 if (errors == Report.Errors)
6662 Report.Error (432, loc, "Alias `{0}' not found", alias);
6665 if (fne.eclass != ExprClass.Namespace) {
6667 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6670 return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6673 public override Expression DoResolve (EmitContext ec)
6675 FullNamedExpression fne;
6676 if (alias == "global") {
6677 fne = RootNamespace.Global;
6679 int errors = Report.Errors;
6680 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6682 if (errors == Report.Errors)
6683 Report.Error (432, loc, "Alias `{0}' not found", alias);
6688 Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6692 if (!(retval is FullNamedExpression)) {
6693 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6697 // We defer this check till the end to match the behaviour of CSC
6698 if (fne.eclass != ExprClass.Namespace) {
6699 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6705 public override void Emit (EmitContext ec)
6707 throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6711 public override string ToString ()
6713 return alias + "::" + identifier;
6716 public override string GetSignatureForError ()
6721 protected override void CloneTo (CloneContext clonectx, Expression t)
6728 /// Implements the member access expression
6730 public class MemberAccess : Expression {
6731 public readonly string Identifier;
6733 readonly TypeArguments args;
6735 public MemberAccess (Expression expr, string id)
6736 : this (expr, id, expr.Location)
6740 public MemberAccess (Expression expr, string identifier, Location loc)
6743 Identifier = identifier;
6747 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6748 : this (expr, identifier, loc)
6753 protected string LookupIdentifier {
6754 get { return MemberName.MakeName (Identifier, args); }
6757 // TODO: this method has very poor performace for Enum fields and
6758 // probably for other constants as well
6759 Expression DoResolve (EmitContext ec, Expression right_side)
6762 throw new Exception ();
6765 // Resolve the expression with flow analysis turned off, we'll do the definite
6766 // assignment checks later. This is because we don't know yet what the expression
6767 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6768 // definite assignment check on the actual field and not on the whole struct.
6771 SimpleName original = expr as SimpleName;
6772 Expression expr_resolved = expr.Resolve (ec,
6773 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6774 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6776 if (expr_resolved == null)
6779 if (expr_resolved is Namespace) {
6780 Namespace ns = (Namespace) expr_resolved;
6781 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6783 if ((retval != null) && (args != null))
6784 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6788 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6792 Type expr_type = expr_resolved.Type;
6793 if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6794 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6797 if (expr_type == TypeManager.anonymous_method_type){
6798 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6802 Constant c = expr_resolved as Constant;
6803 if (c != null && c.GetValue () == null) {
6804 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6805 "System.NullReferenceException");
6808 Expression member_lookup;
6809 member_lookup = MemberLookup (
6810 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6812 if ((member_lookup == null) && (args != null)) {
6813 member_lookup = MemberLookup (
6814 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6817 if (member_lookup == null) {
6818 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6819 if (ex_method_lookup != null) {
6820 ex_method_lookup.ExtensionExpression = expr_resolved;
6821 return ex_method_lookup.DoResolve (ec);
6824 if (!ec.IsInProbingMode)
6825 MemberLookupFailed (
6826 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6830 TypeExpr texpr = member_lookup as TypeExpr;
6831 if (texpr != null) {
6832 if (!(expr_resolved is TypeExpr) &&
6833 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6834 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6835 Identifier, member_lookup.GetSignatureForError ());
6839 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6840 Report.SymbolRelatedToPreviousError (member_lookup.Type);
6841 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6846 ConstructedType ct = expr_resolved as ConstructedType;
6849 // When looking up a nested type in a generic instance
6850 // via reflection, we always get a generic type definition
6851 // and not a generic instance - so we have to do this here.
6853 // See gtest-172-lib.cs and gtest-172.cs for an example.
6855 ct = new ConstructedType (
6856 member_lookup.Type, ct.TypeArguments, loc);
6858 return ct.ResolveAsTypeStep (ec, false);
6861 return member_lookup;
6864 MemberExpr me = (MemberExpr) member_lookup;
6865 member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6866 if (member_lookup == null)
6870 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6872 throw new InternalErrorException ();
6874 return mg.ResolveGeneric (ec, args);
6877 if (original != null && !TypeManager.IsValueType (expr_type)) {
6878 me = member_lookup as MemberExpr;
6879 if (me != null && me.IsInstance) {
6880 LocalVariableReference var = expr_resolved as LocalVariableReference;
6881 if (var != null && !var.VerifyAssigned (ec))
6886 // The following DoResolve/DoResolveLValue will do the definite assignment
6889 if (right_side != null)
6890 return member_lookup.DoResolveLValue (ec, right_side);
6892 return member_lookup.DoResolve (ec);
6895 public override Expression DoResolve (EmitContext ec)
6897 return DoResolve (ec, null);
6900 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6902 return DoResolve (ec, right_side);
6905 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6907 return ResolveNamespaceOrType (ec, silent);
6910 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6912 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6914 if (new_expr == null)
6917 if (new_expr is Namespace) {
6918 Namespace ns = (Namespace) new_expr;
6919 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6921 if ((retval != null) && (args != null))
6922 retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6924 if (!silent && retval == null)
6925 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6929 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6930 if (tnew_expr == null)
6933 Type expr_type = tnew_expr.Type;
6935 if (expr_type.IsPointer){
6936 Error (23, "The `.' operator can not be applied to pointer operands (" +
6937 TypeManager.CSharpName (expr_type) + ")");
6941 Expression member_lookup = MemberLookup (
6942 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6943 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6944 if (member_lookup == null) {
6948 member_lookup = MemberLookup(
6949 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6950 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6952 if (member_lookup == null) {
6953 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6954 Identifier, new_expr.GetSignatureForError ());
6956 // TODO: Report.SymbolRelatedToPreviousError
6957 member_lookup.Error_UnexpectedKind (null, "type", loc);
6962 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6967 TypeArguments the_args = args;
6968 if (TypeManager.HasGenericArguments (expr_type)) {
6969 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6971 TypeArguments new_args = new TypeArguments (loc);
6972 foreach (Type decl in decl_args)
6973 new_args.Add (new TypeExpression (decl, loc));
6976 new_args.Add (args);
6978 the_args = new_args;
6981 if (the_args != null) {
6982 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6983 return ctype.ResolveAsTypeStep (rc, false);
6990 public override void Emit (EmitContext ec)
6992 throw new Exception ("Should not happen");
6995 public override string ToString ()
6997 return expr + "." + MemberName.MakeName (Identifier, args);
7000 public override string GetSignatureForError ()
7002 return expr.GetSignatureForError () + "." + Identifier;
7005 protected override void CloneTo (CloneContext clonectx, Expression t)
7007 MemberAccess target = (MemberAccess) t;
7009 target.expr = expr.Clone (clonectx);
7014 /// Implements checked expressions
7016 public class CheckedExpr : Expression {
7018 public Expression Expr;
7020 public CheckedExpr (Expression e, Location l)
7026 public override Expression DoResolve (EmitContext ec)
7028 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7029 Expr = Expr.Resolve (ec);
7034 if (Expr is Constant)
7037 eclass = Expr.eclass;
7042 public override void Emit (EmitContext ec)
7044 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7048 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7050 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7051 Expr.EmitBranchable (ec, target, onTrue);
7054 protected override void CloneTo (CloneContext clonectx, Expression t)
7056 CheckedExpr target = (CheckedExpr) t;
7058 target.Expr = Expr.Clone (clonectx);
7063 /// Implements the unchecked expression
7065 public class UnCheckedExpr : Expression {
7067 public Expression Expr;
7069 public UnCheckedExpr (Expression e, Location l)
7075 public override Expression DoResolve (EmitContext ec)
7077 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7078 Expr = Expr.Resolve (ec);
7083 if (Expr is Constant)
7086 eclass = Expr.eclass;
7091 public override void Emit (EmitContext ec)
7093 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7097 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7099 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7100 Expr.EmitBranchable (ec, target, onTrue);
7103 protected override void CloneTo (CloneContext clonectx, Expression t)
7105 UnCheckedExpr target = (UnCheckedExpr) t;
7107 target.Expr = Expr.Clone (clonectx);
7112 /// An Element Access expression.
7114 /// During semantic analysis these are transformed into
7115 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7117 public class ElementAccess : Expression {
7118 public ArrayList Arguments;
7119 public Expression Expr;
7121 public ElementAccess (Expression e, ArrayList e_list)
7130 Arguments = new ArrayList ();
7131 foreach (Expression tmp in e_list)
7132 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7136 bool CommonResolve (EmitContext ec)
7138 Expr = Expr.Resolve (ec);
7140 if (Arguments == null)
7143 foreach (Argument a in Arguments){
7144 if (!a.Resolve (ec, loc))
7148 return Expr != null;
7151 Expression MakePointerAccess (EmitContext ec, Type t)
7153 if (t == TypeManager.void_ptr_type){
7154 Error (242, "The array index operation is not valid on void pointers");
7157 if (Arguments.Count != 1){
7158 Error (196, "A pointer must be indexed by only one value");
7163 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7166 return new Indirection (p, loc).Resolve (ec);
7169 public override Expression DoResolve (EmitContext ec)
7171 if (!CommonResolve (ec))
7175 // We perform some simple tests, and then to "split" the emit and store
7176 // code we create an instance of a different class, and return that.
7178 // I am experimenting with this pattern.
7182 if (t == TypeManager.array_type){
7183 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7188 return (new ArrayAccess (this, loc)).Resolve (ec);
7190 return MakePointerAccess (ec, t);
7192 FieldExpr fe = Expr as FieldExpr;
7194 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7196 return MakePointerAccess (ec, ff.ElementType);
7199 return (new IndexerAccess (this, loc)).Resolve (ec);
7202 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7204 if (!CommonResolve (ec))
7209 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7212 return MakePointerAccess (ec, t);
7214 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7217 public override void Emit (EmitContext ec)
7219 throw new Exception ("Should never be reached");
7222 protected override void CloneTo (CloneContext clonectx, Expression t)
7224 ElementAccess target = (ElementAccess) t;
7226 target.Expr = Expr.Clone (clonectx);
7227 target.Arguments = new ArrayList (Arguments.Count);
7228 foreach (Argument a in Arguments)
7229 target.Arguments.Add (a.Clone (clonectx));
7234 /// Implements array access
7236 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7238 // Points to our "data" repository
7242 LocalTemporary temp;
7245 public ArrayAccess (ElementAccess ea_data, Location l)
7248 eclass = ExprClass.Variable;
7252 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7254 return DoResolve (ec);
7257 public override Expression DoResolve (EmitContext ec)
7260 ExprClass eclass = ea.Expr.eclass;
7262 // As long as the type is valid
7263 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7264 eclass == ExprClass.Value)) {
7265 ea.Expr.Error_UnexpectedKind ("variable or value");
7270 Type t = ea.Expr.Type;
7271 if (t.GetArrayRank () != ea.Arguments.Count){
7272 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7273 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7277 type = TypeManager.GetElementType (t);
7278 if (type.IsPointer && !ec.InUnsafe){
7279 UnsafeError (ea.Location);
7283 foreach (Argument a in ea.Arguments){
7284 Type argtype = a.Type;
7286 if (argtype == TypeManager.int32_type ||
7287 argtype == TypeManager.uint32_type ||
7288 argtype == TypeManager.int64_type ||
7289 argtype == TypeManager.uint64_type) {
7290 Constant c = a.Expr as Constant;
7291 if (c != null && c.IsNegative) {
7292 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7298 // Mhm. This is strage, because the Argument.Type is not the same as
7299 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7301 // Wonder if I will run into trouble for this.
7303 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7308 eclass = ExprClass.Variable;
7314 /// Emits the right opcode to load an object of Type `t'
7315 /// from an array of T
7317 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7319 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7320 ig.Emit (OpCodes.Ldelem_U1);
7321 else if (type == TypeManager.sbyte_type)
7322 ig.Emit (OpCodes.Ldelem_I1);
7323 else if (type == TypeManager.short_type)
7324 ig.Emit (OpCodes.Ldelem_I2);
7325 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7326 ig.Emit (OpCodes.Ldelem_U2);
7327 else if (type == TypeManager.int32_type)
7328 ig.Emit (OpCodes.Ldelem_I4);
7329 else if (type == TypeManager.uint32_type)
7330 ig.Emit (OpCodes.Ldelem_U4);
7331 else if (type == TypeManager.uint64_type)
7332 ig.Emit (OpCodes.Ldelem_I8);
7333 else if (type == TypeManager.int64_type)
7334 ig.Emit (OpCodes.Ldelem_I8);
7335 else if (type == TypeManager.float_type)
7336 ig.Emit (OpCodes.Ldelem_R4);
7337 else if (type == TypeManager.double_type)
7338 ig.Emit (OpCodes.Ldelem_R8);
7339 else if (type == TypeManager.intptr_type)
7340 ig.Emit (OpCodes.Ldelem_I);
7341 else if (TypeManager.IsEnumType (type)){
7342 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7343 } else if (type.IsValueType){
7344 ig.Emit (OpCodes.Ldelema, type);
7345 ig.Emit (OpCodes.Ldobj, type);
7347 } else if (type.IsGenericParameter) {
7348 ig.Emit (OpCodes.Ldelem, type);
7350 } else if (type.IsPointer)
7351 ig.Emit (OpCodes.Ldelem_I);
7353 ig.Emit (OpCodes.Ldelem_Ref);
7357 /// Returns the right opcode to store an object of Type `t'
7358 /// from an array of T.
7360 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7362 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7363 has_type_arg = false; is_stobj = false;
7364 t = TypeManager.TypeToCoreType (t);
7365 if (TypeManager.IsEnumType (t))
7366 t = TypeManager.EnumToUnderlying (t);
7367 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7368 t == TypeManager.bool_type)
7369 return OpCodes.Stelem_I1;
7370 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7371 t == TypeManager.char_type)
7372 return OpCodes.Stelem_I2;
7373 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7374 return OpCodes.Stelem_I4;
7375 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7376 return OpCodes.Stelem_I8;
7377 else if (t == TypeManager.float_type)
7378 return OpCodes.Stelem_R4;
7379 else if (t == TypeManager.double_type)
7380 return OpCodes.Stelem_R8;
7381 else if (t == TypeManager.intptr_type) {
7382 has_type_arg = true;
7384 return OpCodes.Stobj;
7385 } else if (t.IsValueType) {
7386 has_type_arg = true;
7388 return OpCodes.Stobj;
7390 } else if (t.IsGenericParameter) {
7391 has_type_arg = true;
7392 return OpCodes.Stelem;
7395 } else if (t.IsPointer)
7396 return OpCodes.Stelem_I;
7398 return OpCodes.Stelem_Ref;
7401 MethodInfo FetchGetMethod ()
7403 ModuleBuilder mb = CodeGen.Module.Builder;
7404 int arg_count = ea.Arguments.Count;
7405 Type [] args = new Type [arg_count];
7408 for (int i = 0; i < arg_count; i++){
7409 //args [i++] = a.Type;
7410 args [i] = TypeManager.int32_type;
7413 get = mb.GetArrayMethod (
7414 ea.Expr.Type, "Get",
7415 CallingConventions.HasThis |
7416 CallingConventions.Standard,
7422 MethodInfo FetchAddressMethod ()
7424 ModuleBuilder mb = CodeGen.Module.Builder;
7425 int arg_count = ea.Arguments.Count;
7426 Type [] args = new Type [arg_count];
7430 ret_type = TypeManager.GetReferenceType (type);
7432 for (int i = 0; i < arg_count; i++){
7433 //args [i++] = a.Type;
7434 args [i] = TypeManager.int32_type;
7437 address = mb.GetArrayMethod (
7438 ea.Expr.Type, "Address",
7439 CallingConventions.HasThis |
7440 CallingConventions.Standard,
7447 // Load the array arguments into the stack.
7449 // If we have been requested to cache the values (cached_locations array
7450 // initialized), then load the arguments the first time and store them
7451 // in locals. otherwise load from local variables.
7453 void LoadArrayAndArguments (EmitContext ec)
7455 ILGenerator ig = ec.ig;
7458 foreach (Argument a in ea.Arguments){
7459 Type argtype = a.Expr.Type;
7463 if (argtype == TypeManager.int64_type)
7464 ig.Emit (OpCodes.Conv_Ovf_I);
7465 else if (argtype == TypeManager.uint64_type)
7466 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7470 public void Emit (EmitContext ec, bool leave_copy)
7472 int rank = ea.Expr.Type.GetArrayRank ();
7473 ILGenerator ig = ec.ig;
7476 LoadArrayAndArguments (ec);
7479 EmitLoadOpcode (ig, type);
7483 method = FetchGetMethod ();
7484 ig.Emit (OpCodes.Call, method);
7487 LoadFromPtr (ec.ig, this.type);
7490 ec.ig.Emit (OpCodes.Dup);
7491 temp = new LocalTemporary (this.type);
7496 public override void Emit (EmitContext ec)
7501 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7503 int rank = ea.Expr.Type.GetArrayRank ();
7504 ILGenerator ig = ec.ig;
7505 Type t = source.Type;
7506 prepared = prepare_for_load;
7508 if (prepare_for_load) {
7509 AddressOf (ec, AddressOp.LoadStore);
7510 ec.ig.Emit (OpCodes.Dup);
7513 ec.ig.Emit (OpCodes.Dup);
7514 temp = new LocalTemporary (this.type);
7517 StoreFromPtr (ec.ig, t);
7527 LoadArrayAndArguments (ec);
7530 bool is_stobj, has_type_arg;
7531 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7533 // The stobj opcode used by value types will need
7534 // an address on the stack, not really an array/array
7538 ig.Emit (OpCodes.Ldelema, t);
7542 ec.ig.Emit (OpCodes.Dup);
7543 temp = new LocalTemporary (this.type);
7548 ig.Emit (OpCodes.Stobj, t);
7549 else if (has_type_arg)
7554 ModuleBuilder mb = CodeGen.Module.Builder;
7555 int arg_count = ea.Arguments.Count;
7556 Type [] args = new Type [arg_count + 1];
7561 ec.ig.Emit (OpCodes.Dup);
7562 temp = new LocalTemporary (this.type);
7566 for (int i = 0; i < arg_count; i++){
7567 //args [i++] = a.Type;
7568 args [i] = TypeManager.int32_type;
7571 args [arg_count] = type;
7573 set = mb.GetArrayMethod (
7574 ea.Expr.Type, "Set",
7575 CallingConventions.HasThis |
7576 CallingConventions.Standard,
7577 TypeManager.void_type, args);
7579 ig.Emit (OpCodes.Call, set);
7588 public void AddressOf (EmitContext ec, AddressOp mode)
7590 int rank = ea.Expr.Type.GetArrayRank ();
7591 ILGenerator ig = ec.ig;
7593 LoadArrayAndArguments (ec);
7596 ig.Emit (OpCodes.Ldelema, type);
7598 MethodInfo address = FetchAddressMethod ();
7599 ig.Emit (OpCodes.Call, address);
7603 public void EmitGetLength (EmitContext ec, int dim)
7605 int rank = ea.Expr.Type.GetArrayRank ();
7606 ILGenerator ig = ec.ig;
7610 ig.Emit (OpCodes.Ldlen);
7611 ig.Emit (OpCodes.Conv_I4);
7613 IntLiteral.EmitInt (ig, dim);
7614 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7620 // note that the ArrayList itself in mutable. We just can't assign to 'Properties' again.
7621 public readonly ArrayList Properties;
7622 static Indexers empty;
7624 public struct Indexer {
7625 public readonly PropertyInfo PropertyInfo;
7626 public readonly MethodInfo Getter, Setter;
7628 public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7630 this.PropertyInfo = property_info;
7638 empty = new Indexers (null);
7641 Indexers (ArrayList array)
7646 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7651 foreach (PropertyInfo property in mi){
7652 MethodInfo get, set;
7654 get = property.GetGetMethod (true);
7655 set = property.GetSetMethod (true);
7656 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7658 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7660 if (get != null || set != null) {
7662 ix = new Indexers (new ArrayList ());
7663 ix.Properties.Add (new Indexer (property, get, set));
7668 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7670 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7672 return TypeManager.MemberLookup (
7673 caller_type, caller_type, lookup_type, MemberTypes.Property,
7674 BindingFlags.Public | BindingFlags.Instance |
7675 BindingFlags.DeclaredOnly, p_name, null);
7678 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type)
7680 Indexers ix = empty;
7683 if (lookup_type.IsGenericParameter) {
7684 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7688 if (gc.HasClassConstraint)
7689 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7691 Type[] ifaces = gc.InterfaceConstraints;
7692 foreach (Type itype in ifaces)
7693 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7699 Type copy = lookup_type;
7700 while (copy != TypeManager.object_type && copy != null){
7701 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7702 copy = copy.BaseType;
7705 if (lookup_type.IsInterface) {
7706 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7707 if (ifaces != null) {
7708 foreach (Type itype in ifaces)
7709 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7718 /// Expressions that represent an indexer call.
7720 public class IndexerAccess : Expression, IAssignMethod {
7722 // Points to our "data" repository
7724 MethodInfo get, set;
7725 ArrayList set_arguments;
7726 bool is_base_indexer;
7728 protected Type indexer_type;
7729 protected Type current_type;
7730 protected Expression instance_expr;
7731 protected ArrayList arguments;
7733 public IndexerAccess (ElementAccess ea, Location loc)
7734 : this (ea.Expr, false, loc)
7736 this.arguments = ea.Arguments;
7739 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7742 this.instance_expr = instance_expr;
7743 this.is_base_indexer = is_base_indexer;
7744 this.eclass = ExprClass.Value;
7748 protected virtual bool CommonResolve (EmitContext ec)
7750 indexer_type = instance_expr.Type;
7751 current_type = ec.ContainerType;
7756 public override Expression DoResolve (EmitContext ec)
7758 if (!CommonResolve (ec))
7762 // Step 1: Query for all `Item' *properties*. Notice
7763 // that the actual methods are pointed from here.
7765 // This is a group of properties, piles of them.
7767 ArrayList AllGetters = null;
7769 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7770 if (ilist.Properties != null) {
7771 AllGetters = new ArrayList(ilist.Properties.Count);
7772 foreach (Indexers.Indexer ix in ilist.Properties) {
7773 if (ix.Getter != null)
7774 AllGetters.Add (ix.Getter);
7778 if (AllGetters == null) {
7779 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7780 TypeManager.CSharpName (indexer_type));
7784 if (AllGetters.Count == 0) {
7785 // FIXME: we cannot simply select first one as the error message is missleading when
7786 // multiple indexers exist
7787 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7788 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7789 TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7793 get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7794 arguments, false, loc);
7797 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7802 // Only base will allow this invocation to happen.
7804 if (get.IsAbstract && this is BaseIndexerAccess){
7805 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7809 type = get.ReturnType;
7810 if (type.IsPointer && !ec.InUnsafe){
7815 instance_expr.CheckMarshalByRefAccess ();
7817 eclass = ExprClass.IndexerAccess;
7821 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7823 if (right_side == EmptyExpression.OutAccess) {
7824 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7825 GetSignatureForError ());
7829 // if the indexer returns a value type, and we try to set a field in it
7830 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7831 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7832 GetSignatureForError ());
7836 ArrayList AllSetters = new ArrayList();
7837 if (!CommonResolve (ec))
7840 bool found_any = false, found_any_setters = false;
7842 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7843 if (ilist.Properties != null) {
7845 foreach (Indexers.Indexer ix in ilist.Properties) {
7846 if (ix.Setter != null)
7847 AllSetters.Add (ix.Setter);
7850 if (AllSetters.Count > 0) {
7851 found_any_setters = true;
7852 set_arguments = (ArrayList) arguments.Clone ();
7853 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7854 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7856 set_arguments, false, loc);
7860 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7861 TypeManager.CSharpName (indexer_type));
7865 if (!found_any_setters) {
7866 Error (154, "indexer can not be used in this context, because " +
7867 "it lacks a `set' accessor");
7872 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7877 // Only base will allow this invocation to happen.
7879 if (set.IsAbstract && this is BaseIndexerAccess){
7880 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7885 // Now look for the actual match in the list of indexers to set our "return" type
7887 type = TypeManager.void_type; // default value
7888 foreach (Indexers.Indexer ix in ilist.Properties){
7889 if (ix.Setter == set){
7890 type = ix.PropertyInfo.PropertyType;
7895 instance_expr.CheckMarshalByRefAccess ();
7897 eclass = ExprClass.IndexerAccess;
7901 bool prepared = false;
7902 LocalTemporary temp;
7904 public void Emit (EmitContext ec, bool leave_copy)
7906 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7908 ec.ig.Emit (OpCodes.Dup);
7909 temp = new LocalTemporary (Type);
7915 // source is ignored, because we already have a copy of it from the
7916 // LValue resolution and we have already constructed a pre-cached
7917 // version of the arguments (ea.set_arguments);
7919 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7921 prepared = prepare_for_load;
7922 Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7927 ec.ig.Emit (OpCodes.Dup);
7928 temp = new LocalTemporary (Type);
7931 } else if (leave_copy) {
7932 temp = new LocalTemporary (Type);
7938 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7947 public override void Emit (EmitContext ec)
7952 public override string GetSignatureForError ()
7954 // FIXME: print the argument list of the indexer
7955 return instance_expr.GetSignatureForError () + ".this[...]";
7958 protected override void CloneTo (CloneContext clonectx, Expression t)
7960 IndexerAccess target = (IndexerAccess) t;
7962 if (arguments != null){
7963 target.arguments = new ArrayList ();
7964 foreach (Argument a in arguments)
7965 target.arguments.Add (a.Clone (clonectx));
7967 if (instance_expr != null)
7968 target.instance_expr = instance_expr.Clone (clonectx);
7973 /// The base operator for method names
7975 public class BaseAccess : Expression {
7976 public readonly string Identifier;
7979 public BaseAccess (string member, Location l)
7981 this.Identifier = member;
7985 public BaseAccess (string member, TypeArguments args, Location l)
7991 public override Expression DoResolve (EmitContext ec)
7993 Expression c = CommonResolve (ec);
7999 // MethodGroups use this opportunity to flag an error on lacking ()
8001 if (!(c is MethodGroupExpr))
8002 return c.Resolve (ec);
8006 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8008 Expression c = CommonResolve (ec);
8014 // MethodGroups use this opportunity to flag an error on lacking ()
8016 if (! (c is MethodGroupExpr))
8017 return c.DoResolveLValue (ec, right_side);
8022 Expression CommonResolve (EmitContext ec)
8024 Expression member_lookup;
8025 Type current_type = ec.ContainerType;
8026 Type base_type = current_type.BaseType;
8029 Error (1511, "Keyword `base' is not available in a static method");
8033 if (ec.IsFieldInitializer){
8034 Error (1512, "Keyword `base' is not available in the current context");
8038 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8039 AllMemberTypes, AllBindingFlags, loc);
8040 if (member_lookup == null) {
8041 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8048 left = new TypeExpression (base_type, loc);
8050 left = ec.GetThis (loc);
8052 MemberExpr me = (MemberExpr) member_lookup;
8054 Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8056 if (e is PropertyExpr) {
8057 PropertyExpr pe = (PropertyExpr) e;
8062 MethodGroupExpr mg = e as MethodGroupExpr;
8068 return mg.ResolveGeneric (ec, args);
8070 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8078 public override void Emit (EmitContext ec)
8080 throw new Exception ("Should never be called");
8083 protected override void CloneTo (CloneContext clonectx, Expression t)
8085 BaseAccess target = (BaseAccess) t;
8087 target.args = args.Clone ();
8092 /// The base indexer operator
8094 public class BaseIndexerAccess : IndexerAccess {
8095 public BaseIndexerAccess (ArrayList args, Location loc)
8096 : base (null, true, loc)
8098 arguments = new ArrayList ();
8099 foreach (Expression tmp in args)
8100 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8103 protected override bool CommonResolve (EmitContext ec)
8105 instance_expr = ec.GetThis (loc);
8107 current_type = ec.ContainerType.BaseType;
8108 indexer_type = current_type;
8110 foreach (Argument a in arguments){
8111 if (!a.Resolve (ec, loc))
8120 /// This class exists solely to pass the Type around and to be a dummy
8121 /// that can be passed to the conversion functions (this is used by
8122 /// foreach implementation to typecast the object return value from
8123 /// get_Current into the proper type. All code has been generated and
8124 /// we only care about the side effect conversions to be performed
8126 /// This is also now used as a placeholder where a no-action expression
8127 /// is needed (the `New' class).
8129 public class EmptyExpression : Expression {
8130 public static readonly EmptyExpression Null = new EmptyExpression ();
8132 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8133 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8134 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8136 static EmptyExpression temp = new EmptyExpression ();
8137 public static EmptyExpression Grab ()
8139 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8144 public static void Release (EmptyExpression e)
8149 // TODO: should be protected
8150 public EmptyExpression ()
8152 type = TypeManager.object_type;
8153 eclass = ExprClass.Value;
8154 loc = Location.Null;
8157 public EmptyExpression (Type t)
8160 eclass = ExprClass.Value;
8161 loc = Location.Null;
8164 public override Expression DoResolve (EmitContext ec)
8169 public override void Emit (EmitContext ec)
8171 // nothing, as we only exist to not do anything.
8175 // This is just because we might want to reuse this bad boy
8176 // instead of creating gazillions of EmptyExpressions.
8177 // (CanImplicitConversion uses it)
8179 public void SetType (Type t)
8185 public class UserCast : Expression {
8189 public UserCast (MethodInfo method, Expression source, Location l)
8191 this.method = method;
8192 this.source = source;
8193 type = method.ReturnType;
8194 eclass = ExprClass.Value;
8198 public Expression Source {
8204 public override Expression DoResolve (EmitContext ec)
8207 // We are born fully resolved
8212 public override void Emit (EmitContext ec)
8214 ILGenerator ig = ec.ig;
8218 if (method is MethodInfo)
8219 ig.Emit (OpCodes.Call, (MethodInfo) method);
8221 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8227 // This class is used to "construct" the type during a typecast
8228 // operation. Since the Type.GetType class in .NET can parse
8229 // the type specification, we just use this to construct the type
8230 // one bit at a time.
8232 public class ComposedCast : TypeExpr {
8236 public ComposedCast (Expression left, string dim)
8237 : this (left, dim, left.Location)
8241 public ComposedCast (Expression left, string dim, Location l)
8249 public Expression RemoveNullable ()
8251 if (dim.EndsWith ("?")) {
8252 dim = dim.Substring (0, dim.Length - 1);
8261 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8263 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8267 Type ltype = lexpr.Type;
8268 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8269 Error_VoidInvalidInTheContext (loc);
8274 if ((dim.Length > 0) && (dim [0] == '?')) {
8275 TypeExpr nullable = new NullableType (left, loc);
8277 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8278 return nullable.ResolveAsTypeTerminal (ec, false);
8282 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8285 if (dim != "" && dim [0] == '[' &&
8286 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8287 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8292 type = TypeManager.GetConstructedType (ltype, dim);
8297 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8299 if (type.IsPointer && !ec.IsInUnsafeScope){
8304 eclass = ExprClass.Type;
8308 public override string Name {
8309 get { return left + dim; }
8312 public override string FullName {
8313 get { return type.FullName; }
8316 public override string GetSignatureForError ()
8318 return left.GetSignatureForError () + dim;
8321 protected override void CloneTo (CloneContext clonectx, Expression t)
8323 ComposedCast target = (ComposedCast) t;
8325 target.left = left.Clone (clonectx);
8329 public class FixedBufferPtr : Expression {
8332 public FixedBufferPtr (Expression array, Type array_type, Location l)
8337 type = TypeManager.GetPointerType (array_type);
8338 eclass = ExprClass.Value;
8341 public override void Emit(EmitContext ec)
8346 public override Expression DoResolve (EmitContext ec)
8349 // We are born fully resolved
8357 // This class is used to represent the address of an array, used
8358 // only by the Fixed statement, this generates "&a [0]" construct
8359 // for fixed (char *pa = a)
8361 public class ArrayPtr : FixedBufferPtr {
8364 public ArrayPtr (Expression array, Type array_type, Location l):
8365 base (array, array_type, l)
8367 this.array_type = array_type;
8370 public override void Emit (EmitContext ec)
8374 ILGenerator ig = ec.ig;
8375 IntLiteral.EmitInt (ig, 0);
8376 ig.Emit (OpCodes.Ldelema, array_type);
8381 // Used by the fixed statement
8383 public class StringPtr : Expression {
8386 public StringPtr (LocalBuilder b, Location l)
8389 eclass = ExprClass.Value;
8390 type = TypeManager.char_ptr_type;
8394 public override Expression DoResolve (EmitContext ec)
8396 // This should never be invoked, we are born in fully
8397 // initialized state.
8402 public override void Emit (EmitContext ec)
8404 ILGenerator ig = ec.ig;
8406 ig.Emit (OpCodes.Ldloc, b);
8407 ig.Emit (OpCodes.Conv_I);
8408 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8409 ig.Emit (OpCodes.Add);
8414 // Implements the `stackalloc' keyword
8416 public class StackAlloc : Expression {
8421 public StackAlloc (Expression type, Expression count, Location l)
8428 public override Expression DoResolve (EmitContext ec)
8430 count = count.Resolve (ec);
8434 if (count.Type != TypeManager.int32_type){
8435 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8440 Constant c = count as Constant;
8441 if (c != null && c.IsNegative) {
8442 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8446 if (ec.InCatch || ec.InFinally) {
8447 Error (255, "Cannot use stackalloc in finally or catch");
8451 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8457 if (!TypeManager.VerifyUnManaged (otype, loc))
8460 type = TypeManager.GetPointerType (otype);
8461 eclass = ExprClass.Value;
8466 public override void Emit (EmitContext ec)
8468 int size = GetTypeSize (otype);
8469 ILGenerator ig = ec.ig;
8472 ig.Emit (OpCodes.Sizeof, otype);
8474 IntConstant.EmitInt (ig, size);
8476 ig.Emit (OpCodes.Mul);
8477 ig.Emit (OpCodes.Localloc);
8480 protected override void CloneTo (CloneContext clonectx, Expression t)
8482 StackAlloc target = (StackAlloc) t;
8483 target.count = count.Clone (clonectx);
8484 target.t = t.Clone (clonectx);
8488 public interface IInitializable
8490 bool Initialize (EmitContext ec, Expression target);
8493 public class Initializer
8495 public readonly string Name;
8496 public readonly object Value;
8498 public Initializer (string name, Expression value)
8504 public Initializer (string name, IInitializable value)
8511 public class ObjectInitializer : IInitializable
8513 readonly ArrayList initializers;
8514 public ObjectInitializer (ArrayList initializers)
8516 this.initializers = initializers;
8519 public bool Initialize (EmitContext ec, Expression target)
8521 ArrayList initialized = new ArrayList (initializers.Count);
8522 for (int i = initializers.Count - 1; i >= 0; i--) {
8523 Initializer initializer = initializers[i] as Initializer;
8524 if (initialized.Contains (initializer.Name)) {
8525 //FIXME proper error
8526 Console.WriteLine ("Object member can only be initialized once");
8530 MemberAccess ma = new MemberAccess (target, initializer.Name);
8531 Expression expr = initializer.Value as Expression;
8532 // If it's an expresison, append the assign.
8534 Assign a = new Assign (ma, expr);
8535 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8537 // If it's another initializer (object or collection), initialize it.
8538 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8541 initialized.Add (initializer.Name);
8547 public class CollectionInitializer : IInitializable
8549 readonly ArrayList items;
8550 public CollectionInitializer (ArrayList items)
8555 bool CheckCollection (EmitContext ec, Expression e)
8557 if (e == null || e.Type == null)
8559 bool is_ienumerable = false;
8560 foreach (Type t in TypeManager.GetInterfaces (e.Type))
8561 if (t == typeof (IEnumerable)) {
8562 is_ienumerable = true;
8566 if (!is_ienumerable)
8569 MethodGroupExpr mg = Expression.MemberLookup (
8570 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8571 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8576 foreach (MethodInfo mi in mg.Methods) {
8577 if (TypeManager.GetParameterData (mi).Count != 1)
8579 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8586 public bool Initialize (EmitContext ec, Expression target)
8588 if (!CheckCollection (ec, target.Resolve (ec))) {
8589 // FIXME throw proper error
8590 Console.WriteLine ("Error: This is not a collection");
8594 for (int i = items.Count - 1; i >= 0; i--) {
8595 MemberAccess ma = new MemberAccess (target, "Add");
8596 ArrayList array = new ArrayList ();
8597 array.Add (new Argument ((Expression)items[i]));
8598 Invocation invoke = new Invocation (ma, array);
8599 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8605 public class AnonymousTypeInitializer : IInitializable
8607 readonly ArrayList initializers;
8608 public AnonymousTypeInitializer (ArrayList initializers)
8610 this.initializers = initializers;
8613 public bool Initialize (EmitContext ec, Expression target)
8615 foreach (AnonymousTypeParameter p in initializers) {
8616 MemberAccess ma = new MemberAccess (target, p.Name);
8617 Assign a = p.Expression as Assign;
8618 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8619 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8625 public class NewInitialize : New, IInitializable
8627 IInitializable initializer;
8629 public bool Initialize (EmitContext ec, Expression target)
8631 return initializer.Initialize (ec, target);
8634 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8635 : base (requested_type, arguments, l)
8637 this.initializer = initializer;
8641 public class AnonymousType : Expression
8643 ArrayList parameters;
8644 TypeContainer parent;
8645 TypeContainer anonymous_type;
8647 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8649 this.parameters = parameters;
8650 this.parent = parent;
8654 public override Expression DoResolve (EmitContext ec)
8656 foreach (AnonymousTypeParameter p in parameters)
8659 anonymous_type = GetAnonymousType (ec);
8661 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8662 AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8663 return new NewInitialize (te, null, ati, loc).Resolve (ec);
8666 TypeContainer GetAnonymousType (EmitContext ec)
8668 // See if we already have an anonymous type with the right fields.
8669 // If not, create one.
8671 // Look through all availible pre-existing anonymous types:
8672 foreach (DictionaryEntry d in parent.AnonymousTypes) {
8673 ArrayList p = d.Key as ArrayList;
8674 if (p.Count != parameters.Count)
8677 // And for each of the fields we need...
8678 foreach (AnonymousTypeParameter atp in parameters) {
8679 // ... check each of the pre-existing A-type's fields.
8681 foreach (AnonymousTypeParameter a in p)
8682 if (atp.Equals(a)) {
8686 // If the pre-existing A-type doesn't have one of our fields, try the next one
8692 // If it's a match, return it.
8694 return d.Value as TypeContainer;
8696 // Otherwise, create a new type.
8697 return CreateAnonymousType (ec);
8700 TypeContainer CreateAnonymousType (EmitContext ec)
8702 TypeContainer type = new AnonymousClass (parent, loc);
8703 foreach (AnonymousTypeParameter p in parameters) {
8704 TypeExpression te = new TypeExpression (p.Type, loc);
8705 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8706 type.AddField (field);
8709 type.DefineMembers ();
8710 parent.AnonymousTypes.Add (parameters, type);
8714 public override void Emit (EmitContext ec)
8716 TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8717 new New (te, null, loc).Emit(ec);
8721 public class AnonymousTypeParameter : Expression
8725 Expression expression;
8727 public LocatedToken Token {
8728 get { return token; }
8731 public string Name {
8732 get { return name; }
8735 public Expression Expression {
8736 get { return expression; }
8739 public override bool Equals (object o)
8741 AnonymousTypeParameter other = o as AnonymousTypeParameter;
8742 return other != null && Name == other.Name && Type == other.Type;
8745 public override int GetHashCode ()
8747 return name.GetHashCode ();
8750 public override Expression DoResolve (EmitContext ec)
8752 Expression e = expression.Resolve(ec);
8757 public override void Emit (EmitContext ec)
8759 expression.Emit(ec);
8762 public AnonymousTypeParameter (Expression expression, string name)
8765 this.expression = expression;
8766 type = expression.Type;