2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 // This is an user operator expression, automatically created during
24 public class UserOperatorCall : Expression {
25 public delegate Expression ExpressionTreeExpression (EmitContext ec, MethodGroupExpr mg);
27 protected readonly Arguments arguments;
28 protected readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
34 this.arguments = args;
35 this.expr_tree = expr_tree;
37 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
38 eclass = ExprClass.Value;
42 public override Expression CreateExpressionTree (EmitContext ec)
44 if (expr_tree != null)
45 return expr_tree (ec, mg);
47 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
48 new NullLiteral (loc),
49 mg.CreateExpressionTree (ec));
51 return CreateExpressionFactoryCall ("Call", args);
54 protected override void CloneTo (CloneContext context, Expression target)
59 public override Expression DoResolve (EmitContext ec)
62 // We are born fully resolved
67 public override void Emit (EmitContext ec)
69 mg.EmitCall (ec, arguments);
72 public MethodGroupExpr Method {
76 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
78 arguments.MutateHoistedGenericType (storey);
79 mg.MutateHoistedGenericType (storey);
83 public class ParenthesizedExpression : Expression
85 public Expression Expr;
87 public ParenthesizedExpression (Expression expr)
93 public override Expression CreateExpressionTree (EmitContext ec)
95 throw new NotSupportedException ("ET");
98 public override Expression DoResolve (EmitContext ec)
100 Expr = Expr.Resolve (ec);
104 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
106 return Expr.DoResolveLValue (ec, right_side);
109 public override void Emit (EmitContext ec)
111 throw new Exception ("Should not happen");
114 protected override void CloneTo (CloneContext clonectx, Expression t)
116 ParenthesizedExpression target = (ParenthesizedExpression) t;
118 target.Expr = Expr.Clone (clonectx);
123 // Unary implements unary expressions.
125 public class Unary : Expression {
126 public enum Operator : byte {
127 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131 static Type [] [] predefined_operators;
133 public readonly Operator Oper;
134 public Expression Expr;
135 Expression enum_conversion;
137 public Unary (Operator op, Expression expr)
145 // This routine will attempt to simplify the unary expression when the
146 // argument is a constant.
148 Constant TryReduceConstant (EmitContext ec, Constant e)
150 if (e is EmptyConstantCast)
151 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
153 if (e is SideEffectConstant) {
154 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
155 return r == null ? null : new SideEffectConstant (r, e, r.Location);
158 Type expr_type = e.Type;
161 case Operator.UnaryPlus:
162 // Unary numeric promotions
163 if (expr_type == TypeManager.byte_type)
164 return new IntConstant (((ByteConstant)e).Value, e.Location);
165 if (expr_type == TypeManager.sbyte_type)
166 return new IntConstant (((SByteConstant)e).Value, e.Location);
167 if (expr_type == TypeManager.short_type)
168 return new IntConstant (((ShortConstant)e).Value, e.Location);
169 if (expr_type == TypeManager.ushort_type)
170 return new IntConstant (((UShortConstant)e).Value, e.Location);
171 if (expr_type == TypeManager.char_type)
172 return new IntConstant (((CharConstant)e).Value, e.Location);
174 // Predefined operators
175 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
176 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
177 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
178 expr_type == TypeManager.decimal_type) {
184 case Operator.UnaryNegation:
185 // Unary numeric promotions
186 if (expr_type == TypeManager.byte_type)
187 return new IntConstant (-((ByteConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.sbyte_type)
189 return new IntConstant (-((SByteConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.short_type)
191 return new IntConstant (-((ShortConstant)e).Value, e.Location);
192 if (expr_type == TypeManager.ushort_type)
193 return new IntConstant (-((UShortConstant)e).Value, e.Location);
194 if (expr_type == TypeManager.char_type)
195 return new IntConstant (-((CharConstant)e).Value, e.Location);
197 // Predefined operators
198 if (expr_type == TypeManager.int32_type) {
199 int value = ((IntConstant)e).Value;
200 if (value == int.MinValue) {
201 if (ec.ConstantCheckState) {
202 ConstantFold.Error_CompileTimeOverflow (loc);
207 return new IntConstant (-value, e.Location);
209 if (expr_type == TypeManager.int64_type) {
210 long value = ((LongConstant)e).Value;
211 if (value == long.MinValue) {
212 if (ec.ConstantCheckState) {
213 ConstantFold.Error_CompileTimeOverflow (loc);
218 return new LongConstant (-value, e.Location);
221 if (expr_type == TypeManager.uint32_type) {
222 UIntLiteral uil = e as UIntLiteral;
224 if (uil.Value == 2147483648)
225 return new IntLiteral (int.MinValue, e.Location);
226 return new LongLiteral (-uil.Value, e.Location);
228 return new LongConstant (-((UIntConstant)e).Value, e.Location);
231 if (expr_type == TypeManager.uint64_type) {
232 ULongLiteral ull = e as ULongLiteral;
233 if (ull != null && ull.Value == 9223372036854775808)
234 return new LongLiteral (long.MinValue, e.Location);
238 if (expr_type == TypeManager.float_type) {
239 FloatLiteral fl = e as FloatLiteral;
240 // For better error reporting
242 return new FloatLiteral (-fl.Value, e.Location);
244 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
246 if (expr_type == TypeManager.double_type) {
247 DoubleLiteral dl = e as DoubleLiteral;
248 // For better error reporting
250 return new DoubleLiteral (-dl.Value, e.Location);
252 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
254 if (expr_type == TypeManager.decimal_type)
255 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
259 case Operator.LogicalNot:
260 if (expr_type != TypeManager.bool_type)
263 bool b = (bool)e.GetValue ();
264 return new BoolConstant (!b, e.Location);
266 case Operator.OnesComplement:
267 // Unary numeric promotions
268 if (expr_type == TypeManager.byte_type)
269 return new IntConstant (~((ByteConstant)e).Value, e.Location);
270 if (expr_type == TypeManager.sbyte_type)
271 return new IntConstant (~((SByteConstant)e).Value, e.Location);
272 if (expr_type == TypeManager.short_type)
273 return new IntConstant (~((ShortConstant)e).Value, e.Location);
274 if (expr_type == TypeManager.ushort_type)
275 return new IntConstant (~((UShortConstant)e).Value, e.Location);
276 if (expr_type == TypeManager.char_type)
277 return new IntConstant (~((CharConstant)e).Value, e.Location);
279 // Predefined operators
280 if (expr_type == TypeManager.int32_type)
281 return new IntConstant (~((IntConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.uint32_type)
283 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.int64_type)
285 return new LongConstant (~((LongConstant)e).Value, e.Location);
286 if (expr_type == TypeManager.uint64_type){
287 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
289 if (e is EnumConstant) {
290 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
292 e = new EnumConstant (e, expr_type);
297 throw new Exception ("Can not constant fold: " + Oper.ToString());
300 protected Expression ResolveOperator (EmitContext ec, Expression expr)
302 eclass = ExprClass.Value;
304 if (predefined_operators == null)
305 CreatePredefinedOperatorsTable ();
307 Type expr_type = expr.Type;
308 Expression best_expr;
311 // Primitive types first
313 if (TypeManager.IsPrimitiveType (expr_type)) {
314 best_expr = ResolvePrimitivePredefinedType (expr);
315 if (best_expr == null)
318 type = best_expr.Type;
324 // E operator ~(E x);
326 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
327 return ResolveEnumOperator (ec, expr);
329 return ResolveUserType (ec, expr);
332 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
334 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
335 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
336 if (best_expr == null)
340 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
342 return EmptyCast.Create (this, type);
345 public override Expression CreateExpressionTree (EmitContext ec)
347 return CreateExpressionTree (ec, null);
350 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
354 case Operator.AddressOf:
355 Error_PointerInsideExpressionTree ();
357 case Operator.UnaryNegation:
358 if (ec.CheckState && user_op == null && !IsFloat (type))
359 method_name = "NegateChecked";
361 method_name = "Negate";
363 case Operator.OnesComplement:
364 case Operator.LogicalNot:
367 case Operator.UnaryPlus:
368 method_name = "UnaryPlus";
371 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
374 Arguments args = new Arguments (2);
375 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
377 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
378 return CreateExpressionFactoryCall (method_name, args);
381 static void CreatePredefinedOperatorsTable ()
383 predefined_operators = new Type [(int) Operator.TOP] [];
386 // 7.6.1 Unary plus operator
388 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
389 TypeManager.int32_type, TypeManager.uint32_type,
390 TypeManager.int64_type, TypeManager.uint64_type,
391 TypeManager.float_type, TypeManager.double_type,
392 TypeManager.decimal_type
396 // 7.6.2 Unary minus operator
398 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
399 TypeManager.int32_type,
400 TypeManager.int64_type,
401 TypeManager.float_type, TypeManager.double_type,
402 TypeManager.decimal_type
406 // 7.6.3 Logical negation operator
408 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
409 TypeManager.bool_type
413 // 7.6.4 Bitwise complement operator
415 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
416 TypeManager.int32_type, TypeManager.uint32_type,
417 TypeManager.int64_type, TypeManager.uint64_type
422 // Unary numeric promotions
424 static Expression DoNumericPromotion (Operator op, Expression expr)
426 Type expr_type = expr.Type;
427 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
428 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
429 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
430 expr_type == TypeManager.char_type)
431 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
433 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
434 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
439 public override Expression DoResolve (EmitContext ec)
441 if (Oper == Operator.AddressOf) {
442 return ResolveAddressOf (ec);
445 Expr = Expr.Resolve (ec);
449 if (TypeManager.IsNullableType (Expr.Type))
450 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
453 // Attempt to use a constant folding operation.
455 Constant cexpr = Expr as Constant;
457 cexpr = TryReduceConstant (ec, cexpr);
462 Expression expr = ResolveOperator (ec, Expr);
464 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
467 // Reduce unary operator on predefined types
469 if (expr == this && Oper == Operator.UnaryPlus)
475 public override Expression DoResolveLValue (EmitContext ec, Expression right)
480 public override void Emit (EmitContext ec)
482 EmitOperator (ec, type);
485 protected void EmitOperator (EmitContext ec, Type type)
487 ILGenerator ig = ec.ig;
490 case Operator.UnaryPlus:
494 case Operator.UnaryNegation:
495 if (ec.CheckState && !IsFloat (type)) {
496 ig.Emit (OpCodes.Ldc_I4_0);
497 if (type == TypeManager.int64_type)
498 ig.Emit (OpCodes.Conv_U8);
500 ig.Emit (OpCodes.Sub_Ovf);
503 ig.Emit (OpCodes.Neg);
508 case Operator.LogicalNot:
510 ig.Emit (OpCodes.Ldc_I4_0);
511 ig.Emit (OpCodes.Ceq);
514 case Operator.OnesComplement:
516 ig.Emit (OpCodes.Not);
519 case Operator.AddressOf:
520 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
524 throw new Exception ("This should not happen: Operator = "
529 // Same trick as in Binary expression
531 if (enum_conversion != null)
532 enum_conversion.Emit (ec);
535 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
537 if (Oper == Operator.LogicalNot)
538 Expr.EmitBranchable (ec, target, !on_true);
540 base.EmitBranchable (ec, target, on_true);
543 public override void EmitSideEffect (EmitContext ec)
545 Expr.EmitSideEffect (ec);
548 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
550 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
551 oper, TypeManager.CSharpName (t));
554 static bool IsFloat (Type t)
556 return t == TypeManager.float_type || t == TypeManager.double_type;
560 // Returns a stringified representation of the Operator
562 public static string OperName (Operator oper)
565 case Operator.UnaryPlus:
567 case Operator.UnaryNegation:
569 case Operator.LogicalNot:
571 case Operator.OnesComplement:
573 case Operator.AddressOf:
577 throw new NotImplementedException (oper.ToString ());
580 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
582 type = storey.MutateType (type);
583 Expr.MutateHoistedGenericType (storey);
586 Expression ResolveAddressOf (EmitContext ec)
591 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
592 if (Expr == null || Expr.eclass != ExprClass.Variable) {
593 Error (211, "Cannot take the address of the given expression");
597 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
601 IVariableReference vr = Expr as IVariableReference;
604 VariableInfo vi = vr.VariableInfo;
606 if (vi.LocalInfo != null)
607 vi.LocalInfo.Used = true;
610 // A variable is considered definitely assigned if you take its address.
615 is_fixed = vr.IsFixed;
616 vr.SetHasAddressTaken ();
619 AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
622 IFixedExpression fe = Expr as IFixedExpression;
623 is_fixed = fe != null && fe.IsFixed;
626 if (!is_fixed && !ec.InFixedInitializer) {
627 Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
630 type = TypeManager.GetPointerType (Expr.Type);
631 eclass = ExprClass.Value;
635 Expression ResolvePrimitivePredefinedType (Expression expr)
637 expr = DoNumericPromotion (Oper, expr);
638 Type expr_type = expr.Type;
639 Type[] predefined = predefined_operators [(int) Oper];
640 foreach (Type t in predefined) {
648 // Perform user-operator overload resolution
650 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
652 CSharp.Operator.OpType op_type;
654 case Operator.LogicalNot:
655 op_type = CSharp.Operator.OpType.LogicalNot; break;
656 case Operator.OnesComplement:
657 op_type = CSharp.Operator.OpType.OnesComplement; break;
658 case Operator.UnaryNegation:
659 op_type = CSharp.Operator.OpType.UnaryNegation; break;
660 case Operator.UnaryPlus:
661 op_type = CSharp.Operator.OpType.UnaryPlus; break;
663 throw new InternalErrorException (Oper.ToString ());
666 string op_name = CSharp.Operator.GetMetadataName (op_type);
667 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
671 Arguments args = new Arguments (1);
672 args.Add (new Argument (expr));
673 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
678 Expr = args [0].Expr;
679 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
683 // Unary user type overload resolution
685 Expression ResolveUserType (EmitContext ec, Expression expr)
687 Expression best_expr = ResolveUserOperator (ec, expr);
688 if (best_expr != null)
691 Type[] predefined = predefined_operators [(int) Oper];
692 foreach (Type t in predefined) {
693 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
694 if (oper_expr == null)
698 // decimal type is predefined but has user-operators
700 if (oper_expr.Type == TypeManager.decimal_type)
701 oper_expr = ResolveUserType (ec, oper_expr);
703 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
705 if (oper_expr == null)
708 if (best_expr == null) {
709 best_expr = oper_expr;
713 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
715 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
716 OperName (Oper), TypeManager.CSharpName (expr.Type));
721 best_expr = oper_expr;
724 if (best_expr == null)
728 // HACK: Decimal user-operator is included in standard operators
730 if (best_expr.Type == TypeManager.decimal_type)
734 type = best_expr.Type;
738 protected override void CloneTo (CloneContext clonectx, Expression t)
740 Unary target = (Unary) t;
742 target.Expr = Expr.Clone (clonectx);
747 // Unary operators are turned into Indirection expressions
748 // after semantic analysis (this is so we can take the address
749 // of an indirection).
751 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
753 LocalTemporary temporary;
756 public Indirection (Expression expr, Location l)
762 public override Expression CreateExpressionTree (EmitContext ec)
764 Error_PointerInsideExpressionTree ();
768 protected override void CloneTo (CloneContext clonectx, Expression t)
770 Indirection target = (Indirection) t;
771 target.expr = expr.Clone (clonectx);
774 public override void Emit (EmitContext ec)
779 LoadFromPtr (ec.ig, Type);
782 public void Emit (EmitContext ec, bool leave_copy)
786 ec.ig.Emit (OpCodes.Dup);
787 temporary = new LocalTemporary (expr.Type);
788 temporary.Store (ec);
792 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
794 prepared = prepare_for_load;
798 if (prepare_for_load)
799 ec.ig.Emit (OpCodes.Dup);
803 ec.ig.Emit (OpCodes.Dup);
804 temporary = new LocalTemporary (expr.Type);
805 temporary.Store (ec);
808 StoreFromPtr (ec.ig, type);
810 if (temporary != null) {
812 temporary.Release (ec);
816 public void AddressOf (EmitContext ec, AddressOp Mode)
821 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
823 return DoResolve (ec);
826 public override Expression DoResolve (EmitContext ec)
828 expr = expr.Resolve (ec);
835 if (!expr.Type.IsPointer) {
836 Error (193, "The * or -> operator must be applied to a pointer");
840 if (expr.Type == TypeManager.void_ptr_type) {
841 Error (242, "The operation in question is undefined on void pointers");
845 type = TypeManager.GetElementType (expr.Type);
846 eclass = ExprClass.Variable;
850 public bool IsFixed {
854 public override string ToString ()
856 return "*(" + expr + ")";
861 /// Unary Mutator expressions (pre and post ++ and --)
865 /// UnaryMutator implements ++ and -- expressions. It derives from
866 /// ExpressionStatement becuase the pre/post increment/decrement
867 /// operators can be used in a statement context.
869 /// FIXME: Idea, we could split this up in two classes, one simpler
870 /// for the common case, and one with the extra fields for more complex
871 /// classes (indexers require temporary access; overloaded require method)
874 public class UnaryMutator : ExpressionStatement {
876 public enum Mode : byte {
883 PreDecrement = IsDecrement,
884 PostIncrement = IsPost,
885 PostDecrement = IsPost | IsDecrement
889 bool is_expr = false;
890 bool recurse = false;
895 // This is expensive for the simplest case.
897 UserOperatorCall method;
899 public UnaryMutator (Mode m, Expression e)
906 static string OperName (Mode mode)
908 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
913 /// Returns whether an object of type `t' can be incremented
914 /// or decremented with add/sub (ie, basically whether we can
915 /// use pre-post incr-decr operations on it, but it is not a
916 /// System.Decimal, which we require operator overloading to catch)
918 static bool IsIncrementableNumber (Type t)
920 return (t == TypeManager.sbyte_type) ||
921 (t == TypeManager.byte_type) ||
922 (t == TypeManager.short_type) ||
923 (t == TypeManager.ushort_type) ||
924 (t == TypeManager.int32_type) ||
925 (t == TypeManager.uint32_type) ||
926 (t == TypeManager.int64_type) ||
927 (t == TypeManager.uint64_type) ||
928 (t == TypeManager.char_type) ||
929 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
930 (t == TypeManager.float_type) ||
931 (t == TypeManager.double_type) ||
932 (t.IsPointer && t != TypeManager.void_ptr_type);
935 Expression ResolveOperator (EmitContext ec)
940 // The operand of the prefix/postfix increment decrement operators
941 // should be an expression that is classified as a variable,
942 // a property access or an indexer access
944 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
945 expr = expr.ResolveLValue (ec, expr);
947 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
951 // Step 1: Perform Operator Overload location
956 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
957 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
959 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
961 mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
964 Arguments args = new Arguments (1);
965 args.Add (new Argument (expr));
966 mg = mg.OverloadResolve (ec, ref args, false, loc);
970 method = new UserOperatorCall (mg, args, null, loc);
971 Convert.ImplicitConversionRequired (ec, method, type, loc);
975 if (!IsIncrementableNumber (type)) {
976 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
977 TypeManager.CSharpName (type) + "'");
984 public override Expression CreateExpressionTree (EmitContext ec)
986 return new SimpleAssign (this, this).CreateExpressionTree (ec);
989 public override Expression DoResolve (EmitContext ec)
991 expr = expr.Resolve (ec);
996 eclass = ExprClass.Value;
998 if (TypeManager.IsNullableType (expr.Type))
999 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1001 return ResolveOperator (ec);
1005 // Loads the proper "1" into the stack based on the type, then it emits the
1006 // opcode for the operation requested
1008 void LoadOneAndEmitOp (EmitContext ec, Type t)
1011 // Measure if getting the typecode and using that is more/less efficient
1012 // that comparing types. t.GetTypeCode() is an internal call.
1014 ILGenerator ig = ec.ig;
1016 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1017 LongConstant.EmitLong (ig, 1);
1018 else if (t == TypeManager.double_type)
1019 ig.Emit (OpCodes.Ldc_R8, 1.0);
1020 else if (t == TypeManager.float_type)
1021 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1022 else if (t.IsPointer){
1023 Type et = TypeManager.GetElementType (t);
1024 int n = GetTypeSize (et);
1027 ig.Emit (OpCodes.Sizeof, et);
1029 IntConstant.EmitInt (ig, n);
1030 ig.Emit (OpCodes.Conv_I);
1033 ig.Emit (OpCodes.Ldc_I4_1);
1036 // Now emit the operation
1039 Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1040 Binary.EmitOperatorOpcode (ec, op, t);
1042 if (t == TypeManager.sbyte_type){
1044 ig.Emit (OpCodes.Conv_Ovf_I1);
1046 ig.Emit (OpCodes.Conv_I1);
1047 } else if (t == TypeManager.byte_type){
1049 ig.Emit (OpCodes.Conv_Ovf_U1);
1051 ig.Emit (OpCodes.Conv_U1);
1052 } else if (t == TypeManager.short_type){
1054 ig.Emit (OpCodes.Conv_Ovf_I2);
1056 ig.Emit (OpCodes.Conv_I2);
1057 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1059 ig.Emit (OpCodes.Conv_Ovf_U2);
1061 ig.Emit (OpCodes.Conv_U2);
1066 void EmitCode (EmitContext ec, bool is_expr)
1069 this.is_expr = is_expr;
1070 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1073 public override void Emit (EmitContext ec)
1076 // We use recurse to allow ourselfs to be the source
1077 // of an assignment. This little hack prevents us from
1078 // having to allocate another expression
1081 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1083 LoadOneAndEmitOp (ec, expr.Type);
1085 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1090 EmitCode (ec, true);
1093 public override void EmitStatement (EmitContext ec)
1095 EmitCode (ec, false);
1098 protected override void CloneTo (CloneContext clonectx, Expression t)
1100 UnaryMutator target = (UnaryMutator) t;
1102 target.expr = expr.Clone (clonectx);
1107 /// Base class for the `Is' and `As' classes.
1111 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1114 public abstract class Probe : Expression {
1115 public Expression ProbeType;
1116 protected Expression expr;
1117 protected TypeExpr probe_type_expr;
1119 public Probe (Expression expr, Expression probe_type, Location l)
1121 ProbeType = probe_type;
1126 public Expression Expr {
1132 public override Expression DoResolve (EmitContext ec)
1134 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1135 if (probe_type_expr == null)
1138 expr = expr.Resolve (ec);
1142 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1143 Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1147 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1148 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1153 if (expr.Type == InternalType.AnonymousMethod) {
1154 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1162 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1164 expr.MutateHoistedGenericType (storey);
1165 probe_type_expr.MutateHoistedGenericType (storey);
1168 protected abstract string OperatorName { get; }
1170 protected override void CloneTo (CloneContext clonectx, Expression t)
1172 Probe target = (Probe) t;
1174 target.expr = expr.Clone (clonectx);
1175 target.ProbeType = ProbeType.Clone (clonectx);
1181 /// Implementation of the `is' operator.
1183 public class Is : Probe {
1184 Nullable.Unwrap expr_unwrap;
1186 public Is (Expression expr, Expression probe_type, Location l)
1187 : base (expr, probe_type, l)
1191 public override Expression CreateExpressionTree (EmitContext ec)
1193 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1194 expr.CreateExpressionTree (ec),
1195 new TypeOf (probe_type_expr, loc));
1197 return CreateExpressionFactoryCall ("TypeIs", args);
1200 public override void Emit (EmitContext ec)
1202 ILGenerator ig = ec.ig;
1203 if (expr_unwrap != null) {
1204 expr_unwrap.EmitCheck (ec);
1209 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1210 ig.Emit (OpCodes.Ldnull);
1211 ig.Emit (OpCodes.Cgt_Un);
1214 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1216 ILGenerator ig = ec.ig;
1217 if (expr_unwrap != null) {
1218 expr_unwrap.EmitCheck (ec);
1221 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1223 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1226 Expression CreateConstantResult (bool result)
1229 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1230 TypeManager.CSharpName (probe_type_expr.Type));
1232 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1233 TypeManager.CSharpName (probe_type_expr.Type));
1235 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1238 public override Expression DoResolve (EmitContext ec)
1240 if (base.DoResolve (ec) == null)
1244 bool d_is_nullable = false;
1247 // If E is a method group or the null literal, or if the type of E is a reference
1248 // type or a nullable type and the value of E is null, the result is false
1250 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1251 return CreateConstantResult (false);
1253 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1254 d = TypeManager.GetTypeArguments (d) [0];
1255 d_is_nullable = true;
1258 type = TypeManager.bool_type;
1259 eclass = ExprClass.Value;
1260 Type t = probe_type_expr.Type;
1261 bool t_is_nullable = false;
1262 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1263 t = TypeManager.GetTypeArguments (t) [0];
1264 t_is_nullable = true;
1267 if (TypeManager.IsStruct (t)) {
1270 // D and T are the same value types but D can be null
1272 if (d_is_nullable && !t_is_nullable) {
1273 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1278 // The result is true if D and T are the same value types
1280 return CreateConstantResult (true);
1283 if (TypeManager.IsGenericParameter (d))
1284 return ResolveGenericParameter (t, d);
1287 // An unboxing conversion exists
1289 if (Convert.ExplicitReferenceConversionExists (d, t))
1292 if (TypeManager.IsGenericParameter (t))
1293 return ResolveGenericParameter (d, t);
1295 if (TypeManager.IsStruct (d)) {
1297 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1298 return CreateConstantResult (true);
1300 if (TypeManager.IsGenericParameter (d))
1301 return ResolveGenericParameter (t, d);
1303 if (TypeManager.ContainsGenericParameters (d))
1306 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1307 Convert.ExplicitReferenceConversionExists (d, t)) {
1313 return CreateConstantResult (false);
1316 Expression ResolveGenericParameter (Type d, Type t)
1318 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1319 if (constraints != null) {
1320 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1321 return CreateConstantResult (false);
1323 if (constraints.IsValueType && !TypeManager.IsStruct (d))
1324 return CreateConstantResult (TypeManager.IsEqual (d, t));
1327 if (!TypeManager.IsReferenceType (expr.Type))
1328 expr = new BoxedCast (expr, d);
1333 protected override string OperatorName {
1334 get { return "is"; }
1339 /// Implementation of the `as' operator.
1341 public class As : Probe {
1343 Expression resolved_type;
1345 public As (Expression expr, Expression probe_type, Location l)
1346 : base (expr, probe_type, l)
1350 public override Expression CreateExpressionTree (EmitContext ec)
1352 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1353 expr.CreateExpressionTree (ec),
1354 new TypeOf (probe_type_expr, loc));
1356 return CreateExpressionFactoryCall ("TypeAs", args);
1359 public override void Emit (EmitContext ec)
1361 ILGenerator ig = ec.ig;
1366 ig.Emit (OpCodes.Isinst, type);
1369 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1370 ig.Emit (OpCodes.Unbox_Any, type);
1374 public override Expression DoResolve (EmitContext ec)
1376 // Because expr is modified
1377 if (eclass != ExprClass.Invalid)
1380 if (resolved_type == null) {
1381 resolved_type = base.DoResolve (ec);
1383 if (resolved_type == null)
1387 type = probe_type_expr.Type;
1388 eclass = ExprClass.Value;
1389 Type etype = expr.Type;
1391 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1392 if (probe_type_expr is TypeParameterExpr) {
1393 Report.Error (413, loc,
1394 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1395 probe_type_expr.GetSignatureForError ());
1397 Report.Error (77, loc,
1398 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1399 TypeManager.CSharpName (type));
1404 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1405 return Nullable.LiftedNull.CreateFromExpression (this);
1408 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1415 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1416 if (TypeManager.IsGenericParameter (etype))
1417 expr = new BoxedCast (expr, etype);
1423 if (TypeManager.ContainsGenericParameters (etype) ||
1424 TypeManager.ContainsGenericParameters (type)) {
1425 expr = new BoxedCast (expr, etype);
1430 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1431 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1436 protected override string OperatorName {
1437 get { return "as"; }
1440 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1442 type = storey.MutateType (type);
1443 base.MutateHoistedGenericType (storey);
1446 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1448 return expr.GetAttributableValue (ec, value_type, out value);
1453 /// This represents a typecast in the source language.
1455 /// FIXME: Cast expressions have an unusual set of parsing
1456 /// rules, we need to figure those out.
1458 public class Cast : Expression {
1459 Expression target_type;
1462 public Cast (Expression cast_type, Expression expr)
1463 : this (cast_type, expr, cast_type.Location)
1467 public Cast (Expression cast_type, Expression expr, Location loc)
1469 this.target_type = cast_type;
1474 public Expression TargetType {
1475 get { return target_type; }
1478 public Expression Expr {
1479 get { return expr; }
1482 public override Expression CreateExpressionTree (EmitContext ec)
1484 throw new NotSupportedException ("ET");
1487 public override Expression DoResolve (EmitContext ec)
1489 expr = expr.Resolve (ec);
1493 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1499 if (type.IsAbstract && type.IsSealed) {
1500 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1504 eclass = ExprClass.Value;
1506 Constant c = expr as Constant;
1508 c = c.TryReduce (ec, type, loc);
1513 if (type.IsPointer && !ec.InUnsafe) {
1517 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1521 public override void Emit (EmitContext ec)
1523 throw new Exception ("Should not happen");
1526 protected override void CloneTo (CloneContext clonectx, Expression t)
1528 Cast target = (Cast) t;
1530 target.target_type = target_type.Clone (clonectx);
1531 target.expr = expr.Clone (clonectx);
1536 // C# 2.0 Default value expression
1538 public class DefaultValueExpression : Expression
1540 sealed class DefaultValueNullLiteral : NullLiteral
1542 public DefaultValueNullLiteral (DefaultValueExpression expr)
1543 : base (expr.type, expr.loc)
1547 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type t, bool expl)
1549 Error_ValueCannotBeConvertedCore (ec, loc, t, expl);
1556 public DefaultValueExpression (Expression expr, Location loc)
1562 public override Expression CreateExpressionTree (EmitContext ec)
1564 Arguments args = new Arguments (2);
1565 args.Add (new Argument (this));
1566 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1567 return CreateExpressionFactoryCall ("Constant", args);
1570 public override Expression DoResolve (EmitContext ec)
1572 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1578 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1579 Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1583 return new NullLiteral (Location).ConvertImplicitly (type);
1585 if (TypeManager.IsReferenceType (type))
1586 return new DefaultValueNullLiteral (this);
1588 Constant c = New.Constantify (type);
1592 eclass = ExprClass.Variable;
1596 public override void Emit (EmitContext ec)
1598 LocalTemporary temp_storage = new LocalTemporary(type);
1600 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1601 ec.ig.Emit(OpCodes.Initobj, type);
1602 temp_storage.Emit(ec);
1605 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1607 type = storey.MutateType (type);
1610 protected override void CloneTo (CloneContext clonectx, Expression t)
1612 DefaultValueExpression target = (DefaultValueExpression) t;
1614 target.expr = expr.Clone (clonectx);
1619 /// Binary operators
1621 public class Binary : Expression {
1623 protected class PredefinedOperator {
1624 protected readonly Type left;
1625 protected readonly Type right;
1626 public readonly Operator OperatorsMask;
1627 public Type ReturnType;
1629 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1630 : this (ltype, rtype, op_mask, ltype)
1634 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1635 : this (type, type, op_mask, return_type)
1639 public PredefinedOperator (Type type, Operator op_mask)
1640 : this (type, type, op_mask, type)
1644 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1646 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1647 throw new InternalErrorException ("Only masked values can be used");
1651 this.OperatorsMask = op_mask;
1652 this.ReturnType = return_type;
1655 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1657 b.type = ReturnType;
1659 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1660 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1663 // A user operators does not support multiple user conversions, but decimal type
1664 // is considered to be predefined type therefore we apply predefined operators rules
1665 // and then look for decimal user-operator implementation
1667 if (left == TypeManager.decimal_type)
1668 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1673 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1676 // We are dealing with primitive types only
1678 return left == ltype && ltype == rtype;
1681 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1683 if (TypeManager.IsEqual (left, lexpr.Type) &&
1684 TypeManager.IsEqual (right, rexpr.Type))
1687 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1688 Convert.ImplicitConversionExists (ec, rexpr, right);
1691 public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
1694 if (left != null && best_operator.left != null) {
1695 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1699 // When second arguments are same as the first one, the result is same
1701 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1702 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1705 if (result == 0 || result > 2)
1708 return result == 1 ? best_operator : this;
1712 class PredefinedStringOperator : PredefinedOperator {
1713 public PredefinedStringOperator (Type type, Operator op_mask)
1714 : base (type, op_mask, type)
1716 ReturnType = TypeManager.string_type;
1719 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1720 : base (ltype, rtype, op_mask)
1722 ReturnType = TypeManager.string_type;
1725 public override Expression ConvertResult (EmitContext ec, Binary b)
1728 // Use original expression for nullable arguments
1730 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1732 b.left = unwrap.Original;
1734 unwrap = b.right as Nullable.Unwrap;
1736 b.right = unwrap.Original;
1738 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1739 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1742 // Start a new concat expression using converted expression
1744 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1748 class PredefinedShiftOperator : PredefinedOperator {
1749 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1750 base (ltype, TypeManager.int32_type, op_mask)
1754 public override Expression ConvertResult (EmitContext ec, Binary b)
1756 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1758 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1760 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1763 // b = b.left >> b.right & (0x1f|0x3f)
1765 b.right = new Binary (Operator.BitwiseAnd,
1766 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1769 // Expression tree representation does not use & mask
1771 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1772 b.type = ReturnType;
1777 class PredefinedPointerOperator : PredefinedOperator {
1778 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1779 : base (ltype, rtype, op_mask)
1783 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1784 : base (ltype, rtype, op_mask, retType)
1788 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1789 : base (type, op_mask, return_type)
1793 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1796 if (!lexpr.Type.IsPointer)
1799 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1803 if (right == null) {
1804 if (!rexpr.Type.IsPointer)
1807 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1814 public override Expression ConvertResult (EmitContext ec, Binary b)
1817 b.left = EmptyCast.Create (b.left, left);
1818 } else if (right != null) {
1819 b.right = EmptyCast.Create (b.right, right);
1822 Type r_type = ReturnType;
1823 Expression left_arg, right_arg;
1824 if (r_type == null) {
1827 right_arg = b.right;
1828 r_type = b.left.Type;
1832 r_type = b.right.Type;
1836 right_arg = b.right;
1839 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1844 public enum Operator {
1845 Multiply = 0 | ArithmeticMask,
1846 Division = 1 | ArithmeticMask,
1847 Modulus = 2 | ArithmeticMask,
1848 Addition = 3 | ArithmeticMask | AdditionMask,
1849 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1851 LeftShift = 5 | ShiftMask,
1852 RightShift = 6 | ShiftMask,
1854 LessThan = 7 | ComparisonMask | RelationalMask,
1855 GreaterThan = 8 | ComparisonMask | RelationalMask,
1856 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1857 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1858 Equality = 11 | ComparisonMask | EqualityMask,
1859 Inequality = 12 | ComparisonMask | EqualityMask,
1861 BitwiseAnd = 13 | BitwiseMask,
1862 ExclusiveOr = 14 | BitwiseMask,
1863 BitwiseOr = 15 | BitwiseMask,
1865 LogicalAnd = 16 | LogicalMask,
1866 LogicalOr = 17 | LogicalMask,
1871 ValuesOnlyMask = ArithmeticMask - 1,
1872 ArithmeticMask = 1 << 5,
1874 ComparisonMask = 1 << 7,
1875 EqualityMask = 1 << 8,
1876 BitwiseMask = 1 << 9,
1877 LogicalMask = 1 << 10,
1878 AdditionMask = 1 << 11,
1879 SubtractionMask = 1 << 12,
1880 RelationalMask = 1 << 13
1883 readonly Operator oper;
1884 protected Expression left, right;
1885 readonly bool is_compound;
1886 Expression enum_conversion;
1888 static PredefinedOperator [] standard_operators;
1889 static PredefinedOperator [] pointer_operators;
1891 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1892 : this (oper, left, right)
1894 this.is_compound = isCompound;
1897 public Binary (Operator oper, Expression left, Expression right)
1902 this.loc = left.Location;
1905 public Operator Oper {
1912 /// Returns a stringified representation of the Operator
1914 string OperName (Operator oper)
1918 case Operator.Multiply:
1921 case Operator.Division:
1924 case Operator.Modulus:
1927 case Operator.Addition:
1930 case Operator.Subtraction:
1933 case Operator.LeftShift:
1936 case Operator.RightShift:
1939 case Operator.LessThan:
1942 case Operator.GreaterThan:
1945 case Operator.LessThanOrEqual:
1948 case Operator.GreaterThanOrEqual:
1951 case Operator.Equality:
1954 case Operator.Inequality:
1957 case Operator.BitwiseAnd:
1960 case Operator.BitwiseOr:
1963 case Operator.ExclusiveOr:
1966 case Operator.LogicalOr:
1969 case Operator.LogicalAnd:
1973 s = oper.ToString ();
1983 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
1985 new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
1988 public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
1991 l = TypeManager.CSharpName (left.Type);
1992 r = TypeManager.CSharpName (right.Type);
1994 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1998 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2000 Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
2003 static string GetOperatorMetadataName (Operator op)
2005 CSharp.Operator.OpType op_type;
2007 case Operator.Addition:
2008 op_type = CSharp.Operator.OpType.Addition; break;
2009 case Operator.BitwiseAnd:
2010 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2011 case Operator.BitwiseOr:
2012 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2013 case Operator.Division:
2014 op_type = CSharp.Operator.OpType.Division; break;
2015 case Operator.Equality:
2016 op_type = CSharp.Operator.OpType.Equality; break;
2017 case Operator.ExclusiveOr:
2018 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2019 case Operator.GreaterThan:
2020 op_type = CSharp.Operator.OpType.GreaterThan; break;
2021 case Operator.GreaterThanOrEqual:
2022 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2023 case Operator.Inequality:
2024 op_type = CSharp.Operator.OpType.Inequality; break;
2025 case Operator.LeftShift:
2026 op_type = CSharp.Operator.OpType.LeftShift; break;
2027 case Operator.LessThan:
2028 op_type = CSharp.Operator.OpType.LessThan; break;
2029 case Operator.LessThanOrEqual:
2030 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2031 case Operator.Modulus:
2032 op_type = CSharp.Operator.OpType.Modulus; break;
2033 case Operator.Multiply:
2034 op_type = CSharp.Operator.OpType.Multiply; break;
2035 case Operator.RightShift:
2036 op_type = CSharp.Operator.OpType.RightShift; break;
2037 case Operator.Subtraction:
2038 op_type = CSharp.Operator.OpType.Subtraction; break;
2040 throw new InternalErrorException (op.ToString ());
2043 return CSharp.Operator.GetMetadataName (op_type);
2046 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2049 ILGenerator ig = ec.ig;
2052 case Operator.Multiply:
2054 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2055 opcode = OpCodes.Mul_Ovf;
2056 else if (!IsFloat (l))
2057 opcode = OpCodes.Mul_Ovf_Un;
2059 opcode = OpCodes.Mul;
2061 opcode = OpCodes.Mul;
2065 case Operator.Division:
2067 opcode = OpCodes.Div_Un;
2069 opcode = OpCodes.Div;
2072 case Operator.Modulus:
2074 opcode = OpCodes.Rem_Un;
2076 opcode = OpCodes.Rem;
2079 case Operator.Addition:
2081 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2082 opcode = OpCodes.Add_Ovf;
2083 else if (!IsFloat (l))
2084 opcode = OpCodes.Add_Ovf_Un;
2086 opcode = OpCodes.Add;
2088 opcode = OpCodes.Add;
2091 case Operator.Subtraction:
2093 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2094 opcode = OpCodes.Sub_Ovf;
2095 else if (!IsFloat (l))
2096 opcode = OpCodes.Sub_Ovf_Un;
2098 opcode = OpCodes.Sub;
2100 opcode = OpCodes.Sub;
2103 case Operator.RightShift:
2105 opcode = OpCodes.Shr_Un;
2107 opcode = OpCodes.Shr;
2110 case Operator.LeftShift:
2111 opcode = OpCodes.Shl;
2114 case Operator.Equality:
2115 opcode = OpCodes.Ceq;
2118 case Operator.Inequality:
2119 ig.Emit (OpCodes.Ceq);
2120 ig.Emit (OpCodes.Ldc_I4_0);
2122 opcode = OpCodes.Ceq;
2125 case Operator.LessThan:
2127 opcode = OpCodes.Clt_Un;
2129 opcode = OpCodes.Clt;
2132 case Operator.GreaterThan:
2134 opcode = OpCodes.Cgt_Un;
2136 opcode = OpCodes.Cgt;
2139 case Operator.LessThanOrEqual:
2140 if (IsUnsigned (l) || IsFloat (l))
2141 ig.Emit (OpCodes.Cgt_Un);
2143 ig.Emit (OpCodes.Cgt);
2144 ig.Emit (OpCodes.Ldc_I4_0);
2146 opcode = OpCodes.Ceq;
2149 case Operator.GreaterThanOrEqual:
2150 if (IsUnsigned (l) || IsFloat (l))
2151 ig.Emit (OpCodes.Clt_Un);
2153 ig.Emit (OpCodes.Clt);
2155 ig.Emit (OpCodes.Ldc_I4_0);
2157 opcode = OpCodes.Ceq;
2160 case Operator.BitwiseOr:
2161 opcode = OpCodes.Or;
2164 case Operator.BitwiseAnd:
2165 opcode = OpCodes.And;
2168 case Operator.ExclusiveOr:
2169 opcode = OpCodes.Xor;
2173 throw new InternalErrorException (oper.ToString ());
2179 static bool IsUnsigned (Type t)
2184 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2185 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2188 static bool IsFloat (Type t)
2190 return t == TypeManager.float_type || t == TypeManager.double_type;
2193 Expression ResolveOperator (EmitContext ec)
2196 Type r = right.Type;
2198 bool primitives_only = false;
2200 if (standard_operators == null)
2201 CreateStandardOperatorsTable ();
2204 // Handles predefined primitive types
2206 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2207 if ((oper & Operator.ShiftMask) == 0) {
2208 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2211 primitives_only = true;
2215 if (l.IsPointer || r.IsPointer)
2216 return ResolveOperatorPointer (ec, l, r);
2219 bool lenum = TypeManager.IsEnumType (l);
2220 bool renum = TypeManager.IsEnumType (r);
2221 if (lenum || renum) {
2222 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2224 // TODO: Can this be ambiguous
2230 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2231 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2233 expr = ResolveOperatorDelegate (ec, l, r);
2235 // TODO: Can this be ambiguous
2241 expr = ResolveUserOperator (ec, l, r);
2245 // Predefined reference types equality
2246 if ((oper & Operator.EqualityMask) != 0) {
2247 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2253 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2256 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2257 // if 'left' is not an enumeration constant, create one from the type of 'right'
2258 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2261 case Operator.BitwiseOr:
2262 case Operator.BitwiseAnd:
2263 case Operator.ExclusiveOr:
2264 case Operator.Equality:
2265 case Operator.Inequality:
2266 case Operator.LessThan:
2267 case Operator.LessThanOrEqual:
2268 case Operator.GreaterThan:
2269 case Operator.GreaterThanOrEqual:
2270 if (TypeManager.IsEnumType (left.Type))
2273 if (left.IsZeroInteger)
2274 return left.TryReduce (ec, right.Type, loc);
2278 case Operator.Addition:
2279 case Operator.Subtraction:
2282 case Operator.Multiply:
2283 case Operator.Division:
2284 case Operator.Modulus:
2285 case Operator.LeftShift:
2286 case Operator.RightShift:
2287 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2291 Error_OperatorCannotBeApplied (this.left, this.right);
2296 // The `|' operator used on types which were extended is dangerous
2298 void CheckBitwiseOrOnSignExtended ()
2300 OpcodeCast lcast = left as OpcodeCast;
2301 if (lcast != null) {
2302 if (IsUnsigned (lcast.UnderlyingType))
2306 OpcodeCast rcast = right as OpcodeCast;
2307 if (rcast != null) {
2308 if (IsUnsigned (rcast.UnderlyingType))
2312 if (lcast == null && rcast == null)
2315 // FIXME: consider constants
2317 Report.Warning (675, 3, loc,
2318 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2319 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2322 static void CreatePointerOperatorsTable ()
2324 ArrayList temp = new ArrayList ();
2327 // Pointer arithmetic:
2329 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2330 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2331 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2332 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2334 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2335 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2336 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2337 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2340 // T* operator + (int y, T* x);
2341 // T* operator + (uint y, T *x);
2342 // T* operator + (long y, T *x);
2343 // T* operator + (ulong y, T *x);
2345 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2346 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2347 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2348 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2351 // long operator - (T* x, T *y)
2353 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2355 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2358 static void CreateStandardOperatorsTable ()
2360 ArrayList temp = new ArrayList ();
2361 Type bool_type = TypeManager.bool_type;
2363 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2364 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2365 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2366 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2367 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2368 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2369 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2371 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2372 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2373 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2374 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2375 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2376 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2377 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2379 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2381 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2382 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2383 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2385 temp.Add (new PredefinedOperator (bool_type,
2386 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2388 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2389 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2390 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2391 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2393 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2397 // Rules used during binary numeric promotion
2399 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2404 Constant c = prim_expr as Constant;
2406 temp = c.ConvertImplicitly (type);
2413 if (type == TypeManager.uint32_type) {
2414 etype = prim_expr.Type;
2415 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2416 type = TypeManager.int64_type;
2418 if (type != second_expr.Type) {
2419 c = second_expr as Constant;
2421 temp = c.ConvertImplicitly (type);
2423 temp = Convert.ImplicitNumericConversion (second_expr, type);
2429 } else if (type == TypeManager.uint64_type) {
2431 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2433 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2434 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2438 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2447 // 7.2.6.2 Binary numeric promotions
2449 public bool DoBinaryOperatorPromotion (EmitContext ec)
2451 Type ltype = left.Type;
2452 Type rtype = right.Type;
2455 foreach (Type t in ConstantFold.binary_promotions) {
2457 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2460 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2463 Type int32 = TypeManager.int32_type;
2464 if (ltype != int32) {
2465 Constant c = left as Constant;
2467 temp = c.ConvertImplicitly (int32);
2469 temp = Convert.ImplicitNumericConversion (left, int32);
2476 if (rtype != int32) {
2477 Constant c = right as Constant;
2479 temp = c.ConvertImplicitly (int32);
2481 temp = Convert.ImplicitNumericConversion (right, int32);
2491 public override Expression DoResolve (EmitContext ec)
2496 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2497 left = ((ParenthesizedExpression) left).Expr;
2498 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2502 if (left.eclass == ExprClass.Type) {
2503 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2507 left = left.Resolve (ec);
2512 Constant lc = left as Constant;
2514 if (lc != null && lc.Type == TypeManager.bool_type &&
2515 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2516 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2518 // FIXME: resolve right expression as unreachable
2519 // right.Resolve (ec);
2521 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2525 right = right.Resolve (ec);
2529 eclass = ExprClass.Value;
2530 Constant rc = right as Constant;
2532 // The conversion rules are ignored in enum context but why
2533 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2534 lc = EnumLiftUp (ec, lc, rc, loc);
2536 rc = EnumLiftUp (ec, rc, lc, loc);
2539 if (rc != null && lc != null) {
2540 int prev_e = Report.Errors;
2541 Expression e = ConstantFold.BinaryFold (
2542 ec, oper, lc, rc, loc);
2543 if (e != null || Report.Errors != prev_e)
2546 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2547 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2549 if ((ResolveOperator (ec)) == null) {
2550 Error_OperatorCannotBeApplied (left, right);
2555 // The result is a constant with side-effect
2557 Constant side_effect = rc == null ?
2558 new SideEffectConstant (lc, right, loc) :
2559 new SideEffectConstant (rc, left, loc);
2561 return ReducedExpression.Create (side_effect, this);
2565 // Comparison warnings
2566 if ((oper & Operator.ComparisonMask) != 0) {
2567 if (left.Equals (right)) {
2568 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2570 CheckUselessComparison (lc, right.Type);
2571 CheckUselessComparison (rc, left.Type);
2574 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2575 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2576 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2577 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2578 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2579 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2581 return DoResolveCore (ec, left, right);
2584 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2586 Expression expr = ResolveOperator (ec);
2588 Error_OperatorCannotBeApplied (left_orig, right_orig);
2590 if (left == null || right == null)
2591 throw new InternalErrorException ("Invalid conversion");
2593 if (oper == Operator.BitwiseOr)
2594 CheckBitwiseOrOnSignExtended ();
2599 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2601 left.MutateHoistedGenericType (storey);
2602 right.MutateHoistedGenericType (storey);
2606 // D operator + (D x, D y)
2607 // D operator - (D x, D y)
2608 // bool operator == (D x, D y)
2609 // bool operator != (D x, D y)
2611 Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
2613 bool is_equality = (oper & Operator.EqualityMask) != 0;
2614 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2616 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2617 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2622 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2623 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2634 // Resolve delegate equality as a user operator
2637 return ResolveUserOperator (ec, l, r);
2640 Arguments args = new Arguments (2);
2641 args.Add (new Argument (left));
2642 args.Add (new Argument (right));
2644 if (oper == Operator.Addition) {
2645 if (TypeManager.delegate_combine_delegate_delegate == null) {
2646 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2647 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2650 method = TypeManager.delegate_combine_delegate_delegate;
2652 if (TypeManager.delegate_remove_delegate_delegate == null) {
2653 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2654 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2657 method = TypeManager.delegate_remove_delegate_delegate;
2660 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2661 mg = mg.OverloadResolve (ec, ref args, false, loc);
2663 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2667 // Enumeration operators
2669 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2672 // bool operator == (E x, E y);
2673 // bool operator != (E x, E y);
2674 // bool operator < (E x, E y);
2675 // bool operator > (E x, E y);
2676 // bool operator <= (E x, E y);
2677 // bool operator >= (E x, E y);
2679 // E operator & (E x, E y);
2680 // E operator | (E x, E y);
2681 // E operator ^ (E x, E y);
2683 // U operator - (E e, E f)
2684 // E operator - (E e, U x)
2686 // E operator + (U x, E e)
2687 // E operator + (E e, U x)
2689 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2690 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2693 Expression ltemp = left;
2694 Expression rtemp = right;
2695 Type underlying_type;
2698 if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
2700 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2706 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2714 if (TypeManager.IsEqual (ltype, rtype)) {
2715 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2717 if (left is Constant)
2718 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2720 left = EmptyCast.Create (left, underlying_type);
2722 if (right is Constant)
2723 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2725 right = EmptyCast.Create (right, underlying_type);
2727 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2729 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2730 Constant c = right as Constant;
2731 if (c == null || !c.IsDefaultValue)
2734 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2737 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2740 if (left is Constant)
2741 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2743 left = EmptyCast.Create (left, underlying_type);
2746 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2748 if (oper != Operator.Addition) {
2749 Constant c = left as Constant;
2750 if (c == null || !c.IsDefaultValue)
2753 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2756 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2759 if (right is Constant)
2760 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2762 right = EmptyCast.Create (right, underlying_type);
2769 // C# specification uses explicit cast syntax which means binary promotion
2770 // should happen, however it seems that csc does not do that
2772 if (!DoBinaryOperatorPromotion (ec)) {
2778 Type res_type = null;
2779 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2780 Type promoted_type = lenum ? left.Type : right.Type;
2781 enum_conversion = Convert.ExplicitNumericConversion (
2782 new EmptyExpression (promoted_type), underlying_type);
2784 if (oper == Operator.Subtraction && renum && lenum)
2785 res_type = underlying_type;
2786 else if (oper == Operator.Addition && renum)
2792 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2793 if (!is_compound || expr == null)
2797 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2800 if (Convert.ImplicitConversionExists (ec, left, rtype))
2803 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2806 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2811 // 7.9.6 Reference type equality operators
2813 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2816 // operator != (object a, object b)
2817 // operator == (object a, object b)
2820 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2822 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2825 type = TypeManager.bool_type;
2826 GenericConstraints constraints;
2828 bool lgen = TypeManager.IsGenericParameter (l);
2830 if (TypeManager.IsEqual (l, r)) {
2833 // Only allow to compare same reference type parameter
2835 constraints = TypeManager.GetTypeParameterConstraints (l);
2836 if (constraints != null && constraints.IsReferenceType)
2842 if (l == InternalType.AnonymousMethod)
2845 if (TypeManager.IsValueType (l))
2851 bool rgen = TypeManager.IsGenericParameter (r);
2854 // a, Both operands are reference-type values or the value null
2855 // b, One operand is a value of type T where T is a type-parameter and
2856 // the other operand is the value null. Furthermore T does not have the
2857 // value type constrain
2859 if (left is NullLiteral || right is NullLiteral) {
2861 constraints = TypeManager.GetTypeParameterConstraints (l);
2862 if (constraints != null && constraints.HasValueTypeConstraint)
2865 left = new BoxedCast (left, TypeManager.object_type);
2870 constraints = TypeManager.GetTypeParameterConstraints (r);
2871 if (constraints != null && constraints.HasValueTypeConstraint)
2874 right = new BoxedCast (right, TypeManager.object_type);
2880 // An interface is converted to the object before the
2881 // standard conversion is applied. It's not clear from the
2882 // standard but it looks like it works like that.
2885 constraints = TypeManager.GetTypeParameterConstraints (l);
2886 if (constraints == null || constraints.IsReferenceType)
2888 } else if (l.IsInterface) {
2889 l = TypeManager.object_type;
2890 } else if (TypeManager.IsStruct (l)) {
2895 constraints = TypeManager.GetTypeParameterConstraints (r);
2896 if (constraints == null || constraints.IsReferenceType)
2898 } else if (r.IsInterface) {
2899 r = TypeManager.object_type;
2900 } else if (TypeManager.IsStruct (r)) {
2905 const string ref_comparison = "Possible unintended reference comparison. " +
2906 "Consider casting the {0} side of the expression to `string' to compare the values";
2909 // A standard implicit conversion exists from the type of either
2910 // operand to the type of the other operand
2912 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2913 if (l == TypeManager.string_type)
2914 Report.Warning (253, 2, loc, ref_comparison, "right");
2919 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2920 if (r == TypeManager.string_type)
2921 Report.Warning (252, 2, loc, ref_comparison, "left");
2930 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2933 // bool operator == (void* x, void* y);
2934 // bool operator != (void* x, void* y);
2935 // bool operator < (void* x, void* y);
2936 // bool operator > (void* x, void* y);
2937 // bool operator <= (void* x, void* y);
2938 // bool operator >= (void* x, void* y);
2940 if ((oper & Operator.ComparisonMask) != 0) {
2943 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2950 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2956 type = TypeManager.bool_type;
2960 if (pointer_operators == null)
2961 CreatePointerOperatorsTable ();
2963 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2967 // Build-in operators method overloading
2969 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2971 PredefinedOperator best_operator = null;
2973 Type r = right.Type;
2974 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2976 foreach (PredefinedOperator po in operators) {
2977 if ((po.OperatorsMask & oper_mask) == 0)
2980 if (primitives_only) {
2981 if (!po.IsPrimitiveApplicable (l, r))
2984 if (!po.IsApplicable (ec, left, right))
2988 if (best_operator == null) {
2990 if (primitives_only)
2996 best_operator = po.ResolveBetterOperator (ec, best_operator);
2998 if (best_operator == null) {
2999 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3000 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
3007 if (best_operator == null)
3010 Expression expr = best_operator.ConvertResult (ec, this);
3011 if (enum_type == null)
3015 // HACK: required by enum_conversion
3017 expr.Type = enum_type;
3018 return EmptyCast.Create (expr, enum_type);
3022 // Performs user-operator overloading
3024 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
3027 if (oper == Operator.LogicalAnd)
3028 user_oper = Operator.BitwiseAnd;
3029 else if (oper == Operator.LogicalOr)
3030 user_oper = Operator.BitwiseOr;
3034 string op = GetOperatorMetadataName (user_oper);
3036 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3037 MethodGroupExpr right_operators = null;
3039 if (!TypeManager.IsEqual (r, l)) {
3040 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3041 if (right_operators == null && left_operators == null)
3043 } else if (left_operators == null) {
3047 Arguments args = new Arguments (2);
3048 Argument larg = new Argument (left);
3050 Argument rarg = new Argument (right);
3053 MethodGroupExpr union;
3056 // User-defined operator implementations always take precedence
3057 // over predefined operator implementations
3059 if (left_operators != null && right_operators != null) {
3060 if (IsPredefinedUserOperator (l, user_oper)) {
3061 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3063 union = left_operators;
3064 } else if (IsPredefinedUserOperator (r, user_oper)) {
3065 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3067 union = right_operators;
3069 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3071 } else if (left_operators != null) {
3072 union = left_operators;
3074 union = right_operators;
3077 union = union.OverloadResolve (ec, ref args, true, loc);
3081 Expression oper_expr;
3083 // TODO: CreateExpressionTree is allocated every time
3084 if (user_oper != oper) {
3085 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3086 oper == Operator.LogicalAnd, loc).Resolve (ec);
3088 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3091 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3092 // and not invoke user operator
3094 if ((oper & Operator.EqualityMask) != 0) {
3095 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3096 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3097 type = TypeManager.bool_type;
3098 if (left is NullLiteral || right is NullLiteral)
3099 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
3100 } else if (l != r) {
3101 MethodInfo mi = (MethodInfo) union;
3104 // Two System.Delegate(s) are never equal
3106 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3117 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3122 private void CheckUselessComparison (Constant c, Type type)
3124 if (c == null || !IsTypeIntegral (type)
3125 || c is StringConstant
3126 || c is BoolConstant
3127 || c is FloatConstant
3128 || c is DoubleConstant
3129 || c is DecimalConstant
3135 if (c is ULongConstant) {
3136 ulong uvalue = ((ULongConstant) c).Value;
3137 if (uvalue > long.MaxValue) {
3138 if (type == TypeManager.byte_type ||
3139 type == TypeManager.sbyte_type ||
3140 type == TypeManager.short_type ||
3141 type == TypeManager.ushort_type ||
3142 type == TypeManager.int32_type ||
3143 type == TypeManager.uint32_type ||
3144 type == TypeManager.int64_type ||
3145 type == TypeManager.char_type)
3146 WarnUselessComparison (type);
3149 value = (long) uvalue;
3151 else if (c is ByteConstant)
3152 value = ((ByteConstant) c).Value;
3153 else if (c is SByteConstant)
3154 value = ((SByteConstant) c).Value;
3155 else if (c is ShortConstant)
3156 value = ((ShortConstant) c).Value;
3157 else if (c is UShortConstant)
3158 value = ((UShortConstant) c).Value;
3159 else if (c is IntConstant)
3160 value = ((IntConstant) c).Value;
3161 else if (c is UIntConstant)
3162 value = ((UIntConstant) c).Value;
3163 else if (c is LongConstant)
3164 value = ((LongConstant) c).Value;
3165 else if (c is CharConstant)
3166 value = ((CharConstant)c).Value;
3171 if (IsValueOutOfRange (value, type))
3172 WarnUselessComparison (type);
3175 static bool IsValueOutOfRange (long value, Type type)
3177 if (IsTypeUnsigned (type) && value < 0)
3179 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3180 type == TypeManager.byte_type && value >= 0x100 ||
3181 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3182 type == TypeManager.ushort_type && value >= 0x10000 ||
3183 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3184 type == TypeManager.uint32_type && value >= 0x100000000;
3187 static bool IsBuildInEqualityOperator (Type t)
3189 return t == TypeManager.object_type || t == TypeManager.string_type ||
3190 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3193 static bool IsPredefinedUserOperator (Type t, Operator op)
3196 // Some predefined types have user operators
3198 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3201 private static bool IsTypeIntegral (Type type)
3203 return type == TypeManager.uint64_type ||
3204 type == TypeManager.int64_type ||
3205 type == TypeManager.uint32_type ||
3206 type == TypeManager.int32_type ||
3207 type == TypeManager.ushort_type ||
3208 type == TypeManager.short_type ||
3209 type == TypeManager.sbyte_type ||
3210 type == TypeManager.byte_type ||
3211 type == TypeManager.char_type;
3214 private static bool IsTypeUnsigned (Type type)
3216 return type == TypeManager.uint64_type ||
3217 type == TypeManager.uint32_type ||
3218 type == TypeManager.ushort_type ||
3219 type == TypeManager.byte_type ||
3220 type == TypeManager.char_type;
3223 private void WarnUselessComparison (Type type)
3225 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}'",
3226 TypeManager.CSharpName (type));
3230 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3231 /// context of a conditional bool expression. This function will return
3232 /// false if it is was possible to use EmitBranchable, or true if it was.
3234 /// The expression's code is generated, and we will generate a branch to `target'
3235 /// if the resulting expression value is equal to isTrue
3237 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3239 ILGenerator ig = ec.ig;
3242 // This is more complicated than it looks, but its just to avoid
3243 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3244 // but on top of that we want for == and != to use a special path
3245 // if we are comparing against null
3247 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3248 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3251 // put the constant on the rhs, for simplicity
3253 if (left is Constant) {
3254 Expression swap = right;
3259 if (((Constant) right).IsZeroInteger) {
3260 left.EmitBranchable (ec, target, my_on_true);
3263 if (right.Type == TypeManager.bool_type) {
3264 // right is a boolean, and it's not 'false' => it is 'true'
3265 left.EmitBranchable (ec, target, !my_on_true);
3269 } else if (oper == Operator.LogicalAnd) {
3272 Label tests_end = ig.DefineLabel ();
3274 left.EmitBranchable (ec, tests_end, false);
3275 right.EmitBranchable (ec, target, true);
3276 ig.MarkLabel (tests_end);
3279 // This optimizes code like this
3280 // if (true && i > 4)
3282 if (!(left is Constant))
3283 left.EmitBranchable (ec, target, false);
3285 if (!(right is Constant))
3286 right.EmitBranchable (ec, target, false);
3291 } else if (oper == Operator.LogicalOr){
3293 left.EmitBranchable (ec, target, true);
3294 right.EmitBranchable (ec, target, true);
3297 Label tests_end = ig.DefineLabel ();
3298 left.EmitBranchable (ec, tests_end, true);
3299 right.EmitBranchable (ec, target, false);
3300 ig.MarkLabel (tests_end);
3305 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3306 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3307 oper == Operator.Equality || oper == Operator.Inequality)) {
3308 base.EmitBranchable (ec, target, on_true);
3316 bool is_float = IsFloat (t);
3317 bool is_unsigned = is_float || IsUnsigned (t);
3320 case Operator.Equality:
3322 ig.Emit (OpCodes.Beq, target);
3324 ig.Emit (OpCodes.Bne_Un, target);
3327 case Operator.Inequality:
3329 ig.Emit (OpCodes.Bne_Un, target);
3331 ig.Emit (OpCodes.Beq, target);
3334 case Operator.LessThan:
3336 if (is_unsigned && !is_float)
3337 ig.Emit (OpCodes.Blt_Un, target);
3339 ig.Emit (OpCodes.Blt, target);
3342 ig.Emit (OpCodes.Bge_Un, target);
3344 ig.Emit (OpCodes.Bge, target);
3347 case Operator.GreaterThan:
3349 if (is_unsigned && !is_float)
3350 ig.Emit (OpCodes.Bgt_Un, target);
3352 ig.Emit (OpCodes.Bgt, target);
3355 ig.Emit (OpCodes.Ble_Un, target);
3357 ig.Emit (OpCodes.Ble, target);
3360 case Operator.LessThanOrEqual:
3362 if (is_unsigned && !is_float)
3363 ig.Emit (OpCodes.Ble_Un, target);
3365 ig.Emit (OpCodes.Ble, target);
3368 ig.Emit (OpCodes.Bgt_Un, target);
3370 ig.Emit (OpCodes.Bgt, target);
3374 case Operator.GreaterThanOrEqual:
3376 if (is_unsigned && !is_float)
3377 ig.Emit (OpCodes.Bge_Un, target);
3379 ig.Emit (OpCodes.Bge, target);
3382 ig.Emit (OpCodes.Blt_Un, target);
3384 ig.Emit (OpCodes.Blt, target);
3387 throw new InternalErrorException (oper.ToString ());
3391 public override void Emit (EmitContext ec)
3393 EmitOperator (ec, left.Type);
3396 protected virtual void EmitOperator (EmitContext ec, Type l)
3398 ILGenerator ig = ec.ig;
3401 // Handle short-circuit operators differently
3404 if ((oper & Operator.LogicalMask) != 0) {
3405 Label load_result = ig.DefineLabel ();
3406 Label end = ig.DefineLabel ();
3408 bool is_or = oper == Operator.LogicalOr;
3409 left.EmitBranchable (ec, load_result, is_or);
3411 ig.Emit (OpCodes.Br_S, end);
3413 ig.MarkLabel (load_result);
3414 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3422 // Optimize zero-based operations
3424 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3426 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3427 Constant rc = right as Constant;
3428 if (rc != null && rc.IsDefaultValue) {
3434 EmitOperatorOpcode (ec, oper, l);
3437 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3438 // expression because that would wrap lifted binary operation
3440 if (enum_conversion != null)
3441 enum_conversion.Emit (ec);
3444 public override void EmitSideEffect (EmitContext ec)
3446 if ((oper & Operator.LogicalMask) != 0 ||
3447 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3448 base.EmitSideEffect (ec);
3450 left.EmitSideEffect (ec);
3451 right.EmitSideEffect (ec);
3455 protected override void CloneTo (CloneContext clonectx, Expression t)
3457 Binary target = (Binary) t;
3459 target.left = left.Clone (clonectx);
3460 target.right = right.Clone (clonectx);
3463 public override Expression CreateExpressionTree (EmitContext ec)
3465 return CreateExpressionTree (ec, null);
3468 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3471 bool lift_arg = false;
3474 case Operator.Addition:
3475 if (method == null && ec.CheckState && !IsFloat (type))
3476 method_name = "AddChecked";
3478 method_name = "Add";
3480 case Operator.BitwiseAnd:
3481 method_name = "And";
3483 case Operator.BitwiseOr:
3486 case Operator.Division:
3487 method_name = "Divide";
3489 case Operator.Equality:
3490 method_name = "Equal";
3493 case Operator.ExclusiveOr:
3494 method_name = "ExclusiveOr";
3496 case Operator.GreaterThan:
3497 method_name = "GreaterThan";
3500 case Operator.GreaterThanOrEqual:
3501 method_name = "GreaterThanOrEqual";
3504 case Operator.Inequality:
3505 method_name = "NotEqual";
3508 case Operator.LeftShift:
3509 method_name = "LeftShift";
3511 case Operator.LessThan:
3512 method_name = "LessThan";
3515 case Operator.LessThanOrEqual:
3516 method_name = "LessThanOrEqual";
3519 case Operator.LogicalAnd:
3520 method_name = "AndAlso";
3522 case Operator.LogicalOr:
3523 method_name = "OrElse";
3525 case Operator.Modulus:
3526 method_name = "Modulo";
3528 case Operator.Multiply:
3529 if (method == null && ec.CheckState && !IsFloat (type))
3530 method_name = "MultiplyChecked";
3532 method_name = "Multiply";
3534 case Operator.RightShift:
3535 method_name = "RightShift";
3537 case Operator.Subtraction:
3538 if (method == null && ec.CheckState && !IsFloat (type))
3539 method_name = "SubtractChecked";
3541 method_name = "Subtract";
3545 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3548 Arguments args = new Arguments (2);
3549 args.Add (new Argument (left.CreateExpressionTree (ec)));
3550 args.Add (new Argument (right.CreateExpressionTree (ec)));
3551 if (method != null) {
3553 args.Add (new Argument (new BoolConstant (false, loc)));
3555 args.Add (new Argument (method.CreateExpressionTree (ec)));
3558 return CreateExpressionFactoryCall (method_name, args);
3563 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3564 // b, c, d... may be strings or objects.
3566 public class StringConcat : Expression {
3567 Arguments arguments;
3569 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3572 type = TypeManager.string_type;
3573 eclass = ExprClass.Value;
3575 arguments = new Arguments (2);
3580 public override Expression CreateExpressionTree (EmitContext ec)
3582 Argument arg = arguments [0];
3583 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3587 // Creates nested calls tree from an array of arguments used for IL emit
3589 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3591 Arguments concat_args = new Arguments (2);
3592 Arguments add_args = new Arguments (3);
3594 concat_args.Add (left);
3595 add_args.Add (new Argument (left_etree));
3597 concat_args.Add (arguments [pos]);
3598 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3600 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3604 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3608 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3610 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3611 if (++pos == arguments.Count)
3614 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3615 return CreateExpressionAddCall (ec, left, expr, pos);
3618 public override Expression DoResolve (EmitContext ec)
3623 public void Append (EmitContext ec, Expression operand)
3628 StringConstant sc = operand as StringConstant;
3630 if (arguments.Count != 0) {
3631 Argument last_argument = arguments [arguments.Count - 1];
3632 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3633 if (last_expr_constant != null) {
3634 last_argument.Expr = new StringConstant (
3635 last_expr_constant.Value + sc.Value, sc.Location);
3641 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3643 StringConcat concat_oper = operand as StringConcat;
3644 if (concat_oper != null) {
3645 arguments.AddRange (concat_oper.arguments);
3650 arguments.Add (new Argument (operand));
3653 Expression CreateConcatMemberExpression ()
3655 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3658 public override void Emit (EmitContext ec)
3660 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3661 concat = concat.Resolve (ec);
3666 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3668 arguments.MutateHoistedGenericType (storey);
3673 // User-defined conditional logical operator
3675 public class ConditionalLogicalOperator : UserOperatorCall {
3676 readonly bool is_and;
3679 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3680 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3681 : base (oper_method, arguments, expr_tree, loc)
3683 this.is_and = is_and;
3686 public override Expression DoResolve (EmitContext ec)
3688 MethodInfo method = (MethodInfo)mg;
3689 type = TypeManager.TypeToCoreType (method.ReturnType);
3690 AParametersCollection pd = TypeManager.GetParameterData (method);
3691 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3692 Report.Error (217, loc,
3693 "A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
3694 TypeManager.CSharpSignature (method));
3698 Expression left_dup = new EmptyExpression (type);
3699 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3700 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3701 if (op_true == null || op_false == null) {
3702 Report.Error (218, loc,
3703 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3704 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3708 oper = is_and ? op_false : op_true;
3709 eclass = ExprClass.Value;
3713 public override void Emit (EmitContext ec)
3715 ILGenerator ig = ec.ig;
3716 Label end_target = ig.DefineLabel ();
3719 // Emit and duplicate left argument
3721 arguments [0].Expr.Emit (ec);
3722 ig.Emit (OpCodes.Dup);
3723 arguments.RemoveAt (0);
3725 oper.EmitBranchable (ec, end_target, true);
3727 ig.MarkLabel (end_target);
3731 public class PointerArithmetic : Expression {
3732 Expression left, right;
3736 // We assume that `l' is always a pointer
3738 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3747 public override Expression CreateExpressionTree (EmitContext ec)
3749 Error_PointerInsideExpressionTree ();
3753 public override Expression DoResolve (EmitContext ec)
3755 eclass = ExprClass.Variable;
3757 if (left.Type == TypeManager.void_ptr_type) {
3758 Error (242, "The operation in question is undefined on void pointers");
3765 public override void Emit (EmitContext ec)
3767 Type op_type = left.Type;
3768 ILGenerator ig = ec.ig;
3770 // It must be either array or fixed buffer
3772 if (TypeManager.HasElementType (op_type)) {
3773 element = TypeManager.GetElementType (op_type);
3775 FieldExpr fe = left as FieldExpr;
3777 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
3782 int size = GetTypeSize (element);
3783 Type rtype = right.Type;
3785 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
3787 // handle (pointer - pointer)
3791 ig.Emit (OpCodes.Sub);
3795 ig.Emit (OpCodes.Sizeof, element);
3797 IntLiteral.EmitInt (ig, size);
3798 ig.Emit (OpCodes.Div);
3800 ig.Emit (OpCodes.Conv_I8);
3803 // handle + and - on (pointer op int)
3805 Constant left_const = left as Constant;
3806 if (left_const != null) {
3808 // Optimize ((T*)null) pointer operations
3810 if (left_const.IsDefaultValue) {
3811 left = EmptyExpression.Null;
3819 Constant right_const = right as Constant;
3820 if (right_const != null) {
3822 // Optimize 0-based arithmetic
3824 if (right_const.IsDefaultValue)
3828 right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3832 ig.Emit (OpCodes.Sizeof, element);
3833 right = EmptyExpression.Null;
3838 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
3839 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
3840 ig.Emit (OpCodes.Conv_I);
3841 } else if (rtype == TypeManager.uint32_type) {
3842 ig.Emit (OpCodes.Conv_U);
3845 if (right_const == null && size != 1){
3847 ig.Emit (OpCodes.Sizeof, element);
3849 IntLiteral.EmitInt (ig, size);
3850 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3851 ig.Emit (OpCodes.Conv_I8);
3853 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
3856 if (left_const == null) {
3857 if (rtype == TypeManager.int64_type)
3858 ig.Emit (OpCodes.Conv_I);
3859 else if (rtype == TypeManager.uint64_type)
3860 ig.Emit (OpCodes.Conv_U);
3862 Binary.EmitOperatorOpcode (ec, op, op_type);
3869 /// Implements the ternary conditional operator (?:)
3871 public class Conditional : Expression {
3872 Expression expr, true_expr, false_expr;
3874 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3877 this.true_expr = true_expr;
3878 this.false_expr = false_expr;
3879 this.loc = expr.Location;
3882 public Expression Expr {
3888 public Expression TrueExpr {
3894 public Expression FalseExpr {
3900 public override Expression CreateExpressionTree (EmitContext ec)
3902 Arguments args = new Arguments (3);
3903 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3904 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3905 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3906 return CreateExpressionFactoryCall ("Condition", args);
3909 public override Expression DoResolve (EmitContext ec)
3911 expr = expr.Resolve (ec);
3916 if (expr.Type != TypeManager.bool_type){
3917 expr = Expression.ResolveBoolean (
3924 Assign ass = expr as Assign;
3925 if (ass != null && ass.Source is Constant) {
3926 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3929 true_expr = true_expr.Resolve (ec);
3930 false_expr = false_expr.Resolve (ec);
3932 if (true_expr == null || false_expr == null)
3935 eclass = ExprClass.Value;
3936 Type true_type = true_expr.Type;
3937 Type false_type = false_expr.Type;
3941 // First, if an implicit conversion exists from true_expr
3942 // to false_expr, then the result type is of type false_expr.Type
3944 if (!TypeManager.IsEqual (true_type, false_type)) {
3945 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3948 // Check if both can convert implicitl to each other's type
3950 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
3952 "Can not compute type of conditional expression " +
3953 "as `" + TypeManager.CSharpName (true_expr.Type) +
3954 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3955 "' convert implicitly to each other");
3960 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
3963 Report.Error (173, loc,
3964 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3965 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3970 // Dead code optimalization
3971 Constant c = expr as Constant;
3973 bool is_false = c.IsDefaultValue;
3974 Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
3975 return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
3981 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3983 expr.MutateHoistedGenericType (storey);
3984 true_expr.MutateHoistedGenericType (storey);
3985 false_expr.MutateHoistedGenericType (storey);
3986 type = storey.MutateType (type);
3989 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3994 public override void Emit (EmitContext ec)
3996 ILGenerator ig = ec.ig;
3997 Label false_target = ig.DefineLabel ();
3998 Label end_target = ig.DefineLabel ();
4000 expr.EmitBranchable (ec, false_target, false);
4001 true_expr.Emit (ec);
4003 if (type.IsInterface) {
4004 LocalBuilder temp = ec.GetTemporaryLocal (type);
4005 ig.Emit (OpCodes.Stloc, temp);
4006 ig.Emit (OpCodes.Ldloc, temp);
4007 ec.FreeTemporaryLocal (temp, type);
4010 ig.Emit (OpCodes.Br, end_target);
4011 ig.MarkLabel (false_target);
4012 false_expr.Emit (ec);
4013 ig.MarkLabel (end_target);
4016 protected override void CloneTo (CloneContext clonectx, Expression t)
4018 Conditional target = (Conditional) t;
4020 target.expr = expr.Clone (clonectx);
4021 target.true_expr = true_expr.Clone (clonectx);
4022 target.false_expr = false_expr.Clone (clonectx);
4026 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4027 LocalTemporary temp;
4030 public abstract HoistedVariable GetHoistedVariable (EmitContext ec);
4031 public abstract bool IsFixed { get; }
4032 public abstract bool IsRef { get; }
4033 public abstract string Name { get; }
4034 public abstract void SetHasAddressTaken ();
4037 // Variable IL data, it has to be protected to encapsulate hoisted variables
4039 protected abstract ILocalVariable Variable { get; }
4042 // Variable flow-analysis data
4044 public abstract VariableInfo VariableInfo { get; }
4047 public void AddressOf (EmitContext ec, AddressOp mode)
4049 HoistedVariable hv = GetHoistedVariable (ec);
4051 hv.AddressOf (ec, mode);
4055 Variable.EmitAddressOf (ec);
4058 public override void Emit (EmitContext ec)
4063 public override void EmitSideEffect (EmitContext ec)
4069 // This method is used by parameters that are references, that are
4070 // being passed as references: we only want to pass the pointer (that
4071 // is already stored in the parameter, not the address of the pointer,
4072 // and not the value of the variable).
4074 public void EmitLoad (EmitContext ec)
4079 public void Emit (EmitContext ec, bool leave_copy)
4081 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4083 HoistedVariable hv = GetHoistedVariable (ec);
4085 hv.Emit (ec, leave_copy);
4093 // If we are a reference, we loaded on the stack a pointer
4094 // Now lets load the real value
4096 LoadFromPtr (ec.ig, type);
4100 ec.ig.Emit (OpCodes.Dup);
4103 temp = new LocalTemporary (Type);
4109 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4110 bool prepare_for_load)
4112 HoistedVariable hv = GetHoistedVariable (ec);
4114 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4118 New n_source = source as New;
4119 if (n_source != null) {
4120 if (!n_source.Emit (ec, this)) {
4133 ec.ig.Emit (OpCodes.Dup);
4135 temp = new LocalTemporary (Type);
4141 StoreFromPtr (ec.ig, type);
4143 Variable.EmitAssign (ec);
4151 public bool IsHoisted {
4152 get { return GetHoistedVariable (null) != null; }
4155 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4157 type = storey.MutateType (type);
4164 public class LocalVariableReference : VariableReference {
4165 readonly string name;
4167 public LocalInfo local_info;
4169 bool resolved; // TODO: merge with eclass
4171 public LocalVariableReference (Block block, string name, Location l)
4179 // Setting `is_readonly' to false will allow you to create a writable
4180 // reference to a read-only variable. This is used by foreach and using.
4182 public LocalVariableReference (Block block, string name, Location l,
4183 LocalInfo local_info, bool is_readonly)
4184 : this (block, name, l)
4186 this.local_info = local_info;
4187 this.is_readonly = is_readonly;
4190 public override VariableInfo VariableInfo {
4191 get { return local_info.VariableInfo; }
4194 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4196 return local_info.HoistedVariableReference;
4200 // A local variable is always fixed
4202 public override bool IsFixed {
4203 get { return true; }
4206 public override bool IsRef {
4207 get { return false; }
4210 public bool IsReadOnly {
4211 get { return is_readonly; }
4214 public override string Name {
4215 get { return name; }
4218 public bool VerifyAssigned (EmitContext ec)
4220 VariableInfo variable_info = local_info.VariableInfo;
4221 return variable_info == null || variable_info.IsAssigned (ec, loc);
4224 void ResolveLocalInfo ()
4226 if (local_info == null) {
4227 local_info = Block.GetLocalInfo (Name);
4228 type = local_info.VariableType;
4229 is_readonly = local_info.ReadOnly;
4233 public override void SetHasAddressTaken ()
4235 local_info.AddressTaken = true;
4238 public override Expression CreateExpressionTree (EmitContext ec)
4240 HoistedVariable hv = GetHoistedVariable (ec);
4242 return hv.CreateExpressionTree (ec);
4244 Arguments arg = new Arguments (1);
4245 arg.Add (new Argument (this));
4246 return CreateExpressionFactoryCall ("Constant", arg);
4249 Expression DoResolveBase (EmitContext ec)
4251 type = local_info.VariableType;
4253 Expression e = Block.GetConstantExpression (Name);
4255 return e.Resolve (ec);
4257 VerifyAssigned (ec);
4260 // If we are referencing a variable from the external block
4261 // flag it for capturing
4263 if (ec.MustCaptureVariable (local_info)) {
4264 if (local_info.AddressTaken)
4265 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4267 if (ec.IsVariableCapturingRequired) {
4268 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4269 storey.CaptureLocalVariable (ec, local_info);
4273 resolved |= ec.DoFlowAnalysis;
4274 eclass = ExprClass.Variable;
4278 public override Expression DoResolve (EmitContext ec)
4283 ResolveLocalInfo ();
4284 local_info.Used = true;
4286 if (type == null && local_info.Type is VarExpr) {
4287 local_info.VariableType = TypeManager.object_type;
4288 Error_VariableIsUsedBeforeItIsDeclared (Name);
4292 return DoResolveBase (ec);
4295 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4297 ResolveLocalInfo ();
4300 if (right_side == EmptyExpression.OutAccess)
4301 local_info.Used = true;
4303 // Infer implicitly typed local variable
4305 VarExpr ve = local_info.Type as VarExpr;
4307 if (!ve.InferType (ec, right_side))
4309 type = local_info.VariableType = ve.Type;
4316 if (right_side == EmptyExpression.OutAccess) {
4317 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4318 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4319 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4320 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4321 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4322 } else if (right_side == EmptyExpression.UnaryAddress) {
4323 code = 459; msg = "Cannot take the address of {1} `{0}'";
4325 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4327 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4328 } else if (VariableInfo != null) {
4329 VariableInfo.SetAssigned (ec);
4332 return DoResolveBase (ec);
4335 public override int GetHashCode ()
4337 return Name.GetHashCode ();
4340 public override bool Equals (object obj)
4342 LocalVariableReference lvr = obj as LocalVariableReference;
4346 return Name == lvr.Name && Block == lvr.Block;
4349 protected override ILocalVariable Variable {
4350 get { return local_info; }
4353 public override string ToString ()
4355 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4358 protected override void CloneTo (CloneContext clonectx, Expression t)
4360 LocalVariableReference target = (LocalVariableReference) t;
4362 target.Block = clonectx.LookupBlock (Block);
4363 if (local_info != null)
4364 target.local_info = clonectx.LookupVariable (local_info);
4369 /// This represents a reference to a parameter in the intermediate
4372 public class ParameterReference : VariableReference {
4373 readonly ToplevelParameterInfo pi;
4375 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4381 public override bool IsRef {
4382 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4385 bool HasOutModifier {
4386 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4389 public override HoistedVariable GetHoistedVariable (EmitContext ec)
4391 return pi.Parameter.HoistedVariableReference;
4395 // A ref or out parameter is classified as a moveable variable, even
4396 // if the argument given for the parameter is a fixed variable
4398 public override bool IsFixed {
4399 get { return !IsRef; }
4402 public override string Name {
4403 get { return Parameter.Name; }
4406 public Parameter Parameter {
4407 get { return pi.Parameter; }
4410 public override VariableInfo VariableInfo {
4411 get { return pi.VariableInfo; }
4414 protected override ILocalVariable Variable {
4415 get { return Parameter; }
4418 public bool IsAssigned (EmitContext ec, Location loc)
4420 // HACK: Variables are not captured in probing mode
4421 if (ec.IsInProbingMode)
4424 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4427 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4431 public override void SetHasAddressTaken ()
4433 Parameter.HasAddressTaken = true;
4436 void SetAssigned (EmitContext ec)
4438 if (HasOutModifier && ec.DoFlowAnalysis)
4439 ec.CurrentBranching.SetAssigned (VariableInfo);
4442 bool DoResolveBase (EmitContext ec)
4444 type = pi.ParameterType;
4445 eclass = ExprClass.Variable;
4447 AnonymousExpression am = ec.CurrentAnonymousMethod;
4451 Block b = ec.CurrentBlock;
4453 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4454 for (int i = 0; i < p.Length; ++i) {
4455 if (p [i] != Parameter)
4459 // Skip closest anonymous method parameters
4461 if (b == ec.CurrentBlock && !am.IsIterator)
4465 Report.Error (1628, loc,
4466 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4467 Name, am.ContainerType);
4475 b = b.Toplevel.Parent;
4478 if (pi.Parameter.HasAddressTaken)
4479 AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
4481 if (ec.IsVariableCapturingRequired) {
4482 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4483 storey.CaptureParameter (ec, this);
4489 public override int GetHashCode ()
4491 return Name.GetHashCode ();
4494 public override bool Equals (object obj)
4496 ParameterReference pr = obj as ParameterReference;
4500 return Name == pr.Name;
4503 protected override void CloneTo (CloneContext clonectx, Expression target)
4508 public override Expression CreateExpressionTree (EmitContext ec)
4510 HoistedVariable hv = GetHoistedVariable (ec);
4512 return hv.CreateExpressionTree (ec);
4514 return Parameter.ExpressionTreeVariableReference ();
4518 // Notice that for ref/out parameters, the type exposed is not the
4519 // same type exposed externally.
4522 // externally we expose "int&"
4523 // here we expose "int".
4525 // We record this in "is_ref". This means that the type system can treat
4526 // the type as it is expected, but when we generate the code, we generate
4527 // the alternate kind of code.
4529 public override Expression DoResolve (EmitContext ec)
4531 if (!DoResolveBase (ec))
4534 // HACK: Variables are not captured in probing mode
4535 if (ec.IsInProbingMode)
4538 if (HasOutModifier && ec.DoFlowAnalysis &&
4539 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4545 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4547 if (!DoResolveBase (ec))
4550 // HACK: parameters are not captured when probing is on
4551 if (!ec.IsInProbingMode)
4557 static public void EmitLdArg (ILGenerator ig, int x)
4560 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4561 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4562 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4563 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4565 if (x > byte.MaxValue)
4566 ig.Emit (OpCodes.Ldarg, x);
4568 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4575 /// Invocation of methods or delegates.
4577 public class Invocation : ExpressionStatement {
4578 protected Arguments Arguments;
4579 protected Expression expr;
4580 protected MethodGroupExpr mg;
4581 bool arguments_resolved;
4584 // arguments is an ArrayList, but we do not want to typecast,
4585 // as it might be null.
4587 public Invocation (Expression expr, Arguments arguments)
4589 SimpleName sn = expr as SimpleName;
4591 this.expr = sn.GetMethodGroup ();
4595 Arguments = arguments;
4597 loc = expr.Location;
4600 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4601 : this (expr, arguments)
4603 this.arguments_resolved = arguments_resolved;
4606 public override Expression CreateExpressionTree (EmitContext ec)
4611 // Special conversion for nested expression trees
4613 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4614 args = new Arguments (1);
4615 args.Add (new Argument (this));
4616 return CreateExpressionFactoryCall ("Quote", args);
4619 Expression instance = mg.IsInstance ?
4620 mg.InstanceExpression.CreateExpressionTree (ec) :
4621 new NullLiteral (loc);
4623 args = Arguments.CreateForExpressionTree (ec, Arguments,
4625 mg.CreateExpressionTree (ec));
4628 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4630 return CreateExpressionFactoryCall ("Call", args);
4633 public override Expression DoResolve (EmitContext ec)
4635 // Don't resolve already resolved expression
4636 if (eclass != ExprClass.Invalid)
4639 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4640 if (expr_resolved == null)
4643 mg = expr_resolved as MethodGroupExpr;
4645 Type expr_type = expr_resolved.Type;
4647 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4648 return (new DelegateInvocation (
4649 expr_resolved, Arguments, loc)).Resolve (ec);
4652 MemberExpr me = expr_resolved as MemberExpr;
4654 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4658 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4660 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4661 expr_resolved.GetSignatureForError ());
4665 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4669 // Next, evaluate all the expressions in the argument list
4671 if (Arguments != null && !arguments_resolved) {
4672 Arguments.Resolve (ec);
4675 mg = DoResolveOverload (ec);
4679 MethodInfo method = (MethodInfo)mg;
4680 if (method != null) {
4681 type = TypeManager.TypeToCoreType (method.ReturnType);
4683 // TODO: this is a copy of mg.ResolveMemberAccess method
4684 Expression iexpr = mg.InstanceExpression;
4685 if (method.IsStatic) {
4686 if (iexpr == null ||
4687 iexpr is This || iexpr is EmptyExpression ||
4688 mg.IdenticalTypeName) {
4689 mg.InstanceExpression = null;
4691 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4695 if (iexpr == null || iexpr == EmptyExpression.Null) {
4696 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4701 if (type.IsPointer){
4709 // Only base will allow this invocation to happen.
4711 if (mg.IsBase && method.IsAbstract){
4712 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4716 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
4718 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4720 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4724 IsSpecialMethodInvocation (method, loc);
4726 if (mg.InstanceExpression != null)
4727 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4729 eclass = ExprClass.Value;
4733 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4735 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4738 public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
4740 if (!TypeManager.IsSpecialMethod (method))
4743 Report.SymbolRelatedToPreviousError (method);
4744 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4745 TypeManager.CSharpSignature (method, true));
4750 static Type[] GetVarargsTypes (MethodBase mb, Arguments arguments)
4752 AParametersCollection pd = TypeManager.GetParameterData (mb);
4754 Argument a = arguments [pd.Count - 1];
4755 Arglist list = (Arglist) a.Expr;
4757 return list.ArgumentTypes;
4761 /// This checks the ConditionalAttribute on the method
4763 public static bool IsMethodExcluded (MethodBase method, Location loc)
4765 if (method.IsConstructor)
4768 method = TypeManager.DropGenericMethodArguments (method);
4769 if (method.DeclaringType.Module == RootContext.ToplevelTypes.Builder) {
4770 IMethodData md = TypeManager.GetMethod (method);
4772 return md.IsExcluded ();
4774 // For some methods (generated by delegate class) GetMethod returns null
4775 // because they are not included in builder_to_method table
4779 return AttributeTester.IsConditionalMethodExcluded (method, loc);
4783 /// is_base tells whether we want to force the use of the `call'
4784 /// opcode instead of using callvirt. Call is required to call
4785 /// a specific method, while callvirt will always use the most
4786 /// recent method in the vtable.
4788 /// is_static tells whether this is an invocation on a static method
4790 /// instance_expr is an expression that represents the instance
4791 /// it must be non-null if is_static is false.
4793 /// method is the method to invoke.
4795 /// Arguments is the list of arguments to pass to the method or constructor.
4797 public static void EmitCall (EmitContext ec, bool is_base,
4798 Expression instance_expr,
4799 MethodBase method, Arguments Arguments, Location loc)
4801 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4804 // `dup_args' leaves an extra copy of the arguments on the stack
4805 // `omit_args' does not leave any arguments at all.
4806 // So, basically, you could make one call with `dup_args' set to true,
4807 // and then another with `omit_args' set to true, and the two calls
4808 // would have the same set of arguments. However, each argument would
4809 // only have been evaluated once.
4810 public static void EmitCall (EmitContext ec, bool is_base,
4811 Expression instance_expr,
4812 MethodBase method, Arguments Arguments, Location loc,
4813 bool dup_args, bool omit_args)
4815 ILGenerator ig = ec.ig;
4816 bool struct_call = false;
4817 bool this_call = false;
4818 LocalTemporary this_arg = null;
4820 Type decl_type = method.DeclaringType;
4822 if (IsMethodExcluded (method, loc))
4825 bool is_static = method.IsStatic;
4827 this_call = instance_expr is This;
4828 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
4832 // If this is ourselves, push "this"
4836 Type iexpr_type = instance_expr.Type;
4839 // Push the instance expression
4841 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
4843 // Special case: calls to a function declared in a
4844 // reference-type with a value-type argument need
4845 // to have their value boxed.
4846 if (TypeManager.IsStruct (decl_type) ||
4847 TypeManager.IsGenericParameter (iexpr_type)) {
4849 // If the expression implements IMemoryLocation, then
4850 // we can optimize and use AddressOf on the
4853 // If not we have to use some temporary storage for
4855 if (instance_expr is IMemoryLocation) {
4856 ((IMemoryLocation)instance_expr).
4857 AddressOf (ec, AddressOp.LoadStore);
4859 LocalTemporary temp = new LocalTemporary (iexpr_type);
4860 instance_expr.Emit (ec);
4862 temp.AddressOf (ec, AddressOp.Load);
4865 // avoid the overhead of doing this all the time.
4867 t = TypeManager.GetReferenceType (iexpr_type);
4869 instance_expr.Emit (ec);
4871 // FIXME: should use instance_expr is IMemoryLocation + constraint.
4872 // to help JIT to produce better code
4873 ig.Emit (OpCodes.Box, instance_expr.Type);
4874 t = TypeManager.object_type;
4877 instance_expr.Emit (ec);
4878 t = instance_expr.Type;
4882 ig.Emit (OpCodes.Dup);
4883 if (Arguments != null && Arguments.Count != 0) {
4884 this_arg = new LocalTemporary (t);
4885 this_arg.Store (ec);
4891 if (!omit_args && Arguments != null)
4892 Arguments.Emit (ec, dup_args, this_arg);
4895 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
4896 call_op = OpCodes.Call;
4898 call_op = OpCodes.Callvirt;
4901 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4902 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4906 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4907 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4908 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4915 // and DoFoo is not virtual, you can omit the callvirt,
4916 // because you don't need the null checking behavior.
4918 if (method is MethodInfo)
4919 ig.Emit (call_op, (MethodInfo) method);
4921 ig.Emit (call_op, (ConstructorInfo) method);
4924 public override void Emit (EmitContext ec)
4926 mg.EmitCall (ec, Arguments);
4929 public override void EmitStatement (EmitContext ec)
4934 // Pop the return value if there is one
4936 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4937 ec.ig.Emit (OpCodes.Pop);
4940 protected override void CloneTo (CloneContext clonectx, Expression t)
4942 Invocation target = (Invocation) t;
4944 if (Arguments != null)
4945 target.Arguments = Arguments.Clone (clonectx);
4947 target.expr = expr.Clone (clonectx);
4950 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4952 mg.MutateHoistedGenericType (storey);
4953 if (Arguments != null) {
4954 Arguments.MutateHoistedGenericType (storey);
4960 // It's either a cast or delegate invocation
4962 public class InvocationOrCast : ExpressionStatement
4965 Expression argument;
4967 public InvocationOrCast (Expression expr, Expression argument)
4970 this.argument = argument;
4971 this.loc = expr.Location;
4974 public override Expression CreateExpressionTree (EmitContext ec)
4976 throw new NotSupportedException ("ET");
4979 public override Expression DoResolve (EmitContext ec)
4981 Expression e = ResolveCore (ec);
4985 return e.Resolve (ec);
4988 Expression ResolveCore (EmitContext ec)
4991 // First try to resolve it as a cast.
4993 TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
4995 return new Cast (te, argument, loc);
4999 // This can either be a type or a delegate invocation.
5000 // Let's just resolve it and see what we'll get.
5002 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5007 // Ok, so it's a Cast.
5009 if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
5010 return new Cast (expr, argument, loc);
5013 if (expr.eclass == ExprClass.Namespace) {
5014 expr.Error_UnexpectedKind (null, "type", loc);
5019 // It's a delegate invocation.
5021 if (!TypeManager.IsDelegateType (expr.Type)) {
5022 Error (149, "Method name expected");
5026 ArrayList args = new ArrayList (1);
5027 args.Add (new Argument (argument, Argument.AType.Expression));
5028 return new DelegateInvocation (expr, args, loc);
5031 public override ExpressionStatement ResolveStatement (EmitContext ec)
5033 Expression e = ResolveCore (ec);
5037 ExpressionStatement s = e as ExpressionStatement;
5039 Error_InvalidExpressionStatement ();
5043 return s.ResolveStatement (ec);
5046 public override void Emit (EmitContext ec)
5048 throw new Exception ("Cannot happen");
5051 public override void EmitStatement (EmitContext ec)
5053 throw new Exception ("Cannot happen");
5056 protected override void CloneTo (CloneContext clonectx, Expression t)
5058 InvocationOrCast target = (InvocationOrCast) t;
5060 target.expr = expr.Clone (clonectx);
5061 target.argument = argument.Clone (clonectx);
5067 /// Implements the new expression
5069 public class New : ExpressionStatement, IMemoryLocation {
5070 Arguments Arguments;
5073 // During bootstrap, it contains the RequestedType,
5074 // but if `type' is not null, it *might* contain a NewDelegate
5075 // (because of field multi-initialization)
5077 Expression RequestedType;
5079 MethodGroupExpr method;
5081 bool is_type_parameter;
5083 public New (Expression requested_type, Arguments arguments, Location l)
5085 RequestedType = requested_type;
5086 Arguments = arguments;
5091 /// Converts complex core type syntax like 'new int ()' to simple constant
5093 public static Constant Constantify (Type t)
5095 if (t == TypeManager.int32_type)
5096 return new IntConstant (0, Location.Null);
5097 if (t == TypeManager.uint32_type)
5098 return new UIntConstant (0, Location.Null);
5099 if (t == TypeManager.int64_type)
5100 return new LongConstant (0, Location.Null);
5101 if (t == TypeManager.uint64_type)
5102 return new ULongConstant (0, Location.Null);
5103 if (t == TypeManager.float_type)
5104 return new FloatConstant (0, Location.Null);
5105 if (t == TypeManager.double_type)
5106 return new DoubleConstant (0, Location.Null);
5107 if (t == TypeManager.short_type)
5108 return new ShortConstant (0, Location.Null);
5109 if (t == TypeManager.ushort_type)
5110 return new UShortConstant (0, Location.Null);
5111 if (t == TypeManager.sbyte_type)
5112 return new SByteConstant (0, Location.Null);
5113 if (t == TypeManager.byte_type)
5114 return new ByteConstant (0, Location.Null);
5115 if (t == TypeManager.char_type)
5116 return new CharConstant ('\0', Location.Null);
5117 if (t == TypeManager.bool_type)
5118 return new BoolConstant (false, Location.Null);
5119 if (t == TypeManager.decimal_type)
5120 return new DecimalConstant (0, Location.Null);
5121 if (TypeManager.IsEnumType (t))
5122 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5123 if (TypeManager.IsNullableType (t))
5124 return Nullable.LiftedNull.Create (t, Location.Null);
5130 // Checks whether the type is an interface that has the
5131 // [ComImport, CoClass] attributes and must be treated
5134 public Expression CheckComImport (EmitContext ec)
5136 if (!type.IsInterface)
5140 // Turn the call into:
5141 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5143 Type real_class = AttributeTester.GetCoClassAttribute (type);
5144 if (real_class == null)
5147 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5148 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5149 return cast.Resolve (ec);
5152 public override Expression CreateExpressionTree (EmitContext ec)
5155 if (method == null) {
5156 args = new Arguments (1);
5157 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5159 args = Arguments.CreateForExpressionTree (ec, Arguments,
5160 method.CreateExpressionTree (ec));
5163 return CreateExpressionFactoryCall ("New", args);
5166 public override Expression DoResolve (EmitContext ec)
5169 // The New DoResolve might be called twice when initializing field
5170 // expressions (see EmitFieldInitializers, the call to
5171 // GetInitializerExpression will perform a resolve on the expression,
5172 // and later the assign will trigger another resolution
5174 // This leads to bugs (#37014)
5177 if (RequestedType is NewDelegate)
5178 return RequestedType;
5182 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5188 if (type.IsPointer) {
5189 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5190 TypeManager.CSharpName (type));
5194 if (Arguments == null) {
5195 Constant c = Constantify (type);
5197 return ReducedExpression.Create (c, this);
5200 if (TypeManager.IsDelegateType (type)) {
5201 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5204 if (TypeManager.IsGenericParameter (type)) {
5205 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5207 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5208 Error (304, String.Format (
5209 "Cannot create an instance of the " +
5210 "variable type '{0}' because it " +
5211 "doesn't have the new() constraint",
5216 if ((Arguments != null) && (Arguments.Count != 0)) {
5217 Error (417, String.Format (
5218 "`{0}': cannot provide arguments " +
5219 "when creating an instance of a " +
5220 "variable type.", type));
5224 if (TypeManager.activator_create_instance == null) {
5225 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5226 if (activator_type != null) {
5227 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5228 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5232 is_type_parameter = true;
5233 eclass = ExprClass.Value;
5237 if (type.IsAbstract && type.IsSealed) {
5238 Report.SymbolRelatedToPreviousError (type);
5239 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5243 if (type.IsInterface || type.IsAbstract){
5244 if (!TypeManager.IsGenericType (type)) {
5245 RequestedType = CheckComImport (ec);
5246 if (RequestedType != null)
5247 return RequestedType;
5250 Report.SymbolRelatedToPreviousError (type);
5251 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5255 bool is_struct = TypeManager.IsStruct (type);
5256 eclass = ExprClass.Value;
5259 // SRE returns a match for .ctor () on structs (the object constructor),
5260 // so we have to manually ignore it.
5262 if (is_struct && Arguments == null)
5265 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5266 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5267 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5269 if (Arguments != null)
5270 Arguments.Resolve (ec);
5275 method = ml as MethodGroupExpr;
5276 if (method == null) {
5277 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5281 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5288 bool DoEmitTypeParameter (EmitContext ec)
5291 ILGenerator ig = ec.ig;
5292 // IMemoryLocation ml;
5294 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5295 new Type [] { type });
5297 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5298 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5299 ig.Emit (OpCodes.Call, ci);
5303 // Allow DoEmit() to be called multiple times.
5304 // We need to create a new LocalTemporary each time since
5305 // you can't share LocalBuilders among ILGeneators.
5306 LocalTemporary temp = new LocalTemporary (type);
5308 Label label_activator = ig.DefineLabel ();
5309 Label label_end = ig.DefineLabel ();
5311 temp.AddressOf (ec, AddressOp.Store);
5312 ig.Emit (OpCodes.Initobj, type);
5315 ig.Emit (OpCodes.Box, type);
5316 ig.Emit (OpCodes.Brfalse, label_activator);
5318 temp.AddressOf (ec, AddressOp.Store);
5319 ig.Emit (OpCodes.Initobj, type);
5321 ig.Emit (OpCodes.Br_S, label_end);
5323 ig.MarkLabel (label_activator);
5325 ig.Emit (OpCodes.Call, ci);
5326 ig.MarkLabel (label_end);
5329 throw new InternalErrorException ();
5334 // This Emit can be invoked in two contexts:
5335 // * As a mechanism that will leave a value on the stack (new object)
5336 // * As one that wont (init struct)
5338 // If we are dealing with a ValueType, we have a few
5339 // situations to deal with:
5341 // * The target is a ValueType, and we have been provided
5342 // the instance (this is easy, we are being assigned).
5344 // * The target of New is being passed as an argument,
5345 // to a boxing operation or a function that takes a
5348 // In this case, we need to create a temporary variable
5349 // that is the argument of New.
5351 // Returns whether a value is left on the stack
5353 // *** Implementation note ***
5355 // To benefit from this optimization, each assignable expression
5356 // has to manually cast to New and call this Emit.
5358 // TODO: It's worth to implement it for arrays and fields
5360 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5362 bool is_value_type = TypeManager.IsValueType (type);
5363 ILGenerator ig = ec.ig;
5364 VariableReference vr = target as VariableReference;
5366 if (target != null && is_value_type && (vr != null || method == null)) {
5367 target.AddressOf (ec, AddressOp.Store);
5368 } else if (vr != null && vr.IsRef) {
5372 if (is_type_parameter)
5373 return DoEmitTypeParameter (ec);
5375 if (Arguments != null)
5376 Arguments.Emit (ec);
5378 if (is_value_type) {
5379 if (method == null) {
5380 ig.Emit (OpCodes.Initobj, type);
5385 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5390 ConstructorInfo ci = (ConstructorInfo) method;
5392 if (TypeManager.IsGenericType (type))
5393 ci = TypeBuilder.GetConstructor (type, ci);
5396 ig.Emit (OpCodes.Newobj, ci);
5400 public override void Emit (EmitContext ec)
5402 LocalTemporary v = null;
5403 if (method == null && TypeManager.IsValueType (type)) {
5404 // TODO: Use temporary variable from pool
5405 v = new LocalTemporary (type);
5412 public override void EmitStatement (EmitContext ec)
5414 LocalTemporary v = null;
5415 if (method == null && TypeManager.IsValueType (type)) {
5416 // TODO: Use temporary variable from pool
5417 v = new LocalTemporary (type);
5421 ec.ig.Emit (OpCodes.Pop);
5424 public bool IsDefaultValueType {
5426 return TypeManager.IsValueType (type) && !HasInitializer && Arguments == null;
5430 public virtual bool HasInitializer {
5436 public void AddressOf (EmitContext ec, AddressOp mode)
5438 EmitAddressOf (ec, mode);
5441 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5443 LocalTemporary value_target = new LocalTemporary (type);
5445 if (is_type_parameter) {
5446 DoEmitTypeParameter (ec);
5447 value_target.Store (ec);
5448 value_target.AddressOf (ec, mode);
5449 return value_target;
5452 if (!TypeManager.IsStruct (type)){
5454 // We throw an exception. So far, I believe we only need to support
5456 // foreach (int j in new StructType ())
5459 throw new Exception ("AddressOf should not be used for classes");
5462 value_target.AddressOf (ec, AddressOp.Store);
5464 if (method == null) {
5465 ec.ig.Emit (OpCodes.Initobj, type);
5467 if (Arguments != null)
5468 Arguments.Emit (ec);
5470 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5473 value_target.AddressOf (ec, mode);
5474 return value_target;
5477 protected override void CloneTo (CloneContext clonectx, Expression t)
5479 New target = (New) t;
5481 target.RequestedType = RequestedType.Clone (clonectx);
5482 if (Arguments != null){
5483 target.Arguments = Arguments.Clone (clonectx);
5487 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5489 if (method != null) {
5490 method.MutateHoistedGenericType (storey);
5491 if (Arguments != null) {
5492 Arguments.MutateHoistedGenericType (storey);
5496 type = storey.MutateType (type);
5501 /// 14.5.10.2: Represents an array creation expression.
5505 /// There are two possible scenarios here: one is an array creation
5506 /// expression that specifies the dimensions and optionally the
5507 /// initialization data and the other which does not need dimensions
5508 /// specified but where initialization data is mandatory.
5510 public class ArrayCreation : Expression {
5511 FullNamedExpression requested_base_type;
5512 ArrayList initializers;
5515 // The list of Argument types.
5516 // This is used to construct the `newarray' or constructor signature
5518 protected ArrayList arguments;
5520 protected Type array_element_type;
5521 bool expect_initializers = false;
5522 int num_arguments = 0;
5523 protected int dimensions;
5524 protected readonly string rank;
5526 protected ArrayList array_data;
5530 // The number of constants in array initializers
5531 int const_initializers_count;
5532 bool only_constant_initializers;
5534 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5536 this.requested_base_type = requested_base_type;
5537 this.initializers = initializers;
5541 arguments = new ArrayList (exprs.Count);
5543 foreach (Expression e in exprs) {
5549 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5551 this.requested_base_type = requested_base_type;
5552 this.initializers = initializers;
5556 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5558 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5560 //dimensions = tmp.Length - 1;
5561 expect_initializers = true;
5564 public static void Error_IncorrectArrayInitializer (Location loc)
5566 Report.Error (178, loc, "Invalid rank specifier: expected `,' or `]'");
5569 protected override void Error_NegativeArrayIndex (Location loc)
5571 Report.Error (248, loc, "Cannot create an array with a negative size");
5574 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims, int child_bounds)
5576 if (specified_dims) {
5577 Expression a = (Expression) arguments [idx];
5582 Constant c = a as Constant;
5584 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5588 Report.Error (150, a.Location, "A constant value is expected");
5592 int value = (int) c.GetValue ();
5594 if (value != probe.Count) {
5595 Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5599 bounds [idx] = value;
5602 only_constant_initializers = true;
5603 for (int i = 0; i < probe.Count; ++i) {
5604 object o = probe [i];
5605 if (o is ArrayList) {
5606 ArrayList sub_probe = o as ArrayList;
5607 if (idx + 1 >= dimensions){
5608 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5612 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5615 } else if (child_bounds > 1) {
5616 Report.Error (846, ((Expression) o).Location, "A nested array initializer was expected");
5618 Expression element = ResolveArrayElement (ec, (Expression) o);
5619 if (element == null)
5622 // Initializers with the default values can be ignored
5623 Constant c = element as Constant;
5625 if (c.IsDefaultInitializer (array_element_type)) {
5629 ++const_initializers_count;
5632 only_constant_initializers = false;
5635 array_data.Add (element);
5642 public override Expression CreateExpressionTree (EmitContext ec)
5646 if (array_data == null) {
5647 args = new Arguments (arguments.Count + 1);
5648 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5649 foreach (Expression a in arguments) {
5650 if (arguments.Count == 1) {
5651 Constant c = a as Constant;
5652 if (c.IsDefaultValue)
5653 return CreateExpressionFactoryCall ("NewArrayInit", args);
5655 args.Add (new Argument (a.CreateExpressionTree (ec)));
5658 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5661 if (dimensions > 1) {
5662 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5666 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5667 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5668 if (array_data != null) {
5669 for (int i = 0; i < array_data.Count; ++i) {
5670 Expression e = (Expression) array_data [i];
5672 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5674 args.Add (new Argument (e.CreateExpressionTree (ec)));
5678 return CreateExpressionFactoryCall ("NewArrayInit", args);
5681 public void UpdateIndices ()
5684 for (ArrayList probe = initializers; probe != null;) {
5685 if (probe.Count > 0 && probe [0] is ArrayList) {
5686 Expression e = new IntConstant (probe.Count, Location.Null);
5689 bounds [i++] = probe.Count;
5691 probe = (ArrayList) probe [0];
5694 Expression e = new IntConstant (probe.Count, Location.Null);
5697 bounds [i++] = probe.Count;
5704 Expression first_emit;
5705 LocalTemporary first_emit_temp;
5707 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5709 element = element.Resolve (ec);
5710 if (element == null)
5713 if (element is CompoundAssign.TargetExpression) {
5714 if (first_emit != null)
5715 throw new InternalErrorException ("Can only handle one mutator at a time");
5716 first_emit = element;
5717 element = first_emit_temp = new LocalTemporary (element.Type);
5720 return Convert.ImplicitConversionRequired (
5721 ec, element, array_element_type, loc);
5724 protected bool ResolveInitializers (EmitContext ec)
5726 if (initializers == null) {
5727 return !expect_initializers;
5731 // We use this to store all the date values in the order in which we
5732 // will need to store them in the byte blob later
5734 array_data = new ArrayList ();
5735 bounds = new System.Collections.Specialized.HybridDictionary ();
5737 if (arguments != null)
5738 return CheckIndices (ec, initializers, 0, true, dimensions);
5740 arguments = new ArrayList ();
5742 if (!CheckIndices (ec, initializers, 0, false, dimensions))
5751 // Resolved the type of the array
5753 bool ResolveArrayType (EmitContext ec)
5755 if (requested_base_type == null) {
5756 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5760 if (requested_base_type is VarExpr) {
5761 Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5765 StringBuilder array_qualifier = new StringBuilder (rank);
5768 // `In the first form allocates an array instace of the type that results
5769 // from deleting each of the individual expression from the expression list'
5771 if (num_arguments > 0) {
5772 array_qualifier.Append ("[");
5773 for (int i = num_arguments-1; i > 0; i--)
5774 array_qualifier.Append (",");
5775 array_qualifier.Append ("]");
5781 TypeExpr array_type_expr;
5782 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5783 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5784 if (array_type_expr == null)
5787 type = array_type_expr.Type;
5788 array_element_type = TypeManager.GetElementType (type);
5789 dimensions = type.GetArrayRank ();
5794 public override Expression DoResolve (EmitContext ec)
5799 if (!ResolveArrayType (ec))
5803 // First step is to validate the initializers and fill
5804 // in any missing bits
5806 if (!ResolveInitializers (ec))
5809 for (int i = 0; i < arguments.Count; ++i) {
5810 Expression e = ((Expression) arguments[i]).Resolve (ec);
5814 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
5817 eclass = ExprClass.Value;
5821 MethodInfo GetArrayMethod (int arguments)
5823 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
5825 Type[] arg_types = new Type[arguments];
5826 for (int i = 0; i < arguments; i++)
5827 arg_types[i] = TypeManager.int32_type;
5829 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5833 Report.Error (-6, "New invocation: Can not find a constructor for " +
5834 "this argument list");
5841 byte [] MakeByteBlob ()
5846 int count = array_data.Count;
5848 if (TypeManager.IsEnumType (array_element_type))
5849 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
5851 factor = GetTypeSize (array_element_type);
5853 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5855 data = new byte [(count * factor + 3) & ~3];
5858 for (int i = 0; i < count; ++i) {
5859 object v = array_data [i];
5861 if (v is EnumConstant)
5862 v = ((EnumConstant) v).Child;
5864 if (v is Constant && !(v is StringConstant))
5865 v = ((Constant) v).GetValue ();
5871 if (array_element_type == TypeManager.int64_type){
5872 if (!(v is Expression)){
5873 long val = (long) v;
5875 for (int j = 0; j < factor; ++j) {
5876 data [idx + j] = (byte) (val & 0xFF);
5880 } else if (array_element_type == TypeManager.uint64_type){
5881 if (!(v is Expression)){
5882 ulong val = (ulong) v;
5884 for (int j = 0; j < factor; ++j) {
5885 data [idx + j] = (byte) (val & 0xFF);
5889 } else if (array_element_type == TypeManager.float_type) {
5890 if (!(v is Expression)){
5891 element = BitConverter.GetBytes ((float) v);
5893 for (int j = 0; j < factor; ++j)
5894 data [idx + j] = element [j];
5895 if (!BitConverter.IsLittleEndian)
5896 System.Array.Reverse (data, idx, 4);
5898 } else if (array_element_type == TypeManager.double_type) {
5899 if (!(v is Expression)){
5900 element = BitConverter.GetBytes ((double) v);
5902 for (int j = 0; j < factor; ++j)
5903 data [idx + j] = element [j];
5905 // FIXME: Handle the ARM float format.
5906 if (!BitConverter.IsLittleEndian)
5907 System.Array.Reverse (data, idx, 8);
5909 } else if (array_element_type == TypeManager.char_type){
5910 if (!(v is Expression)){
5911 int val = (int) ((char) v);
5913 data [idx] = (byte) (val & 0xff);
5914 data [idx+1] = (byte) (val >> 8);
5916 } else if (array_element_type == TypeManager.short_type){
5917 if (!(v is Expression)){
5918 int val = (int) ((short) v);
5920 data [idx] = (byte) (val & 0xff);
5921 data [idx+1] = (byte) (val >> 8);
5923 } else if (array_element_type == TypeManager.ushort_type){
5924 if (!(v is Expression)){
5925 int val = (int) ((ushort) v);
5927 data [idx] = (byte) (val & 0xff);
5928 data [idx+1] = (byte) (val >> 8);
5930 } else if (array_element_type == TypeManager.int32_type) {
5931 if (!(v is Expression)){
5934 data [idx] = (byte) (val & 0xff);
5935 data [idx+1] = (byte) ((val >> 8) & 0xff);
5936 data [idx+2] = (byte) ((val >> 16) & 0xff);
5937 data [idx+3] = (byte) (val >> 24);
5939 } else if (array_element_type == TypeManager.uint32_type) {
5940 if (!(v is Expression)){
5941 uint val = (uint) v;
5943 data [idx] = (byte) (val & 0xff);
5944 data [idx+1] = (byte) ((val >> 8) & 0xff);
5945 data [idx+2] = (byte) ((val >> 16) & 0xff);
5946 data [idx+3] = (byte) (val >> 24);
5948 } else if (array_element_type == TypeManager.sbyte_type) {
5949 if (!(v is Expression)){
5950 sbyte val = (sbyte) v;
5951 data [idx] = (byte) val;
5953 } else if (array_element_type == TypeManager.byte_type) {
5954 if (!(v is Expression)){
5955 byte val = (byte) v;
5956 data [idx] = (byte) val;
5958 } else if (array_element_type == TypeManager.bool_type) {
5959 if (!(v is Expression)){
5960 bool val = (bool) v;
5961 data [idx] = (byte) (val ? 1 : 0);
5963 } else if (array_element_type == TypeManager.decimal_type){
5964 if (!(v is Expression)){
5965 int [] bits = Decimal.GetBits ((decimal) v);
5968 // FIXME: For some reason, this doesn't work on the MS runtime.
5969 int [] nbits = new int [4];
5970 nbits [0] = bits [3];
5971 nbits [1] = bits [2];
5972 nbits [2] = bits [0];
5973 nbits [3] = bits [1];
5975 for (int j = 0; j < 4; j++){
5976 data [p++] = (byte) (nbits [j] & 0xff);
5977 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5978 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5979 data [p++] = (byte) (nbits [j] >> 24);
5983 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5991 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5993 array_element_type = storey.MutateType (array_element_type);
5994 type = storey.MutateType (type);
5995 if (arguments != null) {
5996 foreach (Expression e in arguments)
5997 e.MutateHoistedGenericType (storey);
6000 if (array_data != null) {
6001 foreach (Expression e in array_data) {
6002 // Don't mutate values optimized away
6006 e.MutateHoistedGenericType (storey);
6012 // Emits the initializers for the array
6014 void EmitStaticInitializers (EmitContext ec)
6016 // FIXME: This should go to Resolve !
6017 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6018 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6019 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6020 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6021 if (TypeManager.void_initializearray_array_fieldhandle == null)
6026 // First, the static data
6029 ILGenerator ig = ec.ig;
6031 byte [] data = MakeByteBlob ();
6033 fb = RootContext.MakeStaticData (data);
6035 ig.Emit (OpCodes.Dup);
6036 ig.Emit (OpCodes.Ldtoken, fb);
6037 ig.Emit (OpCodes.Call,
6038 TypeManager.void_initializearray_array_fieldhandle);
6042 // Emits pieces of the array that can not be computed at compile
6043 // time (variables and string locations).
6045 // This always expect the top value on the stack to be the array
6047 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6049 ILGenerator ig = ec.ig;
6050 int dims = bounds.Count;
6051 int [] current_pos = new int [dims];
6053 MethodInfo set = null;
6056 Type [] args = new Type [dims + 1];
6058 for (int j = 0; j < dims; j++)
6059 args [j] = TypeManager.int32_type;
6060 args [dims] = array_element_type;
6062 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6064 CallingConventions.HasThis | CallingConventions.Standard,
6065 TypeManager.void_type, args);
6068 for (int i = 0; i < array_data.Count; i++){
6070 Expression e = (Expression)array_data [i];
6072 // Constant can be initialized via StaticInitializer
6073 if (e != null && !(!emitConstants && e is Constant)) {
6074 Type etype = e.Type;
6076 ig.Emit (OpCodes.Dup);
6078 for (int idx = 0; idx < dims; idx++)
6079 IntConstant.EmitInt (ig, current_pos [idx]);
6082 // If we are dealing with a struct, get the
6083 // address of it, so we can store it.
6085 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6086 (!TypeManager.IsBuiltinOrEnum (etype) ||
6087 etype == TypeManager.decimal_type)) {
6089 ig.Emit (OpCodes.Ldelema, etype);
6095 bool is_stobj, has_type_arg;
6096 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6098 ig.Emit (OpCodes.Stobj, etype);
6099 else if (has_type_arg)
6100 ig.Emit (op, etype);
6104 ig.Emit (OpCodes.Call, set);
6111 for (int j = dims - 1; j >= 0; j--){
6113 if (current_pos [j] < (int) bounds [j])
6115 current_pos [j] = 0;
6120 public override void Emit (EmitContext ec)
6122 ILGenerator ig = ec.ig;
6124 if (first_emit != null) {
6125 first_emit.Emit (ec);
6126 first_emit_temp.Store (ec);
6129 foreach (Expression e in arguments)
6132 if (arguments.Count == 1)
6133 ig.Emit (OpCodes.Newarr, array_element_type);
6135 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6138 if (initializers == null)
6141 // Emit static initializer for arrays which have contain more than 4 items and
6142 // the static initializer will initialize at least 25% of array values.
6143 // NOTE: const_initializers_count does not contain default constant values.
6144 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6145 TypeManager.IsPrimitiveType (array_element_type)) {
6146 EmitStaticInitializers (ec);
6148 if (!only_constant_initializers)
6149 EmitDynamicInitializers (ec, false);
6151 EmitDynamicInitializers (ec, true);
6154 if (first_emit_temp != null)
6155 first_emit_temp.Release (ec);
6158 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6160 if (arguments.Count != 1) {
6161 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6162 return base.GetAttributableValue (ec, null, out value);
6165 if (array_data == null) {
6166 Constant c = (Constant) arguments [0];
6167 if (c.IsDefaultValue) {
6168 value = Array.CreateInstance (array_element_type, 0);
6171 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6172 return base.GetAttributableValue (ec, null, out value);
6175 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6176 object element_value;
6177 for (int i = 0; i < ret.Length; ++i)
6179 Expression e = (Expression)array_data [i];
6181 // Is null when an initializer is optimized (value == predefined value)
6185 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6189 ret.SetValue (element_value, i);
6195 protected override void CloneTo (CloneContext clonectx, Expression t)
6197 ArrayCreation target = (ArrayCreation) t;
6199 if (requested_base_type != null)
6200 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6202 if (arguments != null){
6203 target.arguments = new ArrayList (arguments.Count);
6204 foreach (Expression e in arguments)
6205 target.arguments.Add (e.Clone (clonectx));
6208 if (initializers != null){
6209 target.initializers = new ArrayList (initializers.Count);
6210 foreach (object initializer in initializers)
6211 if (initializer is ArrayList) {
6212 ArrayList this_al = (ArrayList)initializer;
6213 ArrayList al = new ArrayList (this_al.Count);
6214 target.initializers.Add (al);
6215 foreach (Expression e in this_al)
6216 al.Add (e.Clone (clonectx));
6218 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6225 // Represents an implicitly typed array epxression
6227 public class ImplicitlyTypedArrayCreation : ArrayCreation
6229 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6230 : base (null, rank, initializers, loc)
6232 if (RootContext.Version <= LanguageVersion.ISO_2)
6233 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6235 if (rank.Length > 2) {
6236 while (rank [++dimensions] == ',');
6242 public override Expression DoResolve (EmitContext ec)
6247 if (!ResolveInitializers (ec))
6250 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6251 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6252 arguments.Count != dimensions) {
6253 Error_NoBestType ();
6258 // At this point we found common base type for all initializer elements
6259 // but we have to be sure that all static initializer elements are of
6262 UnifyInitializerElement (ec);
6264 type = TypeManager.GetConstructedType (array_element_type, rank);
6265 eclass = ExprClass.Value;
6269 void Error_NoBestType ()
6271 Report.Error (826, loc,
6272 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6276 // Converts static initializer only
6278 void UnifyInitializerElement (EmitContext ec)
6280 for (int i = 0; i < array_data.Count; ++i) {
6281 Expression e = (Expression)array_data[i];
6283 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6287 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6289 element = element.Resolve (ec);
6290 if (element == null)
6293 if (array_element_type == null) {
6294 if (element.Type != TypeManager.null_type)
6295 array_element_type = element.Type;
6300 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6304 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6305 array_element_type = element.Type;
6309 Error_NoBestType ();
6314 public sealed class CompilerGeneratedThis : This
6316 public static This Instance = new CompilerGeneratedThis ();
6318 private CompilerGeneratedThis ()
6319 : base (Location.Null)
6323 public CompilerGeneratedThis (Type type, Location loc)
6329 public override Expression DoResolve (EmitContext ec)
6331 eclass = ExprClass.Variable;
6333 type = ec.ContainerType;
6337 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6344 /// Represents the `this' construct
6347 public class This : VariableReference
6349 sealed class ThisVariable : ILocalVariable
6351 public static readonly ILocalVariable Instance = new ThisVariable ();
6353 public void Emit (EmitContext ec)
6355 ec.ig.Emit (OpCodes.Ldarg_0);
6358 public void EmitAssign (EmitContext ec)
6360 throw new InvalidOperationException ();
6363 public void EmitAddressOf (EmitContext ec)
6365 ec.ig.Emit (OpCodes.Ldarg_0);
6370 VariableInfo variable_info;
6373 public This (Block block, Location loc)
6379 public This (Location loc)
6384 public override VariableInfo VariableInfo {
6385 get { return variable_info; }
6388 public override bool IsFixed {
6389 get { return false; }
6392 public override HoistedVariable GetHoistedVariable (EmitContext ec)
6394 // Is null when probing IsHoisted
6398 if (ec.CurrentAnonymousMethod == null)
6401 AnonymousMethodStorey storey = ec.CurrentAnonymousMethod.Storey;
6402 while (storey != null) {
6403 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6405 return storey.HoistedThis;
6413 public override bool IsRef {
6414 get { return is_struct; }
6417 protected override ILocalVariable Variable {
6418 get { return ThisVariable.Instance; }
6421 public static bool IsThisAvailable (EmitContext ec)
6423 if (ec.IsStatic || ec.IsInFieldInitializer)
6426 if (ec.CurrentAnonymousMethod == null)
6429 if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
6435 public bool ResolveBase (EmitContext ec)
6437 if (eclass != ExprClass.Invalid)
6440 eclass = ExprClass.Variable;
6442 if (ec.TypeContainer.CurrentType != null)
6443 type = ec.TypeContainer.CurrentType;
6445 type = ec.ContainerType;
6447 if (!IsThisAvailable (ec)) {
6449 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6451 Report.Error (1673, loc,
6452 "Anonymous methods inside structs cannot access instance members of `this'. " +
6453 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6457 is_struct = ec.TypeContainer is Struct;
6459 if (block != null) {
6460 if (block.Toplevel.ThisVariable != null)
6461 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6463 AnonymousExpression am = ec.CurrentAnonymousMethod;
6464 if (am != null && ec.IsVariableCapturingRequired) {
6465 am.SetHasThisAccess ();
6473 // Called from Invocation to check if the invocation is correct
6475 public override void CheckMarshalByRefAccess (EmitContext ec)
6477 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6478 !variable_info.IsAssigned (ec)) {
6479 Error (188, "The `this' object cannot be used before all of its " +
6480 "fields are assigned to");
6481 variable_info.SetAssigned (ec);
6485 public override Expression CreateExpressionTree (EmitContext ec)
6487 Arguments args = new Arguments (1);
6488 args.Add (new Argument (this));
6490 // Use typeless constant for ldarg.0 to save some
6491 // space and avoid problems with anonymous stories
6492 return CreateExpressionFactoryCall ("Constant", args);
6495 public override Expression DoResolve (EmitContext ec)
6497 if (!ResolveBase (ec))
6501 if (ec.IsInFieldInitializer) {
6502 Error (27, "Keyword `this' is not available in the current context");
6509 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6511 if (!ResolveBase (ec))
6514 if (variable_info != null)
6515 variable_info.SetAssigned (ec);
6517 if (ec.TypeContainer is Class){
6518 if (right_side == EmptyExpression.UnaryAddress)
6519 Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6520 else if (right_side == EmptyExpression.OutAccess)
6521 Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6523 Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6529 public override int GetHashCode()
6531 return block.GetHashCode ();
6534 public override string Name {
6535 get { return "this"; }
6538 public override bool Equals (object obj)
6540 This t = obj as This;
6544 return block == t.block;
6547 protected override void CloneTo (CloneContext clonectx, Expression t)
6549 This target = (This) t;
6551 target.block = clonectx.LookupBlock (block);
6554 public override void SetHasAddressTaken ()
6561 /// Represents the `__arglist' construct
6563 public class ArglistAccess : Expression
6565 public ArglistAccess (Location loc)
6570 public override Expression CreateExpressionTree (EmitContext ec)
6572 throw new NotSupportedException ("ET");
6575 public override Expression DoResolve (EmitContext ec)
6577 eclass = ExprClass.Variable;
6578 type = TypeManager.runtime_argument_handle_type;
6580 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
6582 Error (190, "The __arglist construct is valid only within " +
6583 "a variable argument method");
6590 public override void Emit (EmitContext ec)
6592 ec.ig.Emit (OpCodes.Arglist);
6595 protected override void CloneTo (CloneContext clonectx, Expression target)
6602 /// Represents the `__arglist (....)' construct
6604 class Arglist : Expression
6606 Arguments Arguments;
6608 public Arglist (Location loc)
6613 public Arglist (Arguments args, Location l)
6619 public Type[] ArgumentTypes {
6621 if (Arguments == null)
6622 return Type.EmptyTypes;
6624 Type[] retval = new Type [Arguments.Count];
6625 for (int i = 0; i < retval.Length; i++)
6626 retval [i] = Arguments [i].Expr.Type;
6632 public override Expression CreateExpressionTree (EmitContext ec)
6634 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6638 public override Expression DoResolve (EmitContext ec)
6640 eclass = ExprClass.Variable;
6641 type = InternalType.Arglist;
6642 if (Arguments != null)
6643 Arguments.Resolve (ec);
6648 public override void Emit (EmitContext ec)
6650 if (Arguments != null)
6651 Arguments.Emit (ec);
6654 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6656 if (Arguments != null)
6657 Arguments.MutateHoistedGenericType (storey);
6660 protected override void CloneTo (CloneContext clonectx, Expression t)
6662 Arglist target = (Arglist) t;
6664 if (Arguments != null)
6665 target.Arguments = Arguments.Clone (clonectx);
6670 /// Implements the typeof operator
6672 public class TypeOf : Expression {
6673 Expression QueriedType;
6674 protected Type typearg;
6676 public TypeOf (Expression queried_type, Location l)
6678 QueriedType = queried_type;
6682 public override Expression CreateExpressionTree (EmitContext ec)
6684 Arguments args = new Arguments (2);
6685 args.Add (new Argument (this));
6686 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6687 return CreateExpressionFactoryCall ("Constant", args);
6690 public override Expression DoResolve (EmitContext ec)
6692 if (eclass != ExprClass.Invalid)
6695 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6699 typearg = texpr.Type;
6701 if (typearg == TypeManager.void_type) {
6702 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6706 if (typearg.IsPointer && !ec.InUnsafe){
6711 type = TypeManager.type_type;
6713 return DoResolveBase ();
6716 protected Expression DoResolveBase ()
6718 if (TypeManager.system_type_get_type_from_handle == null) {
6719 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6720 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6723 // Even though what is returned is a type object, it's treated as a value by the compiler.
6724 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6725 eclass = ExprClass.Value;
6729 public override void Emit (EmitContext ec)
6731 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6732 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6735 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
6737 if (TypeManager.ContainsGenericParameters (typearg) &&
6738 !TypeManager.IsGenericTypeDefinition (typearg)) {
6739 Report.SymbolRelatedToPreviousError (typearg);
6740 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6741 TypeManager.CSharpName (typearg));
6746 if (value_type == TypeManager.object_type) {
6747 value = (object)typearg;
6754 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6756 typearg = storey.MutateType (typearg);
6759 public Type TypeArgument {
6765 protected override void CloneTo (CloneContext clonectx, Expression t)
6767 TypeOf target = (TypeOf) t;
6768 if (QueriedType != null)
6769 target.QueriedType = QueriedType.Clone (clonectx);
6774 /// Implements the `typeof (void)' operator
6776 public class TypeOfVoid : TypeOf {
6777 public TypeOfVoid (Location l) : base (null, l)
6782 public override Expression DoResolve (EmitContext ec)
6784 type = TypeManager.type_type;
6785 typearg = TypeManager.void_type;
6787 return DoResolveBase ();
6791 class TypeOfMethodInfo : TypeOfMethod
6793 public TypeOfMethodInfo (MethodBase method, Location loc)
6794 : base (method, loc)
6798 public override Expression DoResolve (EmitContext ec)
6800 type = typeof (MethodInfo);
6801 return base.DoResolve (ec);
6804 public override void Emit (EmitContext ec)
6806 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
6808 ec.ig.Emit (OpCodes.Castclass, type);
6812 class TypeOfConstructorInfo : TypeOfMethod
6814 public TypeOfConstructorInfo (MethodBase method, Location loc)
6815 : base (method, loc)
6819 public override Expression DoResolve (EmitContext ec)
6821 type = typeof (ConstructorInfo);
6822 return base.DoResolve (ec);
6825 public override void Emit (EmitContext ec)
6827 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
6829 ec.ig.Emit (OpCodes.Castclass, type);
6833 abstract class TypeOfMethod : Expression
6835 protected readonly MethodBase method;
6837 protected TypeOfMethod (MethodBase method, Location loc)
6839 this.method = method;
6843 public override Expression CreateExpressionTree (EmitContext ec)
6845 Arguments args = new Arguments (2);
6846 args.Add (new Argument (this));
6847 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6848 return CreateExpressionFactoryCall ("Constant", args);
6851 public override Expression DoResolve (EmitContext ec)
6853 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6854 MethodInfo mi = is_generic ?
6855 TypeManager.methodbase_get_type_from_handle_generic :
6856 TypeManager.methodbase_get_type_from_handle;
6859 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
6860 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
6862 if (t == null || handle_type == null)
6865 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
6867 new Type[] { handle_type, TypeManager.runtime_handle_type } :
6868 new Type[] { handle_type } );
6871 TypeManager.methodbase_get_type_from_handle_generic = mi;
6873 TypeManager.methodbase_get_type_from_handle = mi;
6876 eclass = ExprClass.Value;
6880 public override void Emit (EmitContext ec)
6882 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6885 mi = TypeManager.methodbase_get_type_from_handle_generic;
6886 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
6888 mi = TypeManager.methodbase_get_type_from_handle;
6891 ec.ig.Emit (OpCodes.Call, mi);
6895 internal class TypeOfField : Expression
6897 readonly FieldInfo field;
6899 public TypeOfField (FieldInfo field, Location loc)
6905 public override Expression CreateExpressionTree (EmitContext ec)
6907 throw new NotSupportedException ("ET");
6910 public override Expression DoResolve (EmitContext ec)
6912 if (TypeManager.fieldinfo_get_field_from_handle == null) {
6913 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
6914 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
6916 if (t != null && handle_type != null)
6917 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
6918 "GetFieldFromHandle", loc, handle_type);
6921 type = typeof (FieldInfo);
6922 eclass = ExprClass.Value;
6926 public override void Emit (EmitContext ec)
6928 ec.ig.Emit (OpCodes.Ldtoken, field);
6929 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
6934 /// Implements the sizeof expression
6936 public class SizeOf : Expression {
6937 readonly Expression QueriedType;
6940 public SizeOf (Expression queried_type, Location l)
6942 this.QueriedType = queried_type;
6946 public override Expression CreateExpressionTree (EmitContext ec)
6948 Error_PointerInsideExpressionTree ();
6952 public override Expression DoResolve (EmitContext ec)
6954 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6958 type_queried = texpr.Type;
6959 if (TypeManager.IsEnumType (type_queried))
6960 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
6962 int size_of = GetTypeSize (type_queried);
6964 return new IntConstant (size_of, loc);
6967 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6972 Report.Error (233, loc,
6973 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
6974 TypeManager.CSharpName (type_queried));
6977 type = TypeManager.int32_type;
6978 eclass = ExprClass.Value;
6982 public override void Emit (EmitContext ec)
6984 int size = GetTypeSize (type_queried);
6987 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6989 IntConstant.EmitInt (ec.ig, size);
6992 protected override void CloneTo (CloneContext clonectx, Expression t)
6998 /// Implements the qualified-alias-member (::) expression.
7000 public class QualifiedAliasMember : MemberAccess
7002 readonly string alias;
7003 public static readonly string GlobalAlias = "global";
7005 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7006 : base (null, identifier, targs, l)
7011 public QualifiedAliasMember (string alias, string identifier, Location l)
7012 : base (null, identifier, l)
7017 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7019 if (alias == GlobalAlias) {
7020 expr = GlobalRootNamespace.Instance;
7021 return base.ResolveAsTypeStep (ec, silent);
7024 int errors = Report.Errors;
7025 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7027 if (errors == Report.Errors)
7028 Report.Error (432, loc, "Alias `{0}' not found", alias);
7032 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7036 if (expr.eclass == ExprClass.Type) {
7038 Report.Error (431, loc,
7039 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7047 public override Expression DoResolve (EmitContext ec)
7049 return ResolveAsTypeStep (ec, false);
7052 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7054 Report.Error (687, loc,
7055 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7056 GetSignatureForError ());
7059 public override string GetSignatureForError ()
7062 if (targs != null) {
7063 name = TypeManager.RemoveGenericArity (Name) + "<" +
7064 targs.GetSignatureForError () + ">";
7067 return alias + "::" + name;
7070 protected override void CloneTo (CloneContext clonectx, Expression t)
7077 /// Implements the member access expression
7079 public class MemberAccess : ATypeNameExpression {
7080 protected Expression expr;
7082 public MemberAccess (Expression expr, string id)
7083 : base (id, expr.Location)
7088 public MemberAccess (Expression expr, string identifier, Location loc)
7089 : base (identifier, loc)
7094 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7095 : base (identifier, args, loc)
7100 Expression DoResolve (EmitContext ec, Expression right_side)
7103 throw new Exception ();
7106 // Resolve the expression with flow analysis turned off, we'll do the definite
7107 // assignment checks later. This is because we don't know yet what the expression
7108 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7109 // definite assignment check on the actual field and not on the whole struct.
7112 SimpleName original = expr as SimpleName;
7113 Expression expr_resolved = expr.Resolve (ec,
7114 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7115 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7117 if (expr_resolved == null)
7120 string LookupIdentifier = MemberName.MakeName (Name, targs);
7122 Namespace ns = expr_resolved as Namespace;
7124 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7127 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, LookupIdentifier);
7128 else if (targs != null)
7129 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7134 Type expr_type = expr_resolved.Type;
7135 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7136 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7137 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7141 Constant c = expr_resolved as Constant;
7142 if (c != null && c.GetValue () == null) {
7143 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7144 "System.NullReferenceException");
7147 if (targs != null) {
7148 if (!targs.Resolve (ec))
7152 Expression member_lookup;
7153 member_lookup = MemberLookup (
7154 ec.ContainerType, expr_type, expr_type, Name, loc);
7156 if (member_lookup == null && targs != null) {
7157 member_lookup = MemberLookup (
7158 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7161 if (member_lookup == null) {
7162 ExprClass expr_eclass = expr_resolved.eclass;
7165 // Extension methods are not allowed on all expression types
7167 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7168 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7169 expr_eclass == ExprClass.EventAccess) {
7170 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7171 if (ex_method_lookup != null) {
7172 ex_method_lookup.ExtensionExpression = expr_resolved;
7174 if (targs != null) {
7175 ex_method_lookup.SetTypeArguments (targs);
7178 return ex_method_lookup.DoResolve (ec);
7182 expr = expr_resolved;
7183 member_lookup = Error_MemberLookupFailed (
7184 ec.ContainerType, expr_type, expr_type, Name, null,
7185 AllMemberTypes, AllBindingFlags);
7186 if (member_lookup == null)
7190 TypeExpr texpr = member_lookup as TypeExpr;
7191 if (texpr != null) {
7192 if (!(expr_resolved is TypeExpr) &&
7193 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7194 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7195 Name, member_lookup.GetSignatureForError ());
7199 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7200 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7201 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7205 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7208 // When looking up a nested type in a generic instance
7209 // via reflection, we always get a generic type definition
7210 // and not a generic instance - so we have to do this here.
7212 // See gtest-172-lib.cs and gtest-172.cs for an example.
7214 ct = new GenericTypeExpr (
7215 member_lookup.Type, ct.TypeArguments, loc);
7217 return ct.ResolveAsTypeStep (ec, false);
7220 return member_lookup;
7223 MemberExpr me = (MemberExpr) member_lookup;
7224 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7228 if (targs != null) {
7229 me.SetTypeArguments (targs);
7232 if (original != null && !TypeManager.IsValueType (expr_type)) {
7233 if (me.IsInstance) {
7234 LocalVariableReference var = expr_resolved as LocalVariableReference;
7235 if (var != null && !var.VerifyAssigned (ec))
7240 // The following DoResolve/DoResolveLValue will do the definite assignment
7243 if (right_side != null)
7244 return me.DoResolveLValue (ec, right_side);
7246 return me.DoResolve (ec);
7249 public override Expression DoResolve (EmitContext ec)
7251 return DoResolve (ec, null);
7254 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7256 return DoResolve (ec, right_side);
7259 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7261 return ResolveNamespaceOrType (ec, silent);
7264 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7266 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7268 if (expr_resolved == null)
7271 string LookupIdentifier = MemberName.MakeName (Name, targs);
7273 Namespace ns = expr_resolved as Namespace;
7275 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7277 if (retval == null && !silent)
7278 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7279 else if (targs != null)
7280 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7285 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7286 if (tnew_expr == null)
7289 if (tnew_expr is TypeParameterExpr) {
7290 Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7291 tnew_expr.GetSignatureForError ());
7295 Type expr_type = tnew_expr.Type;
7296 Expression member_lookup = MemberLookup (
7297 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7298 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7299 if (member_lookup == null) {
7303 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7307 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7311 TypeArguments the_args = targs;
7312 Type declaring_type = texpr.Type.DeclaringType;
7313 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7314 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7315 expr_type = expr_type.BaseType;
7318 TypeArguments new_args = new TypeArguments ();
7319 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7320 new_args.Add (new TypeExpression (decl, loc));
7323 new_args.Add (targs);
7325 the_args = new_args;
7328 if (the_args != null) {
7329 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7330 return ctype.ResolveAsTypeStep (rc, false);
7336 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7338 Expression member_lookup = MemberLookup (
7339 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7340 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7342 if (member_lookup != null) {
7343 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7344 if (expr_type == null)
7347 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type, loc);
7351 member_lookup = MemberLookup (
7352 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7353 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7355 if (member_lookup == null) {
7356 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7357 Name, expr_type.GetSignatureForError ());
7359 // TODO: Report.SymbolRelatedToPreviousError
7360 member_lookup.Error_UnexpectedKind (null, "type", loc);
7364 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7366 if (RootContext.Version > LanguageVersion.ISO_2 &&
7367 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7368 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7369 "extension method `{1}' of type `{0}' could be found " +
7370 "(are you missing a using directive or an assembly reference?)",
7371 TypeManager.CSharpName (type), name);
7375 base.Error_TypeDoesNotContainDefinition (type, name);
7378 public override string GetSignatureForError ()
7380 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7383 protected override void CloneTo (CloneContext clonectx, Expression t)
7385 MemberAccess target = (MemberAccess) t;
7387 target.expr = expr.Clone (clonectx);
7392 /// Implements checked expressions
7394 public class CheckedExpr : Expression {
7396 public Expression Expr;
7398 public CheckedExpr (Expression e, Location l)
7404 public override Expression CreateExpressionTree (EmitContext ec)
7406 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7407 return Expr.CreateExpressionTree (ec);
7410 public override Expression DoResolve (EmitContext ec)
7412 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7413 Expr = Expr.Resolve (ec);
7418 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7421 eclass = Expr.eclass;
7426 public override void Emit (EmitContext ec)
7428 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7432 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7434 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7435 Expr.EmitBranchable (ec, target, on_true);
7438 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7440 Expr.MutateHoistedGenericType (storey);
7443 protected override void CloneTo (CloneContext clonectx, Expression t)
7445 CheckedExpr target = (CheckedExpr) t;
7447 target.Expr = Expr.Clone (clonectx);
7452 /// Implements the unchecked expression
7454 public class UnCheckedExpr : Expression {
7456 public Expression Expr;
7458 public UnCheckedExpr (Expression e, Location l)
7464 public override Expression CreateExpressionTree (EmitContext ec)
7466 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7467 return Expr.CreateExpressionTree (ec);
7470 public override Expression DoResolve (EmitContext ec)
7472 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7473 Expr = Expr.Resolve (ec);
7478 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7481 eclass = Expr.eclass;
7486 public override void Emit (EmitContext ec)
7488 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7492 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7494 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7495 Expr.EmitBranchable (ec, target, on_true);
7498 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7500 Expr.MutateHoistedGenericType (storey);
7503 protected override void CloneTo (CloneContext clonectx, Expression t)
7505 UnCheckedExpr target = (UnCheckedExpr) t;
7507 target.Expr = Expr.Clone (clonectx);
7512 /// An Element Access expression.
7514 /// During semantic analysis these are transformed into
7515 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7517 public class ElementAccess : Expression {
7518 public Arguments Arguments;
7519 public Expression Expr;
7521 public ElementAccess (Expression e, Arguments args)
7525 this.Arguments = args;
7528 bool CommonResolve (EmitContext ec)
7530 Expr = Expr.Resolve (ec);
7532 if (Arguments != null)
7533 Arguments.Resolve (ec);
7535 return Expr != null;
7538 public override Expression CreateExpressionTree (EmitContext ec)
7540 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7541 Expr.CreateExpressionTree (ec));
7543 return CreateExpressionFactoryCall ("ArrayIndex", args);
7546 Expression MakePointerAccess (EmitContext ec, Type t)
7548 if (Arguments.Count != 1){
7549 Error (196, "A pointer must be indexed by only one value");
7553 if (Arguments [0] is NamedArgument)
7554 Error_NamedArgument ((NamedArgument) Arguments[0]);
7556 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr, t, loc).Resolve (ec);
7559 return new Indirection (p, loc).Resolve (ec);
7562 public override Expression DoResolve (EmitContext ec)
7564 if (!CommonResolve (ec))
7568 // We perform some simple tests, and then to "split" the emit and store
7569 // code we create an instance of a different class, and return that.
7571 // I am experimenting with this pattern.
7575 if (t == TypeManager.array_type){
7576 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7581 return (new ArrayAccess (this, loc)).Resolve (ec);
7583 return MakePointerAccess (ec, t);
7585 FieldExpr fe = Expr as FieldExpr;
7587 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7589 return MakePointerAccess (ec, ff.ElementType);
7592 return (new IndexerAccess (this, loc)).Resolve (ec);
7595 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7597 if (!CommonResolve (ec))
7602 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7605 return MakePointerAccess (ec, type);
7607 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7608 Error_CannotModifyIntermediateExpressionValue (ec);
7610 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7613 public override void Emit (EmitContext ec)
7615 throw new Exception ("Should never be reached");
7618 public static void Error_NamedArgument (NamedArgument na)
7620 Report.Error (1742, na.Name.Location, "An element access expression cannot use named argument");
7623 public override string GetSignatureForError ()
7625 return Expr.GetSignatureForError ();
7628 protected override void CloneTo (CloneContext clonectx, Expression t)
7630 ElementAccess target = (ElementAccess) t;
7632 target.Expr = Expr.Clone (clonectx);
7633 if (Arguments != null)
7634 target.Arguments = Arguments.Clone (clonectx);
7639 /// Implements array access
7641 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7643 // Points to our "data" repository
7647 LocalTemporary temp;
7651 public ArrayAccess (ElementAccess ea_data, Location l)
7657 public override Expression CreateExpressionTree (EmitContext ec)
7659 return ea.CreateExpressionTree (ec);
7662 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7664 return DoResolve (ec);
7667 public override Expression DoResolve (EmitContext ec)
7670 ExprClass eclass = ea.Expr.eclass;
7672 // As long as the type is valid
7673 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7674 eclass == ExprClass.Value)) {
7675 ea.Expr.Error_UnexpectedKind ("variable or value");
7680 if (eclass != ExprClass.Invalid)
7683 Type t = ea.Expr.Type;
7684 int rank = ea.Arguments.Count;
7685 if (t.GetArrayRank () != rank) {
7686 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7687 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7691 type = TypeManager.GetElementType (t);
7692 if (type.IsPointer && !ec.InUnsafe) {
7693 UnsafeError (ea.Location);
7697 foreach (Argument a in ea.Arguments) {
7698 if (a is NamedArgument)
7699 ElementAccess.Error_NamedArgument ((NamedArgument) a);
7701 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7704 eclass = ExprClass.Variable;
7710 /// Emits the right opcode to load an object of Type `t'
7711 /// from an array of T
7713 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7716 MethodInfo get = FetchGetMethod ();
7717 ig.Emit (OpCodes.Call, get);
7721 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7722 ig.Emit (OpCodes.Ldelem_U1);
7723 else if (type == TypeManager.sbyte_type)
7724 ig.Emit (OpCodes.Ldelem_I1);
7725 else if (type == TypeManager.short_type)
7726 ig.Emit (OpCodes.Ldelem_I2);
7727 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7728 ig.Emit (OpCodes.Ldelem_U2);
7729 else if (type == TypeManager.int32_type)
7730 ig.Emit (OpCodes.Ldelem_I4);
7731 else if (type == TypeManager.uint32_type)
7732 ig.Emit (OpCodes.Ldelem_U4);
7733 else if (type == TypeManager.uint64_type)
7734 ig.Emit (OpCodes.Ldelem_I8);
7735 else if (type == TypeManager.int64_type)
7736 ig.Emit (OpCodes.Ldelem_I8);
7737 else if (type == TypeManager.float_type)
7738 ig.Emit (OpCodes.Ldelem_R4);
7739 else if (type == TypeManager.double_type)
7740 ig.Emit (OpCodes.Ldelem_R8);
7741 else if (type == TypeManager.intptr_type)
7742 ig.Emit (OpCodes.Ldelem_I);
7743 else if (TypeManager.IsEnumType (type)){
7744 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7745 } else if (TypeManager.IsStruct (type)){
7746 ig.Emit (OpCodes.Ldelema, type);
7747 ig.Emit (OpCodes.Ldobj, type);
7749 } else if (type.IsGenericParameter) {
7750 ig.Emit (OpCodes.Ldelem, type);
7752 } else if (type.IsPointer)
7753 ig.Emit (OpCodes.Ldelem_I);
7755 ig.Emit (OpCodes.Ldelem_Ref);
7758 protected override void Error_NegativeArrayIndex (Location loc)
7760 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7764 /// Returns the right opcode to store an object of Type `t'
7765 /// from an array of T.
7767 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7769 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7770 has_type_arg = false; is_stobj = false;
7771 t = TypeManager.TypeToCoreType (t);
7772 if (TypeManager.IsEnumType (t))
7773 t = TypeManager.GetEnumUnderlyingType (t);
7774 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7775 t == TypeManager.bool_type)
7776 return OpCodes.Stelem_I1;
7777 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7778 t == TypeManager.char_type)
7779 return OpCodes.Stelem_I2;
7780 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7781 return OpCodes.Stelem_I4;
7782 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7783 return OpCodes.Stelem_I8;
7784 else if (t == TypeManager.float_type)
7785 return OpCodes.Stelem_R4;
7786 else if (t == TypeManager.double_type)
7787 return OpCodes.Stelem_R8;
7788 else if (t == TypeManager.intptr_type) {
7789 has_type_arg = true;
7791 return OpCodes.Stobj;
7792 } else if (TypeManager.IsStruct (t)) {
7793 has_type_arg = true;
7795 return OpCodes.Stobj;
7797 } else if (t.IsGenericParameter) {
7798 has_type_arg = true;
7799 return OpCodes.Stelem;
7802 } else if (t.IsPointer)
7803 return OpCodes.Stelem_I;
7805 return OpCodes.Stelem_Ref;
7808 MethodInfo FetchGetMethod ()
7810 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
7811 int arg_count = ea.Arguments.Count;
7812 Type [] args = new Type [arg_count];
7815 for (int i = 0; i < arg_count; i++){
7816 //args [i++] = a.Type;
7817 args [i] = TypeManager.int32_type;
7820 get = mb.GetArrayMethod (
7821 ea.Expr.Type, "Get",
7822 CallingConventions.HasThis |
7823 CallingConventions.Standard,
7829 MethodInfo FetchAddressMethod ()
7831 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
7832 int arg_count = ea.Arguments.Count;
7833 Type [] args = new Type [arg_count];
7837 ret_type = TypeManager.GetReferenceType (type);
7839 for (int i = 0; i < arg_count; i++){
7840 //args [i++] = a.Type;
7841 args [i] = TypeManager.int32_type;
7844 address = mb.GetArrayMethod (
7845 ea.Expr.Type, "Address",
7846 CallingConventions.HasThis |
7847 CallingConventions.Standard,
7854 // Load the array arguments into the stack.
7856 void LoadArrayAndArguments (EmitContext ec)
7860 for (int i = 0; i < ea.Arguments.Count; ++i) {
7861 ea.Arguments [i].Emit (ec);
7865 public void Emit (EmitContext ec, bool leave_copy)
7867 int rank = ea.Expr.Type.GetArrayRank ();
7868 ILGenerator ig = ec.ig;
7871 LoadFromPtr (ig, this.type);
7873 LoadArrayAndArguments (ec);
7874 EmitLoadOpcode (ig, type, rank);
7878 ig.Emit (OpCodes.Dup);
7879 temp = new LocalTemporary (this.type);
7884 public override void Emit (EmitContext ec)
7889 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7891 int rank = ea.Expr.Type.GetArrayRank ();
7892 ILGenerator ig = ec.ig;
7893 Type t = source.Type;
7894 prepared = prepare_for_load;
7897 AddressOf (ec, AddressOp.LoadStore);
7898 ec.ig.Emit (OpCodes.Dup);
7900 LoadArrayAndArguments (ec);
7904 bool is_stobj, has_type_arg;
7905 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7909 // The stobj opcode used by value types will need
7910 // an address on the stack, not really an array/array
7914 ig.Emit (OpCodes.Ldelema, t);
7919 ec.ig.Emit (OpCodes.Dup);
7920 temp = new LocalTemporary (this.type);
7925 StoreFromPtr (ig, t);
7927 ig.Emit (OpCodes.Stobj, t);
7928 else if (has_type_arg)
7935 ec.ig.Emit (OpCodes.Dup);
7936 temp = new LocalTemporary (this.type);
7941 StoreFromPtr (ig, t);
7943 int arg_count = ea.Arguments.Count;
7944 Type [] args = new Type [arg_count + 1];
7945 for (int i = 0; i < arg_count; i++) {
7946 //args [i++] = a.Type;
7947 args [i] = TypeManager.int32_type;
7949 args [arg_count] = type;
7951 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
7952 ea.Expr.Type, "Set",
7953 CallingConventions.HasThis |
7954 CallingConventions.Standard,
7955 TypeManager.void_type, args);
7957 ig.Emit (OpCodes.Call, set);
7967 public void EmitNew (EmitContext ec, New source, bool leave_copy)
7969 if (!source.Emit (ec, this)) {
7971 throw new NotImplementedException ();
7976 throw new NotImplementedException ();
7979 public void AddressOf (EmitContext ec, AddressOp mode)
7981 int rank = ea.Expr.Type.GetArrayRank ();
7982 ILGenerator ig = ec.ig;
7984 LoadArrayAndArguments (ec);
7987 ig.Emit (OpCodes.Ldelema, type);
7989 MethodInfo address = FetchAddressMethod ();
7990 ig.Emit (OpCodes.Call, address);
7994 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7996 type = storey.MutateType (type);
7997 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8002 /// Expressions that represent an indexer call.
8004 public class IndexerAccess : Expression, IAssignMethod
8006 class IndexerMethodGroupExpr : MethodGroupExpr
8008 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8011 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8014 public override string Name {
8020 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8023 // Here is the trick, decrease number of arguments by 1 when only
8024 // available property method is setter. This makes overload resolution
8025 // work correctly for indexers.
8028 if (method.Name [0] == 'g')
8029 return parameters.Count;
8031 return parameters.Count - 1;
8037 // Contains either property getter or setter
8038 public ArrayList Methods;
8039 public ArrayList Properties;
8045 void Append (Type caller_type, MemberInfo [] mi)
8050 foreach (PropertyInfo property in mi) {
8051 MethodInfo accessor = property.GetGetMethod (true);
8052 if (accessor == null)
8053 accessor = property.GetSetMethod (true);
8055 if (Methods == null) {
8056 Methods = new ArrayList ();
8057 Properties = new ArrayList ();
8060 Methods.Add (accessor);
8061 Properties.Add (property);
8065 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8067 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8069 return TypeManager.MemberLookup (
8070 caller_type, caller_type, lookup_type, MemberTypes.Property,
8071 BindingFlags.Public | BindingFlags.Instance |
8072 BindingFlags.DeclaredOnly, p_name, null);
8075 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8077 Indexers ix = new Indexers ();
8079 if (TypeManager.IsGenericParameter (lookup_type)) {
8080 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8084 if (gc.HasClassConstraint) {
8085 Type class_contraint = gc.ClassConstraint;
8086 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8087 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8088 class_contraint = class_contraint.BaseType;
8092 Type[] ifaces = gc.InterfaceConstraints;
8093 foreach (Type itype in ifaces)
8094 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8099 Type copy = lookup_type;
8100 while (copy != TypeManager.object_type && copy != null){
8101 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8102 copy = copy.BaseType;
8105 if (lookup_type.IsInterface) {
8106 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8107 if (ifaces != null) {
8108 foreach (Type itype in ifaces)
8109 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8124 // Points to our "data" repository
8126 MethodInfo get, set;
8127 bool is_base_indexer;
8129 LocalTemporary temp;
8130 LocalTemporary prepared_value;
8131 Expression set_expr;
8133 protected Type indexer_type;
8134 protected Type current_type;
8135 protected Expression instance_expr;
8136 protected Arguments arguments;
8138 public IndexerAccess (ElementAccess ea, Location loc)
8139 : this (ea.Expr, false, loc)
8141 this.arguments = ea.Arguments;
8144 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8147 this.instance_expr = instance_expr;
8148 this.is_base_indexer = is_base_indexer;
8149 this.eclass = ExprClass.Value;
8153 static string GetAccessorName (AccessorType at)
8155 if (at == AccessorType.Set)
8158 if (at == AccessorType.Get)
8161 throw new NotImplementedException (at.ToString ());
8164 public override Expression CreateExpressionTree (EmitContext ec)
8166 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8167 instance_expr.CreateExpressionTree (ec),
8168 new TypeOfMethodInfo (get, loc));
8170 return CreateExpressionFactoryCall ("Call", args);
8173 protected virtual bool CommonResolve (EmitContext ec)
8175 indexer_type = instance_expr.Type;
8176 current_type = ec.ContainerType;
8181 public override Expression DoResolve (EmitContext ec)
8183 return ResolveAccessor (ec, AccessorType.Get);
8186 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8188 if (right_side == EmptyExpression.OutAccess) {
8189 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8190 GetSignatureForError ());
8194 // if the indexer returns a value type, and we try to set a field in it
8195 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8196 Error_CannotModifyIntermediateExpressionValue (ec);
8199 Expression e = ResolveAccessor (ec, AccessorType.Set);
8203 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8207 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8209 if (!CommonResolve (ec))
8212 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8213 if (ilist.Methods == null) {
8214 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8215 TypeManager.CSharpName (indexer_type));
8219 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8220 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8224 MethodInfo mi = (MethodInfo) mg;
8225 PropertyInfo pi = null;
8226 for (int i = 0; i < ilist.Methods.Count; ++i) {
8227 if (ilist.Methods [i] == mi) {
8228 pi = (PropertyInfo) ilist.Properties [i];
8233 type = TypeManager.TypeToCoreType (pi.PropertyType);
8234 if (type.IsPointer && !ec.InUnsafe)
8237 MethodInfo accessor;
8238 if (accessorType == AccessorType.Get) {
8239 accessor = get = pi.GetGetMethod (true);
8241 accessor = set = pi.GetSetMethod (true);
8242 if (accessor == null && pi.GetGetMethod (true) != null) {
8243 Report.SymbolRelatedToPreviousError (pi);
8244 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8245 TypeManager.GetFullNameSignature (pi));
8250 if (accessor == null) {
8251 Report.SymbolRelatedToPreviousError (pi);
8252 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8253 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8258 // Only base will allow this invocation to happen.
8260 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8261 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8264 bool must_do_cs1540_check;
8265 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8267 set = pi.GetSetMethod (true);
8269 get = pi.GetGetMethod (true);
8271 if (set != null && get != null &&
8272 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8273 Report.SymbolRelatedToPreviousError (accessor);
8274 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8275 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8277 Report.SymbolRelatedToPreviousError (pi);
8278 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8282 instance_expr.CheckMarshalByRefAccess (ec);
8283 eclass = ExprClass.IndexerAccess;
8287 public void Emit (EmitContext ec, bool leave_copy)
8290 prepared_value.Emit (ec);
8292 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8293 arguments, loc, false, false);
8297 ec.ig.Emit (OpCodes.Dup);
8298 temp = new LocalTemporary (Type);
8304 // source is ignored, because we already have a copy of it from the
8305 // LValue resolution and we have already constructed a pre-cached
8306 // version of the arguments (ea.set_arguments);
8308 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8310 prepared = prepare_for_load;
8311 Expression value = set_expr;
8314 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8315 arguments, loc, true, false);
8317 prepared_value = new LocalTemporary (type);
8318 prepared_value.Store (ec);
8320 prepared_value.Release (ec);
8323 ec.ig.Emit (OpCodes.Dup);
8324 temp = new LocalTemporary (Type);
8327 } else if (leave_copy) {
8328 temp = new LocalTemporary (Type);
8335 arguments.Add (new Argument (value));
8337 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8345 public override void Emit (EmitContext ec)
8350 public override string GetSignatureForError ()
8352 return TypeManager.CSharpSignature (get != null ? get : set, false);
8355 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8358 get = storey.MutateGenericMethod (get);
8360 set = storey.MutateGenericMethod (set);
8362 instance_expr.MutateHoistedGenericType (storey);
8363 if (arguments != null)
8364 arguments.MutateHoistedGenericType (storey);
8366 type = storey.MutateType (type);
8369 protected override void CloneTo (CloneContext clonectx, Expression t)
8371 IndexerAccess target = (IndexerAccess) t;
8373 if (arguments != null)
8374 target.arguments = arguments.Clone (clonectx);
8376 if (instance_expr != null)
8377 target.instance_expr = instance_expr.Clone (clonectx);
8382 /// The base operator for method names
8384 public class BaseAccess : Expression {
8385 public readonly string Identifier;
8388 public BaseAccess (string member, Location l)
8390 this.Identifier = member;
8394 public BaseAccess (string member, TypeArguments args, Location l)
8400 public override Expression CreateExpressionTree (EmitContext ec)
8402 throw new NotSupportedException ("ET");
8405 public override Expression DoResolve (EmitContext ec)
8407 Expression c = CommonResolve (ec);
8413 // MethodGroups use this opportunity to flag an error on lacking ()
8415 if (!(c is MethodGroupExpr))
8416 return c.Resolve (ec);
8420 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8422 Expression c = CommonResolve (ec);
8428 // MethodGroups use this opportunity to flag an error on lacking ()
8430 if (! (c is MethodGroupExpr))
8431 return c.DoResolveLValue (ec, right_side);
8436 Expression CommonResolve (EmitContext ec)
8438 Expression member_lookup;
8439 Type current_type = ec.ContainerType;
8440 Type base_type = current_type.BaseType;
8442 if (!This.IsThisAvailable (ec)) {
8444 Error (1511, "Keyword `base' is not available in a static method");
8446 Error (1512, "Keyword `base' is not available in the current context");
8451 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8452 AllMemberTypes, AllBindingFlags, loc);
8453 if (member_lookup == null) {
8454 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8455 null, AllMemberTypes, AllBindingFlags);
8462 left = new TypeExpression (base_type, loc);
8464 left = ec.GetThis (loc);
8466 MemberExpr me = (MemberExpr) member_lookup;
8467 me = me.ResolveMemberAccess (ec, left, loc, null);
8474 me.SetTypeArguments (args);
8480 public override void Emit (EmitContext ec)
8482 throw new Exception ("Should never be called");
8485 protected override void CloneTo (CloneContext clonectx, Expression t)
8487 BaseAccess target = (BaseAccess) t;
8490 target.args = args.Clone ();
8495 /// The base indexer operator
8497 public class BaseIndexerAccess : IndexerAccess {
8498 public BaseIndexerAccess (Arguments args, Location loc)
8499 : base (null, true, loc)
8501 this.arguments = args;
8504 protected override bool CommonResolve (EmitContext ec)
8506 instance_expr = ec.GetThis (loc);
8508 current_type = ec.ContainerType.BaseType;
8509 indexer_type = current_type;
8511 arguments.Resolve (ec);
8516 public override Expression CreateExpressionTree (EmitContext ec)
8518 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8519 return base.CreateExpressionTree (ec);
8524 /// This class exists solely to pass the Type around and to be a dummy
8525 /// that can be passed to the conversion functions (this is used by
8526 /// foreach implementation to typecast the object return value from
8527 /// get_Current into the proper type. All code has been generated and
8528 /// we only care about the side effect conversions to be performed
8530 /// This is also now used as a placeholder where a no-action expression
8531 /// is needed (the `New' class).
8533 public class EmptyExpression : Expression {
8534 public static readonly Expression Null = new EmptyExpression ();
8536 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8537 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8538 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8539 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8541 static EmptyExpression temp = new EmptyExpression ();
8542 public static EmptyExpression Grab ()
8544 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8549 public static void Release (EmptyExpression e)
8556 // FIXME: Don't set to object
8557 type = TypeManager.object_type;
8558 eclass = ExprClass.Value;
8559 loc = Location.Null;
8562 public EmptyExpression (Type t)
8565 eclass = ExprClass.Value;
8566 loc = Location.Null;
8569 public override Expression CreateExpressionTree (EmitContext ec)
8571 throw new NotSupportedException ("ET");
8574 public override Expression DoResolve (EmitContext ec)
8579 public override void Emit (EmitContext ec)
8581 // nothing, as we only exist to not do anything.
8584 public override void EmitSideEffect (EmitContext ec)
8589 // This is just because we might want to reuse this bad boy
8590 // instead of creating gazillions of EmptyExpressions.
8591 // (CanImplicitConversion uses it)
8593 public void SetType (Type t)
8600 // Empty statement expression
8602 public sealed class EmptyExpressionStatement : ExpressionStatement
8604 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8606 private EmptyExpressionStatement ()
8608 eclass = ExprClass.Value;
8609 loc = Location.Null;
8612 public override Expression CreateExpressionTree (EmitContext ec)
8617 public override void EmitStatement (EmitContext ec)
8622 public override Expression DoResolve (EmitContext ec)
8624 type = TypeManager.object_type;
8628 public override void Emit (EmitContext ec)
8634 public class UserCast : Expression {
8638 public UserCast (MethodInfo method, Expression source, Location l)
8640 this.method = method;
8641 this.source = source;
8642 type = TypeManager.TypeToCoreType (method.ReturnType);
8646 public Expression Source {
8652 public override Expression CreateExpressionTree (EmitContext ec)
8654 Arguments args = new Arguments (3);
8655 args.Add (new Argument (source.CreateExpressionTree (ec)));
8656 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8657 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8658 return CreateExpressionFactoryCall ("Convert", args);
8661 public override Expression DoResolve (EmitContext ec)
8663 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8665 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
8667 eclass = ExprClass.Value;
8671 public override void Emit (EmitContext ec)
8674 ec.ig.Emit (OpCodes.Call, method);
8677 public override string GetSignatureForError ()
8679 return TypeManager.CSharpSignature (method);
8682 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8684 source.MutateHoistedGenericType (storey);
8685 method = storey.MutateGenericMethod (method);
8690 // This class is used to "construct" the type during a typecast
8691 // operation. Since the Type.GetType class in .NET can parse
8692 // the type specification, we just use this to construct the type
8693 // one bit at a time.
8695 public class ComposedCast : TypeExpr {
8696 FullNamedExpression left;
8699 public ComposedCast (FullNamedExpression left, string dim)
8700 : this (left, dim, left.Location)
8704 public ComposedCast (FullNamedExpression left, string dim, Location l)
8711 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8713 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8717 Type ltype = lexpr.Type;
8718 if ((dim.Length > 0) && (dim [0] == '?')) {
8719 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
8721 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8722 return nullable.ResolveAsTypeTerminal (ec, false);
8725 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8728 if (dim.Length != 0 && dim [0] == '[') {
8729 if (TypeManager.IsSpecialType (ltype)) {
8730 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8734 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
8735 Report.SymbolRelatedToPreviousError (ltype);
8736 Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
8737 TypeManager.CSharpName (ltype));
8742 type = TypeManager.GetConstructedType (ltype, dim);
8747 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8749 if (type.IsPointer && !ec.IsInUnsafeScope){
8753 eclass = ExprClass.Type;
8757 public override string GetSignatureForError ()
8759 return left.GetSignatureForError () + dim;
8762 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
8764 return ResolveAsBaseTerminal (ec, silent);
8768 public class FixedBufferPtr : Expression {
8771 public FixedBufferPtr (Expression array, Type array_type, Location l)
8776 type = TypeManager.GetPointerType (array_type);
8777 eclass = ExprClass.Value;
8780 public override Expression CreateExpressionTree (EmitContext ec)
8782 Error_PointerInsideExpressionTree ();
8786 public override void Emit(EmitContext ec)
8791 public override Expression DoResolve (EmitContext ec)
8794 // We are born fully resolved
8802 // This class is used to represent the address of an array, used
8803 // only by the Fixed statement, this generates "&a [0]" construct
8804 // for fixed (char *pa = a)
8806 public class ArrayPtr : FixedBufferPtr {
8809 public ArrayPtr (Expression array, Type array_type, Location l):
8810 base (array, array_type, l)
8812 this.array_type = array_type;
8815 public override void Emit (EmitContext ec)
8819 ILGenerator ig = ec.ig;
8820 IntLiteral.EmitInt (ig, 0);
8821 ig.Emit (OpCodes.Ldelema, array_type);
8826 // Encapsulates a conversion rules required for array indexes
8828 public class ArrayIndexCast : TypeCast
8830 public ArrayIndexCast (Expression expr)
8831 : base (expr, expr.Type)
8835 public override Expression CreateExpressionTree (EmitContext ec)
8837 Arguments args = new Arguments (2);
8838 args.Add (new Argument (child.CreateExpressionTree (ec)));
8839 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8840 return CreateExpressionFactoryCall ("ConvertChecked", args);
8843 public override void Emit (EmitContext ec)
8847 if (type == TypeManager.int32_type)
8850 if (type == TypeManager.uint32_type)
8851 ec.ig.Emit (OpCodes.Conv_U);
8852 else if (type == TypeManager.int64_type)
8853 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8854 else if (type == TypeManager.uint64_type)
8855 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8857 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8862 // Implements the `stackalloc' keyword
8864 public class StackAlloc : Expression {
8869 public StackAlloc (Expression type, Expression count, Location l)
8876 public override Expression CreateExpressionTree (EmitContext ec)
8878 throw new NotSupportedException ("ET");
8881 public override Expression DoResolve (EmitContext ec)
8883 count = count.Resolve (ec);
8887 if (count.Type != TypeManager.uint32_type){
8888 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8893 Constant c = count as Constant;
8894 if (c != null && c.IsNegative) {
8895 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8899 if (ec.InCatch || ec.InFinally) {
8900 Error (255, "Cannot use stackalloc in finally or catch");
8904 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8910 if (!TypeManager.VerifyUnManaged (otype, loc))
8913 type = TypeManager.GetPointerType (otype);
8914 eclass = ExprClass.Value;
8919 public override void Emit (EmitContext ec)
8921 int size = GetTypeSize (otype);
8922 ILGenerator ig = ec.ig;
8927 ig.Emit (OpCodes.Sizeof, otype);
8929 IntConstant.EmitInt (ig, size);
8931 ig.Emit (OpCodes.Mul_Ovf_Un);
8932 ig.Emit (OpCodes.Localloc);
8935 protected override void CloneTo (CloneContext clonectx, Expression t)
8937 StackAlloc target = (StackAlloc) t;
8938 target.count = count.Clone (clonectx);
8939 target.t = t.Clone (clonectx);
8944 // An object initializer expression
8946 public class ElementInitializer : Assign
8948 public readonly string Name;
8950 public ElementInitializer (string name, Expression initializer, Location loc)
8951 : base (null, initializer, loc)
8956 protected override void CloneTo (CloneContext clonectx, Expression t)
8958 ElementInitializer target = (ElementInitializer) t;
8959 target.source = source.Clone (clonectx);
8962 public override Expression CreateExpressionTree (EmitContext ec)
8964 Arguments args = new Arguments (2);
8965 FieldExpr fe = target as FieldExpr;
8967 args.Add (new Argument (fe.CreateTypeOfExpression ()));
8969 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
8971 args.Add (new Argument (source.CreateExpressionTree (ec)));
8972 return CreateExpressionFactoryCall (
8973 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
8977 public override Expression DoResolve (EmitContext ec)
8980 return EmptyExpressionStatement.Instance;
8982 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
8983 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
8989 me.InstanceExpression = ec.CurrentInitializerVariable;
8991 if (source is CollectionOrObjectInitializers) {
8992 Expression previous = ec.CurrentInitializerVariable;
8993 ec.CurrentInitializerVariable = target;
8994 source = source.Resolve (ec);
8995 ec.CurrentInitializerVariable = previous;
8999 eclass = source.eclass;
9004 Expression expr = base.DoResolve (ec);
9009 // Ignore field initializers with default value
9011 Constant c = source as Constant;
9012 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9013 return EmptyExpressionStatement.Instance.DoResolve (ec);
9018 protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
9020 MemberInfo member = members [0];
9021 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9022 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9023 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9025 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9026 TypeManager.GetFullNameSignature (member));
9031 public override void EmitStatement (EmitContext ec)
9033 if (source is CollectionOrObjectInitializers)
9036 base.EmitStatement (ec);
9041 // A collection initializer expression
9043 class CollectionElementInitializer : Invocation
9045 public class ElementInitializerArgument : Argument
9047 public ElementInitializerArgument (Expression e)
9053 sealed class AddMemberAccess : MemberAccess
9055 public AddMemberAccess (Expression expr, Location loc)
9056 : base (expr, "Add", loc)
9060 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
9062 if (TypeManager.HasElementType (type))
9065 base.Error_TypeDoesNotContainDefinition (type, name);
9069 public CollectionElementInitializer (Expression argument)
9070 : base (null, new Arguments (1), true)
9072 Arguments.Add (new ElementInitializerArgument (argument));
9073 this.loc = argument.Location;
9076 public CollectionElementInitializer (ArrayList arguments, Location loc)
9077 : base (null, new Arguments (arguments.Count), true)
9079 foreach (Expression e in arguments)
9080 Arguments.Add (new ElementInitializerArgument (e));
9085 public override Expression CreateExpressionTree (EmitContext ec)
9087 Arguments args = new Arguments (2);
9088 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9090 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9091 foreach (Argument a in Arguments)
9092 expr_initializers.Add (a.CreateExpressionTree (ec));
9094 args.Add (new Argument (new ArrayCreation (
9095 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9096 return CreateExpressionFactoryCall ("ElementInit", args);
9099 protected override void CloneTo (CloneContext clonectx, Expression t)
9101 CollectionElementInitializer target = (CollectionElementInitializer) t;
9103 target.Arguments = Arguments.Clone (clonectx);
9106 public override Expression DoResolve (EmitContext ec)
9108 if (eclass != ExprClass.Invalid)
9111 // TODO: We could call a constructor which takes element count argument,
9112 // for known types like List<T>, Dictionary<T, U>
9114 Arguments.Resolve (ec);
9116 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9118 return base.DoResolve (ec);
9123 // A block of object or collection initializers
9125 public class CollectionOrObjectInitializers : ExpressionStatement
9127 ArrayList initializers;
9128 bool is_collection_initialization;
9130 public static readonly CollectionOrObjectInitializers Empty =
9131 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9133 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9135 this.initializers = initializers;
9139 public bool IsEmpty {
9141 return initializers.Count == 0;
9145 public bool IsCollectionInitializer {
9147 return is_collection_initialization;
9151 protected override void CloneTo (CloneContext clonectx, Expression target)
9153 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9155 t.initializers = new ArrayList (initializers.Count);
9156 foreach (Expression e in initializers)
9157 t.initializers.Add (e.Clone (clonectx));
9160 public override Expression CreateExpressionTree (EmitContext ec)
9162 ArrayList expr_initializers = new ArrayList (initializers.Count);
9163 foreach (Expression e in initializers) {
9164 Expression expr = e.CreateExpressionTree (ec);
9166 expr_initializers.Add (expr);
9169 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9172 public override Expression DoResolve (EmitContext ec)
9174 if (eclass != ExprClass.Invalid)
9177 ArrayList element_names = null;
9178 for (int i = 0; i < initializers.Count; ++i) {
9179 Expression initializer = (Expression) initializers [i];
9180 ElementInitializer element_initializer = initializer as ElementInitializer;
9183 if (element_initializer != null) {
9184 element_names = new ArrayList (initializers.Count);
9185 element_names.Add (element_initializer.Name);
9186 } else if (initializer is CompletingExpression){
9187 initializer.Resolve (ec);
9188 throw new InternalErrorException ("This line should never be reached");
9190 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9191 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9192 "object initializer because type `{1}' does not implement `{2}' interface",
9193 ec.CurrentInitializerVariable.GetSignatureForError (),
9194 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9195 TypeManager.CSharpName (TypeManager.ienumerable_type));
9198 is_collection_initialization = true;
9201 if (is_collection_initialization != (element_initializer == null)) {
9202 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9203 is_collection_initialization ? "collection initializer" : "object initializer");
9207 if (!is_collection_initialization) {
9208 if (element_names.Contains (element_initializer.Name)) {
9209 Report.Error (1912, element_initializer.Location,
9210 "An object initializer includes more than one member `{0}' initialization",
9211 element_initializer.Name);
9213 element_names.Add (element_initializer.Name);
9218 Expression e = initializer.Resolve (ec);
9219 if (e == EmptyExpressionStatement.Instance)
9220 initializers.RemoveAt (i--);
9222 initializers [i] = e;
9225 type = ec.CurrentInitializerVariable.Type;
9226 if (is_collection_initialization) {
9227 if (TypeManager.HasElementType (type)) {
9228 Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9229 TypeManager.CSharpName (type));
9233 eclass = ExprClass.Variable;
9237 public override void Emit (EmitContext ec)
9242 public override void EmitStatement (EmitContext ec)
9244 foreach (ExpressionStatement e in initializers)
9245 e.EmitStatement (ec);
9248 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9250 foreach (Expression e in initializers)
9251 e.MutateHoistedGenericType (storey);
9256 // New expression with element/object initializers
9258 public class NewInitialize : New
9261 // This class serves as a proxy for variable initializer target instances.
9262 // A real variable is assigned later when we resolve left side of an
9265 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9267 NewInitialize new_instance;
9269 public InitializerTargetExpression (NewInitialize newInstance)
9271 this.type = newInstance.type;
9272 this.loc = newInstance.loc;
9273 this.eclass = newInstance.eclass;
9274 this.new_instance = newInstance;
9277 public override Expression CreateExpressionTree (EmitContext ec)
9279 // Should not be reached
9280 throw new NotSupportedException ("ET");
9283 public override Expression DoResolve (EmitContext ec)
9288 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9293 public override void Emit (EmitContext ec)
9295 Expression e = (Expression) new_instance.instance;
9299 #region IMemoryLocation Members
9301 public void AddressOf (EmitContext ec, AddressOp mode)
9303 new_instance.instance.AddressOf (ec, mode);
9309 CollectionOrObjectInitializers initializers;
9310 IMemoryLocation instance;
9312 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9313 : base (requested_type, arguments, l)
9315 this.initializers = initializers;
9318 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9320 instance = base.EmitAddressOf (ec, Mode);
9322 if (!initializers.IsEmpty)
9323 initializers.Emit (ec);
9328 protected override void CloneTo (CloneContext clonectx, Expression t)
9330 base.CloneTo (clonectx, t);
9332 NewInitialize target = (NewInitialize) t;
9333 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9336 public override Expression CreateExpressionTree (EmitContext ec)
9338 Arguments args = new Arguments (2);
9339 args.Add (new Argument (base.CreateExpressionTree (ec)));
9340 if (!initializers.IsEmpty)
9341 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9343 return CreateExpressionFactoryCall (
9344 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9348 public override Expression DoResolve (EmitContext ec)
9350 if (eclass != ExprClass.Invalid)
9353 Expression e = base.DoResolve (ec);
9357 Expression previous = ec.CurrentInitializerVariable;
9358 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9359 initializers.Resolve (ec);
9360 ec.CurrentInitializerVariable = previous;
9364 public override bool Emit (EmitContext ec, IMemoryLocation target)
9366 bool left_on_stack = base.Emit (ec, target);
9368 if (initializers.IsEmpty)
9369 return left_on_stack;
9371 LocalTemporary temp = target as LocalTemporary;
9373 if (!left_on_stack) {
9374 VariableReference vr = target as VariableReference;
9376 // FIXME: This still does not work correctly for pre-set variables
9377 if (vr != null && vr.IsRef)
9378 target.AddressOf (ec, AddressOp.Load);
9380 ((Expression) target).Emit (ec);
9381 left_on_stack = true;
9384 temp = new LocalTemporary (type);
9391 initializers.Emit (ec);
9393 if (left_on_stack) {
9398 return left_on_stack;
9401 public override bool HasInitializer {
9403 return !initializers.IsEmpty;
9407 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9409 base.MutateHoistedGenericType (storey);
9410 initializers.MutateHoistedGenericType (storey);
9414 public class AnonymousTypeDeclaration : Expression
9416 ArrayList parameters;
9417 readonly TypeContainer parent;
9418 static readonly ArrayList EmptyParameters = new ArrayList (0);
9420 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9422 this.parameters = parameters;
9423 this.parent = parent;
9427 protected override void CloneTo (CloneContext clonectx, Expression target)
9429 if (parameters == null)
9432 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9433 t.parameters = new ArrayList (parameters.Count);
9434 foreach (AnonymousTypeParameter atp in parameters)
9435 t.parameters.Add (atp.Clone (clonectx));
9438 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9440 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
9444 type = AnonymousTypeClass.Create (parent, parameters, loc);
9451 if (Report.Errors == 0)
9454 parent.Module.AddAnonymousType (type);
9458 public override Expression CreateExpressionTree (EmitContext ec)
9460 throw new NotSupportedException ("ET");
9463 public override Expression DoResolve (EmitContext ec)
9465 AnonymousTypeClass anonymous_type;
9467 if (!ec.IsAnonymousMethodAllowed) {
9468 Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9472 if (parameters == null) {
9473 anonymous_type = CreateAnonymousType (EmptyParameters);
9474 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9475 null, loc).Resolve (ec);
9479 Arguments arguments = new Arguments (parameters.Count);
9480 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9481 for (int i = 0; i < parameters.Count; ++i) {
9482 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9488 arguments.Add (new Argument (e));
9489 t_args [i] = new TypeExpression (e.Type, e.Location);
9495 anonymous_type = CreateAnonymousType (parameters);
9496 if (anonymous_type == null)
9499 GenericTypeExpr te = new GenericTypeExpr (anonymous_type.TypeBuilder,
9500 new TypeArguments (t_args), loc);
9502 return new New (te, arguments, loc).Resolve (ec);
9505 public override void Emit (EmitContext ec)
9507 throw new InternalErrorException ("Should not be reached");
9511 public class AnonymousTypeParameter : Expression
9513 public readonly string Name;
9514 Expression initializer;
9516 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9520 this.initializer = initializer;
9523 public AnonymousTypeParameter (Parameter parameter)
9525 this.Name = parameter.Name;
9526 this.loc = parameter.Location;
9527 this.initializer = new SimpleName (Name, loc);
9530 protected override void CloneTo (CloneContext clonectx, Expression target)
9532 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9533 t.initializer = initializer.Clone (clonectx);
9536 public override Expression CreateExpressionTree (EmitContext ec)
9538 throw new NotSupportedException ("ET");
9541 public override bool Equals (object o)
9543 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9544 return other != null && Name == other.Name;
9547 public override int GetHashCode ()
9549 return Name.GetHashCode ();
9552 public override Expression DoResolve (EmitContext ec)
9554 Expression e = initializer.Resolve (ec);
9558 if (e.eclass == ExprClass.MethodGroup) {
9559 Error_InvalidInitializer (e.ExprClassName);
9564 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9565 type == InternalType.AnonymousMethod || type.IsPointer) {
9566 Error_InvalidInitializer (e.GetSignatureForError ());
9573 protected virtual void Error_InvalidInitializer (string initializer)
9575 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9579 public override void Emit (EmitContext ec)
9581 throw new InternalErrorException ("Should not be reached");