2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
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 ArrayList arguments;
28 protected readonly MethodGroupExpr mg;
29 readonly ExpressionTreeExpression expr_tree;
31 public UserOperatorCall (MethodGroupExpr mg, ArrayList 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 ArrayList args = new ArrayList (arguments.Count + 1);
48 args.Add (new Argument (new NullLiteral (loc)));
49 args.Add (new Argument (mg.CreateExpressionTree (ec)));
50 foreach (Argument a in arguments) {
51 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
54 return CreateExpressionFactoryCall ("Call", args);
57 public override Expression DoResolve (EmitContext ec)
60 // We are born fully resolved
65 public override void Emit (EmitContext ec)
67 mg.EmitCall (ec, arguments);
70 [Obsolete ("It may not be compatible with expression trees")]
71 static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
72 Expression e, Location loc)
76 args = new ArrayList (1);
77 Argument a = new Argument (e, Argument.AType.Expression);
79 // We need to resolve the arguments before sending them in !
80 if (!a.Resolve (ec, loc))
84 mg = mg.OverloadResolve (ec, ref args, false, loc);
89 return new UserOperatorCall (mg, args, null, loc);
92 public MethodGroupExpr Method {
97 public class ParenthesizedExpression : Expression
99 public Expression Expr;
101 public ParenthesizedExpression (Expression expr)
104 this.loc = expr.Location;
107 public override Expression CreateExpressionTree (EmitContext ec)
109 throw new NotSupportedException ("ET");
112 public override Expression DoResolve (EmitContext ec)
114 Expr = Expr.Resolve (ec);
118 public override void Emit (EmitContext ec)
120 throw new Exception ("Should not happen");
123 protected override void CloneTo (CloneContext clonectx, Expression t)
125 ParenthesizedExpression target = (ParenthesizedExpression) t;
127 target.Expr = Expr.Clone (clonectx);
132 // Unary implements unary expressions.
134 public class Unary : Expression {
135 public enum Operator : byte {
136 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
140 static Type [] [] predefined_operators;
142 public readonly Operator Oper;
143 public Expression Expr;
144 Expression enum_conversion;
146 public Unary (Operator op, Expression expr, Location loc)
154 // This routine will attempt to simplify the unary expression when the
155 // argument is a constant.
157 Constant TryReduceConstant (EmitContext ec, Constant e)
159 if (e is SideEffectConstant) {
160 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
161 return r == null ? null : new SideEffectConstant (r, e, r.Location);
164 Type expr_type = e.Type;
167 case Operator.UnaryPlus:
168 // Unary numeric promotions
169 if (expr_type == TypeManager.byte_type)
170 return new IntConstant (((ByteConstant)e).Value, e.Location);
171 if (expr_type == TypeManager.sbyte_type)
172 return new IntConstant (((SByteConstant)e).Value, e.Location);
173 if (expr_type == TypeManager.short_type)
174 return new IntConstant (((ShortConstant)e).Value, e.Location);
175 if (expr_type == TypeManager.ushort_type)
176 return new IntConstant (((UShortConstant)e).Value, e.Location);
177 if (expr_type == TypeManager.char_type)
178 return new IntConstant (((CharConstant)e).Value, e.Location);
180 // Predefined operators
181 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
182 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
183 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
184 expr_type == TypeManager.decimal_type)
191 case Operator.UnaryNegation:
192 // Unary numeric promotions
193 if (expr_type == TypeManager.byte_type)
194 return new IntConstant (-((ByteConstant)e).Value, e.Location);
195 if (expr_type == TypeManager.sbyte_type)
196 return new IntConstant (-((SByteConstant)e).Value, e.Location);
197 if (expr_type == TypeManager.short_type)
198 return new IntConstant (-((ShortConstant)e).Value, e.Location);
199 if (expr_type == TypeManager.ushort_type)
200 return new IntConstant (-((UShortConstant)e).Value, e.Location);
201 if (expr_type == TypeManager.char_type)
202 return new IntConstant (-((CharConstant)e).Value, e.Location);
204 // Predefined operators
205 if (expr_type == TypeManager.int32_type) {
206 int value = ((IntConstant)e).Value;
207 if (value == int.MinValue) {
208 if (ec.ConstantCheckState) {
209 ConstantFold.Error_CompileTimeOverflow (loc);
214 return new IntConstant (-value, e.Location);
216 if (expr_type == TypeManager.int64_type) {
217 long value = ((LongConstant)e).Value;
218 if (value == long.MinValue) {
219 if (ec.ConstantCheckState) {
220 ConstantFold.Error_CompileTimeOverflow (loc);
225 return new LongConstant (-value, e.Location);
228 if (expr_type == TypeManager.uint32_type) {
229 UIntLiteral uil = e as UIntLiteral;
231 if (uil.Value == 2147483648)
232 return new IntLiteral (int.MinValue, e.Location);
233 return new LongLiteral (-uil.Value, e.Location);
235 return new LongConstant (-((UIntConstant)e).Value, e.Location);
238 if (expr_type == TypeManager.uint64_type) {
239 ULongLiteral ull = e as ULongLiteral;
240 if (ull != null && ull.Value == 9223372036854775808)
241 return new LongLiteral (long.MinValue, e.Location);
245 if (expr_type == TypeManager.float_type) {
246 FloatLiteral fl = e as FloatLiteral;
247 // For better error reporting
249 fl.Value = -fl.Value;
252 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
254 if (expr_type == TypeManager.double_type) {
255 DoubleLiteral dl = e as DoubleLiteral;
256 // For better error reporting
258 dl.Value = -dl.Value;
262 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
264 if (expr_type == TypeManager.decimal_type)
265 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
269 case Operator.LogicalNot:
270 if (expr_type != TypeManager.bool_type)
273 bool b = (bool)e.GetValue ();
274 return new BoolConstant (!b, e.Location);
276 case Operator.OnesComplement:
277 // Unary numeric promotions
278 if (expr_type == TypeManager.byte_type)
279 return new IntConstant (~((ByteConstant)e).Value, e.Location);
280 if (expr_type == TypeManager.sbyte_type)
281 return new IntConstant (~((SByteConstant)e).Value, e.Location);
282 if (expr_type == TypeManager.short_type)
283 return new IntConstant (~((ShortConstant)e).Value, e.Location);
284 if (expr_type == TypeManager.ushort_type)
285 return new IntConstant (~((UShortConstant)e).Value, e.Location);
286 if (expr_type == TypeManager.char_type)
287 return new IntConstant (~((CharConstant)e).Value, e.Location);
289 // Predefined operators
290 if (expr_type == TypeManager.int32_type)
291 return new IntConstant (~((IntConstant)e).Value, e.Location);
292 if (expr_type == TypeManager.uint32_type)
293 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
294 if (expr_type == TypeManager.int64_type)
295 return new LongConstant (~((LongConstant)e).Value, e.Location);
296 if (expr_type == TypeManager.uint64_type){
297 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
299 if (e is EnumConstant) {
300 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
302 e = new EnumConstant (e, expr_type);
307 throw new Exception ("Can not constant fold: " + Oper.ToString());
310 protected Expression ResolveOperator (EmitContext ec, Expression expr)
312 eclass = ExprClass.Value;
314 if (predefined_operators == null)
315 CreatePredefinedOperatorsTable ();
317 Type expr_type = expr.Type;
318 Expression best_expr;
321 // Primitive types first
323 if (TypeManager.IsPrimitiveType (expr_type)) {
324 best_expr = ResolvePrimitivePredefinedType (expr);
325 if (best_expr == null)
328 type = best_expr.Type;
334 // E operator ~(E x);
336 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
337 return ResolveEnumOperator (ec, expr);
339 return ResolveUserType (ec, expr);
342 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
344 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
345 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
346 if (best_expr == null)
350 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
352 return EmptyCast.Create (this, type);
355 public override Expression CreateExpressionTree (EmitContext ec)
357 return CreateExpressionTree (ec, null);
360 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
364 case Operator.AddressOf:
365 Error_PointerInsideExpressionTree ();
367 case Operator.UnaryNegation:
368 if (ec.CheckState && user_op == null && !IsFloat (type))
369 method_name = "NegateChecked";
371 method_name = "Negate";
373 case Operator.OnesComplement:
374 case Operator.LogicalNot:
377 case Operator.UnaryPlus:
378 method_name = "UnaryPlus";
381 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
384 ArrayList args = new ArrayList (2);
385 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
387 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
388 return CreateExpressionFactoryCall (method_name, args);
391 static void CreatePredefinedOperatorsTable ()
393 predefined_operators = new Type [(int) Operator.TOP] [];
396 // 7.6.1 Unary plus operator
398 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
399 TypeManager.int32_type, TypeManager.uint32_type,
400 TypeManager.int64_type, TypeManager.uint64_type,
401 TypeManager.float_type, TypeManager.double_type,
402 TypeManager.decimal_type
406 // 7.6.2 Unary minus operator
408 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
409 TypeManager.int32_type,
410 TypeManager.int64_type,
411 TypeManager.float_type, TypeManager.double_type,
412 TypeManager.decimal_type
416 // 7.6.3 Logical negation operator
418 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
419 TypeManager.bool_type
423 // 7.6.4 Bitwise complement operator
425 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
426 TypeManager.int32_type, TypeManager.uint32_type,
427 TypeManager.int64_type, TypeManager.uint64_type
432 // Unary numeric promotions
434 static Expression DoNumericPromotion (Operator op, Expression expr)
436 Type expr_type = expr.Type;
437 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
438 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
439 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
440 expr_type == TypeManager.char_type)
441 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
443 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
444 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
449 public override Expression DoResolve (EmitContext ec)
451 if (Oper == Operator.AddressOf) {
452 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
454 if (Expr == null || Expr.eclass != ExprClass.Variable){
455 Error (211, "Cannot take the address of the given expression");
459 return ResolveAddressOf (ec);
462 Expr = Expr.Resolve (ec);
466 if (TypeManager.IsNullableValueType (Expr.Type))
467 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
470 // Attempt to use a constant folding operation.
472 Constant cexpr = Expr as Constant;
474 cexpr = TryReduceConstant (ec, cexpr);
479 Expression expr = ResolveOperator (ec, Expr);
481 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
484 // Reduce unary operator on predefined types
486 if (expr == this && Oper == Operator.UnaryPlus)
492 public override Expression DoResolveLValue (EmitContext ec, Expression right)
497 public override void Emit (EmitContext ec)
499 EmitOperator (ec, type);
502 protected void EmitOperator (EmitContext ec, Type type)
504 ILGenerator ig = ec.ig;
507 case Operator.UnaryPlus:
511 case Operator.UnaryNegation:
512 if (ec.CheckState && !IsFloat (type)) {
513 ig.Emit (OpCodes.Ldc_I4_0);
514 if (type == TypeManager.int64_type)
515 ig.Emit (OpCodes.Conv_U8);
517 ig.Emit (OpCodes.Sub_Ovf);
520 ig.Emit (OpCodes.Neg);
525 case Operator.LogicalNot:
527 ig.Emit (OpCodes.Ldc_I4_0);
528 ig.Emit (OpCodes.Ceq);
531 case Operator.OnesComplement:
533 ig.Emit (OpCodes.Not);
536 case Operator.AddressOf:
537 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
541 throw new Exception ("This should not happen: Operator = "
546 // Same trick as in Binary expression
548 if (enum_conversion != null)
549 enum_conversion.Emit (ec);
552 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
554 if (Oper == Operator.LogicalNot)
555 Expr.EmitBranchable (ec, target, !on_true);
557 base.EmitBranchable (ec, target, on_true);
560 public override void EmitSideEffect (EmitContext ec)
562 Expr.EmitSideEffect (ec);
565 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
567 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
568 oper, TypeManager.CSharpName (t));
571 static bool IsFloat (Type t)
573 return t == TypeManager.float_type || t == TypeManager.double_type;
577 // Returns a stringified representation of the Operator
579 public static string OperName (Operator oper)
582 case Operator.UnaryPlus:
584 case Operator.UnaryNegation:
586 case Operator.LogicalNot:
588 case Operator.OnesComplement:
590 case Operator.AddressOf:
594 throw new NotImplementedException (oper.ToString ());
597 Expression ResolveAddressOf (EmitContext ec)
604 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
608 IVariable variable = Expr as IVariable;
609 bool is_fixed = variable != null && variable.VerifyFixed ();
611 if (!ec.InFixedInitializer && !is_fixed) {
612 Error (212, "You can only take the address of unfixed expression inside " +
613 "of a fixed statement initializer");
617 if (ec.InFixedInitializer && is_fixed) {
618 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
622 LocalVariableReference lr = Expr as LocalVariableReference;
624 if (lr.local_info.IsCaptured) {
625 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
628 lr.local_info.AddressTaken = true;
629 lr.local_info.Used = true;
632 ParameterReference pr = Expr as ParameterReference;
633 if ((pr != null) && pr.Parameter.IsCaptured) {
634 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
638 // According to the specs, a variable is considered definitely assigned if you take
640 if ((variable != null) && (variable.VariableInfo != null)) {
641 variable.VariableInfo.SetAssigned (ec);
644 type = TypeManager.GetPointerType (Expr.Type);
645 eclass = ExprClass.Value;
649 Expression ResolvePrimitivePredefinedType (Expression expr)
651 expr = DoNumericPromotion (Oper, expr);
652 Type expr_type = expr.Type;
653 Type[] predefined = predefined_operators [(int) Oper];
654 foreach (Type t in predefined) {
662 // Perform user-operator overload resolution
664 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
666 CSharp.Operator.OpType op_type;
668 case Operator.LogicalNot:
669 op_type = CSharp.Operator.OpType.LogicalNot; break;
670 case Operator.OnesComplement:
671 op_type = CSharp.Operator.OpType.OnesComplement; break;
672 case Operator.UnaryNegation:
673 op_type = CSharp.Operator.OpType.UnaryNegation; break;
674 case Operator.UnaryPlus:
675 op_type = CSharp.Operator.OpType.UnaryPlus; break;
677 throw new InternalErrorException (Oper.ToString ());
680 string op_name = CSharp.Operator.GetMetadataName (op_type);
681 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
685 ArrayList args = new ArrayList (1);
686 args.Add (new Argument (expr));
687 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
692 Expr = ((Argument) args [0]).Expr;
693 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
697 // Unary user type overload resolution
699 Expression ResolveUserType (EmitContext ec, Expression expr)
701 Expression best_expr = ResolveUserOperator (ec, expr);
702 if (best_expr != null)
705 Type[] predefined = predefined_operators [(int) Oper];
706 foreach (Type t in predefined) {
707 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
708 if (oper_expr == null)
712 // decimal type is predefined but has user-operators
714 if (oper_expr.Type == TypeManager.decimal_type)
715 oper_expr = ResolveUserType (ec, oper_expr);
717 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
719 if (oper_expr == null)
722 if (best_expr == null) {
723 best_expr = oper_expr;
727 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
729 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
730 OperName (Oper), TypeManager.CSharpName (expr.Type));
735 best_expr = oper_expr;
738 if (best_expr == null)
742 // HACK: Decimal user-operator is included in standard operators
744 if (best_expr.Type == TypeManager.decimal_type)
748 type = best_expr.Type;
752 protected override void CloneTo (CloneContext clonectx, Expression t)
754 Unary target = (Unary) t;
756 target.Expr = Expr.Clone (clonectx);
761 // Unary operators are turned into Indirection expressions
762 // after semantic analysis (this is so we can take the address
763 // of an indirection).
765 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
767 LocalTemporary temporary;
770 public Indirection (Expression expr, Location l)
776 public override Expression CreateExpressionTree (EmitContext ec)
778 Error_PointerInsideExpressionTree ();
782 public override void Emit (EmitContext ec)
787 LoadFromPtr (ec.ig, Type);
790 public void Emit (EmitContext ec, bool leave_copy)
794 ec.ig.Emit (OpCodes.Dup);
795 temporary = new LocalTemporary (expr.Type);
796 temporary.Store (ec);
800 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
802 prepared = prepare_for_load;
806 if (prepare_for_load)
807 ec.ig.Emit (OpCodes.Dup);
811 ec.ig.Emit (OpCodes.Dup);
812 temporary = new LocalTemporary (expr.Type);
813 temporary.Store (ec);
816 StoreFromPtr (ec.ig, type);
818 if (temporary != null) {
820 temporary.Release (ec);
824 public void AddressOf (EmitContext ec, AddressOp Mode)
829 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
831 return DoResolve (ec);
834 public override Expression DoResolve (EmitContext ec)
836 expr = expr.Resolve (ec);
843 if (!expr.Type.IsPointer) {
844 Error (193, "The * or -> operator must be applied to a pointer");
848 type = TypeManager.GetElementType (expr.Type);
849 eclass = ExprClass.Variable;
853 public override string ToString ()
855 return "*(" + expr + ")";
858 #region IVariable Members
860 public VariableInfo VariableInfo {
864 public bool VerifyFixed ()
866 // A pointer-indirection is always fixed.
874 /// Unary Mutator expressions (pre and post ++ and --)
878 /// UnaryMutator implements ++ and -- expressions. It derives from
879 /// ExpressionStatement becuase the pre/post increment/decrement
880 /// operators can be used in a statement context.
882 /// FIXME: Idea, we could split this up in two classes, one simpler
883 /// for the common case, and one with the extra fields for more complex
884 /// classes (indexers require temporary access; overloaded require method)
887 public class UnaryMutator : ExpressionStatement {
889 public enum Mode : byte {
896 PreDecrement = IsDecrement,
897 PostIncrement = IsPost,
898 PostDecrement = IsPost | IsDecrement
902 bool is_expr = false;
903 bool recurse = false;
908 // This is expensive for the simplest case.
910 UserOperatorCall method;
912 public UnaryMutator (Mode m, Expression e, Location l)
919 static string OperName (Mode mode)
921 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
926 /// Returns whether an object of type `t' can be incremented
927 /// or decremented with add/sub (ie, basically whether we can
928 /// use pre-post incr-decr operations on it, but it is not a
929 /// System.Decimal, which we require operator overloading to catch)
931 static bool IsIncrementableNumber (Type t)
933 return (t == TypeManager.sbyte_type) ||
934 (t == TypeManager.byte_type) ||
935 (t == TypeManager.short_type) ||
936 (t == TypeManager.ushort_type) ||
937 (t == TypeManager.int32_type) ||
938 (t == TypeManager.uint32_type) ||
939 (t == TypeManager.int64_type) ||
940 (t == TypeManager.uint64_type) ||
941 (t == TypeManager.char_type) ||
942 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
943 (t == TypeManager.float_type) ||
944 (t == TypeManager.double_type) ||
945 (t.IsPointer && t != TypeManager.void_ptr_type);
948 Expression ResolveOperator (EmitContext ec)
950 Type expr_type = expr.Type;
953 // Step 1: Perform Operator Overload location
958 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
959 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
961 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
963 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
966 method = UserOperatorCall.MakeSimpleCall (
967 ec, (MethodGroupExpr) mg, expr, loc);
970 } else if (!IsIncrementableNumber (expr_type)) {
971 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
972 TypeManager.CSharpName (expr_type) + "'");
977 // The operand of the prefix/postfix increment decrement operators
978 // should be an expression that is classified as a variable,
979 // a property access or an indexer access
982 if (expr.eclass == ExprClass.Variable){
983 LocalVariableReference var = expr as LocalVariableReference;
984 if ((var != null) && var.IsReadOnly) {
985 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
988 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
989 expr = expr.ResolveLValue (ec, this, Location);
993 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1000 public override Expression CreateExpressionTree (EmitContext ec)
1002 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1005 public override Expression DoResolve (EmitContext ec)
1007 expr = expr.Resolve (ec);
1012 eclass = ExprClass.Value;
1015 if (TypeManager.IsNullableValueType (expr.Type))
1016 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1019 return ResolveOperator (ec);
1023 // Loads the proper "1" into the stack based on the type, then it emits the
1024 // opcode for the operation requested
1026 void LoadOneAndEmitOp (EmitContext ec, Type t)
1029 // Measure if getting the typecode and using that is more/less efficient
1030 // that comparing types. t.GetTypeCode() is an internal call.
1032 ILGenerator ig = ec.ig;
1034 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1035 LongConstant.EmitLong (ig, 1);
1036 else if (t == TypeManager.double_type)
1037 ig.Emit (OpCodes.Ldc_R8, 1.0);
1038 else if (t == TypeManager.float_type)
1039 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1040 else if (t.IsPointer){
1041 Type et = TypeManager.GetElementType (t);
1042 int n = GetTypeSize (et);
1045 ig.Emit (OpCodes.Sizeof, et);
1047 IntConstant.EmitInt (ig, n);
1049 ig.Emit (OpCodes.Ldc_I4_1);
1052 // Now emit the operation
1055 if (t == TypeManager.int32_type ||
1056 t == TypeManager.int64_type){
1057 if ((mode & Mode.IsDecrement) != 0)
1058 ig.Emit (OpCodes.Sub_Ovf);
1060 ig.Emit (OpCodes.Add_Ovf);
1061 } else if (t == TypeManager.uint32_type ||
1062 t == TypeManager.uint64_type){
1063 if ((mode & Mode.IsDecrement) != 0)
1064 ig.Emit (OpCodes.Sub_Ovf_Un);
1066 ig.Emit (OpCodes.Add_Ovf_Un);
1068 if ((mode & Mode.IsDecrement) != 0)
1069 ig.Emit (OpCodes.Sub_Ovf);
1071 ig.Emit (OpCodes.Add_Ovf);
1074 if ((mode & Mode.IsDecrement) != 0)
1075 ig.Emit (OpCodes.Sub);
1077 ig.Emit (OpCodes.Add);
1080 if (t == TypeManager.sbyte_type){
1082 ig.Emit (OpCodes.Conv_Ovf_I1);
1084 ig.Emit (OpCodes.Conv_I1);
1085 } else if (t == TypeManager.byte_type){
1087 ig.Emit (OpCodes.Conv_Ovf_U1);
1089 ig.Emit (OpCodes.Conv_U1);
1090 } else if (t == TypeManager.short_type){
1092 ig.Emit (OpCodes.Conv_Ovf_I2);
1094 ig.Emit (OpCodes.Conv_I2);
1095 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1097 ig.Emit (OpCodes.Conv_Ovf_U2);
1099 ig.Emit (OpCodes.Conv_U2);
1104 void EmitCode (EmitContext ec, bool is_expr)
1107 this.is_expr = is_expr;
1108 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1111 public override void Emit (EmitContext ec)
1114 // We use recurse to allow ourselfs to be the source
1115 // of an assignment. This little hack prevents us from
1116 // having to allocate another expression
1119 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1121 LoadOneAndEmitOp (ec, expr.Type);
1123 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1128 EmitCode (ec, true);
1131 public override void EmitStatement (EmitContext ec)
1133 EmitCode (ec, false);
1136 protected override void CloneTo (CloneContext clonectx, Expression t)
1138 UnaryMutator target = (UnaryMutator) t;
1140 target.expr = expr.Clone (clonectx);
1145 /// Base class for the `Is' and `As' classes.
1149 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1152 public abstract class Probe : Expression {
1153 public Expression ProbeType;
1154 protected Expression expr;
1155 protected TypeExpr probe_type_expr;
1157 public Probe (Expression expr, Expression probe_type, Location l)
1159 ProbeType = probe_type;
1164 public Expression Expr {
1170 public override Expression DoResolve (EmitContext ec)
1172 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1173 if (probe_type_expr == null)
1176 expr = expr.Resolve (ec);
1180 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1181 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1186 if (expr.Type == TypeManager.anonymous_method_type) {
1187 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1195 protected abstract string OperatorName { get; }
1197 protected override void CloneTo (CloneContext clonectx, Expression t)
1199 Probe target = (Probe) t;
1201 target.expr = expr.Clone (clonectx);
1202 target.ProbeType = ProbeType.Clone (clonectx);
1208 /// Implementation of the `is' operator.
1210 public class Is : Probe {
1211 Nullable.Unwrap expr_unwrap;
1213 public Is (Expression expr, Expression probe_type, Location l)
1214 : base (expr, probe_type, l)
1218 public override Expression CreateExpressionTree (EmitContext ec)
1220 ArrayList args = new ArrayList (2);
1221 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1222 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1223 return CreateExpressionFactoryCall ("TypeIs", args);
1226 public override void Emit (EmitContext ec)
1228 ILGenerator ig = ec.ig;
1229 if (expr_unwrap != null) {
1230 expr_unwrap.EmitCheck (ec);
1235 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1236 ig.Emit (OpCodes.Ldnull);
1237 ig.Emit (OpCodes.Cgt_Un);
1240 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1242 ILGenerator ig = ec.ig;
1243 if (expr_unwrap != null) {
1244 expr_unwrap.EmitCheck (ec);
1247 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1249 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1252 Expression CreateConstantResult (bool result)
1255 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1256 TypeManager.CSharpName (probe_type_expr.Type));
1258 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1259 TypeManager.CSharpName (probe_type_expr.Type));
1261 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1264 public override Expression DoResolve (EmitContext ec)
1266 if (base.DoResolve (ec) == null)
1270 bool d_is_nullable = false;
1272 if (expr is Constant) {
1274 // If E is a method group or the null literal, of if the type of E is a reference
1275 // type or a nullable type and the value of E is null, the result is false
1278 return CreateConstantResult (false);
1279 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1280 d = TypeManager.GetTypeArguments (d) [0];
1281 d_is_nullable = true;
1284 type = TypeManager.bool_type;
1285 eclass = ExprClass.Value;
1286 Type t = probe_type_expr.Type;
1287 bool t_is_nullable = false;
1288 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1289 t = TypeManager.GetTypeArguments (t) [0];
1290 t_is_nullable = true;
1293 if (t.IsValueType) {
1296 // D and T are the same value types but D can be null
1298 if (d_is_nullable && !t_is_nullable) {
1299 expr_unwrap = Nullable.Unwrap.Create (expr, ec);
1304 // The result is true if D and T are the same value types
1306 return CreateConstantResult (true);
1309 if (TypeManager.IsGenericParameter (d))
1310 return ResolveGenericParameter (t, d);
1313 // An unboxing conversion exists
1315 if (Convert.ExplicitReferenceConversionExists (d, t))
1318 if (TypeManager.IsGenericParameter (t))
1319 return ResolveGenericParameter (d, t);
1321 if (d.IsValueType) {
1323 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1324 return CreateConstantResult (true);
1326 if (TypeManager.IsGenericParameter (d))
1327 return ResolveGenericParameter (t, d);
1329 if (TypeManager.ContainsGenericParameters (d))
1332 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1333 Convert.ExplicitReferenceConversionExists (d, t)) {
1339 return CreateConstantResult (false);
1342 Expression ResolveGenericParameter (Type d, Type t)
1345 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1346 if (constraints != null) {
1347 if (constraints.IsReferenceType && d.IsValueType)
1348 return CreateConstantResult (false);
1350 if (constraints.IsValueType && !d.IsValueType)
1351 return CreateConstantResult (false);
1354 expr = new BoxedCast (expr, d);
1361 protected override string OperatorName {
1362 get { return "is"; }
1367 /// Implementation of the `as' operator.
1369 public class As : Probe {
1371 Expression resolved_type;
1373 public As (Expression expr, Expression probe_type, Location l)
1374 : base (expr, probe_type, l)
1378 public override Expression CreateExpressionTree (EmitContext ec)
1380 ArrayList args = new ArrayList (2);
1381 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1382 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1383 return CreateExpressionFactoryCall ("TypeAs", args);
1386 public override void Emit (EmitContext ec)
1388 ILGenerator ig = ec.ig;
1393 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1396 if (TypeManager.IsNullableType (type))
1397 ig.Emit (OpCodes.Unbox_Any, type);
1401 static void Error_CannotConvertType (Type source, Type target, Location loc)
1403 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1404 TypeManager.CSharpName (source),
1405 TypeManager.CSharpName (target));
1408 public override Expression DoResolve (EmitContext ec)
1410 if (resolved_type == null) {
1411 resolved_type = base.DoResolve (ec);
1413 if (resolved_type == null)
1417 type = probe_type_expr.Type;
1418 eclass = ExprClass.Value;
1419 Type etype = expr.Type;
1421 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1422 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1423 TypeManager.CSharpName (type));
1430 // If the type is a type parameter, ensure
1431 // that it is constrained by a class
1433 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1435 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1438 if (constraints == null)
1441 if (!constraints.HasClassConstraint)
1442 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1446 Report.Error (413, loc,
1447 "The as operator requires that the `{0}' type parameter be constrained by a class",
1448 probe_type_expr.GetSignatureForError ());
1453 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1454 return Nullable.LiftedNull.CreateFromExpression (this);
1457 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1464 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1465 if (TypeManager.IsGenericParameter (etype))
1466 expr = new BoxedCast (expr, etype);
1472 if (TypeManager.ContainsGenericParameters (etype) ||
1473 TypeManager.ContainsGenericParameters (type)) {
1474 expr = new BoxedCast (expr, etype);
1479 Error_CannotConvertType (etype, type, loc);
1483 protected override string OperatorName {
1484 get { return "as"; }
1487 public override bool GetAttributableValue (Type value_type, out object value)
1489 return expr.GetAttributableValue (value_type, out value);
1494 /// This represents a typecast in the source language.
1496 /// FIXME: Cast expressions have an unusual set of parsing
1497 /// rules, we need to figure those out.
1499 public class Cast : Expression {
1500 Expression target_type;
1503 public Cast (Expression cast_type, Expression expr)
1504 : this (cast_type, expr, cast_type.Location)
1508 public Cast (Expression cast_type, Expression expr, Location loc)
1510 this.target_type = cast_type;
1514 if (target_type == TypeManager.system_void_expr)
1515 Error_VoidInvalidInTheContext (loc);
1518 public Expression TargetType {
1519 get { return target_type; }
1522 public Expression Expr {
1523 get { return expr; }
1526 public override Expression CreateExpressionTree (EmitContext ec)
1528 throw new NotSupportedException ("ET");
1531 public override Expression DoResolve (EmitContext ec)
1533 expr = expr.Resolve (ec);
1537 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1543 if (type.IsAbstract && type.IsSealed) {
1544 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1548 eclass = ExprClass.Value;
1550 Constant c = expr as Constant;
1552 c = c.TryReduce (ec, type, loc);
1557 if (type.IsPointer && !ec.InUnsafe) {
1561 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1565 public override void Emit (EmitContext ec)
1567 throw new Exception ("Should not happen");
1570 protected override void CloneTo (CloneContext clonectx, Expression t)
1572 Cast target = (Cast) t;
1574 target.target_type = target_type.Clone (clonectx);
1575 target.expr = expr.Clone (clonectx);
1580 // C# 2.0 Default value expression
1582 public class DefaultValueExpression : Expression
1586 public DefaultValueExpression (Expression expr, Location loc)
1592 public override Expression CreateExpressionTree (EmitContext ec)
1594 ArrayList args = new ArrayList (2);
1595 args.Add (new Argument (this));
1596 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1597 return CreateExpressionFactoryCall ("Constant", args);
1600 public override Expression DoResolve (EmitContext ec)
1602 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1608 if (type == TypeManager.void_type) {
1609 Error_VoidInvalidInTheContext (loc);
1613 if (TypeManager.IsGenericParameter (type)) {
1614 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1615 if (constraints != null && constraints.IsReferenceType)
1616 return new EmptyConstantCast (new NullLiteral (Location), type);
1618 Constant c = New.Constantify (type);
1622 if (!TypeManager.IsValueType (type))
1623 return new EmptyConstantCast (new NullLiteral (Location), type);
1625 eclass = ExprClass.Variable;
1629 public override void Emit (EmitContext ec)
1631 LocalTemporary temp_storage = new LocalTemporary(type);
1633 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1634 ec.ig.Emit(OpCodes.Initobj, type);
1635 temp_storage.Emit(ec);
1638 protected override void CloneTo (CloneContext clonectx, Expression t)
1640 DefaultValueExpression target = (DefaultValueExpression) t;
1642 target.expr = expr.Clone (clonectx);
1647 /// Binary operators
1649 public class Binary : Expression {
1651 protected class PredefinedOperator {
1652 protected readonly Type left;
1653 protected readonly Type right;
1654 public readonly Operator OperatorsMask;
1655 public Type ReturnType;
1657 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1658 : this (ltype, rtype, op_mask, ltype)
1662 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1663 : this (type, type, op_mask, return_type)
1667 public PredefinedOperator (Type type, Operator op_mask)
1668 : this (type, type, op_mask, type)
1672 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1674 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1675 throw new InternalErrorException ("Only masked values can be used");
1679 this.OperatorsMask = op_mask;
1680 this.ReturnType = return_type;
1683 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1685 b.type = ReturnType;
1688 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1691 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1696 public bool IsPrimitiveApplicable (Type type)
1699 // We are dealing with primitive types only
1701 return left == type;
1704 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1706 if (TypeManager.IsEqual (left, lexpr.Type) &&
1707 TypeManager.IsEqual (right, rexpr.Type))
1710 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1711 Convert.ImplicitConversionExists (ec, rexpr, right);
1714 public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
1717 if (left != null && best_operator.left != null) {
1718 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1722 // When second arguments are same as the first one, the result is same
1724 if (left != right || best_operator.left != best_operator.right) {
1725 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1728 if (result == 0 || result > 2)
1731 return result == 1 ? best_operator : this;
1735 class PredefinedStringOperator : PredefinedOperator {
1736 public PredefinedStringOperator (Type type, Operator op_mask)
1737 : base (type, op_mask, type)
1739 ReturnType = TypeManager.string_type;
1742 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1743 : base (ltype, rtype, op_mask)
1745 ReturnType = TypeManager.string_type;
1748 public override Expression ConvertResult (EmitContext ec, Binary b)
1751 // Use original expression for nullable arguments
1753 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1755 b.left = unwrap.Original;
1757 unwrap = b.right as Nullable.Unwrap;
1759 b.right = unwrap.Original;
1761 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1762 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1765 // Start a new concat expression using converted expression
1767 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1771 class PredefinedShiftOperator : PredefinedOperator {
1772 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1773 base (ltype, TypeManager.int32_type, op_mask)
1777 public override Expression ConvertResult (EmitContext ec, Binary b)
1779 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1781 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1783 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1786 // b = b.left >> b.right & (0x1f|0x3f)
1788 b.right = new Binary (Operator.BitwiseAnd,
1789 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1792 // Expression tree representation does not use & mask
1794 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1795 b.type = ReturnType;
1800 class PredefinedPointerOperator : PredefinedOperator {
1801 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1802 : base (ltype, rtype, op_mask)
1806 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1807 : base (type, op_mask, return_type)
1811 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1814 if (!lexpr.Type.IsPointer)
1817 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1821 if (right == null) {
1822 if (!rexpr.Type.IsPointer)
1825 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1832 public override Expression ConvertResult (EmitContext ec, Binary b)
1834 base.ConvertResult (ec, b);
1836 Type r_type = ReturnType;
1837 if (r_type == null) {
1838 r_type = b.left.Type;
1840 r_type = b.right.Type;
1843 return new PointerArithmetic (b.oper == Operator.Addition,
1844 b.left, b.right, r_type, b.loc).Resolve (ec);
1849 public enum Operator {
1850 Multiply = 0 | ArithmeticMask,
1851 Division = 1 | ArithmeticMask,
1852 Modulus = 2 | ArithmeticMask,
1853 Addition = 3 | ArithmeticMask | AdditionMask,
1854 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1856 LeftShift = 5 | ShiftMask,
1857 RightShift = 6 | ShiftMask,
1859 LessThan = 7 | ComparisonMask | RelationalMask,
1860 GreaterThan = 8 | ComparisonMask | RelationalMask,
1861 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1862 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1863 Equality = 11 | ComparisonMask | EqualityMask,
1864 Inequality = 12 | ComparisonMask | EqualityMask,
1866 BitwiseAnd = 13 | BitwiseMask,
1867 ExclusiveOr = 14 | BitwiseMask,
1868 BitwiseOr = 15 | BitwiseMask,
1870 LogicalAnd = 16 | LogicalMask,
1871 LogicalOr = 17 | LogicalMask,
1876 ValuesOnlyMask = ArithmeticMask - 1,
1877 ArithmeticMask = 1 << 5,
1879 ComparisonMask = 1 << 7,
1880 EqualityMask = 1 << 8,
1881 BitwiseMask = 1 << 9,
1882 LogicalMask = 1 << 10,
1883 AdditionMask = 1 << 11,
1884 SubtractionMask = 1 << 12,
1885 RelationalMask = 1 << 13
1888 readonly Operator oper;
1889 protected Expression left, right;
1890 readonly bool is_compound;
1891 Expression enum_conversion;
1893 static PredefinedOperator [] standard_operators;
1894 static PredefinedOperator [] pointer_operators;
1896 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1897 : this (oper, left, right)
1899 this.is_compound = isCompound;
1902 public Binary (Operator oper, Expression left, Expression right)
1907 this.loc = left.Location;
1910 public Operator Oper {
1917 /// Returns a stringified representation of the Operator
1919 string OperName (Operator oper)
1923 case Operator.Multiply:
1926 case Operator.Division:
1929 case Operator.Modulus:
1932 case Operator.Addition:
1935 case Operator.Subtraction:
1938 case Operator.LeftShift:
1941 case Operator.RightShift:
1944 case Operator.LessThan:
1947 case Operator.GreaterThan:
1950 case Operator.LessThanOrEqual:
1953 case Operator.GreaterThanOrEqual:
1956 case Operator.Equality:
1959 case Operator.Inequality:
1962 case Operator.BitwiseAnd:
1965 case Operator.BitwiseOr:
1968 case Operator.ExclusiveOr:
1971 case Operator.LogicalOr:
1974 case Operator.LogicalAnd:
1978 s = oper.ToString ();
1988 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1990 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1993 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1995 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
1999 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2002 // TODO: This should be handled as Type of method group in CSharpName
2003 if (left.eclass == ExprClass.MethodGroup)
2004 l = left.ExprClassName;
2006 l = TypeManager.CSharpName (left.Type);
2008 if (right.eclass == ExprClass.MethodGroup)
2009 r = right.ExprClassName;
2011 r = TypeManager.CSharpName (right.Type);
2013 Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
2016 static string GetOperatorMetadataName (Operator op)
2018 CSharp.Operator.OpType op_type;
2020 case Operator.Addition:
2021 op_type = CSharp.Operator.OpType.Addition; break;
2022 case Operator.BitwiseAnd:
2023 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2024 case Operator.BitwiseOr:
2025 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2026 case Operator.Division:
2027 op_type = CSharp.Operator.OpType.Division; break;
2028 case Operator.Equality:
2029 op_type = CSharp.Operator.OpType.Equality; break;
2030 case Operator.ExclusiveOr:
2031 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2032 case Operator.GreaterThan:
2033 op_type = CSharp.Operator.OpType.GreaterThan; break;
2034 case Operator.GreaterThanOrEqual:
2035 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2036 case Operator.Inequality:
2037 op_type = CSharp.Operator.OpType.Inequality; break;
2038 case Operator.LeftShift:
2039 op_type = CSharp.Operator.OpType.LeftShift; break;
2040 case Operator.LessThan:
2041 op_type = CSharp.Operator.OpType.LessThan; break;
2042 case Operator.LessThanOrEqual:
2043 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2044 case Operator.Modulus:
2045 op_type = CSharp.Operator.OpType.Modulus; break;
2046 case Operator.Multiply:
2047 op_type = CSharp.Operator.OpType.Multiply; break;
2048 case Operator.RightShift:
2049 op_type = CSharp.Operator.OpType.RightShift; break;
2050 case Operator.Subtraction:
2051 op_type = CSharp.Operator.OpType.Subtraction; break;
2053 throw new InternalErrorException (op.ToString ());
2056 return CSharp.Operator.GetMetadataName (op_type);
2059 static bool IsUnsigned (Type t)
2062 t = TypeManager.GetElementType (t);
2064 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2065 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2068 static bool IsFloat (Type t)
2070 return t == TypeManager.float_type || t == TypeManager.double_type;
2073 Expression ResolveOperator (EmitContext ec)
2076 Type r = right.Type;
2078 bool primitives_only = false;
2080 if (standard_operators == null)
2081 CreateStandardOperatorsTable ();
2084 // Handles predefined primitive types
2086 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2087 if ((oper & Operator.ShiftMask) == 0) {
2088 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2091 primitives_only = true;
2095 if (l.IsPointer || r.IsPointer)
2096 return ResolveOperatorPointer (ec, l, r);
2099 bool lenum = TypeManager.IsEnumType (l);
2100 bool renum = TypeManager.IsEnumType (r);
2101 if (lenum || renum) {
2102 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2104 // TODO: Can this be ambiguous
2110 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2111 if (TypeManager.IsDelegateType (l))
2112 return ResolveOperatorDelegateBinary (ec, l, r);
2116 expr = ResolveUserOperator (ec, l, r);
2120 // Predefined reference types equality
2121 if ((oper & Operator.EqualityMask) != 0) {
2122 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2128 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2131 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2132 // if 'left' is not an enumeration constant, create one from the type of 'right'
2133 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2136 case Operator.BitwiseOr:
2137 case Operator.BitwiseAnd:
2138 case Operator.ExclusiveOr:
2139 case Operator.Equality:
2140 case Operator.Inequality:
2141 case Operator.LessThan:
2142 case Operator.LessThanOrEqual:
2143 case Operator.GreaterThan:
2144 case Operator.GreaterThanOrEqual:
2145 if (TypeManager.IsEnumType (left.Type))
2148 if (left.IsZeroInteger)
2149 return left.TryReduce (ec, right.Type, loc);
2153 case Operator.Addition:
2154 case Operator.Subtraction:
2157 case Operator.Multiply:
2158 case Operator.Division:
2159 case Operator.Modulus:
2160 case Operator.LeftShift:
2161 case Operator.RightShift:
2162 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2166 Error_OperatorCannotBeApplied (this.left, this.right);
2171 // The `|' operator used on types which were extended is dangerous
2173 void CheckBitwiseOrOnSignExtended ()
2175 OpcodeCast lcast = left as OpcodeCast;
2176 if (lcast != null) {
2177 if (IsUnsigned (lcast.UnderlyingType))
2181 OpcodeCast rcast = right as OpcodeCast;
2182 if (rcast != null) {
2183 if (IsUnsigned (rcast.UnderlyingType))
2187 if (lcast == null && rcast == null)
2190 // FIXME: consider constants
2192 Report.Warning (675, 3, loc,
2193 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2194 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2197 static void CreatePointerOperatorsTable ()
2199 ArrayList temp = new ArrayList ();
2202 // Pointer arithmetic:
2204 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2205 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2206 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2207 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2209 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2210 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2211 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2212 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2215 // T* operator + (int y, T* x);
2216 // T* operator + (uint y, T *x);
2217 // T* operator + (long y, T *x);
2218 // T* operator + (ulong y, T *x);
2220 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
2221 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
2222 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
2223 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
2226 // long operator - (T* x, T *y)
2228 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2230 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2233 static void CreateStandardOperatorsTable ()
2235 ArrayList temp = new ArrayList ();
2236 Type bool_type = TypeManager.bool_type;
2238 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2239 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2240 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2241 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2242 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2243 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2245 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2246 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2247 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2248 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2249 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2250 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2252 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2254 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2255 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2256 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2258 temp.Add (new PredefinedOperator (bool_type,
2259 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2261 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2262 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2263 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2264 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2266 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2270 // Rules used during binary numeric promotion
2272 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2277 Constant c = prim_expr as Constant;
2279 temp = c.ConvertImplicitly (type);
2286 if (type == TypeManager.uint32_type) {
2287 etype = prim_expr.Type;
2288 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2289 type = TypeManager.int64_type;
2291 if (type != second_expr.Type) {
2292 c = second_expr as Constant;
2294 temp = c.ConvertImplicitly (type);
2296 temp = Convert.ImplicitNumericConversion (second_expr, type);
2302 } else if (type == TypeManager.uint64_type) {
2304 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2306 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2307 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2311 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2320 // 7.2.6.2 Binary numeric promotions
2322 public bool DoBinaryOperatorPromotion (EmitContext ec)
2324 Type ltype = left.Type;
2325 Type rtype = right.Type;
2328 foreach (Type t in ConstantFold.binary_promotions) {
2330 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2333 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2336 Type int32 = TypeManager.int32_type;
2337 if (ltype != int32) {
2338 Constant c = left as Constant;
2340 temp = c.ConvertImplicitly (int32);
2342 temp = Convert.ImplicitNumericConversion (left, int32);
2349 if (rtype != int32) {
2350 Constant c = right as Constant;
2352 temp = c.ConvertImplicitly (int32);
2354 temp = Convert.ImplicitNumericConversion (right, int32);
2364 public override Expression DoResolve (EmitContext ec)
2369 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2370 left = ((ParenthesizedExpression) left).Expr;
2371 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2375 if (left.eclass == ExprClass.Type) {
2376 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2380 left = left.Resolve (ec);
2385 Constant lc = left as Constant;
2387 if (lc != null && lc.Type == TypeManager.bool_type &&
2388 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2389 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2391 // FIXME: resolve right expression as unreachable
2392 // right.Resolve (ec);
2394 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2398 right = right.Resolve (ec);
2402 eclass = ExprClass.Value;
2403 Constant rc = right as Constant;
2405 // The conversion rules are ignored in enum context but why
2406 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2407 left = lc = EnumLiftUp (ec, lc, rc, loc);
2411 right = rc = EnumLiftUp (ec, rc, lc, loc);
2416 if (rc != null && lc != null) {
2417 int prev_e = Report.Errors;
2418 Expression e = ConstantFold.BinaryFold (
2419 ec, oper, lc, rc, loc);
2420 if (e != null || Report.Errors != prev_e)
2423 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2424 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2426 if ((ResolveOperator (ec)) == null) {
2427 Error_OperatorCannotBeApplied (left, right);
2436 // The result is a constant with side-effect
2437 return new SideEffectConstant (lc, right, loc);
2441 // Comparison warnings
2442 if ((oper & Operator.ComparisonMask) != 0) {
2443 if (left.Equals (right)) {
2444 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2446 CheckUselessComparison (lc, right.Type);
2447 CheckUselessComparison (rc, left.Type);
2450 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2451 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2452 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2453 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2455 return DoResolveCore (ec, left, right);
2458 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2460 Expression expr = ResolveOperator (ec);
2462 Error_OperatorCannotBeApplied (left_orig, right_orig);
2464 if (left == null || right == null)
2465 throw new InternalErrorException ("Invalid conversion");
2467 if (oper == Operator.BitwiseOr)
2468 CheckBitwiseOrOnSignExtended ();
2474 // D operator + (D x, D y)
2475 // D operator - (D x, D y)
2477 Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
2479 if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
2480 if ((RootContext.Version != LanguageVersion.ISO_1)) {
2481 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2488 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
2493 ArrayList args = new ArrayList (2);
2494 args.Add (new Argument (left, Argument.AType.Expression));
2495 args.Add (new Argument (right, Argument.AType.Expression));
2497 if (oper == Operator.Addition) {
2498 if (TypeManager.delegate_combine_delegate_delegate == null) {
2499 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2500 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2503 method = TypeManager.delegate_combine_delegate_delegate;
2505 if (TypeManager.delegate_remove_delegate_delegate == null) {
2506 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2507 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2510 method = TypeManager.delegate_remove_delegate_delegate;
2513 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2514 mg = mg.OverloadResolve (ec, ref args, false, loc);
2516 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2520 // Enumeration operators
2522 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2525 // bool operator == (E x, E y);
2526 // bool operator != (E x, E y);
2527 // bool operator < (E x, E y);
2528 // bool operator > (E x, E y);
2529 // bool operator <= (E x, E y);
2530 // bool operator >= (E x, E y);
2532 // E operator & (E x, E y);
2533 // E operator | (E x, E y);
2534 // E operator ^ (E x, E y);
2536 // U operator - (E e, E f)
2537 // E operator - (E e, U x)
2539 // E operator + (U x, E e)
2540 // E operator + (E e, U x)
2542 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2543 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2546 Expression ltemp = left;
2547 Expression rtemp = right;
2548 Type underlying_type;
2550 if (TypeManager.IsEqual (ltype, rtype)) {
2551 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2553 if (left is Constant)
2554 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2556 left = EmptyCast.Create (left, underlying_type);
2558 if (right is Constant)
2559 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2561 right = EmptyCast.Create (right, underlying_type);
2563 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2564 Constant c = right as Constant;
2565 if (c == null || !c.IsDefaultValue)
2569 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2570 if (left is Constant)
2571 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2573 left = EmptyCast.Create (left, underlying_type);
2575 if (oper != Operator.Addition) {
2576 Constant c = left as Constant;
2577 if (c == null || !c.IsDefaultValue)
2581 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2582 if (right is Constant)
2583 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2585 right = EmptyCast.Create (right, underlying_type);
2591 // C# specification uses explicit cast syntax which means binary promotion
2592 // should happen, however it seems that csc does not do that
2594 if (!DoBinaryOperatorPromotion (ec)) {
2600 Type res_type = null;
2601 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2602 Type promoted_type = lenum ? left.Type : right.Type;
2603 enum_conversion = Convert.ExplicitNumericConversion (
2604 new EmptyExpression (promoted_type), underlying_type);
2606 if (oper == Operator.Subtraction && renum && lenum)
2607 res_type = underlying_type;
2608 else if (oper == Operator.Addition && renum)
2614 Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2615 if (!is_compound || expr == null)
2619 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2622 if (Convert.ImplicitConversionExists (ec, left, rtype))
2625 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2628 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2633 // 7.9.6 Reference type equality operators
2635 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2638 // operator != (object a, object b)
2639 // operator == (object a, object b)
2642 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2644 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2647 type = TypeManager.bool_type;
2648 GenericConstraints constraints;
2650 bool lgen = TypeManager.IsGenericParameter (l);
2652 if (TypeManager.IsEqual (l, r)) {
2655 // Only allow to compare same reference type parameter
2657 constraints = TypeManager.GetTypeParameterConstraints (l);
2658 if (constraints != null && constraints.IsReferenceType)
2664 if (l == TypeManager.anonymous_method_type)
2667 if (TypeManager.IsValueType (l))
2673 bool rgen = TypeManager.IsGenericParameter (r);
2676 // a, Both operands are reference-type values or the value null
2677 // b, One operand is a value of type T where T is a type-parameter and
2678 // the other operand is the value null. Furthermore T does not have the
2679 // value type constrain
2681 if (left is NullLiteral || right is NullLiteral) {
2683 constraints = TypeManager.GetTypeParameterConstraints (l);
2684 if (constraints != null && constraints.HasValueTypeConstraint)
2687 left = new BoxedCast (left, TypeManager.object_type);
2692 constraints = TypeManager.GetTypeParameterConstraints (r);
2693 if (constraints != null && constraints.HasValueTypeConstraint)
2696 right = new BoxedCast (right, TypeManager.object_type);
2702 // An interface is converted to the object before the
2703 // standard conversion is applied. It's not clear from the
2704 // standard but it looks like it works like that.
2707 constraints = TypeManager.GetTypeParameterConstraints (l);
2708 if (constraints == null || constraints.IsReferenceType)
2710 } else if (l.IsInterface) {
2711 l = TypeManager.object_type;
2712 } else if (l.IsValueType) {
2717 constraints = TypeManager.GetTypeParameterConstraints (r);
2718 if (constraints == null || constraints.IsReferenceType)
2720 } else if (r.IsInterface) {
2721 r = TypeManager.object_type;
2722 } else if (r.IsValueType) {
2727 const string ref_comparison = "Possible unintended reference comparison. " +
2728 "Consider casting the {0} side of the expression to `string' to compare the values";
2731 // A standard implicit conversion exists from the type of either
2732 // operand to the type of the other operand
2734 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2735 if (l == TypeManager.string_type)
2736 Report.Warning (253, 2, loc, ref_comparison, "right");
2741 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2742 if (r == TypeManager.string_type)
2743 Report.Warning (252, 2, loc, ref_comparison, "left");
2752 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2755 // bool operator == (void* x, void* y);
2756 // bool operator != (void* x, void* y);
2757 // bool operator < (void* x, void* y);
2758 // bool operator > (void* x, void* y);
2759 // bool operator <= (void* x, void* y);
2760 // bool operator >= (void* x, void* y);
2762 if ((oper & Operator.ComparisonMask) != 0) {
2765 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2772 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2778 type = TypeManager.bool_type;
2782 if (pointer_operators == null)
2783 CreatePointerOperatorsTable ();
2785 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2789 // Build-in operators method overloading
2791 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2793 PredefinedOperator best_operator = null;
2795 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2797 foreach (PredefinedOperator po in operators) {
2798 if ((po.OperatorsMask & oper_mask) == 0)
2801 if (primitives_only) {
2802 if (!po.IsPrimitiveApplicable (l))
2805 if (!po.IsApplicable (ec, left, right))
2809 if (best_operator == null) {
2811 if (primitives_only)
2817 best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
2819 if (best_operator == null) {
2820 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2821 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2828 if (best_operator == null)
2831 Expression expr = best_operator.ConvertResult (ec, this);
2832 if (enum_type == null)
2836 // HACK: required by enum_conversion
2838 expr.Type = enum_type;
2839 return EmptyCast.Create (expr, enum_type);
2843 // Performs user-operator overloading
2845 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
2848 if (oper == Operator.LogicalAnd)
2849 user_oper = Operator.BitwiseAnd;
2850 else if (oper == Operator.LogicalOr)
2851 user_oper = Operator.BitwiseOr;
2855 string op = GetOperatorMetadataName (user_oper);
2857 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2858 MethodGroupExpr right_operators = null;
2860 if (!TypeManager.IsEqual (r, l)) {
2861 right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2862 if (right_operators == null && left_operators == null)
2864 } else if (left_operators == null) {
2868 ArrayList args = new ArrayList (2);
2869 Argument larg = new Argument (left);
2871 Argument rarg = new Argument (right);
2874 MethodGroupExpr union;
2877 // User-defined operator implementations always take precedence
2878 // over predefined operator implementations
2880 if (left_operators != null && right_operators != null) {
2881 if (IsPredefinedUserOperator (l, user_oper)) {
2882 union = right_operators.OverloadResolve (ec, ref args, true, loc);
2884 union = left_operators;
2885 } else if (IsPredefinedUserOperator (r, user_oper)) {
2886 union = left_operators.OverloadResolve (ec, ref args, true, loc);
2888 union = right_operators;
2890 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2892 } else if (left_operators != null) {
2893 union = left_operators;
2895 union = right_operators;
2898 union = union.OverloadResolve (ec, ref args, true, loc);
2902 Expression oper_expr;
2904 // TODO: CreateExpressionTree is allocated every time
2905 if (user_oper != oper) {
2906 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
2907 oper == Operator.LogicalAnd, loc).Resolve (ec);
2909 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
2912 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2913 // and not invoke user operator
2915 if ((oper & Operator.EqualityMask) != 0) {
2916 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
2917 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
2918 type = TypeManager.bool_type;
2919 if (left is NullLiteral || right is NullLiteral)
2920 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
2921 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
2923 // Two System.Delegate(s) are never equal
2935 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2940 private void CheckUselessComparison (Constant c, Type type)
2942 if (c == null || !IsTypeIntegral (type)
2943 || c is StringConstant
2944 || c is BoolConstant
2945 || c is FloatConstant
2946 || c is DoubleConstant
2947 || c is DecimalConstant
2953 if (c is ULongConstant) {
2954 ulong uvalue = ((ULongConstant) c).Value;
2955 if (uvalue > long.MaxValue) {
2956 if (type == TypeManager.byte_type ||
2957 type == TypeManager.sbyte_type ||
2958 type == TypeManager.short_type ||
2959 type == TypeManager.ushort_type ||
2960 type == TypeManager.int32_type ||
2961 type == TypeManager.uint32_type ||
2962 type == TypeManager.int64_type ||
2963 type == TypeManager.char_type)
2964 WarnUselessComparison (type);
2967 value = (long) uvalue;
2969 else if (c is ByteConstant)
2970 value = ((ByteConstant) c).Value;
2971 else if (c is SByteConstant)
2972 value = ((SByteConstant) c).Value;
2973 else if (c is ShortConstant)
2974 value = ((ShortConstant) c).Value;
2975 else if (c is UShortConstant)
2976 value = ((UShortConstant) c).Value;
2977 else if (c is IntConstant)
2978 value = ((IntConstant) c).Value;
2979 else if (c is UIntConstant)
2980 value = ((UIntConstant) c).Value;
2981 else if (c is LongConstant)
2982 value = ((LongConstant) c).Value;
2983 else if (c is CharConstant)
2984 value = ((CharConstant)c).Value;
2989 if (IsValueOutOfRange (value, type))
2990 WarnUselessComparison (type);
2993 private bool IsValueOutOfRange (long value, Type type)
2995 if (IsTypeUnsigned (type) && value < 0)
2997 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2998 type == TypeManager.byte_type && value >= 0x100 ||
2999 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3000 type == TypeManager.ushort_type && value >= 0x10000 ||
3001 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3002 type == TypeManager.uint32_type && value >= 0x100000000;
3005 static bool IsBuildInEqualityOperator (Type t)
3007 return t == TypeManager.object_type || t == TypeManager.string_type ||
3008 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3011 static bool IsPredefinedUserOperator (Type t, Operator op)
3014 // Some predefined types have user operators
3016 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3019 private static bool IsTypeIntegral (Type type)
3021 return type == TypeManager.uint64_type ||
3022 type == TypeManager.int64_type ||
3023 type == TypeManager.uint32_type ||
3024 type == TypeManager.int32_type ||
3025 type == TypeManager.ushort_type ||
3026 type == TypeManager.short_type ||
3027 type == TypeManager.sbyte_type ||
3028 type == TypeManager.byte_type ||
3029 type == TypeManager.char_type;
3032 private static bool IsTypeUnsigned (Type type)
3034 return type == TypeManager.uint64_type ||
3035 type == TypeManager.uint32_type ||
3036 type == TypeManager.ushort_type ||
3037 type == TypeManager.byte_type ||
3038 type == TypeManager.char_type;
3041 private void WarnUselessComparison (Type type)
3043 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}'",
3044 TypeManager.CSharpName (type));
3048 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3049 /// context of a conditional bool expression. This function will return
3050 /// false if it is was possible to use EmitBranchable, or true if it was.
3052 /// The expression's code is generated, and we will generate a branch to `target'
3053 /// if the resulting expression value is equal to isTrue
3055 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3057 ILGenerator ig = ec.ig;
3060 // This is more complicated than it looks, but its just to avoid
3061 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3062 // but on top of that we want for == and != to use a special path
3063 // if we are comparing against null
3065 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3066 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3069 // put the constant on the rhs, for simplicity
3071 if (left is Constant) {
3072 Expression swap = right;
3077 if (((Constant) right).IsZeroInteger) {
3078 left.EmitBranchable (ec, target, my_on_true);
3081 if (right.Type == TypeManager.bool_type) {
3082 // right is a boolean, and it's not 'false' => it is 'true'
3083 left.EmitBranchable (ec, target, !my_on_true);
3087 } else if (oper == Operator.LogicalAnd) {
3090 Label tests_end = ig.DefineLabel ();
3092 left.EmitBranchable (ec, tests_end, false);
3093 right.EmitBranchable (ec, target, true);
3094 ig.MarkLabel (tests_end);
3097 // This optimizes code like this
3098 // if (true && i > 4)
3100 if (!(left is Constant))
3101 left.EmitBranchable (ec, target, false);
3103 if (!(right is Constant))
3104 right.EmitBranchable (ec, target, false);
3109 } else if (oper == Operator.LogicalOr){
3111 left.EmitBranchable (ec, target, true);
3112 right.EmitBranchable (ec, target, true);
3115 Label tests_end = ig.DefineLabel ();
3116 left.EmitBranchable (ec, tests_end, true);
3117 right.EmitBranchable (ec, target, false);
3118 ig.MarkLabel (tests_end);
3123 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3124 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3125 oper == Operator.Equality || oper == Operator.Inequality)) {
3126 base.EmitBranchable (ec, target, on_true);
3134 bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
3137 case Operator.Equality:
3139 ig.Emit (OpCodes.Beq, target);
3141 ig.Emit (OpCodes.Bne_Un, target);
3144 case Operator.Inequality:
3146 ig.Emit (OpCodes.Bne_Un, target);
3148 ig.Emit (OpCodes.Beq, target);
3151 case Operator.LessThan:
3154 ig.Emit (OpCodes.Blt_Un, target);
3156 ig.Emit (OpCodes.Blt, target);
3159 ig.Emit (OpCodes.Bge_Un, target);
3161 ig.Emit (OpCodes.Bge, target);
3164 case Operator.GreaterThan:
3167 ig.Emit (OpCodes.Bgt_Un, target);
3169 ig.Emit (OpCodes.Bgt, target);
3172 ig.Emit (OpCodes.Ble_Un, target);
3174 ig.Emit (OpCodes.Ble, target);
3177 case Operator.LessThanOrEqual:
3180 ig.Emit (OpCodes.Ble_Un, target);
3182 ig.Emit (OpCodes.Ble, target);
3185 ig.Emit (OpCodes.Bgt_Un, target);
3187 ig.Emit (OpCodes.Bgt, target);
3191 case Operator.GreaterThanOrEqual:
3194 ig.Emit (OpCodes.Bge_Un, target);
3196 ig.Emit (OpCodes.Bge, target);
3199 ig.Emit (OpCodes.Blt_Un, target);
3201 ig.Emit (OpCodes.Blt, target);
3204 throw new InternalErrorException (oper.ToString ());
3208 public override void Emit (EmitContext ec)
3210 EmitOperator (ec, left.Type);
3213 protected virtual void EmitOperator (EmitContext ec, Type l)
3215 ILGenerator ig = ec.ig;
3218 // Handle short-circuit operators differently
3221 if ((oper & Operator.LogicalMask) != 0) {
3222 Label load_result = ig.DefineLabel ();
3223 Label end = ig.DefineLabel ();
3225 bool is_or = oper == Operator.LogicalOr;
3226 left.EmitBranchable (ec, load_result, is_or);
3228 ig.Emit (OpCodes.Br_S, end);
3230 ig.MarkLabel (load_result);
3231 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3239 // Optimize zero-based operations
3241 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3243 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3244 Constant rc = right as Constant;
3245 if (rc != null && rc.IsDefaultValue) {
3255 case Operator.Multiply:
3257 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3258 opcode = OpCodes.Mul_Ovf;
3259 else if (!IsFloat (l))
3260 opcode = OpCodes.Mul_Ovf_Un;
3262 opcode = OpCodes.Mul;
3264 opcode = OpCodes.Mul;
3268 case Operator.Division:
3270 opcode = OpCodes.Div_Un;
3272 opcode = OpCodes.Div;
3275 case Operator.Modulus:
3277 opcode = OpCodes.Rem_Un;
3279 opcode = OpCodes.Rem;
3282 case Operator.Addition:
3284 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3285 opcode = OpCodes.Add_Ovf;
3286 else if (!IsFloat (l))
3287 opcode = OpCodes.Add_Ovf_Un;
3289 opcode = OpCodes.Add;
3291 opcode = OpCodes.Add;
3294 case Operator.Subtraction:
3296 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3297 opcode = OpCodes.Sub_Ovf;
3298 else if (!IsFloat (l))
3299 opcode = OpCodes.Sub_Ovf_Un;
3301 opcode = OpCodes.Sub;
3303 opcode = OpCodes.Sub;
3306 case Operator.RightShift:
3308 opcode = OpCodes.Shr_Un;
3310 opcode = OpCodes.Shr;
3313 case Operator.LeftShift:
3314 opcode = OpCodes.Shl;
3317 case Operator.Equality:
3318 opcode = OpCodes.Ceq;
3321 case Operator.Inequality:
3322 ig.Emit (OpCodes.Ceq);
3323 ig.Emit (OpCodes.Ldc_I4_0);
3325 opcode = OpCodes.Ceq;
3328 case Operator.LessThan:
3330 opcode = OpCodes.Clt_Un;
3332 opcode = OpCodes.Clt;
3335 case Operator.GreaterThan:
3337 opcode = OpCodes.Cgt_Un;
3339 opcode = OpCodes.Cgt;
3342 case Operator.LessThanOrEqual:
3343 if (IsUnsigned (l) || IsFloat (l))
3344 ig.Emit (OpCodes.Cgt_Un);
3346 ig.Emit (OpCodes.Cgt);
3347 ig.Emit (OpCodes.Ldc_I4_0);
3349 opcode = OpCodes.Ceq;
3352 case Operator.GreaterThanOrEqual:
3353 if (IsUnsigned (l) || IsFloat (l))
3354 ig.Emit (OpCodes.Clt_Un);
3356 ig.Emit (OpCodes.Clt);
3358 ig.Emit (OpCodes.Ldc_I4_0);
3360 opcode = OpCodes.Ceq;
3363 case Operator.BitwiseOr:
3364 opcode = OpCodes.Or;
3367 case Operator.BitwiseAnd:
3368 opcode = OpCodes.And;
3371 case Operator.ExclusiveOr:
3372 opcode = OpCodes.Xor;
3376 throw new InternalErrorException (oper.ToString ());
3382 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3383 // expression because that would wrap lifted binary operation
3385 if (enum_conversion != null)
3386 enum_conversion.Emit (ec);
3389 public override void EmitSideEffect (EmitContext ec)
3391 if ((oper & Operator.LogicalMask) != 0 ||
3392 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3393 base.EmitSideEffect (ec);
3395 left.EmitSideEffect (ec);
3396 right.EmitSideEffect (ec);
3400 protected override void CloneTo (CloneContext clonectx, Expression t)
3402 Binary target = (Binary) t;
3404 target.left = left.Clone (clonectx);
3405 target.right = right.Clone (clonectx);
3408 public override Expression CreateExpressionTree (EmitContext ec)
3410 return CreateExpressionTree (ec, null);
3413 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3416 bool lift_arg = false;
3419 case Operator.Addition:
3420 if (method == null && ec.CheckState && !IsFloat (type))
3421 method_name = "AddChecked";
3423 method_name = "Add";
3425 case Operator.BitwiseAnd:
3426 method_name = "And";
3428 case Operator.BitwiseOr:
3431 case Operator.Division:
3432 method_name = "Divide";
3434 case Operator.Equality:
3435 method_name = "Equal";
3438 case Operator.ExclusiveOr:
3439 method_name = "ExclusiveOr";
3441 case Operator.GreaterThan:
3442 method_name = "GreaterThan";
3445 case Operator.GreaterThanOrEqual:
3446 method_name = "GreaterThanOrEqual";
3449 case Operator.Inequality:
3450 method_name = "NotEqual";
3453 case Operator.LeftShift:
3454 method_name = "LeftShift";
3456 case Operator.LessThan:
3457 method_name = "LessThan";
3460 case Operator.LessThanOrEqual:
3461 method_name = "LessThanOrEqual";
3464 case Operator.LogicalAnd:
3465 method_name = "AndAlso";
3467 case Operator.LogicalOr:
3468 method_name = "OrElse";
3470 case Operator.Modulus:
3471 method_name = "Modulo";
3473 case Operator.Multiply:
3474 if (method == null && ec.CheckState && !IsFloat (type))
3475 method_name = "MultiplyChecked";
3477 method_name = "Multiply";
3479 case Operator.RightShift:
3480 method_name = "RightShift";
3482 case Operator.Subtraction:
3483 if (method == null && ec.CheckState && !IsFloat (type))
3484 method_name = "SubtractChecked";
3486 method_name = "Subtract";
3490 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3493 ArrayList args = new ArrayList (2);
3494 args.Add (new Argument (left.CreateExpressionTree (ec)));
3495 args.Add (new Argument (right.CreateExpressionTree (ec)));
3496 if (method != null) {
3498 args.Add (new Argument (new BoolConstant (false, loc)));
3500 args.Add (new Argument (method.CreateExpressionTree (ec)));
3503 return CreateExpressionFactoryCall (method_name, args);
3508 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3509 // b, c, d... may be strings or objects.
3511 public class StringConcat : Expression {
3512 ArrayList arguments;
3514 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3517 type = TypeManager.string_type;
3518 eclass = ExprClass.Value;
3520 arguments = new ArrayList (2);
3525 public override Expression CreateExpressionTree (EmitContext ec)
3527 Argument arg = (Argument) arguments [0];
3528 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3532 // Creates nested calls tree from an array of arguments used for IL emit
3534 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3536 ArrayList concat_args = new ArrayList (2);
3537 ArrayList add_args = new ArrayList (3);
3539 concat_args.Add (left);
3540 add_args.Add (new Argument (left_etree));
3542 concat_args.Add (arguments [pos]);
3543 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3545 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3549 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3553 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3555 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3556 if (++pos == arguments.Count)
3559 left = new Argument (new EmptyExpression (method.Type));
3560 return CreateExpressionAddCall (ec, left, expr, pos);
3563 public override Expression DoResolve (EmitContext ec)
3568 public void Append (EmitContext ec, Expression operand)
3573 StringConstant sc = operand as StringConstant;
3575 if (arguments.Count != 0) {
3576 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3577 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3578 if (last_expr_constant != null) {
3579 last_argument.Expr = new StringConstant (
3580 last_expr_constant.Value + sc.Value, sc.Location);
3586 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3588 StringConcat concat_oper = operand as StringConcat;
3589 if (concat_oper != null) {
3590 arguments.AddRange (concat_oper.arguments);
3595 arguments.Add (new Argument (operand));
3598 Expression CreateConcatMemberExpression ()
3600 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3603 public override void Emit (EmitContext ec)
3605 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3606 concat = concat.Resolve (ec);
3613 // User-defined conditional logical operator
3615 public class ConditionalLogicalOperator : UserOperatorCall {
3616 readonly bool is_and;
3619 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3620 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3621 : base (oper_method, arguments, expr_tree, loc)
3623 this.is_and = is_and;
3626 public override Expression DoResolve (EmitContext ec)
3628 MethodInfo method = (MethodInfo)mg;
3629 type = TypeManager.TypeToCoreType (method.ReturnType);
3630 ParameterData pd = TypeManager.GetParameterData (method);
3631 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3632 Report.Error (217, loc,
3633 "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",
3634 TypeManager.CSharpSignature (method));
3638 Expression left_dup = new EmptyExpression (type);
3639 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3640 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3641 if (op_true == null || op_false == null) {
3642 Report.Error (218, loc,
3643 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3644 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3648 oper = is_and ? op_false : op_true;
3649 eclass = ExprClass.Value;
3653 public override void Emit (EmitContext ec)
3655 ILGenerator ig = ec.ig;
3656 Label end_target = ig.DefineLabel ();
3659 // Emit and duplicate left argument
3661 ((Argument)arguments [0]).Expr.Emit (ec);
3662 ig.Emit (OpCodes.Dup);
3663 arguments.RemoveAt (0);
3665 oper.EmitBranchable (ec, end_target, true);
3667 ig.MarkLabel (end_target);
3671 public class PointerArithmetic : Expression {
3672 Expression left, right;
3676 // We assume that `l' is always a pointer
3678 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3684 is_add = is_addition;
3687 public override Expression CreateExpressionTree (EmitContext ec)
3689 Error_PointerInsideExpressionTree ();
3693 public override Expression DoResolve (EmitContext ec)
3695 eclass = ExprClass.Variable;
3697 if (left.Type == TypeManager.void_ptr_type) {
3698 Error (242, "The operation in question is undefined on void pointers");
3705 public override void Emit (EmitContext ec)
3707 Type op_type = left.Type;
3708 ILGenerator ig = ec.ig;
3710 // It must be either array or fixed buffer
3711 Type element = TypeManager.HasElementType (op_type) ?
3712 element = TypeManager.GetElementType (op_type) :
3713 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3715 int size = GetTypeSize (element);
3716 Type rtype = right.Type;
3718 if (rtype.IsPointer){
3720 // handle (pointer - pointer)
3724 ig.Emit (OpCodes.Sub);
3728 ig.Emit (OpCodes.Sizeof, element);
3730 IntLiteral.EmitInt (ig, size);
3731 ig.Emit (OpCodes.Div);
3733 ig.Emit (OpCodes.Conv_I8);
3736 // handle + and - on (pointer op int)
3739 ig.Emit (OpCodes.Conv_I);
3741 Constant right_const = right as Constant;
3742 if (right_const != null && size != 0) {
3743 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3751 ig.Emit (OpCodes.Sizeof, element);
3753 IntLiteral.EmitInt (ig, size);
3754 if (rtype == TypeManager.int64_type)
3755 ig.Emit (OpCodes.Conv_I8);
3756 else if (rtype == TypeManager.uint64_type)
3757 ig.Emit (OpCodes.Conv_U8);
3758 ig.Emit (OpCodes.Mul);
3762 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3763 ig.Emit (OpCodes.Conv_I);
3766 ig.Emit (OpCodes.Add);
3768 ig.Emit (OpCodes.Sub);
3774 /// Implements the ternary conditional operator (?:)
3776 public class Conditional : Expression {
3777 Expression expr, true_expr, false_expr;
3779 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3782 this.true_expr = true_expr;
3783 this.false_expr = false_expr;
3784 this.loc = expr.Location;
3787 public Expression Expr {
3793 public Expression TrueExpr {
3799 public Expression FalseExpr {
3805 public override Expression CreateExpressionTree (EmitContext ec)
3807 ArrayList args = new ArrayList (3);
3808 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3809 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3810 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3811 return CreateExpressionFactoryCall ("Condition", args);
3814 public override Expression DoResolve (EmitContext ec)
3816 expr = expr.Resolve (ec);
3821 if (expr.Type != TypeManager.bool_type){
3822 expr = Expression.ResolveBoolean (
3829 Assign ass = expr as Assign;
3830 if (ass != null && ass.Source is Constant) {
3831 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3834 true_expr = true_expr.Resolve (ec);
3835 false_expr = false_expr.Resolve (ec);
3837 if (true_expr == null || false_expr == null)
3840 eclass = ExprClass.Value;
3841 if (true_expr.Type == false_expr.Type) {
3842 type = true_expr.Type;
3843 if (type == TypeManager.null_type) {
3844 // TODO: probably will have to implement ConditionalConstant
3845 // to call method without return constant as well
3846 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3851 Type true_type = true_expr.Type;
3852 Type false_type = false_expr.Type;
3855 // First, if an implicit conversion exists from true_expr
3856 // to false_expr, then the result type is of type false_expr.Type
3858 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3861 // Check if both can convert implicitl to each other's type
3863 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3865 "Can not compute type of conditional expression " +
3866 "as `" + TypeManager.CSharpName (true_expr.Type) +
3867 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3868 "' convert implicitly to each other");
3873 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3877 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3878 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3883 // Dead code optimalization
3884 if (expr is BoolConstant){
3885 BoolConstant bc = (BoolConstant) expr;
3887 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3888 return bc.Value ? true_expr : false_expr;
3894 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3899 public override void Emit (EmitContext ec)
3901 ILGenerator ig = ec.ig;
3902 Label false_target = ig.DefineLabel ();
3903 Label end_target = ig.DefineLabel ();
3905 expr.EmitBranchable (ec, false_target, false);
3906 true_expr.Emit (ec);
3908 if (type.IsInterface) {
3909 LocalBuilder temp = ec.GetTemporaryLocal (type);
3910 ig.Emit (OpCodes.Stloc, temp);
3911 ig.Emit (OpCodes.Ldloc, temp);
3912 ec.FreeTemporaryLocal (temp, type);
3915 ig.Emit (OpCodes.Br, end_target);
3916 ig.MarkLabel (false_target);
3917 false_expr.Emit (ec);
3918 ig.MarkLabel (end_target);
3921 protected override void CloneTo (CloneContext clonectx, Expression t)
3923 Conditional target = (Conditional) t;
3925 target.expr = expr.Clone (clonectx);
3926 target.true_expr = true_expr.Clone (clonectx);
3927 target.false_expr = false_expr.Clone (clonectx);
3931 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3933 LocalTemporary temp;
3935 public abstract Variable Variable {
3939 public abstract bool IsRef {
3943 public override void Emit (EmitContext ec)
3948 public override void EmitSideEffect (EmitContext ec)
3954 // This method is used by parameters that are references, that are
3955 // being passed as references: we only want to pass the pointer (that
3956 // is already stored in the parameter, not the address of the pointer,
3957 // and not the value of the variable).
3959 public void EmitLoad (EmitContext ec)
3961 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3963 Variable.EmitInstance (ec);
3967 public void Emit (EmitContext ec, bool leave_copy)
3969 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3975 // If we are a reference, we loaded on the stack a pointer
3976 // Now lets load the real value
3978 LoadFromPtr (ec.ig, type);
3982 ec.ig.Emit (OpCodes.Dup);
3984 if (IsRef || Variable.NeedsTemporary) {
3985 temp = new LocalTemporary (Type);
3991 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3992 bool prepare_for_load)
3994 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3997 ILGenerator ig = ec.ig;
3998 prepared = prepare_for_load;
4000 Variable.EmitInstance (ec);
4001 if (prepare_for_load) {
4002 if (Variable.HasInstance)
4003 ig.Emit (OpCodes.Dup);
4011 // HACK: variable is already emitted when source is an initializer
4012 if (source is NewInitialize) {
4014 Variable.EmitInstance (ec);
4021 ig.Emit (OpCodes.Dup);
4022 if (IsRef || Variable.NeedsTemporary) {
4023 temp = new LocalTemporary (Type);
4029 StoreFromPtr (ig, type);
4031 Variable.EmitAssign (ec);
4039 public void AddressOf (EmitContext ec, AddressOp mode)
4041 Variable.EmitInstance (ec);
4042 Variable.EmitAddressOf (ec);
4049 public class LocalVariableReference : VariableReference, IVariable {
4050 public readonly string Name;
4052 public LocalInfo local_info;
4056 public LocalVariableReference (Block block, string name, Location l)
4061 eclass = ExprClass.Variable;
4065 // Setting `is_readonly' to false will allow you to create a writable
4066 // reference to a read-only variable. This is used by foreach and using.
4068 public LocalVariableReference (Block block, string name, Location l,
4069 LocalInfo local_info, bool is_readonly)
4070 : this (block, name, l)
4072 this.local_info = local_info;
4073 this.is_readonly = is_readonly;
4076 public VariableInfo VariableInfo {
4077 get { return local_info.VariableInfo; }
4080 public override bool IsRef {
4081 get { return false; }
4084 public bool IsReadOnly {
4085 get { return is_readonly; }
4088 public bool VerifyAssigned (EmitContext ec)
4090 VariableInfo variable_info = local_info.VariableInfo;
4091 return variable_info == null || variable_info.IsAssigned (ec, loc);
4094 void ResolveLocalInfo ()
4096 if (local_info == null) {
4097 local_info = Block.GetLocalInfo (Name);
4098 type = local_info.VariableType;
4099 is_readonly = local_info.ReadOnly;
4103 public override Expression CreateExpressionTree (EmitContext ec)
4105 ArrayList arg = new ArrayList (1);
4106 arg.Add (new Argument (this));
4107 return CreateExpressionFactoryCall ("Constant", arg);
4110 protected Expression DoResolveBase (EmitContext ec)
4112 type = local_info.VariableType;
4114 Expression e = Block.GetConstantExpression (Name);
4116 return e.Resolve (ec);
4118 if (!VerifyAssigned (ec))
4122 // If we are referencing a variable from the external block
4123 // flag it for capturing
4125 if (ec.MustCaptureVariable (local_info)) {
4126 if (local_info.AddressTaken){
4127 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
4131 if (!ec.IsInProbingMode)
4133 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
4134 variable = scope.AddLocal (local_info);
4135 type = variable.Type;
4142 public override Expression DoResolve (EmitContext ec)
4144 ResolveLocalInfo ();
4145 local_info.Used = true;
4147 if (type == null && local_info.Type is VarExpr) {
4148 local_info.VariableType = TypeManager.object_type;
4149 Error_VariableIsUsedBeforeItIsDeclared (Name);
4153 return DoResolveBase (ec);
4156 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4158 ResolveLocalInfo ();
4161 if (right_side == EmptyExpression.OutAccess)
4162 local_info.Used = true;
4164 // Infer implicitly typed local variable
4166 VarExpr ve = local_info.Type as VarExpr;
4168 if (!ve.InferType (ec, right_side))
4170 type = local_info.VariableType = ve.Type;
4177 if (right_side == EmptyExpression.OutAccess) {
4178 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4179 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4180 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4181 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4182 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4184 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4186 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4190 if (VariableInfo != null)
4191 VariableInfo.SetAssigned (ec);
4193 return DoResolveBase (ec);
4196 public bool VerifyFixed ()
4198 // A local Variable is always fixed.
4202 public override int GetHashCode ()
4204 return Name.GetHashCode ();
4207 public override bool Equals (object obj)
4209 LocalVariableReference lvr = obj as LocalVariableReference;
4213 return Name == lvr.Name && Block == lvr.Block;
4216 public override Variable Variable {
4217 get { return variable != null ? variable : local_info.Variable; }
4220 public override string ToString ()
4222 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4225 protected override void CloneTo (CloneContext clonectx, Expression t)
4227 LocalVariableReference target = (LocalVariableReference) t;
4229 target.Block = clonectx.LookupBlock (Block);
4230 if (local_info != null)
4231 target.local_info = clonectx.LookupVariable (local_info);
4236 /// This represents a reference to a parameter in the intermediate
4239 public class ParameterReference : VariableReference, IVariable {
4240 readonly ToplevelParameterInfo pi;
4241 readonly ToplevelBlock referenced;
4244 public bool is_ref, is_out;
4247 get { return is_out; }
4250 public override bool IsRef {
4251 get { return is_ref; }
4254 public string Name {
4255 get { return Parameter.Name; }
4258 public Parameter Parameter {
4259 get { return pi.Parameter; }
4262 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4265 this.referenced = referenced;
4267 eclass = ExprClass.Variable;
4270 public VariableInfo VariableInfo {
4271 get { return pi.VariableInfo; }
4274 public override Variable Variable {
4275 get { return variable != null ? variable : Parameter.Variable; }
4278 public bool VerifyFixed ()
4280 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4281 return Parameter.ModFlags == Parameter.Modifier.NONE;
4284 public bool IsAssigned (EmitContext ec, Location loc)
4286 // HACK: Variables are not captured in probing mode
4287 if (ec.IsInProbingMode)
4290 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
4293 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4297 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4299 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
4302 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
4306 public void SetAssigned (EmitContext ec)
4308 if (is_out && ec.DoFlowAnalysis)
4309 ec.CurrentBranching.SetAssigned (VariableInfo);
4312 public void SetFieldAssigned (EmitContext ec, string field_name)
4314 if (is_out && ec.DoFlowAnalysis)
4315 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
4318 protected bool DoResolveBase (EmitContext ec)
4320 Parameter par = Parameter;
4321 if (!par.Resolve (ec)) {
4325 type = par.ParameterType;
4326 Parameter.Modifier mod = par.ModFlags;
4327 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4328 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
4329 eclass = ExprClass.Variable;
4331 AnonymousContainer am = ec.CurrentAnonymousMethod;
4335 ToplevelBlock declared = pi.Block;
4336 if (is_ref && declared != referenced) {
4337 Report.Error (1628, Location,
4338 "Cannot use ref or out parameter `{0}' inside an " +
4339 "anonymous method block", par.Name);
4343 if (!am.IsIterator && declared == referenced)
4346 // Don't capture aruments when the probing is on
4347 if (!ec.IsInProbingMode) {
4348 ScopeInfo scope = declared.CreateScopeInfo ();
4349 variable = scope.AddParameter (par, pi.Index);
4350 type = variable.Type;
4355 public override int GetHashCode ()
4357 return Name.GetHashCode ();
4360 public override bool Equals (object obj)
4362 ParameterReference pr = obj as ParameterReference;
4366 return Name == pr.Name && referenced == pr.referenced;
4369 public override Expression CreateExpressionTree (EmitContext ec)
4371 return Parameter.ExpressionTreeVariableReference ();
4375 // Notice that for ref/out parameters, the type exposed is not the
4376 // same type exposed externally.
4379 // externally we expose "int&"
4380 // here we expose "int".
4382 // We record this in "is_ref". This means that the type system can treat
4383 // the type as it is expected, but when we generate the code, we generate
4384 // the alternate kind of code.
4386 public override Expression DoResolve (EmitContext ec)
4388 if (!DoResolveBase (ec))
4391 if (is_out && ec.DoFlowAnalysis &&
4392 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4398 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4400 if (!DoResolveBase (ec))
4403 // HACK: parameters are not captured when probing is on
4404 if (!ec.IsInProbingMode)
4410 static public void EmitLdArg (ILGenerator ig, int x)
4414 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4415 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4416 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4417 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4418 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4421 ig.Emit (OpCodes.Ldarg, x);
4424 public override string ToString ()
4426 return "ParameterReference[" + Name + "]";
4431 /// Used for arguments to New(), Invocation()
4433 public class Argument {
4434 public enum AType : byte {
4441 public static readonly Argument[] Empty = new Argument [0];
4443 public readonly AType ArgType;
4444 public Expression Expr;
4446 public Argument (Expression expr, AType type)
4449 this.ArgType = type;
4452 public Argument (Expression expr)
4455 this.ArgType = AType.Expression;
4460 if (ArgType == AType.Ref || ArgType == AType.Out)
4461 return TypeManager.GetReferenceType (Expr.Type);
4467 public Parameter.Modifier Modifier
4472 return Parameter.Modifier.OUT;
4475 return Parameter.Modifier.REF;
4478 return Parameter.Modifier.NONE;
4483 public string GetSignatureForError ()
4485 if (Expr.eclass == ExprClass.MethodGroup)
4486 return Expr.ExprClassName;
4488 return Expr.GetSignatureForError ();
4491 public bool ResolveMethodGroup (EmitContext ec)
4493 SimpleName sn = Expr as SimpleName;
4495 Expr = sn.GetMethodGroup ();
4497 // FIXME: csc doesn't report any error if you try to use `ref' or
4498 // `out' in a delegate creation expression.
4499 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4506 public bool Resolve (EmitContext ec, Location loc)
4511 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4512 // Verify that the argument is readable
4513 if (ArgType != AType.Out)
4514 Expr = Expr.Resolve (ec);
4516 // Verify that the argument is writeable
4517 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4518 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4520 return Expr != null;
4524 public void Emit (EmitContext ec)
4526 if (ArgType != AType.Ref && ArgType != AType.Out) {
4531 AddressOp mode = AddressOp.Store;
4532 if (ArgType == AType.Ref)
4533 mode |= AddressOp.Load;
4535 IMemoryLocation ml = (IMemoryLocation) Expr;
4536 ParameterReference pr = ml as ParameterReference;
4539 // ParameterReferences might already be references, so we want
4540 // to pass just the value
4542 if (pr != null && pr.IsRef)
4545 ml.AddressOf (ec, mode);
4548 public Argument Clone (CloneContext clonectx)
4550 return new Argument (Expr.Clone (clonectx), ArgType);
4555 /// Invocation of methods or delegates.
4557 public class Invocation : ExpressionStatement {
4558 protected ArrayList Arguments;
4559 protected Expression expr;
4560 protected MethodGroupExpr mg;
4561 bool arguments_resolved;
4564 // arguments is an ArrayList, but we do not want to typecast,
4565 // as it might be null.
4567 public Invocation (Expression expr, ArrayList arguments)
4569 SimpleName sn = expr as SimpleName;
4571 this.expr = sn.GetMethodGroup ();
4575 Arguments = arguments;
4577 loc = expr.Location;
4580 public Invocation (Expression expr, ArrayList arguments, bool arguments_resolved)
4581 : this (expr, arguments)
4583 this.arguments_resolved = arguments_resolved;
4586 public override Expression CreateExpressionTree (EmitContext ec)
4591 // Special conversion for nested expression trees
4593 if (TypeManager.DropGenericTypeArguments (type) == TypeManager.expression_type) {
4594 args = new ArrayList (1);
4595 args.Add (new Argument (this));
4596 return CreateExpressionFactoryCall ("Quote", args);
4599 args = new ArrayList (Arguments == null ? 2 : Arguments.Count + 2);
4601 args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
4603 args.Add (new Argument (new NullLiteral (loc)));
4605 args.Add (new Argument (mg.CreateExpressionTree (ec)));
4606 if (Arguments != null) {
4607 foreach (Argument a in Arguments) {
4608 Expression e = a.Expr.CreateExpressionTree (ec);
4610 args.Add (new Argument (e));
4615 MemberExpr.Error_BaseAccessInExpressionTree (loc);
4617 return CreateExpressionFactoryCall ("Call", args);
4620 public override Expression DoResolve (EmitContext ec)
4622 // Don't resolve already resolved expression
4623 if (eclass != ExprClass.Invalid)
4626 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4627 if (expr_resolved == null)
4630 mg = expr_resolved as MethodGroupExpr;
4632 Type expr_type = expr_resolved.Type;
4634 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4635 return (new DelegateInvocation (
4636 expr_resolved, Arguments, loc)).Resolve (ec);
4639 MemberExpr me = expr_resolved as MemberExpr;
4641 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4645 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4647 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4648 expr_resolved.GetSignatureForError ());
4652 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4656 // Next, evaluate all the expressions in the argument list
4658 if (Arguments != null && !arguments_resolved) {
4659 for (int i = 0; i < Arguments.Count; ++i)
4661 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4666 mg = DoResolveOverload (ec);
4670 MethodInfo method = (MethodInfo)mg;
4671 if (method != null) {
4672 type = TypeManager.TypeToCoreType (method.ReturnType);
4674 // TODO: this is a copy of mg.ResolveMemberAccess method
4675 Expression iexpr = mg.InstanceExpression;
4676 if (method.IsStatic) {
4677 if (iexpr == null ||
4678 iexpr is This || iexpr is EmptyExpression ||
4679 mg.IdenticalTypeName) {
4680 mg.InstanceExpression = null;
4682 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4688 if (type.IsPointer){
4696 // Only base will allow this invocation to happen.
4698 if (mg.IsBase && method.IsAbstract){
4699 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4703 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4705 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4707 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4711 if (IsSpecialMethodInvocation (method)) {
4715 if (mg.InstanceExpression != null)
4716 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4718 eclass = ExprClass.Value;
4722 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4724 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4727 bool IsSpecialMethodInvocation (MethodBase method)
4729 if (!TypeManager.IsSpecialMethod (method))
4732 Report.SymbolRelatedToPreviousError (method);
4733 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4734 TypeManager.CSharpSignature (method, true));
4740 /// Emits a list of resolved Arguments that are in the arguments
4743 /// The MethodBase argument might be null if the
4744 /// emission of the arguments is known not to contain
4745 /// a `params' field (for example in constructors or other routines
4746 /// that keep their arguments in this structure)
4748 /// if `dup_args' is true, a copy of the arguments will be left
4749 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4750 /// which will be duplicated before any other args. Only EmitCall
4751 /// should be using this interface.
4753 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4755 if (arguments == null)
4758 int top = arguments.Count;
4759 LocalTemporary [] temps = null;
4761 if (dup_args && top != 0)
4762 temps = new LocalTemporary [top];
4764 int argument_index = 0;
4766 for (int i = 0; i < top; i++) {
4767 a = (Argument) arguments [argument_index++];
4770 ec.ig.Emit (OpCodes.Dup);
4771 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4776 if (this_arg != null)
4779 for (int i = 0; i < top; i ++) {
4780 temps [i].Emit (ec);
4781 temps [i].Release (ec);
4786 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4788 ParameterData pd = TypeManager.GetParameterData (mb);
4790 if (arguments == null)
4791 return new Type [0];
4793 Argument a = (Argument) arguments [pd.Count - 1];
4794 Arglist list = (Arglist) a.Expr;
4796 return list.ArgumentTypes;
4800 /// This checks the ConditionalAttribute on the method
4802 public static bool IsMethodExcluded (MethodBase method)
4804 if (method.IsConstructor)
4807 method = TypeManager.DropGenericMethodArguments (method);
4808 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4809 IMethodData md = TypeManager.GetMethod (method);
4811 return md.IsExcluded ();
4813 // For some methods (generated by delegate class) GetMethod returns null
4814 // because they are not included in builder_to_method table
4818 return AttributeTester.IsConditionalMethodExcluded (method);
4822 /// is_base tells whether we want to force the use of the `call'
4823 /// opcode instead of using callvirt. Call is required to call
4824 /// a specific method, while callvirt will always use the most
4825 /// recent method in the vtable.
4827 /// is_static tells whether this is an invocation on a static method
4829 /// instance_expr is an expression that represents the instance
4830 /// it must be non-null if is_static is false.
4832 /// method is the method to invoke.
4834 /// Arguments is the list of arguments to pass to the method or constructor.
4836 public static void EmitCall (EmitContext ec, bool is_base,
4837 Expression instance_expr,
4838 MethodBase method, ArrayList Arguments, Location loc)
4840 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4843 // `dup_args' leaves an extra copy of the arguments on the stack
4844 // `omit_args' does not leave any arguments at all.
4845 // So, basically, you could make one call with `dup_args' set to true,
4846 // and then another with `omit_args' set to true, and the two calls
4847 // would have the same set of arguments. However, each argument would
4848 // only have been evaluated once.
4849 public static void EmitCall (EmitContext ec, bool is_base,
4850 Expression instance_expr,
4851 MethodBase method, ArrayList Arguments, Location loc,
4852 bool dup_args, bool omit_args)
4854 ILGenerator ig = ec.ig;
4855 bool struct_call = false;
4856 bool this_call = false;
4857 LocalTemporary this_arg = null;
4859 Type decl_type = method.DeclaringType;
4861 if (!ec.IsInObsoleteScope) {
4863 // This checks ObsoleteAttribute on the method and on the declaring type
4865 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4867 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4869 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4871 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4875 if (IsMethodExcluded (method))
4878 bool is_static = method.IsStatic;
4880 if (instance_expr == EmptyExpression.Null) {
4881 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4885 this_call = instance_expr is This;
4886 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4890 // If this is ourselves, push "this"
4894 Type iexpr_type = instance_expr.Type;
4897 // Push the instance expression
4899 if (TypeManager.IsValueType (iexpr_type)) {
4901 // Special case: calls to a function declared in a
4902 // reference-type with a value-type argument need
4903 // to have their value boxed.
4904 if (decl_type.IsValueType ||
4905 TypeManager.IsGenericParameter (iexpr_type)) {
4907 // If the expression implements IMemoryLocation, then
4908 // we can optimize and use AddressOf on the
4911 // If not we have to use some temporary storage for
4913 if (instance_expr is IMemoryLocation) {
4914 ((IMemoryLocation)instance_expr).
4915 AddressOf (ec, AddressOp.LoadStore);
4917 LocalTemporary temp = new LocalTemporary (iexpr_type);
4918 instance_expr.Emit (ec);
4920 temp.AddressOf (ec, AddressOp.Load);
4923 // avoid the overhead of doing this all the time.
4925 t = TypeManager.GetReferenceType (iexpr_type);
4927 instance_expr.Emit (ec);
4928 ig.Emit (OpCodes.Box, instance_expr.Type);
4929 t = TypeManager.object_type;
4932 instance_expr.Emit (ec);
4933 t = instance_expr.Type;
4937 ig.Emit (OpCodes.Dup);
4938 if (Arguments != null && Arguments.Count != 0) {
4939 this_arg = new LocalTemporary (t);
4940 this_arg.Store (ec);
4947 EmitArguments (ec, Arguments, dup_args, this_arg);
4950 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4951 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4955 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4956 call_op = OpCodes.Call;
4958 call_op = OpCodes.Callvirt;
4960 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4961 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4962 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4969 // and DoFoo is not virtual, you can omit the callvirt,
4970 // because you don't need the null checking behavior.
4972 if (method is MethodInfo)
4973 ig.Emit (call_op, (MethodInfo) method);
4975 ig.Emit (call_op, (ConstructorInfo) method);
4978 public override void Emit (EmitContext ec)
4980 mg.EmitCall (ec, Arguments);
4983 public override void EmitStatement (EmitContext ec)
4988 // Pop the return value if there is one
4990 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4991 ec.ig.Emit (OpCodes.Pop);
4994 protected override void CloneTo (CloneContext clonectx, Expression t)
4996 Invocation target = (Invocation) t;
4998 if (Arguments != null) {
4999 target.Arguments = new ArrayList (Arguments.Count);
5000 foreach (Argument a in Arguments)
5001 target.Arguments.Add (a.Clone (clonectx));
5004 target.expr = expr.Clone (clonectx);
5008 public class InvocationOrCast : ExpressionStatement
5011 Expression argument;
5013 public InvocationOrCast (Expression expr, Expression argument)
5016 this.argument = argument;
5017 this.loc = expr.Location;
5020 public override Expression CreateExpressionTree (EmitContext ec)
5022 throw new NotSupportedException ("ET");
5025 public override Expression DoResolve (EmitContext ec)
5028 // First try to resolve it as a cast.
5030 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5031 if ((te != null) && (te.eclass == ExprClass.Type)) {
5032 Cast cast = new Cast (te, argument, loc);
5033 return cast.Resolve (ec);
5037 // This can either be a type or a delegate invocation.
5038 // Let's just resolve it and see what we'll get.
5040 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5045 // Ok, so it's a Cast.
5047 if (expr.eclass == ExprClass.Type) {
5048 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5049 return cast.Resolve (ec);
5053 // It's a delegate invocation.
5055 if (!TypeManager.IsDelegateType (expr.Type)) {
5056 Error (149, "Method name expected");
5060 ArrayList args = new ArrayList ();
5061 args.Add (new Argument (argument, Argument.AType.Expression));
5062 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5063 return invocation.Resolve (ec);
5066 public override ExpressionStatement ResolveStatement (EmitContext ec)
5069 // First try to resolve it as a cast.
5071 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5072 if ((te != null) && (te.eclass == ExprClass.Type)) {
5073 Error_InvalidExpressionStatement ();
5078 // This can either be a type or a delegate invocation.
5079 // Let's just resolve it and see what we'll get.
5081 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5082 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5083 Error_InvalidExpressionStatement ();
5088 // It's a delegate invocation.
5090 if (!TypeManager.IsDelegateType (expr.Type)) {
5091 Error (149, "Method name expected");
5095 ArrayList args = new ArrayList ();
5096 args.Add (new Argument (argument, Argument.AType.Expression));
5097 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5098 return invocation.ResolveStatement (ec);
5101 public override void Emit (EmitContext ec)
5103 throw new Exception ("Cannot happen");
5106 public override void EmitStatement (EmitContext ec)
5108 throw new Exception ("Cannot happen");
5111 protected override void CloneTo (CloneContext clonectx, Expression t)
5113 InvocationOrCast target = (InvocationOrCast) t;
5115 target.expr = expr.Clone (clonectx);
5116 target.argument = argument.Clone (clonectx);
5121 // This class is used to "disable" the code generation for the
5122 // temporary variable when initializing value types.
5124 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5125 public void AddressOf (EmitContext ec, AddressOp Mode)
5132 /// Implements the new expression
5134 public class New : ExpressionStatement, IMemoryLocation {
5135 ArrayList Arguments;
5138 // During bootstrap, it contains the RequestedType,
5139 // but if `type' is not null, it *might* contain a NewDelegate
5140 // (because of field multi-initialization)
5142 public Expression RequestedType;
5144 MethodGroupExpr method;
5147 // If set, the new expression is for a value_target, and
5148 // we will not leave anything on the stack.
5150 protected Expression value_target;
5151 protected bool value_target_set;
5152 bool is_type_parameter = false;
5154 public New (Expression requested_type, ArrayList arguments, Location l)
5156 RequestedType = requested_type;
5157 Arguments = arguments;
5161 public bool SetTargetVariable (Expression value)
5163 value_target = value;
5164 value_target_set = true;
5165 if (!(value_target is IMemoryLocation)){
5166 Error_UnexpectedKind (null, "variable", loc);
5173 // This function is used to disable the following code sequence for
5174 // value type initialization:
5176 // AddressOf (temporary)
5180 // Instead the provide will have provided us with the address on the
5181 // stack to store the results.
5183 static Expression MyEmptyExpression;
5185 public void DisableTemporaryValueType ()
5187 if (MyEmptyExpression == null)
5188 MyEmptyExpression = new EmptyAddressOf ();
5191 // To enable this, look into:
5192 // test-34 and test-89 and self bootstrapping.
5194 // For instance, we can avoid a copy by using `newobj'
5195 // instead of Call + Push-temp on value types.
5196 // value_target = MyEmptyExpression;
5201 /// Converts complex core type syntax like 'new int ()' to simple constant
5203 public static Constant Constantify (Type t)
5205 if (t == TypeManager.int32_type)
5206 return new IntConstant (0, Location.Null);
5207 if (t == TypeManager.uint32_type)
5208 return new UIntConstant (0, Location.Null);
5209 if (t == TypeManager.int64_type)
5210 return new LongConstant (0, Location.Null);
5211 if (t == TypeManager.uint64_type)
5212 return new ULongConstant (0, Location.Null);
5213 if (t == TypeManager.float_type)
5214 return new FloatConstant (0, Location.Null);
5215 if (t == TypeManager.double_type)
5216 return new DoubleConstant (0, Location.Null);
5217 if (t == TypeManager.short_type)
5218 return new ShortConstant (0, Location.Null);
5219 if (t == TypeManager.ushort_type)
5220 return new UShortConstant (0, Location.Null);
5221 if (t == TypeManager.sbyte_type)
5222 return new SByteConstant (0, Location.Null);
5223 if (t == TypeManager.byte_type)
5224 return new ByteConstant (0, Location.Null);
5225 if (t == TypeManager.char_type)
5226 return new CharConstant ('\0', Location.Null);
5227 if (t == TypeManager.bool_type)
5228 return new BoolConstant (false, Location.Null);
5229 if (t == TypeManager.decimal_type)
5230 return new DecimalConstant (0, Location.Null);
5231 if (TypeManager.IsEnumType (t))
5232 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5238 // Checks whether the type is an interface that has the
5239 // [ComImport, CoClass] attributes and must be treated
5242 public Expression CheckComImport (EmitContext ec)
5244 if (!type.IsInterface)
5248 // Turn the call into:
5249 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5251 Type real_class = AttributeTester.GetCoClassAttribute (type);
5252 if (real_class == null)
5255 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5256 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5257 return cast.Resolve (ec);
5260 public override Expression CreateExpressionTree (EmitContext ec)
5262 ArrayList args = Arguments == null ?
5263 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5265 if (method == null) {
5266 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5268 args.Add (new Argument (method.CreateExpressionTree (ec)));
5269 if (Arguments != null) {
5271 foreach (Argument a in Arguments) {
5272 expr = a.Expr.CreateExpressionTree (ec);
5274 args.Add (new Argument (expr));
5279 return CreateExpressionFactoryCall ("New", args);
5282 public override Expression DoResolve (EmitContext ec)
5285 // The New DoResolve might be called twice when initializing field
5286 // expressions (see EmitFieldInitializers, the call to
5287 // GetInitializerExpression will perform a resolve on the expression,
5288 // and later the assign will trigger another resolution
5290 // This leads to bugs (#37014)
5293 if (RequestedType is NewDelegate)
5294 return RequestedType;
5298 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5304 if (type == TypeManager.void_type) {
5305 Error_VoidInvalidInTheContext (loc);
5309 if (type.IsPointer) {
5310 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5311 TypeManager.CSharpName (type));
5315 if (Arguments == null) {
5316 Expression c = Constantify (type);
5321 if (TypeManager.IsDelegateType (type)) {
5322 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5323 if (RequestedType != null)
5324 if (!(RequestedType is DelegateCreation))
5325 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5326 return RequestedType;
5330 if (type.IsGenericParameter) {
5331 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5333 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5334 Error (304, String.Format (
5335 "Cannot create an instance of the " +
5336 "variable type '{0}' because it " +
5337 "doesn't have the new() constraint",
5342 if ((Arguments != null) && (Arguments.Count != 0)) {
5343 Error (417, String.Format (
5344 "`{0}': cannot provide arguments " +
5345 "when creating an instance of a " +
5346 "variable type.", type));
5350 if (TypeManager.activator_create_instance == null) {
5351 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5352 if (activator_type != null) {
5353 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5354 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5358 is_type_parameter = true;
5359 eclass = ExprClass.Value;
5364 if (type.IsAbstract && type.IsSealed) {
5365 Report.SymbolRelatedToPreviousError (type);
5366 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5370 if (type.IsInterface || type.IsAbstract){
5371 if (!TypeManager.IsGenericType (type)) {
5372 RequestedType = CheckComImport (ec);
5373 if (RequestedType != null)
5374 return RequestedType;
5377 Report.SymbolRelatedToPreviousError (type);
5378 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5382 bool is_struct = type.IsValueType;
5383 eclass = ExprClass.Value;
5386 // SRE returns a match for .ctor () on structs (the object constructor),
5387 // so we have to manually ignore it.
5389 if (is_struct && Arguments == null)
5392 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5393 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5394 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5396 if (Arguments != null){
5397 foreach (Argument a in Arguments){
5398 if (!a.Resolve (ec, loc))
5406 method = ml as MethodGroupExpr;
5407 if (method == null) {
5408 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5412 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5419 bool DoEmitTypeParameter (EmitContext ec)
5422 ILGenerator ig = ec.ig;
5423 // IMemoryLocation ml;
5425 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5426 new Type [] { type });
5428 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5429 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5430 ig.Emit (OpCodes.Call, ci);
5434 // Allow DoEmit() to be called multiple times.
5435 // We need to create a new LocalTemporary each time since
5436 // you can't share LocalBuilders among ILGeneators.
5437 LocalTemporary temp = new LocalTemporary (type);
5439 Label label_activator = ig.DefineLabel ();
5440 Label label_end = ig.DefineLabel ();
5442 temp.AddressOf (ec, AddressOp.Store);
5443 ig.Emit (OpCodes.Initobj, type);
5446 ig.Emit (OpCodes.Box, type);
5447 ig.Emit (OpCodes.Brfalse, label_activator);
5449 temp.AddressOf (ec, AddressOp.Store);
5450 ig.Emit (OpCodes.Initobj, type);
5452 ig.Emit (OpCodes.Br, label_end);
5454 ig.MarkLabel (label_activator);
5456 ig.Emit (OpCodes.Call, ci);
5457 ig.MarkLabel (label_end);
5460 throw new InternalErrorException ();
5465 // This DoEmit can be invoked in two contexts:
5466 // * As a mechanism that will leave a value on the stack (new object)
5467 // * As one that wont (init struct)
5469 // You can control whether a value is required on the stack by passing
5470 // need_value_on_stack. The code *might* leave a value on the stack
5471 // so it must be popped manually
5473 // If we are dealing with a ValueType, we have a few
5474 // situations to deal with:
5476 // * The target is a ValueType, and we have been provided
5477 // the instance (this is easy, we are being assigned).
5479 // * The target of New is being passed as an argument,
5480 // to a boxing operation or a function that takes a
5483 // In this case, we need to create a temporary variable
5484 // that is the argument of New.
5486 // Returns whether a value is left on the stack
5488 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5490 bool is_value_type = TypeManager.IsValueType (type);
5491 ILGenerator ig = ec.ig;
5496 // Allow DoEmit() to be called multiple times.
5497 // We need to create a new LocalTemporary each time since
5498 // you can't share LocalBuilders among ILGeneators.
5499 if (!value_target_set)
5500 value_target = new LocalTemporary (type);
5502 ml = (IMemoryLocation) value_target;
5503 ml.AddressOf (ec, AddressOp.Store);
5507 method.EmitArguments (ec, Arguments);
5511 ig.Emit (OpCodes.Initobj, type);
5513 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5514 if (need_value_on_stack){
5515 value_target.Emit (ec);
5520 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5525 public override void Emit (EmitContext ec)
5527 if (is_type_parameter)
5528 DoEmitTypeParameter (ec);
5533 public override void EmitStatement (EmitContext ec)
5535 bool value_on_stack;
5537 if (is_type_parameter)
5538 value_on_stack = DoEmitTypeParameter (ec);
5540 value_on_stack = DoEmit (ec, false);
5543 ec.ig.Emit (OpCodes.Pop);
5547 public virtual bool HasInitializer {
5553 public void AddressOf (EmitContext ec, AddressOp Mode)
5555 if (is_type_parameter) {
5556 LocalTemporary temp = new LocalTemporary (type);
5557 DoEmitTypeParameter (ec);
5559 temp.AddressOf (ec, Mode);
5563 if (!type.IsValueType){
5565 // We throw an exception. So far, I believe we only need to support
5567 // foreach (int j in new StructType ())
5570 throw new Exception ("AddressOf should not be used for classes");
5573 if (!value_target_set)
5574 value_target = new LocalTemporary (type);
5575 IMemoryLocation ml = (IMemoryLocation) value_target;
5577 ml.AddressOf (ec, AddressOp.Store);
5578 if (method == null) {
5579 ec.ig.Emit (OpCodes.Initobj, type);
5581 method.EmitArguments (ec, Arguments);
5582 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5585 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5588 protected override void CloneTo (CloneContext clonectx, Expression t)
5590 New target = (New) t;
5592 target.RequestedType = RequestedType.Clone (clonectx);
5593 if (Arguments != null){
5594 target.Arguments = new ArrayList ();
5595 foreach (Argument a in Arguments){
5596 target.Arguments.Add (a.Clone (clonectx));
5603 /// 14.5.10.2: Represents an array creation expression.
5607 /// There are two possible scenarios here: one is an array creation
5608 /// expression that specifies the dimensions and optionally the
5609 /// initialization data and the other which does not need dimensions
5610 /// specified but where initialization data is mandatory.
5612 public class ArrayCreation : Expression {
5613 FullNamedExpression requested_base_type;
5614 ArrayList initializers;
5617 // The list of Argument types.
5618 // This is used to construct the `newarray' or constructor signature
5620 protected ArrayList arguments;
5622 protected Type array_element_type;
5623 bool expect_initializers = false;
5624 int num_arguments = 0;
5625 protected int dimensions;
5626 protected readonly string rank;
5628 protected ArrayList array_data;
5632 // The number of constants in array initializers
5633 int const_initializers_count;
5634 bool only_constant_initializers;
5636 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5638 this.requested_base_type = requested_base_type;
5639 this.initializers = initializers;
5643 arguments = new ArrayList ();
5645 foreach (Expression e in exprs) {
5646 arguments.Add (new Argument (e, Argument.AType.Expression));
5651 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5653 this.requested_base_type = requested_base_type;
5654 this.initializers = initializers;
5658 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5660 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5662 //dimensions = tmp.Length - 1;
5663 expect_initializers = true;
5666 void Error_IncorrectArrayInitializer ()
5668 Error (178, "Invalid rank specifier: expected `,' or `]'");
5671 protected override void Error_NegativeArrayIndex (Location loc)
5673 Report.Error (248, loc, "Cannot create an array with a negative size");
5676 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5678 if (specified_dims) {
5679 Argument a = (Argument) arguments [idx];
5681 if (!a.Resolve (ec, loc))
5684 Constant c = a.Expr as Constant;
5686 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5690 Report.Error (150, a.Expr.Location, "A constant value is expected");
5694 int value = (int) c.GetValue ();
5696 if (value != probe.Count) {
5697 Error_IncorrectArrayInitializer ();
5701 bounds [idx] = value;
5704 int child_bounds = -1;
5705 only_constant_initializers = true;
5706 for (int i = 0; i < probe.Count; ++i) {
5707 object o = probe [i];
5708 if (o is ArrayList) {
5709 ArrayList sub_probe = o as ArrayList;
5710 int current_bounds = sub_probe.Count;
5712 if (child_bounds == -1)
5713 child_bounds = current_bounds;
5715 else if (child_bounds != current_bounds){
5716 Error_IncorrectArrayInitializer ();
5719 if (idx + 1 >= dimensions){
5720 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5724 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5728 if (child_bounds != -1){
5729 Error_IncorrectArrayInitializer ();
5733 Expression element = ResolveArrayElement (ec, (Expression) o);
5734 if (element == null)
5737 // Initializers with the default values can be ignored
5738 Constant c = element as Constant;
5740 if (c.IsDefaultInitializer (array_element_type)) {
5744 ++const_initializers_count;
5747 only_constant_initializers = false;
5750 array_data.Add (element);
5757 public override Expression CreateExpressionTree (EmitContext ec)
5761 if (array_data == null) {
5762 args = new ArrayList (arguments.Count + 1);
5763 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5764 foreach (Argument a in arguments) {
5765 if (arguments.Count == 1) {
5766 Constant c = a.Expr as Constant;
5767 if (c.IsDefaultValue)
5768 return CreateExpressionFactoryCall ("NewArrayInit", args);
5770 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5773 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5776 if (dimensions > 1) {
5777 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5781 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5782 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5783 if (array_data != null) {
5784 foreach (Expression e in array_data)
5785 args.Add (new Argument (e.CreateExpressionTree (ec)));
5788 return CreateExpressionFactoryCall ("NewArrayInit", args);
5791 public void UpdateIndices ()
5794 for (ArrayList probe = initializers; probe != null;) {
5795 if (probe.Count > 0 && probe [0] is ArrayList) {
5796 Expression e = new IntConstant (probe.Count, Location.Null);
5797 arguments.Add (new Argument (e, Argument.AType.Expression));
5799 bounds [i++] = probe.Count;
5801 probe = (ArrayList) probe [0];
5804 Expression e = new IntConstant (probe.Count, Location.Null);
5805 arguments.Add (new Argument (e, Argument.AType.Expression));
5807 bounds [i++] = probe.Count;
5814 Expression first_emit;
5815 LocalTemporary first_emit_temp;
5817 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5819 element = element.Resolve (ec);
5820 if (element == null)
5823 if (element is CompoundAssign.Helper) {
5824 if (first_emit != null)
5825 throw new InternalErrorException ("Can only handle one mutator at a time");
5826 first_emit = element;
5827 element = first_emit_temp = new LocalTemporary (element.Type);
5830 return Convert.ImplicitConversionRequired (
5831 ec, element, array_element_type, loc);
5834 protected bool ResolveInitializers (EmitContext ec)
5836 if (initializers == null) {
5837 return !expect_initializers;
5841 // We use this to store all the date values in the order in which we
5842 // will need to store them in the byte blob later
5844 array_data = new ArrayList ();
5845 bounds = new System.Collections.Specialized.HybridDictionary ();
5847 if (arguments != null)
5848 return CheckIndices (ec, initializers, 0, true);
5850 arguments = new ArrayList ();
5852 if (!CheckIndices (ec, initializers, 0, false))
5861 // Resolved the type of the array
5863 bool ResolveArrayType (EmitContext ec)
5865 if (requested_base_type == null) {
5866 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5870 StringBuilder array_qualifier = new StringBuilder (rank);
5873 // `In the first form allocates an array instace of the type that results
5874 // from deleting each of the individual expression from the expression list'
5876 if (num_arguments > 0) {
5877 array_qualifier.Append ("[");
5878 for (int i = num_arguments-1; i > 0; i--)
5879 array_qualifier.Append (",");
5880 array_qualifier.Append ("]");
5886 TypeExpr array_type_expr;
5887 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5888 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5889 if (array_type_expr == null)
5892 type = array_type_expr.Type;
5893 array_element_type = TypeManager.GetElementType (type);
5894 dimensions = type.GetArrayRank ();
5899 public override Expression DoResolve (EmitContext ec)
5904 if (!ResolveArrayType (ec))
5907 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5908 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5909 TypeManager.CSharpName (array_element_type));
5913 // First step is to validate the initializers and fill
5914 // in any missing bits
5916 if (!ResolveInitializers (ec))
5919 if (arguments.Count != dimensions) {
5920 Error_IncorrectArrayInitializer ();
5923 foreach (Argument a in arguments){
5924 if (!a.Resolve (ec, loc))
5927 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5930 eclass = ExprClass.Value;
5934 MethodInfo GetArrayMethod (int arguments)
5936 ModuleBuilder mb = CodeGen.Module.Builder;
5938 Type[] arg_types = new Type[arguments];
5939 for (int i = 0; i < arguments; i++)
5940 arg_types[i] = TypeManager.int32_type;
5942 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5946 Report.Error (-6, "New invocation: Can not find a constructor for " +
5947 "this argument list");
5954 byte [] MakeByteBlob ()
5959 int count = array_data.Count;
5961 if (TypeManager.IsEnumType (array_element_type))
5962 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
5964 factor = GetTypeSize (array_element_type);
5966 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5968 data = new byte [(count * factor + 3) & ~3];
5971 for (int i = 0; i < count; ++i) {
5972 object v = array_data [i];
5974 if (v is EnumConstant)
5975 v = ((EnumConstant) v).Child;
5977 if (v is Constant && !(v is StringConstant))
5978 v = ((Constant) v).GetValue ();
5984 if (array_element_type == TypeManager.int64_type){
5985 if (!(v is Expression)){
5986 long val = (long) v;
5988 for (int j = 0; j < factor; ++j) {
5989 data [idx + j] = (byte) (val & 0xFF);
5993 } else if (array_element_type == TypeManager.uint64_type){
5994 if (!(v is Expression)){
5995 ulong val = (ulong) v;
5997 for (int j = 0; j < factor; ++j) {
5998 data [idx + j] = (byte) (val & 0xFF);
6002 } else if (array_element_type == TypeManager.float_type) {
6003 if (!(v is Expression)){
6004 element = BitConverter.GetBytes ((float) v);
6006 for (int j = 0; j < factor; ++j)
6007 data [idx + j] = element [j];
6008 if (!BitConverter.IsLittleEndian)
6009 System.Array.Reverse (data, idx, 4);
6011 } else if (array_element_type == TypeManager.double_type) {
6012 if (!(v is Expression)){
6013 element = BitConverter.GetBytes ((double) v);
6015 for (int j = 0; j < factor; ++j)
6016 data [idx + j] = element [j];
6018 // FIXME: Handle the ARM float format.
6019 if (!BitConverter.IsLittleEndian)
6020 System.Array.Reverse (data, idx, 8);
6022 } else if (array_element_type == TypeManager.char_type){
6023 if (!(v is Expression)){
6024 int val = (int) ((char) v);
6026 data [idx] = (byte) (val & 0xff);
6027 data [idx+1] = (byte) (val >> 8);
6029 } else if (array_element_type == TypeManager.short_type){
6030 if (!(v is Expression)){
6031 int val = (int) ((short) v);
6033 data [idx] = (byte) (val & 0xff);
6034 data [idx+1] = (byte) (val >> 8);
6036 } else if (array_element_type == TypeManager.ushort_type){
6037 if (!(v is Expression)){
6038 int val = (int) ((ushort) v);
6040 data [idx] = (byte) (val & 0xff);
6041 data [idx+1] = (byte) (val >> 8);
6043 } else if (array_element_type == TypeManager.int32_type) {
6044 if (!(v is Expression)){
6047 data [idx] = (byte) (val & 0xff);
6048 data [idx+1] = (byte) ((val >> 8) & 0xff);
6049 data [idx+2] = (byte) ((val >> 16) & 0xff);
6050 data [idx+3] = (byte) (val >> 24);
6052 } else if (array_element_type == TypeManager.uint32_type) {
6053 if (!(v is Expression)){
6054 uint val = (uint) v;
6056 data [idx] = (byte) (val & 0xff);
6057 data [idx+1] = (byte) ((val >> 8) & 0xff);
6058 data [idx+2] = (byte) ((val >> 16) & 0xff);
6059 data [idx+3] = (byte) (val >> 24);
6061 } else if (array_element_type == TypeManager.sbyte_type) {
6062 if (!(v is Expression)){
6063 sbyte val = (sbyte) v;
6064 data [idx] = (byte) val;
6066 } else if (array_element_type == TypeManager.byte_type) {
6067 if (!(v is Expression)){
6068 byte val = (byte) v;
6069 data [idx] = (byte) val;
6071 } else if (array_element_type == TypeManager.bool_type) {
6072 if (!(v is Expression)){
6073 bool val = (bool) v;
6074 data [idx] = (byte) (val ? 1 : 0);
6076 } else if (array_element_type == TypeManager.decimal_type){
6077 if (!(v is Expression)){
6078 int [] bits = Decimal.GetBits ((decimal) v);
6081 // FIXME: For some reason, this doesn't work on the MS runtime.
6082 int [] nbits = new int [4];
6083 nbits [0] = bits [3];
6084 nbits [1] = bits [2];
6085 nbits [2] = bits [0];
6086 nbits [3] = bits [1];
6088 for (int j = 0; j < 4; j++){
6089 data [p++] = (byte) (nbits [j] & 0xff);
6090 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6091 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6092 data [p++] = (byte) (nbits [j] >> 24);
6096 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6105 // Emits the initializers for the array
6107 void EmitStaticInitializers (EmitContext ec)
6109 // FIXME: This should go to Resolve !
6110 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6111 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6112 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6113 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6114 if (TypeManager.void_initializearray_array_fieldhandle == null)
6119 // First, the static data
6122 ILGenerator ig = ec.ig;
6124 byte [] data = MakeByteBlob ();
6126 fb = RootContext.MakeStaticData (data);
6128 ig.Emit (OpCodes.Dup);
6129 ig.Emit (OpCodes.Ldtoken, fb);
6130 ig.Emit (OpCodes.Call,
6131 TypeManager.void_initializearray_array_fieldhandle);
6135 // Emits pieces of the array that can not be computed at compile
6136 // time (variables and string locations).
6138 // This always expect the top value on the stack to be the array
6140 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6142 ILGenerator ig = ec.ig;
6143 int dims = bounds.Count;
6144 int [] current_pos = new int [dims];
6146 MethodInfo set = null;
6149 Type [] args = new Type [dims + 1];
6151 for (int j = 0; j < dims; j++)
6152 args [j] = TypeManager.int32_type;
6153 args [dims] = array_element_type;
6155 set = CodeGen.Module.Builder.GetArrayMethod (
6157 CallingConventions.HasThis | CallingConventions.Standard,
6158 TypeManager.void_type, args);
6161 for (int i = 0; i < array_data.Count; i++){
6163 Expression e = (Expression)array_data [i];
6165 // Constant can be initialized via StaticInitializer
6166 if (e != null && !(!emitConstants && e is Constant)) {
6167 Type etype = e.Type;
6169 ig.Emit (OpCodes.Dup);
6171 for (int idx = 0; idx < dims; idx++)
6172 IntConstant.EmitInt (ig, current_pos [idx]);
6175 // If we are dealing with a struct, get the
6176 // address of it, so we can store it.
6178 if ((dims == 1) && etype.IsValueType &&
6179 (!TypeManager.IsBuiltinOrEnum (etype) ||
6180 etype == TypeManager.decimal_type)) {
6185 // Let new know that we are providing
6186 // the address where to store the results
6188 n.DisableTemporaryValueType ();
6191 ig.Emit (OpCodes.Ldelema, etype);
6197 bool is_stobj, has_type_arg;
6198 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6200 ig.Emit (OpCodes.Stobj, etype);
6201 else if (has_type_arg)
6202 ig.Emit (op, etype);
6206 ig.Emit (OpCodes.Call, set);
6213 for (int j = dims - 1; j >= 0; j--){
6215 if (current_pos [j] < (int) bounds [j])
6217 current_pos [j] = 0;
6222 public override void Emit (EmitContext ec)
6224 ILGenerator ig = ec.ig;
6226 if (first_emit != null) {
6227 first_emit.Emit (ec);
6228 first_emit_temp.Store (ec);
6231 foreach (Argument a in arguments)
6234 if (arguments.Count == 1)
6235 ig.Emit (OpCodes.Newarr, array_element_type);
6237 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6240 if (initializers == null)
6243 // Emit static initializer for arrays which have contain more than 4 items and
6244 // the static initializer will initialize at least 25% of array values.
6245 // NOTE: const_initializers_count does not contain default constant values.
6246 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6247 TypeManager.IsPrimitiveType (array_element_type)) {
6248 EmitStaticInitializers (ec);
6250 if (!only_constant_initializers)
6251 EmitDynamicInitializers (ec, false);
6253 EmitDynamicInitializers (ec, true);
6256 if (first_emit_temp != null)
6257 first_emit_temp.Release (ec);
6260 public override bool GetAttributableValue (Type value_type, out object value)
6262 if (arguments.Count != 1) {
6263 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6264 return base.GetAttributableValue (null, out value);
6267 if (array_data == null) {
6268 Constant c = (Constant)((Argument)arguments [0]).Expr;
6269 if (c.IsDefaultValue) {
6270 value = Array.CreateInstance (array_element_type, 0);
6273 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6274 return base.GetAttributableValue (null, out value);
6277 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6278 object element_value;
6279 for (int i = 0; i < ret.Length; ++i)
6281 Expression e = (Expression)array_data [i];
6283 // Is null when an initializer is optimized (value == predefined value)
6287 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6291 ret.SetValue (element_value, i);
6297 protected override void CloneTo (CloneContext clonectx, Expression t)
6299 ArrayCreation target = (ArrayCreation) t;
6301 if (requested_base_type != null)
6302 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6304 if (arguments != null){
6305 target.arguments = new ArrayList (arguments.Count);
6306 foreach (Argument a in arguments)
6307 target.arguments.Add (a.Clone (clonectx));
6310 if (initializers != null){
6311 target.initializers = new ArrayList (initializers.Count);
6312 foreach (object initializer in initializers)
6313 if (initializer is ArrayList) {
6314 ArrayList this_al = (ArrayList)initializer;
6315 ArrayList al = new ArrayList (this_al.Count);
6316 target.initializers.Add (al);
6317 foreach (Expression e in this_al)
6318 al.Add (e.Clone (clonectx));
6320 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6327 // Represents an implicitly typed array epxression
6329 public class ImplicitlyTypedArrayCreation : ArrayCreation
6331 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6332 : base (null, rank, initializers, loc)
6334 if (RootContext.Version <= LanguageVersion.ISO_2)
6335 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6337 if (rank.Length > 2) {
6338 while (rank [++dimensions] == ',');
6344 public override Expression DoResolve (EmitContext ec)
6349 if (!ResolveInitializers (ec))
6352 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6353 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6354 arguments.Count != dimensions) {
6355 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6360 // At this point we found common base type for all initializer elements
6361 // but we have to be sure that all static initializer elements are of
6364 UnifyInitializerElement (ec);
6366 type = TypeManager.GetConstructedType (array_element_type, rank);
6367 eclass = ExprClass.Value;
6372 // Converts static initializer only
6374 void UnifyInitializerElement (EmitContext ec)
6376 for (int i = 0; i < array_data.Count; ++i) {
6377 Expression e = (Expression)array_data[i];
6379 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6383 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6385 element = element.Resolve (ec);
6386 if (element == null)
6389 if (array_element_type == null) {
6390 array_element_type = element.Type;
6394 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6398 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6399 array_element_type = element.Type;
6403 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6408 public sealed class CompilerGeneratedThis : This
6410 public static This Instance = new CompilerGeneratedThis ();
6412 private CompilerGeneratedThis ()
6413 : base (Location.Null)
6417 public override Expression DoResolve (EmitContext ec)
6419 eclass = ExprClass.Variable;
6420 type = ec.ContainerType;
6421 variable = new SimpleThis (type);
6427 /// Represents the `this' construct
6430 public class This : VariableReference, IVariable
6433 VariableInfo variable_info;
6434 protected Variable variable;
6437 public This (Block block, Location loc)
6443 public This (Location loc)
6448 public VariableInfo VariableInfo {
6449 get { return variable_info; }
6452 public bool VerifyFixed ()
6454 return !TypeManager.IsValueType (Type);
6457 public override bool IsRef {
6458 get { return is_struct; }
6461 public override Variable Variable {
6462 get { return variable; }
6465 public bool ResolveBase (EmitContext ec)
6467 eclass = ExprClass.Variable;
6469 if (ec.TypeContainer.CurrentType != null)
6470 type = ec.TypeContainer.CurrentType;
6472 type = ec.ContainerType;
6474 is_struct = ec.TypeContainer is Struct;
6477 Error (26, "Keyword `this' is not valid in a static property, " +
6478 "static method, or static field initializer");
6482 if (block != null) {
6483 if (block.Toplevel.ThisVariable != null)
6484 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6486 AnonymousContainer am = ec.CurrentAnonymousMethod;
6487 if (is_struct && (am != null) && !am.IsIterator) {
6488 Report.Error (1673, loc, "Anonymous methods inside structs " +
6489 "cannot access instance members of `this'. " +
6490 "Consider copying `this' to a local variable " +
6491 "outside the anonymous method and using the " +
6495 RootScopeInfo host = block.Toplevel.RootScope;
6496 if ((host != null) && !ec.IsConstructor &&
6497 (!is_struct || host.IsIterator)) {
6498 variable = host.CaptureThis ();
6499 type = variable.Type;
6504 if (variable == null)
6505 variable = new SimpleThis (type);
6511 // Called from Invocation to check if the invocation is correct
6513 public override void CheckMarshalByRefAccess (EmitContext ec)
6515 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6516 !variable_info.IsAssigned (ec)) {
6517 Error (188, "The `this' object cannot be used before all of its " +
6518 "fields are assigned to");
6519 variable_info.SetAssigned (ec);
6523 public override Expression CreateExpressionTree (EmitContext ec)
6525 ArrayList args = new ArrayList (2);
6526 args.Add (new Argument (this));
6527 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6528 return CreateExpressionFactoryCall ("Constant", args);
6531 public override Expression DoResolve (EmitContext ec)
6533 if (!ResolveBase (ec))
6537 if (ec.IsInFieldInitializer) {
6538 Error (27, "Keyword `this' is not available in the current context");
6545 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6547 if (!ResolveBase (ec))
6550 if (variable_info != null)
6551 variable_info.SetAssigned (ec);
6553 if (ec.TypeContainer is Class){
6554 Error (1604, "Cannot assign to 'this' because it is read-only");
6560 public override int GetHashCode()
6562 return block.GetHashCode ();
6565 public override bool Equals (object obj)
6567 This t = obj as This;
6571 return block == t.block;
6574 protected class SimpleThis : Variable
6578 public SimpleThis (Type type)
6583 public override Type Type {
6584 get { return type; }
6587 public override bool HasInstance {
6588 get { return false; }
6591 public override bool NeedsTemporary {
6592 get { return false; }
6595 public override void EmitInstance (EmitContext ec)
6600 public override void Emit (EmitContext ec)
6602 ec.ig.Emit (OpCodes.Ldarg_0);
6605 public override void EmitAssign (EmitContext ec)
6607 throw new InvalidOperationException ();
6610 public override void EmitAddressOf (EmitContext ec)
6612 ec.ig.Emit (OpCodes.Ldarg_0);
6616 protected override void CloneTo (CloneContext clonectx, Expression t)
6618 This target = (This) t;
6620 target.block = clonectx.LookupBlock (block);
6625 /// Represents the `__arglist' construct
6627 public class ArglistAccess : Expression
6629 public ArglistAccess (Location loc)
6634 public override Expression CreateExpressionTree (EmitContext ec)
6636 throw new NotSupportedException ("ET");
6639 public override Expression DoResolve (EmitContext ec)
6641 eclass = ExprClass.Variable;
6642 type = TypeManager.runtime_argument_handle_type;
6644 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6646 Error (190, "The __arglist construct is valid only within " +
6647 "a variable argument method");
6654 public override void Emit (EmitContext ec)
6656 ec.ig.Emit (OpCodes.Arglist);
6659 protected override void CloneTo (CloneContext clonectx, Expression target)
6666 /// Represents the `__arglist (....)' construct
6668 public class Arglist : Expression
6670 Argument[] Arguments;
6672 public Arglist (Location loc)
6673 : this (Argument.Empty, loc)
6677 public Arglist (Argument[] args, Location l)
6683 public Type[] ArgumentTypes {
6685 Type[] retval = new Type [Arguments.Length];
6686 for (int i = 0; i < Arguments.Length; i++)
6687 retval [i] = Arguments [i].Type;
6692 public override Expression CreateExpressionTree (EmitContext ec)
6694 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6698 public override Expression DoResolve (EmitContext ec)
6700 eclass = ExprClass.Variable;
6701 type = TypeManager.runtime_argument_handle_type;
6703 foreach (Argument arg in Arguments) {
6704 if (!arg.Resolve (ec, loc))
6711 public override void Emit (EmitContext ec)
6713 foreach (Argument arg in Arguments)
6717 protected override void CloneTo (CloneContext clonectx, Expression t)
6719 Arglist target = (Arglist) t;
6721 target.Arguments = new Argument [Arguments.Length];
6722 for (int i = 0; i < Arguments.Length; i++)
6723 target.Arguments [i] = Arguments [i].Clone (clonectx);
6728 /// Implements the typeof operator
6730 public class TypeOf : Expression {
6731 Expression QueriedType;
6732 protected Type typearg;
6734 public TypeOf (Expression queried_type, Location l)
6736 QueriedType = queried_type;
6740 public override Expression CreateExpressionTree (EmitContext ec)
6742 ArrayList args = new ArrayList (2);
6743 args.Add (new Argument (this));
6744 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6745 return CreateExpressionFactoryCall ("Constant", args);
6748 public override Expression DoResolve (EmitContext ec)
6750 if (eclass != ExprClass.Invalid)
6753 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6757 typearg = texpr.Type;
6759 if (typearg == TypeManager.void_type) {
6760 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6764 if (typearg.IsPointer && !ec.InUnsafe){
6769 type = TypeManager.type_type;
6771 return DoResolveBase ();
6774 protected Expression DoResolveBase ()
6776 if (TypeManager.system_type_get_type_from_handle == null) {
6777 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6778 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6781 // Even though what is returned is a type object, it's treated as a value by the compiler.
6782 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6783 eclass = ExprClass.Value;
6787 public override void Emit (EmitContext ec)
6789 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6790 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6793 public override bool GetAttributableValue (Type value_type, out object value)
6795 if (TypeManager.ContainsGenericParameters (typearg) &&
6796 !TypeManager.IsGenericTypeDefinition (typearg)) {
6797 Report.SymbolRelatedToPreviousError (typearg);
6798 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6799 TypeManager.CSharpName (typearg));
6804 if (value_type == TypeManager.object_type) {
6805 value = (object)typearg;
6812 public Type TypeArgument
6820 protected override void CloneTo (CloneContext clonectx, Expression t)
6822 TypeOf target = (TypeOf) t;
6823 if (QueriedType != null)
6824 target.QueriedType = QueriedType.Clone (clonectx);
6829 /// Implements the `typeof (void)' operator
6831 public class TypeOfVoid : TypeOf {
6832 public TypeOfVoid (Location l) : base (null, l)
6837 public override Expression DoResolve (EmitContext ec)
6839 type = TypeManager.type_type;
6840 typearg = TypeManager.void_type;
6842 return DoResolveBase ();
6846 class TypeOfMethodInfo : TypeOfMethod
6848 public TypeOfMethodInfo (MethodBase method, Location loc)
6849 : base (method, loc)
6853 public override Expression DoResolve (EmitContext ec)
6855 type = typeof (MethodInfo);
6856 return base.DoResolve (ec);
6859 public override void Emit (EmitContext ec)
6861 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
6863 ec.ig.Emit (OpCodes.Castclass, type);
6867 class TypeOfConstructorInfo : TypeOfMethod
6869 public TypeOfConstructorInfo (MethodBase method, Location loc)
6870 : base (method, loc)
6874 public override Expression DoResolve (EmitContext ec)
6876 type = typeof (ConstructorInfo);
6877 return base.DoResolve (ec);
6880 public override void Emit (EmitContext ec)
6882 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
6884 ec.ig.Emit (OpCodes.Castclass, type);
6888 abstract class TypeOfMethod : Expression
6890 protected readonly MethodBase method;
6892 protected TypeOfMethod (MethodBase method, Location loc)
6894 this.method = method;
6898 public override Expression CreateExpressionTree (EmitContext ec)
6900 ArrayList args = new ArrayList (2);
6901 args.Add (new Argument (this));
6902 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6903 return CreateExpressionFactoryCall ("Constant", args);
6906 public override Expression DoResolve (EmitContext ec)
6908 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6909 MethodInfo mi = is_generic ?
6910 TypeManager.methodbase_get_type_from_handle_generic :
6911 TypeManager.methodbase_get_type_from_handle;
6914 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
6915 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
6917 if (t == null || handle_type == null)
6920 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
6922 new Type[] { handle_type, TypeManager.runtime_handle_type } :
6923 new Type[] { handle_type } );
6926 TypeManager.methodbase_get_type_from_handle_generic = mi;
6928 TypeManager.methodbase_get_type_from_handle = mi;
6931 eclass = ExprClass.Value;
6935 public override void Emit (EmitContext ec)
6937 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6940 mi = TypeManager.methodbase_get_type_from_handle_generic;
6941 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
6943 mi = TypeManager.methodbase_get_type_from_handle;
6946 ec.ig.Emit (OpCodes.Call, mi);
6950 internal class TypeOfField : Expression
6952 readonly FieldInfo field;
6954 public TypeOfField (FieldInfo field, Location loc)
6960 public override Expression CreateExpressionTree (EmitContext ec)
6962 throw new NotSupportedException ("ET");
6965 public override Expression DoResolve (EmitContext ec)
6967 if (TypeManager.fieldinfo_get_field_from_handle == null) {
6968 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
6969 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
6971 if (t != null && handle_type != null)
6972 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
6973 "GetFieldFromHandle", loc, handle_type);
6976 type = typeof (FieldInfo);
6977 eclass = ExprClass.Value;
6981 public override void Emit (EmitContext ec)
6983 ec.ig.Emit (OpCodes.Ldtoken, field);
6984 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
6989 /// Implements the sizeof expression
6991 public class SizeOf : Expression {
6992 readonly Expression QueriedType;
6995 public SizeOf (Expression queried_type, Location l)
6997 this.QueriedType = queried_type;
7001 public override Expression CreateExpressionTree (EmitContext ec)
7003 Error_PointerInsideExpressionTree ();
7007 public override Expression DoResolve (EmitContext ec)
7009 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7013 type_queried = texpr.Type;
7014 if (TypeManager.IsEnumType (type_queried))
7015 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7017 if (type_queried == TypeManager.void_type) {
7018 Expression.Error_VoidInvalidInTheContext (loc);
7022 int size_of = GetTypeSize (type_queried);
7024 return new IntConstant (size_of, loc);
7027 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7032 Report.Error (233, loc,
7033 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7034 TypeManager.CSharpName (type_queried));
7037 type = TypeManager.int32_type;
7038 eclass = ExprClass.Value;
7042 public override void Emit (EmitContext ec)
7044 int size = GetTypeSize (type_queried);
7047 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7049 IntConstant.EmitInt (ec.ig, size);
7052 protected override void CloneTo (CloneContext clonectx, Expression t)
7058 /// Implements the qualified-alias-member (::) expression.
7060 public class QualifiedAliasMember : MemberAccess
7062 readonly string alias;
7064 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7065 : base (null, identifier, targs, l)
7070 public QualifiedAliasMember (string alias, string identifier, Location l)
7071 : base (null, identifier, l)
7076 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7078 if (alias == "global") {
7079 expr = RootNamespace.Global;
7080 return base.ResolveAsTypeStep (ec, silent);
7083 int errors = Report.Errors;
7084 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7086 if (errors == Report.Errors)
7087 Report.Error (432, loc, "Alias `{0}' not found", alias);
7091 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7095 if (expr.eclass == ExprClass.Type) {
7097 Report.Error (431, loc,
7098 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7106 public override Expression DoResolve (EmitContext ec)
7108 return ResolveAsTypeStep (ec, false);
7111 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7113 Report.Error (687, loc,
7114 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7115 GetSignatureForError ());
7118 public override string GetSignatureForError ()
7121 if (targs != null) {
7122 name = TypeManager.RemoveGenericArity (Name) + "<" +
7123 targs.GetSignatureForError () + ">";
7126 return alias + "::" + name;
7129 protected override void CloneTo (CloneContext clonectx, Expression t)
7136 /// Implements the member access expression
7138 public class MemberAccess : ATypeNameExpression {
7139 protected Expression expr;
7141 public MemberAccess (Expression expr, string id)
7142 : base (id, expr.Location)
7147 public MemberAccess (Expression expr, string identifier, Location loc)
7148 : base (identifier, loc)
7153 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7154 : base (identifier, args, loc)
7159 // TODO: this method has very poor performace for Enum fields and
7160 // probably for other constants as well
7161 Expression DoResolve (EmitContext ec, Expression right_side)
7164 throw new Exception ();
7167 // Resolve the expression with flow analysis turned off, we'll do the definite
7168 // assignment checks later. This is because we don't know yet what the expression
7169 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7170 // definite assignment check on the actual field and not on the whole struct.
7173 SimpleName original = expr as SimpleName;
7174 Expression expr_resolved = expr.Resolve (ec,
7175 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7176 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7178 if (expr_resolved == null)
7181 string LookupIdentifier = MemberName.MakeName (Name, targs);
7183 if (expr_resolved is Namespace) {
7184 Namespace ns = (Namespace) expr_resolved;
7185 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7187 if ((retval != null) && (targs != null))
7188 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7192 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7196 Type expr_type = expr_resolved.Type;
7197 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7198 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7199 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7203 Constant c = expr_resolved as Constant;
7204 if (c != null && c.GetValue () == null) {
7205 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7206 "System.NullReferenceException");
7209 if (targs != null) {
7210 if (!targs.Resolve (ec))
7214 Expression member_lookup;
7215 member_lookup = MemberLookup (
7216 ec.ContainerType, expr_type, expr_type, Name, loc);
7218 if ((member_lookup == null) && (targs != null)) {
7219 member_lookup = MemberLookup (
7220 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7223 if (member_lookup == null) {
7224 ExprClass expr_eclass = expr_resolved.eclass;
7227 // Extension methods are not allowed on all expression types
7229 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7230 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7231 expr_eclass == ExprClass.EventAccess) {
7232 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7233 if (ex_method_lookup != null) {
7234 ex_method_lookup.ExtensionExpression = expr_resolved;
7236 if (targs != null) {
7237 ex_method_lookup.SetTypeArguments (targs);
7240 return ex_method_lookup.DoResolve (ec);
7244 expr = expr_resolved;
7245 Error_MemberLookupFailed (
7246 ec.ContainerType, expr_type, expr_type, Name, null,
7247 AllMemberTypes, AllBindingFlags);
7251 TypeExpr texpr = member_lookup as TypeExpr;
7252 if (texpr != null) {
7253 if (!(expr_resolved is TypeExpr) &&
7254 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7255 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7256 Name, member_lookup.GetSignatureForError ());
7260 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7261 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7262 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7267 ConstructedType ct = expr_resolved as ConstructedType;
7270 // When looking up a nested type in a generic instance
7271 // via reflection, we always get a generic type definition
7272 // and not a generic instance - so we have to do this here.
7274 // See gtest-172-lib.cs and gtest-172.cs for an example.
7276 ct = new ConstructedType (
7277 member_lookup.Type, ct.TypeArguments, loc);
7279 return ct.ResolveAsTypeStep (ec, false);
7282 return member_lookup;
7285 MemberExpr me = (MemberExpr) member_lookup;
7286 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7290 if (targs != null) {
7291 me.SetTypeArguments (targs);
7294 if (original != null && !TypeManager.IsValueType (expr_type)) {
7295 if (me.IsInstance) {
7296 LocalVariableReference var = expr_resolved as LocalVariableReference;
7297 if (var != null && !var.VerifyAssigned (ec))
7302 // The following DoResolve/DoResolveLValue will do the definite assignment
7305 if (right_side != null)
7306 return me.DoResolveLValue (ec, right_side);
7308 return me.DoResolve (ec);
7311 public override Expression DoResolve (EmitContext ec)
7313 return DoResolve (ec, null);
7316 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7318 return DoResolve (ec, right_side);
7321 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7323 return ResolveNamespaceOrType (ec, silent);
7326 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7328 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7330 if (new_expr == null)
7333 string LookupIdentifier = MemberName.MakeName (Name, targs);
7335 if (new_expr is Namespace) {
7336 Namespace ns = (Namespace) new_expr;
7337 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7339 if ((retval != null) && (targs != null))
7340 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7342 if (!silent && retval == null)
7343 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7347 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7348 if (tnew_expr == null)
7351 Type expr_type = tnew_expr.Type;
7353 if (expr_type.IsPointer){
7354 Error (23, "The `.' operator can not be applied to pointer operands (" +
7355 TypeManager.CSharpName (expr_type) + ")");
7359 Expression member_lookup = MemberLookup (
7360 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7361 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7362 if (member_lookup == null) {
7366 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7370 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7375 TypeArguments the_args = targs;
7376 Type declaring_type = texpr.Type.DeclaringType;
7377 if (TypeManager.HasGenericArguments (declaring_type)) {
7378 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7379 expr_type = expr_type.BaseType;
7382 TypeArguments new_args = new TypeArguments (loc);
7383 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7384 new_args.Add (new TypeExpression (decl, loc));
7387 new_args.Add (targs);
7389 the_args = new_args;
7392 if (the_args != null) {
7393 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7394 return ctype.ResolveAsTypeStep (rc, false);
7401 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7403 Expression member_lookup = MemberLookup (
7404 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7405 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7407 if (member_lookup != null) {
7408 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7409 if (expr_type == null)
7412 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7416 member_lookup = MemberLookup (
7417 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7418 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7420 if (member_lookup == null) {
7421 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7422 Name, expr_type.GetSignatureForError ());
7424 // TODO: Report.SymbolRelatedToPreviousError
7425 member_lookup.Error_UnexpectedKind (null, "type", loc);
7429 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7431 if (RootContext.Version > LanguageVersion.ISO_2 &&
7432 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7433 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7434 "extension method `{1}' of type `{0}' could be found " +
7435 "(are you missing a using directive or an assembly reference?)",
7436 TypeManager.CSharpName (type), name);
7440 base.Error_TypeDoesNotContainDefinition (type, name);
7443 public override string GetSignatureForError ()
7445 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7448 protected override void CloneTo (CloneContext clonectx, Expression t)
7450 MemberAccess target = (MemberAccess) t;
7452 target.expr = expr.Clone (clonectx);
7457 /// Implements checked expressions
7459 public class CheckedExpr : Expression {
7461 public Expression Expr;
7463 public CheckedExpr (Expression e, Location l)
7469 public override Expression CreateExpressionTree (EmitContext ec)
7471 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7472 return Expr.CreateExpressionTree (ec);
7475 public override Expression DoResolve (EmitContext ec)
7477 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7478 Expr = Expr.Resolve (ec);
7483 if (Expr is Constant)
7486 eclass = Expr.eclass;
7491 public override void Emit (EmitContext ec)
7493 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7497 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7499 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7500 Expr.EmitBranchable (ec, target, on_true);
7503 protected override void CloneTo (CloneContext clonectx, Expression t)
7505 CheckedExpr target = (CheckedExpr) t;
7507 target.Expr = Expr.Clone (clonectx);
7512 /// Implements the unchecked expression
7514 public class UnCheckedExpr : Expression {
7516 public Expression Expr;
7518 public UnCheckedExpr (Expression e, Location l)
7524 public override Expression CreateExpressionTree (EmitContext ec)
7526 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7527 return Expr.CreateExpressionTree (ec);
7530 public override Expression DoResolve (EmitContext ec)
7532 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7533 Expr = Expr.Resolve (ec);
7538 if (Expr is Constant)
7541 eclass = Expr.eclass;
7546 public override void Emit (EmitContext ec)
7548 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7552 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7554 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7555 Expr.EmitBranchable (ec, target, on_true);
7558 protected override void CloneTo (CloneContext clonectx, Expression t)
7560 UnCheckedExpr target = (UnCheckedExpr) t;
7562 target.Expr = Expr.Clone (clonectx);
7567 /// An Element Access expression.
7569 /// During semantic analysis these are transformed into
7570 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7572 public class ElementAccess : Expression {
7573 public ArrayList Arguments;
7574 public Expression Expr;
7576 public ElementAccess (Expression e, ArrayList e_list)
7585 Arguments = new ArrayList ();
7586 foreach (Expression tmp in e_list)
7587 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7591 bool CommonResolve (EmitContext ec)
7593 Expr = Expr.Resolve (ec);
7595 if (Arguments == null)
7598 foreach (Argument a in Arguments){
7599 if (!a.Resolve (ec, loc))
7603 return Expr != null;
7606 public override Expression CreateExpressionTree (EmitContext ec)
7608 ArrayList args = new ArrayList (Arguments.Count + 1);
7609 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7610 foreach (Argument a in Arguments)
7611 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7613 return CreateExpressionFactoryCall ("ArrayIndex", args);
7616 Expression MakePointerAccess (EmitContext ec, Type t)
7618 if (t == TypeManager.void_ptr_type){
7619 Error (242, "The array index operation is not valid on void pointers");
7622 if (Arguments.Count != 1){
7623 Error (196, "A pointer must be indexed by only one value");
7628 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7631 return new Indirection (p, loc).Resolve (ec);
7634 public override Expression DoResolve (EmitContext ec)
7636 if (!CommonResolve (ec))
7640 // We perform some simple tests, and then to "split" the emit and store
7641 // code we create an instance of a different class, and return that.
7643 // I am experimenting with this pattern.
7647 if (t == TypeManager.array_type){
7648 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7653 return (new ArrayAccess (this, loc)).Resolve (ec);
7655 return MakePointerAccess (ec, t);
7657 FieldExpr fe = Expr as FieldExpr;
7659 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7661 return MakePointerAccess (ec, ff.ElementType);
7664 return (new IndexerAccess (this, loc)).Resolve (ec);
7667 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7669 if (!CommonResolve (ec))
7674 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7677 return MakePointerAccess (ec, type);
7679 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7680 Error_CannotModifyIntermediateExpressionValue (ec);
7682 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7685 public override void Emit (EmitContext ec)
7687 throw new Exception ("Should never be reached");
7690 public override string GetSignatureForError ()
7692 return Expr.GetSignatureForError ();
7695 protected override void CloneTo (CloneContext clonectx, Expression t)
7697 ElementAccess target = (ElementAccess) t;
7699 target.Expr = Expr.Clone (clonectx);
7700 target.Arguments = new ArrayList (Arguments.Count);
7701 foreach (Argument a in Arguments)
7702 target.Arguments.Add (a.Clone (clonectx));
7707 /// Implements array access
7709 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7711 // Points to our "data" repository
7715 LocalTemporary temp;
7719 public ArrayAccess (ElementAccess ea_data, Location l)
7722 eclass = ExprClass.Variable;
7726 public override Expression CreateExpressionTree (EmitContext ec)
7728 return ea.CreateExpressionTree (ec);
7731 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7733 return DoResolve (ec);
7736 public override Expression DoResolve (EmitContext ec)
7739 ExprClass eclass = ea.Expr.eclass;
7741 // As long as the type is valid
7742 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7743 eclass == ExprClass.Value)) {
7744 ea.Expr.Error_UnexpectedKind ("variable or value");
7749 Type t = ea.Expr.Type;
7750 int rank = ea.Arguments.Count;
7751 if (t.GetArrayRank () != rank) {
7752 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7753 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7757 if (rank != 1 && TypeManager.int_getlength_int == null) {
7758 TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
7759 TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
7762 type = TypeManager.GetElementType (t);
7763 if (type.IsPointer && !ec.InUnsafe) {
7764 UnsafeError (ea.Location);
7768 foreach (Argument a in ea.Arguments) {
7769 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7772 eclass = ExprClass.Variable;
7778 /// Emits the right opcode to load an object of Type `t'
7779 /// from an array of T
7781 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7784 MethodInfo get = FetchGetMethod ();
7785 ig.Emit (OpCodes.Call, get);
7789 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7790 ig.Emit (OpCodes.Ldelem_U1);
7791 else if (type == TypeManager.sbyte_type)
7792 ig.Emit (OpCodes.Ldelem_I1);
7793 else if (type == TypeManager.short_type)
7794 ig.Emit (OpCodes.Ldelem_I2);
7795 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7796 ig.Emit (OpCodes.Ldelem_U2);
7797 else if (type == TypeManager.int32_type)
7798 ig.Emit (OpCodes.Ldelem_I4);
7799 else if (type == TypeManager.uint32_type)
7800 ig.Emit (OpCodes.Ldelem_U4);
7801 else if (type == TypeManager.uint64_type)
7802 ig.Emit (OpCodes.Ldelem_I8);
7803 else if (type == TypeManager.int64_type)
7804 ig.Emit (OpCodes.Ldelem_I8);
7805 else if (type == TypeManager.float_type)
7806 ig.Emit (OpCodes.Ldelem_R4);
7807 else if (type == TypeManager.double_type)
7808 ig.Emit (OpCodes.Ldelem_R8);
7809 else if (type == TypeManager.intptr_type)
7810 ig.Emit (OpCodes.Ldelem_I);
7811 else if (TypeManager.IsEnumType (type)){
7812 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7813 } else if (type.IsValueType){
7814 ig.Emit (OpCodes.Ldelema, type);
7815 ig.Emit (OpCodes.Ldobj, type);
7817 } else if (type.IsGenericParameter) {
7818 ig.Emit (OpCodes.Ldelem, type);
7820 } else if (type.IsPointer)
7821 ig.Emit (OpCodes.Ldelem_I);
7823 ig.Emit (OpCodes.Ldelem_Ref);
7826 protected override void Error_NegativeArrayIndex (Location loc)
7828 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7832 /// Returns the right opcode to store an object of Type `t'
7833 /// from an array of T.
7835 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7837 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7838 has_type_arg = false; is_stobj = false;
7839 t = TypeManager.TypeToCoreType (t);
7840 if (TypeManager.IsEnumType (t))
7841 t = TypeManager.GetEnumUnderlyingType (t);
7842 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7843 t == TypeManager.bool_type)
7844 return OpCodes.Stelem_I1;
7845 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7846 t == TypeManager.char_type)
7847 return OpCodes.Stelem_I2;
7848 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7849 return OpCodes.Stelem_I4;
7850 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7851 return OpCodes.Stelem_I8;
7852 else if (t == TypeManager.float_type)
7853 return OpCodes.Stelem_R4;
7854 else if (t == TypeManager.double_type)
7855 return OpCodes.Stelem_R8;
7856 else if (t == TypeManager.intptr_type) {
7857 has_type_arg = true;
7859 return OpCodes.Stobj;
7860 } else if (t.IsValueType) {
7861 has_type_arg = true;
7863 return OpCodes.Stobj;
7865 } else if (t.IsGenericParameter) {
7866 has_type_arg = true;
7867 return OpCodes.Stelem;
7870 } else if (t.IsPointer)
7871 return OpCodes.Stelem_I;
7873 return OpCodes.Stelem_Ref;
7876 MethodInfo FetchGetMethod ()
7878 ModuleBuilder mb = CodeGen.Module.Builder;
7879 int arg_count = ea.Arguments.Count;
7880 Type [] args = new Type [arg_count];
7883 for (int i = 0; i < arg_count; i++){
7884 //args [i++] = a.Type;
7885 args [i] = TypeManager.int32_type;
7888 get = mb.GetArrayMethod (
7889 ea.Expr.Type, "Get",
7890 CallingConventions.HasThis |
7891 CallingConventions.Standard,
7897 MethodInfo FetchAddressMethod ()
7899 ModuleBuilder mb = CodeGen.Module.Builder;
7900 int arg_count = ea.Arguments.Count;
7901 Type [] args = new Type [arg_count];
7905 ret_type = TypeManager.GetReferenceType (type);
7907 for (int i = 0; i < arg_count; i++){
7908 //args [i++] = a.Type;
7909 args [i] = TypeManager.int32_type;
7912 address = mb.GetArrayMethod (
7913 ea.Expr.Type, "Address",
7914 CallingConventions.HasThis |
7915 CallingConventions.Standard,
7922 // Load the array arguments into the stack.
7924 void LoadArrayAndArguments (EmitContext ec)
7928 for (int i = 0; i < ea.Arguments.Count; ++i) {
7929 ((Argument)ea.Arguments [i]).Emit (ec);
7933 public void Emit (EmitContext ec, bool leave_copy)
7935 int rank = ea.Expr.Type.GetArrayRank ();
7936 ILGenerator ig = ec.ig;
7939 LoadFromPtr (ig, this.type);
7941 LoadArrayAndArguments (ec);
7942 EmitLoadOpcode (ig, type, rank);
7946 ig.Emit (OpCodes.Dup);
7947 temp = new LocalTemporary (this.type);
7952 public override void Emit (EmitContext ec)
7957 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7959 int rank = ea.Expr.Type.GetArrayRank ();
7960 ILGenerator ig = ec.ig;
7961 Type t = source.Type;
7962 prepared = prepare_for_load;
7965 AddressOf (ec, AddressOp.LoadStore);
7966 ec.ig.Emit (OpCodes.Dup);
7968 LoadArrayAndArguments (ec);
7972 bool is_stobj, has_type_arg;
7973 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7977 // The stobj opcode used by value types will need
7978 // an address on the stack, not really an array/array
7982 ig.Emit (OpCodes.Ldelema, t);
7987 ec.ig.Emit (OpCodes.Dup);
7988 temp = new LocalTemporary (this.type);
7993 StoreFromPtr (ig, t);
7995 ig.Emit (OpCodes.Stobj, t);
7996 else if (has_type_arg)
8003 ec.ig.Emit (OpCodes.Dup);
8004 temp = new LocalTemporary (this.type);
8009 StoreFromPtr (ig, t);
8011 int arg_count = ea.Arguments.Count;
8012 Type [] args = new Type [arg_count + 1];
8013 for (int i = 0; i < arg_count; i++) {
8014 //args [i++] = a.Type;
8015 args [i] = TypeManager.int32_type;
8017 args [arg_count] = type;
8019 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8020 ea.Expr.Type, "Set",
8021 CallingConventions.HasThis |
8022 CallingConventions.Standard,
8023 TypeManager.void_type, args);
8025 ig.Emit (OpCodes.Call, set);
8035 public void AddressOf (EmitContext ec, AddressOp mode)
8037 int rank = ea.Expr.Type.GetArrayRank ();
8038 ILGenerator ig = ec.ig;
8040 LoadArrayAndArguments (ec);
8043 ig.Emit (OpCodes.Ldelema, type);
8045 MethodInfo address = FetchAddressMethod ();
8046 ig.Emit (OpCodes.Call, address);
8050 public void EmitGetLength (EmitContext ec, int dim)
8052 int rank = ea.Expr.Type.GetArrayRank ();
8053 ILGenerator ig = ec.ig;
8057 ig.Emit (OpCodes.Ldlen);
8058 ig.Emit (OpCodes.Conv_I4);
8060 IntLiteral.EmitInt (ig, dim);
8061 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8067 /// Expressions that represent an indexer call.
8069 public class IndexerAccess : Expression, IAssignMethod
8071 class IndexerMethodGroupExpr : MethodGroupExpr
8073 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8076 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8079 public override string Name {
8085 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
8088 // Here is the trick, decrease number of arguments by 1 when only
8089 // available property method is setter. This makes overload resolution
8090 // work correctly for indexers.
8093 if (method.Name [0] == 'g')
8094 return parameters.Count;
8096 return parameters.Count - 1;
8102 // Contains either property getter or setter
8103 public ArrayList Methods;
8104 public ArrayList Properties;
8110 void Append (Type caller_type, MemberInfo [] mi)
8115 foreach (PropertyInfo property in mi) {
8116 MethodInfo accessor = property.GetGetMethod (true);
8117 if (accessor == null)
8118 accessor = property.GetSetMethod (true);
8120 if (Methods == null) {
8121 Methods = new ArrayList ();
8122 Properties = new ArrayList ();
8125 Methods.Add (accessor);
8126 Properties.Add (property);
8130 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8132 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8134 return TypeManager.MemberLookup (
8135 caller_type, caller_type, lookup_type, MemberTypes.Property,
8136 BindingFlags.Public | BindingFlags.Instance |
8137 BindingFlags.DeclaredOnly, p_name, null);
8140 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8142 Indexers ix = new Indexers ();
8145 if (lookup_type.IsGenericParameter) {
8146 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8150 if (gc.HasClassConstraint)
8151 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8153 Type[] ifaces = gc.InterfaceConstraints;
8154 foreach (Type itype in ifaces)
8155 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8161 Type copy = lookup_type;
8162 while (copy != TypeManager.object_type && copy != null){
8163 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8164 copy = copy.BaseType;
8167 if (lookup_type.IsInterface) {
8168 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8169 if (ifaces != null) {
8170 foreach (Type itype in ifaces)
8171 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8186 // Points to our "data" repository
8188 MethodInfo get, set;
8189 bool is_base_indexer;
8191 LocalTemporary temp;
8192 LocalTemporary prepared_value;
8193 Expression set_expr;
8195 protected Type indexer_type;
8196 protected Type current_type;
8197 protected Expression instance_expr;
8198 protected ArrayList arguments;
8200 public IndexerAccess (ElementAccess ea, Location loc)
8201 : this (ea.Expr, false, loc)
8203 this.arguments = ea.Arguments;
8206 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8209 this.instance_expr = instance_expr;
8210 this.is_base_indexer = is_base_indexer;
8211 this.eclass = ExprClass.Value;
8215 static string GetAccessorName (AccessorType at)
8217 if (at == AccessorType.Set)
8220 if (at == AccessorType.Get)
8223 throw new NotImplementedException (at.ToString ());
8226 public override Expression CreateExpressionTree (EmitContext ec)
8228 ArrayList args = new ArrayList (arguments.Count + 2);
8229 args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
8230 args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
8231 foreach (Argument a in arguments)
8232 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
8234 return CreateExpressionFactoryCall ("Call", args);
8237 protected virtual bool CommonResolve (EmitContext ec)
8239 indexer_type = instance_expr.Type;
8240 current_type = ec.ContainerType;
8245 public override Expression DoResolve (EmitContext ec)
8247 return ResolveAccessor (ec, AccessorType.Get);
8250 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8252 if (right_side == EmptyExpression.OutAccess) {
8253 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8254 GetSignatureForError ());
8258 // if the indexer returns a value type, and we try to set a field in it
8259 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8260 Error_CannotModifyIntermediateExpressionValue (ec);
8263 Expression e = ResolveAccessor (ec, AccessorType.Set);
8267 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8271 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8273 if (!CommonResolve (ec))
8276 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8277 if (ilist.Methods == null) {
8278 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8279 TypeManager.CSharpName (indexer_type));
8283 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8284 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8288 MethodInfo mi = (MethodInfo) mg;
8289 PropertyInfo pi = null;
8290 for (int i = 0; i < ilist.Methods.Count; ++i) {
8291 if (ilist.Methods [i] == mi) {
8292 pi = (PropertyInfo) ilist.Properties [i];
8297 type = TypeManager.TypeToCoreType (pi.PropertyType);
8298 if (type.IsPointer && !ec.InUnsafe)
8301 MethodInfo accessor;
8302 if (accessorType == AccessorType.Get) {
8303 accessor = get = pi.GetGetMethod (true);
8305 accessor = set = pi.GetSetMethod (true);
8306 if (accessor == null && pi.GetGetMethod (true) != null) {
8307 Report.SymbolRelatedToPreviousError (pi);
8308 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8309 TypeManager.GetFullNameSignature (pi));
8314 if (accessor == null) {
8315 Report.SymbolRelatedToPreviousError (pi);
8316 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8317 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8322 // Only base will allow this invocation to happen.
8324 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8325 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8328 bool must_do_cs1540_check;
8329 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8331 set = pi.GetSetMethod (true);
8333 get = pi.GetGetMethod (true);
8335 if (set != null && get != null &&
8336 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8337 Report.SymbolRelatedToPreviousError (accessor);
8338 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8339 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8341 Report.SymbolRelatedToPreviousError (pi);
8342 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8346 instance_expr.CheckMarshalByRefAccess (ec);
8347 eclass = ExprClass.IndexerAccess;
8351 public void Emit (EmitContext ec, bool leave_copy)
8354 prepared_value.Emit (ec);
8356 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8357 arguments, loc, false, false);
8361 ec.ig.Emit (OpCodes.Dup);
8362 temp = new LocalTemporary (Type);
8368 // source is ignored, because we already have a copy of it from the
8369 // LValue resolution and we have already constructed a pre-cached
8370 // version of the arguments (ea.set_arguments);
8372 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8374 prepared = prepare_for_load;
8375 Expression value = set_expr;
8378 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8379 arguments, loc, true, false);
8381 prepared_value = new LocalTemporary (type);
8382 prepared_value.Store (ec);
8384 prepared_value.Release (ec);
8387 ec.ig.Emit (OpCodes.Dup);
8388 temp = new LocalTemporary (Type);
8391 } else if (leave_copy) {
8392 temp = new LocalTemporary (Type);
8398 arguments.Add (new Argument (value, Argument.AType.Expression));
8399 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8407 public override void Emit (EmitContext ec)
8412 public override string GetSignatureForError ()
8414 return TypeManager.CSharpSignature (get != null ? get : set, false);
8417 protected override void CloneTo (CloneContext clonectx, Expression t)
8419 IndexerAccess target = (IndexerAccess) t;
8421 if (arguments != null){
8422 target.arguments = new ArrayList ();
8423 foreach (Argument a in arguments)
8424 target.arguments.Add (a.Clone (clonectx));
8426 if (instance_expr != null)
8427 target.instance_expr = instance_expr.Clone (clonectx);
8432 /// The base operator for method names
8434 public class BaseAccess : Expression {
8435 public readonly string Identifier;
8438 public BaseAccess (string member, Location l)
8440 this.Identifier = member;
8444 public BaseAccess (string member, TypeArguments args, Location l)
8450 public override Expression CreateExpressionTree (EmitContext ec)
8452 throw new NotSupportedException ("ET");
8455 public override Expression DoResolve (EmitContext ec)
8457 Expression c = CommonResolve (ec);
8463 // MethodGroups use this opportunity to flag an error on lacking ()
8465 if (!(c is MethodGroupExpr))
8466 return c.Resolve (ec);
8470 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8472 Expression c = CommonResolve (ec);
8478 // MethodGroups use this opportunity to flag an error on lacking ()
8480 if (! (c is MethodGroupExpr))
8481 return c.DoResolveLValue (ec, right_side);
8486 Expression CommonResolve (EmitContext ec)
8488 Expression member_lookup;
8489 Type current_type = ec.ContainerType;
8490 Type base_type = current_type.BaseType;
8493 Error (1511, "Keyword `base' is not available in a static method");
8497 if (ec.IsInFieldInitializer){
8498 Error (1512, "Keyword `base' is not available in the current context");
8502 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8503 AllMemberTypes, AllBindingFlags, loc);
8504 if (member_lookup == null) {
8505 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8506 null, AllMemberTypes, AllBindingFlags);
8513 left = new TypeExpression (base_type, loc);
8515 left = ec.GetThis (loc);
8517 MemberExpr me = (MemberExpr) member_lookup;
8518 me = me.ResolveMemberAccess (ec, left, loc, null);
8525 me.SetTypeArguments (args);
8531 public override void Emit (EmitContext ec)
8533 throw new Exception ("Should never be called");
8536 protected override void CloneTo (CloneContext clonectx, Expression t)
8538 BaseAccess target = (BaseAccess) t;
8541 target.args = args.Clone ();
8546 /// The base indexer operator
8548 public class BaseIndexerAccess : IndexerAccess {
8549 public BaseIndexerAccess (ArrayList args, Location loc)
8550 : base (null, true, loc)
8552 arguments = new ArrayList ();
8553 foreach (Expression tmp in args)
8554 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8557 protected override bool CommonResolve (EmitContext ec)
8559 instance_expr = ec.GetThis (loc);
8561 current_type = ec.ContainerType.BaseType;
8562 indexer_type = current_type;
8564 foreach (Argument a in arguments){
8565 if (!a.Resolve (ec, loc))
8572 public override Expression CreateExpressionTree (EmitContext ec)
8574 MemberExpr.Error_BaseAccessInExpressionTree (loc);
8575 return base.CreateExpressionTree (ec);
8580 /// This class exists solely to pass the Type around and to be a dummy
8581 /// that can be passed to the conversion functions (this is used by
8582 /// foreach implementation to typecast the object return value from
8583 /// get_Current into the proper type. All code has been generated and
8584 /// we only care about the side effect conversions to be performed
8586 /// This is also now used as a placeholder where a no-action expression
8587 /// is needed (the `New' class).
8589 public class EmptyExpression : Expression {
8590 public static readonly EmptyExpression Null = new EmptyExpression ();
8592 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8593 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8594 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8596 static EmptyExpression temp = new EmptyExpression ();
8597 public static EmptyExpression Grab ()
8599 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8604 public static void Release (EmptyExpression e)
8609 // TODO: should be protected
8610 public EmptyExpression ()
8612 type = TypeManager.object_type;
8613 eclass = ExprClass.Value;
8614 loc = Location.Null;
8617 public EmptyExpression (Type t)
8620 eclass = ExprClass.Value;
8621 loc = Location.Null;
8624 public override Expression CreateExpressionTree (EmitContext ec)
8626 throw new NotSupportedException ("ET");
8629 public override Expression DoResolve (EmitContext ec)
8634 public override void Emit (EmitContext ec)
8636 // nothing, as we only exist to not do anything.
8639 public override void EmitSideEffect (EmitContext ec)
8644 // This is just because we might want to reuse this bad boy
8645 // instead of creating gazillions of EmptyExpressions.
8646 // (CanImplicitConversion uses it)
8648 public void SetType (Type t)
8655 // Empty statement expression
8657 public sealed class EmptyExpressionStatement : ExpressionStatement
8659 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8661 private EmptyExpressionStatement ()
8663 type = TypeManager.object_type;
8664 eclass = ExprClass.Value;
8665 loc = Location.Null;
8668 public override Expression CreateExpressionTree (EmitContext ec)
8673 public override void EmitStatement (EmitContext ec)
8678 public override Expression DoResolve (EmitContext ec)
8683 public override void Emit (EmitContext ec)
8689 public class UserCast : Expression {
8693 public UserCast (MethodInfo method, Expression source, Location l)
8695 this.method = method;
8696 this.source = source;
8697 type = TypeManager.TypeToCoreType (method.ReturnType);
8698 eclass = ExprClass.Value;
8702 public Expression Source {
8708 public override Expression CreateExpressionTree (EmitContext ec)
8710 ArrayList args = new ArrayList (3);
8711 args.Add (new Argument (source.CreateExpressionTree (ec)));
8712 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8713 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8714 return CreateExpressionFactoryCall ("Convert", args);
8717 public override Expression DoResolve (EmitContext ec)
8720 // We are born fully resolved
8725 public override void Emit (EmitContext ec)
8728 ec.ig.Emit (OpCodes.Call, method);
8733 // This class is used to "construct" the type during a typecast
8734 // operation. Since the Type.GetType class in .NET can parse
8735 // the type specification, we just use this to construct the type
8736 // one bit at a time.
8738 public class ComposedCast : TypeExpr {
8739 FullNamedExpression left;
8742 public ComposedCast (FullNamedExpression left, string dim)
8743 : this (left, dim, left.Location)
8747 public ComposedCast (FullNamedExpression left, string dim, Location l)
8754 public Expression RemoveNullable ()
8756 if (dim.EndsWith ("?")) {
8757 dim = dim.Substring (0, dim.Length - 1);
8758 if (dim.Length == 0)
8765 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8767 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8771 Type ltype = lexpr.Type;
8772 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8773 Error_VoidInvalidInTheContext (loc);
8778 if ((dim.Length > 0) && (dim [0] == '?')) {
8779 TypeExpr nullable = new Nullable.NullableType (left, loc);
8781 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8782 return nullable.ResolveAsTypeTerminal (ec, false);
8786 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8789 if (dim != "" && dim [0] == '[' &&
8790 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8791 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8796 type = TypeManager.GetConstructedType (ltype, dim);
8801 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8803 if (type.IsPointer && !ec.IsInUnsafeScope){
8808 eclass = ExprClass.Type;
8812 public override string GetSignatureForError ()
8814 return left.GetSignatureForError () + dim;
8817 protected override void CloneTo (CloneContext clonectx, Expression t)
8819 ComposedCast target = (ComposedCast) t;
8821 target.left = (FullNamedExpression)left.Clone (clonectx);
8825 public class FixedBufferPtr : Expression {
8828 public FixedBufferPtr (Expression array, Type array_type, Location l)
8833 type = TypeManager.GetPointerType (array_type);
8834 eclass = ExprClass.Value;
8837 public override Expression CreateExpressionTree (EmitContext ec)
8839 Error_PointerInsideExpressionTree ();
8843 public override void Emit(EmitContext ec)
8848 public override Expression DoResolve (EmitContext ec)
8851 // We are born fully resolved
8859 // This class is used to represent the address of an array, used
8860 // only by the Fixed statement, this generates "&a [0]" construct
8861 // for fixed (char *pa = a)
8863 public class ArrayPtr : FixedBufferPtr {
8866 public ArrayPtr (Expression array, Type array_type, Location l):
8867 base (array, array_type, l)
8869 this.array_type = array_type;
8872 public override void Emit (EmitContext ec)
8876 ILGenerator ig = ec.ig;
8877 IntLiteral.EmitInt (ig, 0);
8878 ig.Emit (OpCodes.Ldelema, array_type);
8883 // Encapsulates a conversion rules required for array indexes
8885 public class ArrayIndexCast : TypeCast
8887 public ArrayIndexCast (Expression expr)
8888 : base (expr, expr.Type)
8892 public override Expression CreateExpressionTree (EmitContext ec)
8894 ArrayList args = new ArrayList (2);
8895 args.Add (new Argument (child.CreateExpressionTree (ec)));
8896 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8897 return CreateExpressionFactoryCall ("ConvertChecked", args);
8900 public override void Emit (EmitContext ec)
8904 if (type == TypeManager.int32_type)
8907 if (type == TypeManager.uint32_type)
8908 ec.ig.Emit (OpCodes.Conv_U);
8909 else if (type == TypeManager.int64_type)
8910 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8911 else if (type == TypeManager.uint64_type)
8912 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8914 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8919 // Implements the `stackalloc' keyword
8921 public class StackAlloc : Expression {
8926 public StackAlloc (Expression type, Expression count, Location l)
8933 public override Expression CreateExpressionTree (EmitContext ec)
8935 throw new NotSupportedException ("ET");
8938 public override Expression DoResolve (EmitContext ec)
8940 count = count.Resolve (ec);
8944 if (count.Type != TypeManager.int32_type){
8945 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8950 Constant c = count as Constant;
8951 if (c != null && c.IsNegative) {
8952 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8956 if (ec.InCatch || ec.InFinally) {
8957 Error (255, "Cannot use stackalloc in finally or catch");
8961 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8967 if (!TypeManager.VerifyUnManaged (otype, loc))
8970 type = TypeManager.GetPointerType (otype);
8971 eclass = ExprClass.Value;
8976 public override void Emit (EmitContext ec)
8978 int size = GetTypeSize (otype);
8979 ILGenerator ig = ec.ig;
8982 ig.Emit (OpCodes.Sizeof, otype);
8984 IntConstant.EmitInt (ig, size);
8986 ig.Emit (OpCodes.Mul);
8987 ig.Emit (OpCodes.Localloc);
8990 protected override void CloneTo (CloneContext clonectx, Expression t)
8992 StackAlloc target = (StackAlloc) t;
8993 target.count = count.Clone (clonectx);
8994 target.t = t.Clone (clonectx);
8999 // An object initializer expression
9001 public class ElementInitializer : Assign
9003 public readonly string Name;
9005 public ElementInitializer (string name, Expression initializer, Location loc)
9006 : base (null, initializer, loc)
9011 protected override void CloneTo (CloneContext clonectx, Expression t)
9013 ElementInitializer target = (ElementInitializer) t;
9014 target.source = source.Clone (clonectx);
9017 public override Expression CreateExpressionTree (EmitContext ec)
9019 ArrayList args = new ArrayList (2);
9020 FieldExpr fe = target as FieldExpr;
9022 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9024 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9026 args.Add (new Argument (source.CreateExpressionTree (ec)));
9027 return CreateExpressionFactoryCall (
9028 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9032 public override Expression DoResolve (EmitContext ec)
9035 return EmptyExpressionStatement.Instance;
9037 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9038 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9044 me.InstanceExpression = ec.CurrentInitializerVariable;
9046 if (source is CollectionOrObjectInitializers) {
9047 Expression previous = ec.CurrentInitializerVariable;
9048 ec.CurrentInitializerVariable = target;
9049 source = source.Resolve (ec);
9050 ec.CurrentInitializerVariable = previous;
9054 eclass = source.eclass;
9059 Expression expr = base.DoResolve (ec);
9064 // Ignore field initializers with default value
9066 Constant c = source as Constant;
9067 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9068 return EmptyExpressionStatement.Instance;
9073 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9075 MemberInfo member = members [0];
9076 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9077 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9078 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9080 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9081 TypeManager.GetFullNameSignature (member));
9086 public override void EmitStatement (EmitContext ec)
9088 if (source is CollectionOrObjectInitializers)
9091 base.EmitStatement (ec);
9096 // A collection initializer expression
9098 public class CollectionElementInitializer : Invocation
9100 public class ElementInitializerArgument : Argument
9102 public ElementInitializerArgument (Expression e)
9108 public CollectionElementInitializer (Expression argument)
9109 : base (null, new ArrayList (1), true)
9111 Arguments.Add (argument);
9112 this.loc = argument.Location;
9115 public CollectionElementInitializer (ArrayList arguments, Location loc)
9116 : base (null, arguments, true)
9121 public override Expression CreateExpressionTree (EmitContext ec)
9123 ArrayList args = new ArrayList (2);
9124 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9126 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9127 foreach (Argument a in Arguments)
9128 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9130 args.Add (new Argument (new ArrayCreation (
9131 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9132 return CreateExpressionFactoryCall ("ElementInit", args);
9135 protected override void CloneTo (CloneContext clonectx, Expression t)
9137 CollectionElementInitializer target = (CollectionElementInitializer) t;
9139 target.Arguments = new ArrayList (Arguments.Count);
9140 foreach (Expression e in Arguments)
9141 target.Arguments.Add (e.Clone (clonectx));
9144 public override Expression DoResolve (EmitContext ec)
9146 if (eclass != ExprClass.Invalid)
9149 // TODO: We could call a constructor which takes element count argument,
9150 // for known types like List<T>, Dictionary<T, U>
9152 for (int i = 0; i < Arguments.Count; ++i) {
9153 Expression expr = ((Expression) Arguments [i]).Resolve (ec);
9157 Arguments [i] = new ElementInitializerArgument (expr);
9160 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9162 return base.DoResolve (ec);
9167 // A block of object or collection initializers
9169 public class CollectionOrObjectInitializers : ExpressionStatement
9171 ArrayList initializers;
9173 public static readonly CollectionOrObjectInitializers Empty =
9174 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9176 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9178 this.initializers = initializers;
9182 public bool IsEmpty {
9184 return initializers.Count == 0;
9188 public bool IsCollectionInitializer {
9190 return type == typeof (CollectionOrObjectInitializers);
9194 protected override void CloneTo (CloneContext clonectx, Expression target)
9196 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9198 t.initializers = new ArrayList (initializers.Count);
9199 foreach (Expression e in initializers)
9200 t.initializers.Add (e.Clone (clonectx));
9203 public override Expression CreateExpressionTree (EmitContext ec)
9205 ArrayList expr_initializers = new ArrayList (initializers.Count);
9206 foreach (Expression e in initializers) {
9207 Expression expr = e.CreateExpressionTree (ec);
9209 expr_initializers.Add (expr);
9212 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9215 public override Expression DoResolve (EmitContext ec)
9217 if (eclass != ExprClass.Invalid)
9220 bool is_elements_initialization = false;
9221 ArrayList element_names = null;
9222 for (int i = 0; i < initializers.Count; ++i) {
9223 Expression initializer = (Expression) initializers [i];
9224 ElementInitializer element_initializer = initializer as ElementInitializer;
9227 if (element_initializer != null) {
9228 is_elements_initialization = true;
9229 element_names = new ArrayList (initializers.Count);
9230 element_names.Add (element_initializer.Name);
9232 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9233 TypeManager.ienumerable_type)) {
9234 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9235 "object initializer because type `{1}' does not implement `{2}' interface",
9236 ec.CurrentInitializerVariable.GetSignatureForError (),
9237 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9238 TypeManager.CSharpName (TypeManager.ienumerable_type));
9243 if (is_elements_initialization == (element_initializer == null)) {
9244 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9245 is_elements_initialization ? "object initializer" : "collection initializer");
9249 if (is_elements_initialization) {
9250 if (element_names.Contains (element_initializer.Name)) {
9251 Report.Error (1912, element_initializer.Location,
9252 "An object initializer includes more than one member `{0}' initialization",
9253 element_initializer.Name);
9255 element_names.Add (element_initializer.Name);
9260 Expression e = initializer.Resolve (ec);
9261 if (e == EmptyExpressionStatement.Instance)
9262 initializers.RemoveAt (i--);
9264 initializers [i] = e;
9267 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9268 eclass = ExprClass.Variable;
9272 public override void Emit (EmitContext ec)
9277 public override void EmitStatement (EmitContext ec)
9279 foreach (ExpressionStatement e in initializers)
9280 e.EmitStatement (ec);
9285 // New expression with element/object initializers
9287 public class NewInitialize : New
9290 // This class serves as a proxy for variable initializer target instances.
9291 // A real variable is assigned later when we resolve left side of an
9294 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9296 NewInitialize new_instance;
9298 public InitializerTargetExpression (NewInitialize newInstance)
9300 this.type = newInstance.type;
9301 this.loc = newInstance.loc;
9302 this.eclass = newInstance.eclass;
9303 this.new_instance = newInstance;
9306 public override Expression CreateExpressionTree (EmitContext ec)
9308 // Should not be reached
9309 throw new NotSupportedException ("ET");
9312 public override Expression DoResolve (EmitContext ec)
9317 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9322 public override void Emit (EmitContext ec)
9324 new_instance.value_target.Emit (ec);
9327 #region IMemoryLocation Members
9329 public void AddressOf (EmitContext ec, AddressOp mode)
9331 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9337 CollectionOrObjectInitializers initializers;
9339 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9340 : base (requested_type, arguments, l)
9342 this.initializers = initializers;
9345 protected override void CloneTo (CloneContext clonectx, Expression t)
9347 base.CloneTo (clonectx, t);
9349 NewInitialize target = (NewInitialize) t;
9350 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9353 public override Expression CreateExpressionTree (EmitContext ec)
9355 ArrayList args = new ArrayList (2);
9356 args.Add (new Argument (base.CreateExpressionTree (ec)));
9357 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9359 return CreateExpressionFactoryCall (
9360 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9364 public override Expression DoResolve (EmitContext ec)
9366 if (eclass != ExprClass.Invalid)
9369 Expression e = base.DoResolve (ec);
9373 // Empty initializer can be optimized to simple new
9374 if (initializers.IsEmpty)
9377 Expression previous = ec.CurrentInitializerVariable;
9378 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9379 initializers.Resolve (ec);
9380 ec.CurrentInitializerVariable = previous;
9384 public override void Emit (EmitContext ec)
9389 // If target is a value, let's use it
9391 VariableReference variable = value_target as VariableReference;
9392 if (variable != null) {
9394 StoreFromPtr (ec.ig, type);
9396 variable.Variable.EmitAssign (ec);
9398 if (value_target == null || value_target_set)
9399 value_target = new LocalTemporary (type);
9401 ((LocalTemporary) value_target).Store (ec);
9404 initializers.Emit (ec);
9406 if (variable == null)
9407 value_target.Emit (ec);
9410 public override void EmitStatement (EmitContext ec)
9412 if (initializers.IsEmpty) {
9413 base.EmitStatement (ec);
9419 if (value_target == null) {
9420 LocalTemporary variable = new LocalTemporary (type);
9421 variable.Store (ec);
9422 value_target = variable;
9425 initializers.EmitStatement (ec);
9428 public override bool HasInitializer {
9430 return !initializers.IsEmpty;
9435 public class AnonymousTypeDeclaration : Expression
9437 ArrayList parameters;
9438 readonly TypeContainer parent;
9439 static readonly ArrayList EmptyParameters = new ArrayList (0);
9441 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9443 this.parameters = parameters;
9444 this.parent = parent;
9448 protected override void CloneTo (CloneContext clonectx, Expression target)
9450 if (parameters == null)
9453 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9454 t.parameters = new ArrayList (parameters.Count);
9455 foreach (AnonymousTypeParameter atp in parameters)
9456 t.parameters.Add (atp.Clone (clonectx));
9459 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9461 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9465 type = AnonymousTypeClass.Create (parent, parameters, loc);
9470 type.DefineMembers ();
9474 RootContext.ToplevelTypes.AddAnonymousType (type);
9478 public override Expression CreateExpressionTree (EmitContext ec)
9480 throw new NotSupportedException ("ET");
9483 public override Expression DoResolve (EmitContext ec)
9485 AnonymousTypeClass anonymous_type;
9487 if (parameters == null) {
9488 anonymous_type = CreateAnonymousType (EmptyParameters);
9489 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9490 null, loc).Resolve (ec);
9494 ArrayList arguments = new ArrayList (parameters.Count);
9495 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9496 for (int i = 0; i < parameters.Count; ++i) {
9497 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9503 arguments.Add (new Argument (e));
9504 t_args [i] = new TypeExpression (e.Type, e.Location);
9510 anonymous_type = CreateAnonymousType (parameters);
9511 if (anonymous_type == null)
9514 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9515 new TypeArguments (loc, t_args), loc);
9517 return new New (te, arguments, loc).Resolve (ec);
9520 public override void Emit (EmitContext ec)
9522 throw new InternalErrorException ("Should not be reached");
9526 public class AnonymousTypeParameter : Expression
9528 public readonly string Name;
9529 Expression initializer;
9531 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9535 this.initializer = initializer;
9538 public AnonymousTypeParameter (Parameter parameter)
9540 this.Name = parameter.Name;
9541 this.loc = parameter.Location;
9542 this.initializer = new SimpleName (Name, loc);
9545 protected override void CloneTo (CloneContext clonectx, Expression target)
9547 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9548 t.initializer = initializer.Clone (clonectx);
9551 public override Expression CreateExpressionTree (EmitContext ec)
9553 throw new NotSupportedException ("ET");
9556 public override bool Equals (object o)
9558 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9559 return other != null && Name == other.Name;
9562 public override int GetHashCode ()
9564 return Name.GetHashCode ();
9567 public override Expression DoResolve (EmitContext ec)
9569 Expression e = initializer.Resolve (ec);
9574 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9575 type == TypeManager.anonymous_method_type || type.IsPointer) {
9576 Error_InvalidInitializer (e);
9583 protected virtual void Error_InvalidInitializer (Expression initializer)
9585 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9586 Name, initializer.GetSignatureForError ());
9589 public override void Emit (EmitContext ec)
9591 throw new InternalErrorException ("Should not be reached");