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)
106 public override Expression DoResolve (EmitContext ec)
108 Expr = Expr.Resolve (ec);
112 public override void Emit (EmitContext ec)
114 throw new Exception ("Should not happen");
117 public override Location Location
120 return Expr.Location;
124 protected override void CloneTo (CloneContext clonectx, Expression t)
126 ParenthesizedExpression target = (ParenthesizedExpression) t;
128 target.Expr = Expr.Clone (clonectx);
133 // Unary implements unary expressions.
135 public class Unary : Expression {
136 public enum Operator : byte {
137 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
141 public static readonly string [] oper_names;
142 static Type [] [] predefined_operators;
144 public readonly Operator Oper;
145 public Expression Expr;
146 Expression enum_conversion;
148 public Unary (Operator op, Expression expr, Location loc)
157 oper_names = new string [(int)Operator.TOP];
159 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
160 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
161 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
162 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
163 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
167 // This routine will attempt to simplify the unary expression when the
168 // argument is a constant.
170 Constant TryReduceConstant (EmitContext ec, Constant e)
172 if (e is SideEffectConstant) {
173 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
174 return r == null ? null : new SideEffectConstant (r, e, r.Location);
177 Type expr_type = e.Type;
180 case Operator.UnaryPlus:
181 // Unary numeric promotions
182 if (expr_type == TypeManager.byte_type)
183 return new IntConstant (((ByteConstant)e).Value, e.Location);
184 if (expr_type == TypeManager.sbyte_type)
185 return new IntConstant (((SByteConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.short_type)
187 return new IntConstant (((ShortConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.ushort_type)
189 return new IntConstant (((UShortConstant)e).Value, e.Location);
190 if (expr_type == TypeManager.char_type)
191 return new IntConstant (((CharConstant)e).Value, e.Location);
193 // Predefined operators
194 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
195 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
196 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
197 expr_type == TypeManager.decimal_type)
204 case Operator.UnaryNegation:
205 // Unary numeric promotions
206 if (expr_type == TypeManager.byte_type)
207 return new IntConstant (-((ByteConstant)e).Value, e.Location);
208 if (expr_type == TypeManager.sbyte_type)
209 return new IntConstant (-((SByteConstant)e).Value, e.Location);
210 if (expr_type == TypeManager.short_type)
211 return new IntConstant (-((ShortConstant)e).Value, e.Location);
212 if (expr_type == TypeManager.ushort_type)
213 return new IntConstant (-((UShortConstant)e).Value, e.Location);
214 if (expr_type == TypeManager.char_type)
215 return new IntConstant (-((CharConstant)e).Value, e.Location);
217 // Predefined operators
218 if (expr_type == TypeManager.int32_type) {
219 int value = ((IntConstant)e).Value;
220 if (value == int.MinValue) {
221 if (ec.ConstantCheckState) {
222 ConstantFold.Error_CompileTimeOverflow (loc);
227 return new IntConstant (-value, e.Location);
229 if (expr_type == TypeManager.int64_type) {
230 long value = ((LongConstant)e).Value;
231 if (value == long.MinValue) {
232 if (ec.ConstantCheckState) {
233 ConstantFold.Error_CompileTimeOverflow (loc);
238 return new LongConstant (-value, e.Location);
241 if (expr_type == TypeManager.uint32_type) {
242 UIntLiteral uil = e as UIntLiteral;
244 if (uil.Value == 2147483648)
245 return new IntLiteral (int.MinValue, e.Location);
246 return new LongLiteral (-uil.Value, e.Location);
248 return new LongConstant (-((UIntConstant)e).Value, e.Location);
251 if (expr_type == TypeManager.uint64_type) {
252 ULongLiteral ull = e as ULongLiteral;
253 if (ull != null && ull.Value == 9223372036854775808)
254 return new LongLiteral (long.MinValue, e.Location);
258 if (expr_type == TypeManager.float_type) {
259 FloatLiteral fl = e as FloatLiteral;
260 // For better error reporting
262 fl.Value = -fl.Value;
265 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
267 if (expr_type == TypeManager.double_type) {
268 DoubleLiteral dl = e as DoubleLiteral;
269 // For better error reporting
271 dl.Value = -dl.Value;
275 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
277 if (expr_type == TypeManager.decimal_type)
278 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
282 case Operator.LogicalNot:
283 if (expr_type != TypeManager.bool_type)
286 bool b = (bool)e.GetValue ();
287 return new BoolConstant (!b, e.Location);
289 case Operator.OnesComplement:
290 // Unary numeric promotions
291 if (expr_type == TypeManager.byte_type)
292 return new IntConstant (~((ByteConstant)e).Value, e.Location);
293 if (expr_type == TypeManager.sbyte_type)
294 return new IntConstant (~((SByteConstant)e).Value, e.Location);
295 if (expr_type == TypeManager.short_type)
296 return new IntConstant (~((ShortConstant)e).Value, e.Location);
297 if (expr_type == TypeManager.ushort_type)
298 return new IntConstant (~((UShortConstant)e).Value, e.Location);
299 if (expr_type == TypeManager.char_type)
300 return new IntConstant (~((CharConstant)e).Value, e.Location);
302 // Predefined operators
303 if (expr_type == TypeManager.int32_type)
304 return new IntConstant (~((IntConstant)e).Value, e.Location);
305 if (expr_type == TypeManager.uint32_type)
306 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
307 if (expr_type == TypeManager.int64_type)
308 return new LongConstant (~((LongConstant)e).Value, e.Location);
309 if (expr_type == TypeManager.uint64_type){
310 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
312 if (e is EnumConstant) {
313 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
315 e = new EnumConstant (e, expr_type);
320 throw new Exception ("Can not constant fold: " + Oper.ToString());
323 protected Expression ResolveOperator (EmitContext ec, Expression expr)
325 eclass = ExprClass.Value;
327 if (predefined_operators == null)
328 CreatePredefinedOperatorsTable ();
330 Type expr_type = expr.Type;
331 Expression best_expr;
334 // Primitive types first
336 if (TypeManager.IsPrimitiveType (expr_type)) {
337 best_expr = ResolvePrimitivePredefinedType (expr);
338 if (best_expr == null)
341 type = best_expr.Type;
347 // E operator ~(E x);
349 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
350 return ResolveEnumOperator (ec, expr);
352 return ResolveUserType (ec, expr);
355 protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
357 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
358 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
359 if (best_expr == null)
363 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
365 return EmptyCast.Create (this, type);
368 public override Expression CreateExpressionTree (EmitContext ec)
370 return CreateExpressionTree (ec, null);
373 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr user_op)
377 case Operator.UnaryNegation:
378 if (ec.CheckState && user_op == null && !IsFloat (type))
379 method_name = "NegateChecked";
381 method_name = "Negate";
383 case Operator.OnesComplement:
384 case Operator.LogicalNot:
387 case Operator.UnaryPlus:
388 method_name = "UnaryPlus";
391 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
394 ArrayList args = new ArrayList (2);
395 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
397 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
398 return CreateExpressionFactoryCall (method_name, args);
401 static void CreatePredefinedOperatorsTable ()
403 predefined_operators = new Type [(int) Operator.TOP] [];
406 // 7.6.1 Unary plus operator
408 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
409 TypeManager.int32_type, TypeManager.uint32_type,
410 TypeManager.int64_type, TypeManager.uint64_type,
411 TypeManager.float_type, TypeManager.double_type,
412 TypeManager.decimal_type
416 // 7.6.2 Unary minus operator
418 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
419 TypeManager.int32_type,
420 TypeManager.int64_type,
421 TypeManager.float_type, TypeManager.double_type,
422 TypeManager.decimal_type
426 // 7.6.3 Logical negation operator
428 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
429 TypeManager.bool_type
433 // 7.6.4 Bitwise complement operator
435 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
436 TypeManager.int32_type, TypeManager.uint32_type,
437 TypeManager.int64_type, TypeManager.uint64_type
442 // Unary numeric promotions
444 static Expression DoNumericPromotion (Operator op, Expression expr)
446 Type expr_type = expr.Type;
447 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
448 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
449 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
450 expr_type == TypeManager.char_type)
451 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
453 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
454 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
459 public override Expression DoResolve (EmitContext ec)
461 if (Oper == Operator.AddressOf) {
462 Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
464 if (Expr == null || Expr.eclass != ExprClass.Variable){
465 Error (211, "Cannot take the address of the given expression");
469 return ResolveAddressOf (ec);
472 Expr = Expr.Resolve (ec);
476 if (TypeManager.IsNullableValueType (Expr.Type))
477 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
480 // Attempt to use a constant folding operation.
482 Constant cexpr = Expr as Constant;
484 cexpr = TryReduceConstant (ec, cexpr);
489 Expression expr = ResolveOperator (ec, Expr);
491 Error_OperatorCannotBeApplied (loc, OperName (Oper), Expr.Type);
494 // Reduce unary operator on predefined types
496 if (expr == this && Oper == Operator.UnaryPlus)
502 public override Expression DoResolveLValue (EmitContext ec, Expression right)
507 public override void Emit (EmitContext ec)
509 EmitOperator (ec, type);
512 protected void EmitOperator (EmitContext ec, Type type)
514 ILGenerator ig = ec.ig;
517 case Operator.UnaryPlus:
521 case Operator.UnaryNegation:
522 if (ec.CheckState && !IsFloat (type)) {
523 ig.Emit (OpCodes.Ldc_I4_0);
524 if (type == TypeManager.int64_type)
525 ig.Emit (OpCodes.Conv_U8);
527 ig.Emit (OpCodes.Sub_Ovf);
530 ig.Emit (OpCodes.Neg);
535 case Operator.LogicalNot:
537 ig.Emit (OpCodes.Ldc_I4_0);
538 ig.Emit (OpCodes.Ceq);
541 case Operator.OnesComplement:
543 ig.Emit (OpCodes.Not);
546 case Operator.AddressOf:
547 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
551 throw new Exception ("This should not happen: Operator = "
556 // Same trick as in Binary expression
558 if (enum_conversion != null)
559 enum_conversion.Emit (ec);
562 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
564 if (Oper == Operator.LogicalNot)
565 Expr.EmitBranchable (ec, target, !on_true);
567 base.EmitBranchable (ec, target, on_true);
570 public override void EmitSideEffect (EmitContext ec)
572 Expr.EmitSideEffect (ec);
575 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
577 Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
578 oper, TypeManager.CSharpName (t));
581 static bool IsFloat (Type t)
583 return t == TypeManager.float_type || t == TypeManager.double_type;
587 // Returns a stringified representation of the Operator
589 public static string OperName (Operator oper)
592 case Operator.UnaryPlus:
594 case Operator.UnaryNegation:
596 case Operator.LogicalNot:
598 case Operator.OnesComplement:
600 case Operator.AddressOf:
604 throw new NotImplementedException (oper.ToString ());
607 Expression ResolveAddressOf (EmitContext ec)
614 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)) {
618 IVariable variable = Expr as IVariable;
619 bool is_fixed = variable != null && variable.VerifyFixed ();
621 if (!ec.InFixedInitializer && !is_fixed) {
622 Error (212, "You can only take the address of unfixed expression inside " +
623 "of a fixed statement initializer");
627 if (ec.InFixedInitializer && is_fixed) {
628 Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
632 LocalVariableReference lr = Expr as LocalVariableReference;
634 if (lr.local_info.IsCaptured) {
635 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
638 lr.local_info.AddressTaken = true;
639 lr.local_info.Used = true;
642 ParameterReference pr = Expr as ParameterReference;
643 if ((pr != null) && pr.Parameter.IsCaptured) {
644 AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
648 // According to the specs, a variable is considered definitely assigned if you take
650 if ((variable != null) && (variable.VariableInfo != null)) {
651 variable.VariableInfo.SetAssigned (ec);
654 type = TypeManager.GetPointerType (Expr.Type);
655 eclass = ExprClass.Value;
659 Expression ResolvePrimitivePredefinedType (Expression expr)
661 expr = DoNumericPromotion (Oper, expr);
662 Type expr_type = expr.Type;
663 Type[] predefined = predefined_operators [(int) Oper];
664 foreach (Type t in predefined) {
672 // Perform user-operator overload resolution
674 protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
676 string op_name = oper_names [(int) Oper];
677 MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
681 ArrayList args = new ArrayList (1);
682 args.Add (new Argument (expr));
683 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
688 Expr = ((Argument) args [0]).Expr;
689 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
693 // Unary user type overload resolution
695 Expression ResolveUserType (EmitContext ec, Expression expr)
697 Expression best_expr = ResolveUserOperator (ec, expr);
698 if (best_expr != null)
701 Type[] predefined = predefined_operators [(int) Oper];
702 foreach (Type t in predefined) {
703 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false);
704 if (oper_expr == null)
708 // decimal type is predefined but has user-operators
710 if (oper_expr.Type == TypeManager.decimal_type)
711 oper_expr = ResolveUserType (ec, oper_expr);
713 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
715 if (oper_expr == null)
718 if (best_expr == null) {
719 best_expr = oper_expr;
723 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
725 Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
726 OperName (Oper), TypeManager.CSharpName (expr.Type));
731 best_expr = oper_expr;
734 if (best_expr == null)
738 // HACK: Decimal user-operator is included in standard operators
740 if (best_expr.Type == TypeManager.decimal_type)
744 type = best_expr.Type;
748 protected override void CloneTo (CloneContext clonectx, Expression t)
750 Unary target = (Unary) t;
752 target.Expr = Expr.Clone (clonectx);
757 // Unary operators are turned into Indirection expressions
758 // after semantic analysis (this is so we can take the address
759 // of an indirection).
761 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
763 LocalTemporary temporary;
766 public Indirection (Expression expr, Location l)
772 public override void Emit (EmitContext ec)
777 LoadFromPtr (ec.ig, Type);
780 public void Emit (EmitContext ec, bool leave_copy)
784 ec.ig.Emit (OpCodes.Dup);
785 temporary = new LocalTemporary (expr.Type);
786 temporary.Store (ec);
790 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
792 prepared = prepare_for_load;
796 if (prepare_for_load)
797 ec.ig.Emit (OpCodes.Dup);
801 ec.ig.Emit (OpCodes.Dup);
802 temporary = new LocalTemporary (expr.Type);
803 temporary.Store (ec);
806 StoreFromPtr (ec.ig, type);
808 if (temporary != null) {
810 temporary.Release (ec);
814 public void AddressOf (EmitContext ec, AddressOp Mode)
819 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
821 return DoResolve (ec);
824 public override Expression DoResolve (EmitContext ec)
826 expr = expr.Resolve (ec);
833 if (!expr.Type.IsPointer) {
834 Error (193, "The * or -> operator must be applied to a pointer");
838 type = TypeManager.GetElementType (expr.Type);
839 eclass = ExprClass.Variable;
843 public override string ToString ()
845 return "*(" + expr + ")";
848 #region IVariable Members
850 public VariableInfo VariableInfo {
854 public bool VerifyFixed ()
856 // A pointer-indirection is always fixed.
864 /// Unary Mutator expressions (pre and post ++ and --)
868 /// UnaryMutator implements ++ and -- expressions. It derives from
869 /// ExpressionStatement becuase the pre/post increment/decrement
870 /// operators can be used in a statement context.
872 /// FIXME: Idea, we could split this up in two classes, one simpler
873 /// for the common case, and one with the extra fields for more complex
874 /// classes (indexers require temporary access; overloaded require method)
877 public class UnaryMutator : ExpressionStatement {
879 public enum Mode : byte {
886 PreDecrement = IsDecrement,
887 PostIncrement = IsPost,
888 PostDecrement = IsPost | IsDecrement
892 bool is_expr = false;
893 bool recurse = false;
898 // This is expensive for the simplest case.
900 UserOperatorCall method;
902 public UnaryMutator (Mode m, Expression e, Location l)
909 static string OperName (Mode mode)
911 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
916 /// Returns whether an object of type `t' can be incremented
917 /// or decremented with add/sub (ie, basically whether we can
918 /// use pre-post incr-decr operations on it, but it is not a
919 /// System.Decimal, which we require operator overloading to catch)
921 static bool IsIncrementableNumber (Type t)
923 return (t == TypeManager.sbyte_type) ||
924 (t == TypeManager.byte_type) ||
925 (t == TypeManager.short_type) ||
926 (t == TypeManager.ushort_type) ||
927 (t == TypeManager.int32_type) ||
928 (t == TypeManager.uint32_type) ||
929 (t == TypeManager.int64_type) ||
930 (t == TypeManager.uint64_type) ||
931 (t == TypeManager.char_type) ||
932 (TypeManager.IsSubclassOf (t, TypeManager.enum_type)) ||
933 (t == TypeManager.float_type) ||
934 (t == TypeManager.double_type) ||
935 (t.IsPointer && t != TypeManager.void_ptr_type);
938 Expression ResolveOperator (EmitContext ec)
940 Type expr_type = expr.Type;
943 // Step 1: Perform Operator Overload location
948 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
949 op_name = "op_Increment";
951 op_name = "op_Decrement";
953 mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
956 method = UserOperatorCall.MakeSimpleCall (
957 ec, (MethodGroupExpr) mg, expr, loc);
960 } else if (!IsIncrementableNumber (expr_type)) {
961 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
962 TypeManager.CSharpName (expr_type) + "'");
967 // The operand of the prefix/postfix increment decrement operators
968 // should be an expression that is classified as a variable,
969 // a property access or an indexer access
972 if (expr.eclass == ExprClass.Variable){
973 LocalVariableReference var = expr as LocalVariableReference;
974 if ((var != null) && var.IsReadOnly) {
975 Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
978 } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
979 expr = expr.ResolveLValue (ec, this, Location);
983 Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
990 public override Expression CreateExpressionTree (EmitContext ec)
992 return new SimpleAssign (this, this).CreateExpressionTree (ec);
995 public override Expression DoResolve (EmitContext ec)
997 expr = expr.Resolve (ec);
1002 eclass = ExprClass.Value;
1005 if (TypeManager.IsNullableValueType (expr.Type))
1006 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1009 return ResolveOperator (ec);
1013 // Loads the proper "1" into the stack based on the type, then it emits the
1014 // opcode for the operation requested
1016 void LoadOneAndEmitOp (EmitContext ec, Type t)
1019 // Measure if getting the typecode and using that is more/less efficient
1020 // that comparing types. t.GetTypeCode() is an internal call.
1022 ILGenerator ig = ec.ig;
1024 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
1025 LongConstant.EmitLong (ig, 1);
1026 else if (t == TypeManager.double_type)
1027 ig.Emit (OpCodes.Ldc_R8, 1.0);
1028 else if (t == TypeManager.float_type)
1029 ig.Emit (OpCodes.Ldc_R4, 1.0F);
1030 else if (t.IsPointer){
1031 Type et = TypeManager.GetElementType (t);
1032 int n = GetTypeSize (et);
1035 ig.Emit (OpCodes.Sizeof, et);
1037 IntConstant.EmitInt (ig, n);
1039 ig.Emit (OpCodes.Ldc_I4_1);
1042 // Now emit the operation
1045 if (t == TypeManager.int32_type ||
1046 t == TypeManager.int64_type){
1047 if ((mode & Mode.IsDecrement) != 0)
1048 ig.Emit (OpCodes.Sub_Ovf);
1050 ig.Emit (OpCodes.Add_Ovf);
1051 } else if (t == TypeManager.uint32_type ||
1052 t == TypeManager.uint64_type){
1053 if ((mode & Mode.IsDecrement) != 0)
1054 ig.Emit (OpCodes.Sub_Ovf_Un);
1056 ig.Emit (OpCodes.Add_Ovf_Un);
1058 if ((mode & Mode.IsDecrement) != 0)
1059 ig.Emit (OpCodes.Sub_Ovf);
1061 ig.Emit (OpCodes.Add_Ovf);
1064 if ((mode & Mode.IsDecrement) != 0)
1065 ig.Emit (OpCodes.Sub);
1067 ig.Emit (OpCodes.Add);
1070 if (t == TypeManager.sbyte_type){
1072 ig.Emit (OpCodes.Conv_Ovf_I1);
1074 ig.Emit (OpCodes.Conv_I1);
1075 } else if (t == TypeManager.byte_type){
1077 ig.Emit (OpCodes.Conv_Ovf_U1);
1079 ig.Emit (OpCodes.Conv_U1);
1080 } else if (t == TypeManager.short_type){
1082 ig.Emit (OpCodes.Conv_Ovf_I2);
1084 ig.Emit (OpCodes.Conv_I2);
1085 } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
1087 ig.Emit (OpCodes.Conv_Ovf_U2);
1089 ig.Emit (OpCodes.Conv_U2);
1094 void EmitCode (EmitContext ec, bool is_expr)
1097 this.is_expr = is_expr;
1098 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1101 public override void Emit (EmitContext ec)
1104 // We use recurse to allow ourselfs to be the source
1105 // of an assignment. This little hack prevents us from
1106 // having to allocate another expression
1109 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1111 LoadOneAndEmitOp (ec, expr.Type);
1113 ec.ig.Emit (OpCodes.Call, (MethodInfo)method.Method);
1118 EmitCode (ec, true);
1121 public override void EmitStatement (EmitContext ec)
1123 EmitCode (ec, false);
1126 protected override void CloneTo (CloneContext clonectx, Expression t)
1128 UnaryMutator target = (UnaryMutator) t;
1130 target.expr = expr.Clone (clonectx);
1135 /// Base class for the `Is' and `As' classes.
1139 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1142 public abstract class Probe : Expression {
1143 public Expression ProbeType;
1144 protected Expression expr;
1145 protected TypeExpr probe_type_expr;
1147 public Probe (Expression expr, Expression probe_type, Location l)
1149 ProbeType = probe_type;
1154 public Expression Expr {
1160 public override Expression DoResolve (EmitContext ec)
1162 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1163 if (probe_type_expr == null)
1166 expr = expr.Resolve (ec);
1170 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1171 Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1176 if (expr.Type == TypeManager.anonymous_method_type) {
1177 Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1185 protected abstract string OperatorName { get; }
1187 protected override void CloneTo (CloneContext clonectx, Expression t)
1189 Probe target = (Probe) t;
1191 target.expr = expr.Clone (clonectx);
1192 target.ProbeType = ProbeType.Clone (clonectx);
1198 /// Implementation of the `is' operator.
1200 public class Is : Probe {
1201 public Is (Expression expr, Expression probe_type, Location l)
1202 : base (expr, probe_type, l)
1206 public override Expression CreateExpressionTree (EmitContext ec)
1208 ArrayList args = new ArrayList (2);
1209 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1210 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1211 return CreateExpressionFactoryCall ("TypeIs", args);
1214 public override void Emit (EmitContext ec)
1216 ILGenerator ig = ec.ig;
1219 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1220 ig.Emit (OpCodes.Ldnull);
1221 ig.Emit (OpCodes.Cgt_Un);
1224 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1226 ILGenerator ig = ec.ig;
1229 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1230 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1233 Expression CreateConstantResult (bool result)
1236 Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1237 TypeManager.CSharpName (probe_type_expr.Type));
1239 Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1240 TypeManager.CSharpName (probe_type_expr.Type));
1242 return ReducedExpression.Create (new BoolConstant (result, loc), this);
1245 public override Expression DoResolve (EmitContext ec)
1247 if (base.DoResolve (ec) == null)
1251 bool d_is_nullable = false;
1253 if (expr is Constant) {
1255 // If E is a method group or the null literal, of if the type of E is a reference
1256 // type or a nullable type and the value of E is null, the result is false
1259 return CreateConstantResult (false);
1260 } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1261 d = TypeManager.GetTypeArguments (d) [0];
1262 d_is_nullable = true;
1265 type = TypeManager.bool_type;
1266 eclass = ExprClass.Value;
1267 Type t = probe_type_expr.Type;
1268 bool t_is_nullable = false;
1269 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1270 t = TypeManager.GetTypeArguments (t) [0];
1271 t_is_nullable = true;
1274 if (t.IsValueType) {
1277 // D and T are the same value types but D can be null
1279 if (d_is_nullable && !t_is_nullable)
1280 return Nullable.HasValue.Create (expr, ec);
1283 // The result is true if D and T are the same value types
1285 return CreateConstantResult (true);
1288 if (TypeManager.IsGenericParameter (d))
1289 return ResolveGenericParameter (t, d);
1292 // An unboxing conversion exists
1294 if (Convert.ExplicitReferenceConversionExists (d, t))
1297 if (TypeManager.IsGenericParameter (t))
1298 return ResolveGenericParameter (d, t);
1300 if (d.IsValueType) {
1302 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1303 return CreateConstantResult (true);
1305 if (TypeManager.IsGenericParameter (d))
1306 return ResolveGenericParameter (t, d);
1308 if (TypeManager.ContainsGenericParameters (d))
1311 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1312 Convert.ExplicitReferenceConversionExists (d, t)) {
1318 return CreateConstantResult (false);
1321 Expression ResolveGenericParameter (Type d, Type t)
1324 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1325 if (constraints != null) {
1326 if (constraints.IsReferenceType && d.IsValueType)
1327 return CreateConstantResult (false);
1329 if (constraints.IsValueType && !d.IsValueType)
1330 return CreateConstantResult (false);
1333 expr = new BoxedCast (expr, d);
1340 protected override string OperatorName {
1341 get { return "is"; }
1346 /// Implementation of the `as' operator.
1348 public class As : Probe {
1350 Expression resolved_type;
1352 public As (Expression expr, Expression probe_type, Location l)
1353 : base (expr, probe_type, l)
1357 public override Expression CreateExpressionTree (EmitContext ec)
1359 ArrayList args = new ArrayList (2);
1360 args.Add (new Argument (expr.CreateExpressionTree (ec)));
1361 args.Add (new Argument (new TypeOf (probe_type_expr, loc)));
1362 return CreateExpressionFactoryCall ("TypeAs", args);
1365 public override void Emit (EmitContext ec)
1367 ILGenerator ig = ec.ig;
1372 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1375 if (TypeManager.IsNullableType (type))
1376 ig.Emit (OpCodes.Unbox_Any, type);
1380 static void Error_CannotConvertType (Type source, Type target, Location loc)
1382 Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1383 TypeManager.CSharpName (source),
1384 TypeManager.CSharpName (target));
1387 public override Expression DoResolve (EmitContext ec)
1389 if (resolved_type == null) {
1390 resolved_type = base.DoResolve (ec);
1392 if (resolved_type == null)
1396 type = probe_type_expr.Type;
1397 eclass = ExprClass.Value;
1398 Type etype = expr.Type;
1400 if (type.IsValueType && !TypeManager.IsNullableType (type)) {
1401 Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
1402 TypeManager.CSharpName (type));
1409 // If the type is a type parameter, ensure
1410 // that it is constrained by a class
1412 TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
1414 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
1417 if (constraints == null)
1420 if (!constraints.HasClassConstraint)
1421 if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
1425 Report.Error (413, loc,
1426 "The as operator requires that the `{0}' type parameter be constrained by a class",
1427 probe_type_expr.GetSignatureForError ());
1432 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1433 return Nullable.LiftedNull.CreateFromExpression (this);
1436 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1443 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1444 if (TypeManager.IsGenericParameter (etype))
1445 expr = new BoxedCast (expr, etype);
1451 if (TypeManager.ContainsGenericParameters (etype) ||
1452 TypeManager.ContainsGenericParameters (type)) {
1453 expr = new BoxedCast (expr, etype);
1458 Error_CannotConvertType (etype, type, loc);
1462 protected override string OperatorName {
1463 get { return "as"; }
1466 public override bool GetAttributableValue (Type value_type, out object value)
1468 return expr.GetAttributableValue (value_type, out value);
1473 /// This represents a typecast in the source language.
1475 /// FIXME: Cast expressions have an unusual set of parsing
1476 /// rules, we need to figure those out.
1478 public class Cast : Expression {
1479 Expression target_type;
1482 public Cast (Expression cast_type, Expression expr)
1483 : this (cast_type, expr, cast_type.Location)
1487 public Cast (Expression cast_type, Expression expr, Location loc)
1489 this.target_type = cast_type;
1493 if (target_type == TypeManager.system_void_expr)
1494 Error_VoidInvalidInTheContext (loc);
1497 public Expression TargetType {
1498 get { return target_type; }
1501 public Expression Expr {
1502 get { return expr; }
1505 public override Expression DoResolve (EmitContext ec)
1507 expr = expr.Resolve (ec);
1511 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1517 if (type.IsAbstract && type.IsSealed) {
1518 Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1522 eclass = ExprClass.Value;
1524 Constant c = expr as Constant;
1526 c = c.TryReduce (ec, type, loc);
1531 if (type.IsPointer && !ec.InUnsafe) {
1535 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1539 public override void Emit (EmitContext ec)
1541 throw new Exception ("Should not happen");
1544 protected override void CloneTo (CloneContext clonectx, Expression t)
1546 Cast target = (Cast) t;
1548 target.target_type = target_type.Clone (clonectx);
1549 target.expr = expr.Clone (clonectx);
1554 // C# 2.0 Default value expression
1556 public class DefaultValueExpression : Expression
1560 public DefaultValueExpression (Expression expr, Location loc)
1566 public override Expression CreateExpressionTree (EmitContext ec)
1568 ArrayList args = new ArrayList (2);
1569 args.Add (new Argument (this));
1570 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1571 return CreateExpressionFactoryCall ("Constant", args);
1574 public override Expression DoResolve (EmitContext ec)
1576 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1582 if (type == TypeManager.void_type) {
1583 Error_VoidInvalidInTheContext (loc);
1587 if (TypeManager.IsGenericParameter (type)) {
1588 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
1589 if (constraints != null && constraints.IsReferenceType)
1590 return new EmptyConstantCast (new NullLiteral (Location), type);
1592 Constant c = New.Constantify (type);
1594 return new EmptyConstantCast (c, type);
1596 if (!TypeManager.IsValueType (type))
1597 return new EmptyConstantCast (new NullLiteral (Location), type);
1599 eclass = ExprClass.Variable;
1603 public override void Emit (EmitContext ec)
1605 LocalTemporary temp_storage = new LocalTemporary(type);
1607 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1608 ec.ig.Emit(OpCodes.Initobj, type);
1609 temp_storage.Emit(ec);
1612 protected override void CloneTo (CloneContext clonectx, Expression t)
1614 DefaultValueExpression target = (DefaultValueExpression) t;
1616 target.expr = expr.Clone (clonectx);
1621 /// Binary operators
1623 public class Binary : Expression {
1625 protected class PredefinedOperator {
1626 protected readonly Type left;
1627 protected readonly Type right;
1628 public readonly Operator OperatorsMask;
1629 public Type ReturnType;
1631 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1632 : this (ltype, rtype, op_mask, ltype)
1636 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1637 : this (type, type, op_mask, return_type)
1641 public PredefinedOperator (Type type, Operator op_mask)
1642 : this (type, type, op_mask, type)
1646 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1648 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1649 throw new InternalErrorException ("Only masked values can be used");
1653 this.OperatorsMask = op_mask;
1654 this.ReturnType = return_type;
1657 public virtual Expression ConvertResult (EmitContext ec, Binary b)
1659 b.type = ReturnType;
1662 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1665 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1670 public bool IsPrimitiveApplicable (Type type)
1673 // We are dealing with primitive types only
1675 return left == type;
1678 public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1680 if (TypeManager.IsEqual (left, lexpr.Type) &&
1681 TypeManager.IsEqual (right, rexpr.Type))
1684 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1685 Convert.ImplicitConversionExists (ec, rexpr, right);
1688 public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
1691 if (left != null && best_operator.left != null) {
1692 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1696 // When second arguments are same as the first one, the result is same
1698 if (left != right || best_operator.left != best_operator.right) {
1699 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1702 if (result == 0 || result > 2)
1705 return result == 1 ? best_operator : this;
1709 class PredefinedStringOperator : PredefinedOperator {
1710 public PredefinedStringOperator (Type type, Operator op_mask)
1711 : base (type, op_mask, type)
1713 ReturnType = TypeManager.string_type;
1716 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1717 : base (ltype, rtype, op_mask)
1719 ReturnType = TypeManager.string_type;
1722 public override Expression ConvertResult (EmitContext ec, Binary b)
1725 // Use original expression for nullable arguments
1727 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1729 b.left = unwrap.Original;
1731 unwrap = b.right as Nullable.Unwrap;
1733 b.right = unwrap.Original;
1735 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1736 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1739 // Start a new concat expression using converted expression
1741 return new StringConcat (ec, b.loc, b.left, b.right).Resolve (ec);
1745 class PredefinedShiftOperator : PredefinedOperator {
1746 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1747 base (ltype, TypeManager.int32_type, op_mask)
1751 public override Expression ConvertResult (EmitContext ec, Binary b)
1753 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1755 Expression expr_tree_expr = EmptyCast.Create (b.right, TypeManager.int32_type);
1757 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1760 // b = b.left >> b.right & (0x1f|0x3f)
1762 b.right = new Binary (Operator.BitwiseAnd,
1763 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1766 // Expression tree representation does not use & mask
1768 b.right = ReducedExpression.Create (b.right, expr_tree_expr).Resolve (ec);
1769 b.type = ReturnType;
1774 class PredefinedPointerOperator : PredefinedOperator {
1775 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1776 : base (ltype, rtype, op_mask)
1780 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1781 : base (type, op_mask, return_type)
1785 public override bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
1788 if (!lexpr.Type.IsPointer)
1791 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1795 if (right == null) {
1796 if (!rexpr.Type.IsPointer)
1799 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1806 public override Expression ConvertResult (EmitContext ec, Binary b)
1808 base.ConvertResult (ec, b);
1810 Type r_type = ReturnType;
1811 if (r_type == null) {
1812 r_type = b.left.Type;
1814 r_type = b.right.Type;
1817 return new PointerArithmetic (b.oper == Operator.Addition,
1818 b.left, b.right, r_type, b.loc).Resolve (ec);
1823 public enum Operator {
1824 Multiply = 0 | ArithmeticMask,
1825 Division = 1 | ArithmeticMask,
1826 Modulus = 2 | ArithmeticMask,
1827 Addition = 3 | ArithmeticMask | AdditionMask,
1828 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1830 LeftShift = 5 | ShiftMask,
1831 RightShift = 6 | ShiftMask,
1833 LessThan = 7 | ComparisonMask | RelationalMask,
1834 GreaterThan = 8 | ComparisonMask | RelationalMask,
1835 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1836 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1837 Equality = 11 | ComparisonMask | EqualityMask,
1838 Inequality = 12 | ComparisonMask | EqualityMask,
1840 BitwiseAnd = 13 | BitwiseMask,
1841 ExclusiveOr = 14 | BitwiseMask,
1842 BitwiseOr = 15 | BitwiseMask,
1844 LogicalAnd = 16 | LogicalMask,
1845 LogicalOr = 17 | LogicalMask,
1850 ValuesOnlyMask = ArithmeticMask - 1,
1851 ArithmeticMask = 1 << 5,
1853 ComparisonMask = 1 << 7,
1854 EqualityMask = 1 << 8,
1855 BitwiseMask = 1 << 9,
1856 LogicalMask = 1 << 10,
1857 AdditionMask = 1 << 11,
1858 SubtractionMask = 1 << 12,
1859 RelationalMask = 1 << 13
1862 readonly Operator oper;
1863 protected Expression left, right;
1864 readonly bool is_compound;
1865 Expression enum_conversion;
1867 // This must be kept in sync with Operator!!!
1868 public static readonly string [] oper_names;
1870 static PredefinedOperator [] standard_operators;
1871 static PredefinedOperator [] pointer_operators;
1875 oper_names = new string [18];
1877 oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
1878 oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
1879 oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
1880 oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
1881 oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
1882 oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
1883 oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
1884 oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
1885 oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
1886 oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
1887 oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
1888 oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
1889 oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
1890 oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
1891 oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
1892 oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
1893 oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
1894 oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
1897 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1898 : this (oper, left, right)
1900 this.is_compound = isCompound;
1903 public Binary (Operator oper, Expression left, Expression right)
1908 this.loc = left.Location;
1911 public Operator Oper {
1918 /// Returns a stringified representation of the Operator
1920 string OperName (Operator oper)
1924 case Operator.Multiply:
1927 case Operator.Division:
1930 case Operator.Modulus:
1933 case Operator.Addition:
1936 case Operator.Subtraction:
1939 case Operator.LeftShift:
1942 case Operator.RightShift:
1945 case Operator.LessThan:
1948 case Operator.GreaterThan:
1951 case Operator.LessThanOrEqual:
1954 case Operator.GreaterThanOrEqual:
1957 case Operator.Equality:
1960 case Operator.Inequality:
1963 case Operator.BitwiseAnd:
1966 case Operator.BitwiseOr:
1969 case Operator.ExclusiveOr:
1972 case Operator.LogicalOr:
1975 case Operator.LogicalAnd:
1979 s = oper.ToString ();
1989 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1991 Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
1994 public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
1996 Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2000 protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
2003 // TODO: This should be handled as Type of method group in CSharpName
2004 if (left.eclass == ExprClass.MethodGroup)
2005 l = left.ExprClassName;
2007 l = TypeManager.CSharpName (left.Type);
2009 if (right.eclass == ExprClass.MethodGroup)
2010 r = right.ExprClassName;
2012 r = TypeManager.CSharpName (right.Type);
2014 Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
2017 public static string GetOperatorMetadataName (Operator op)
2019 return oper_names [(int)(op & Operator.ValuesOnlyMask)];
2022 static bool IsUnsigned (Type t)
2025 t = TypeManager.GetElementType (t);
2027 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2028 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2031 static bool IsFloat (Type t)
2033 return t == TypeManager.float_type || t == TypeManager.double_type;
2036 Expression ResolveOperator (EmitContext ec)
2039 Type r = right.Type;
2041 bool primitives_only = false;
2043 if (standard_operators == null)
2044 CreateStandardOperatorsTable ();
2047 // Handles predefined primitive types
2049 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2050 if ((oper & Operator.ShiftMask) == 0) {
2051 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2054 primitives_only = true;
2058 if (l.IsPointer || r.IsPointer)
2059 return ResolveOperatorPointer (ec, l, r);
2062 bool lenum = TypeManager.IsEnumType (l);
2063 bool renum = TypeManager.IsEnumType (r);
2064 if (lenum || renum) {
2065 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2067 // TODO: Can this be ambiguous
2073 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2074 if (TypeManager.IsDelegateType (l))
2075 return ResolveOperatorDelegateBinary (ec, l, r);
2079 expr = ResolveUserOperator (ec, l, r);
2083 // Predefined reference types equality
2084 if ((oper & Operator.EqualityMask) != 0) {
2085 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2091 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2094 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2095 // if 'left' is not an enumeration constant, create one from the type of 'right'
2096 Constant EnumLiftUp (EmitContext ec, Constant left, Constant right, Location loc)
2099 case Operator.BitwiseOr:
2100 case Operator.BitwiseAnd:
2101 case Operator.ExclusiveOr:
2102 case Operator.Equality:
2103 case Operator.Inequality:
2104 case Operator.LessThan:
2105 case Operator.LessThanOrEqual:
2106 case Operator.GreaterThan:
2107 case Operator.GreaterThanOrEqual:
2108 if (TypeManager.IsEnumType (left.Type))
2111 if (left.IsZeroInteger)
2112 return left.TryReduce (ec, right.Type, loc);
2116 case Operator.Addition:
2117 case Operator.Subtraction:
2120 case Operator.Multiply:
2121 case Operator.Division:
2122 case Operator.Modulus:
2123 case Operator.LeftShift:
2124 case Operator.RightShift:
2125 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2129 Error_OperatorCannotBeApplied (this.left, this.right);
2134 // The `|' operator used on types which were extended is dangerous
2136 void CheckBitwiseOrOnSignExtended ()
2138 OpcodeCast lcast = left as OpcodeCast;
2139 if (lcast != null) {
2140 if (IsUnsigned (lcast.UnderlyingType))
2144 OpcodeCast rcast = right as OpcodeCast;
2145 if (rcast != null) {
2146 if (IsUnsigned (rcast.UnderlyingType))
2150 if (lcast == null && rcast == null)
2153 // FIXME: consider constants
2155 Report.Warning (675, 3, loc,
2156 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2157 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2160 static void CreatePointerOperatorsTable ()
2162 ArrayList temp = new ArrayList ();
2165 // Pointer arithmetic:
2167 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2168 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2169 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2170 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2172 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2173 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2174 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2175 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2178 // T* operator + (int y, T* x);
2179 // T* operator + (uint y, T *x);
2180 // T* operator + (long y, T *x);
2181 // T* operator + (ulong y, T *x);
2183 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
2184 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
2185 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
2186 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
2189 // long operator - (T* x, T *y)
2191 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2193 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2196 static void CreateStandardOperatorsTable ()
2198 ArrayList temp = new ArrayList ();
2199 Type bool_type = TypeManager.bool_type;
2201 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2202 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2203 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2204 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2205 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2206 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2208 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2209 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2210 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2211 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2212 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2213 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2215 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2217 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2218 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2219 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2221 temp.Add (new PredefinedOperator (bool_type,
2222 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2224 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2225 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2226 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2227 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2229 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2233 // Rules used during binary numeric promotion
2235 static bool DoNumericPromotion (ref Expression prim_expr, ref Expression second_expr, Type type)
2240 Constant c = prim_expr as Constant;
2242 temp = c.ConvertImplicitly (type);
2249 if (type == TypeManager.uint32_type) {
2250 etype = prim_expr.Type;
2251 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2252 type = TypeManager.int64_type;
2254 if (type != second_expr.Type) {
2255 c = second_expr as Constant;
2257 temp = c.ConvertImplicitly (type);
2259 temp = Convert.ImplicitNumericConversion (second_expr, type);
2265 } else if (type == TypeManager.uint64_type) {
2267 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2269 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2270 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2274 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2283 // 7.2.6.2 Binary numeric promotions
2285 public bool DoBinaryOperatorPromotion (EmitContext ec)
2287 Type ltype = left.Type;
2288 Type rtype = right.Type;
2291 foreach (Type t in ConstantFold.binary_promotions) {
2293 return t == rtype || DoNumericPromotion (ref right, ref left, t);
2296 return t == ltype || DoNumericPromotion (ref left, ref right, t);
2299 Type int32 = TypeManager.int32_type;
2300 if (ltype != int32) {
2301 Constant c = left as Constant;
2303 temp = c.ConvertImplicitly (int32);
2305 temp = Convert.ImplicitNumericConversion (left, int32);
2312 if (rtype != int32) {
2313 Constant c = right as Constant;
2315 temp = c.ConvertImplicitly (int32);
2317 temp = Convert.ImplicitNumericConversion (right, int32);
2327 public override Expression DoResolve (EmitContext ec)
2332 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2333 left = ((ParenthesizedExpression) left).Expr;
2334 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2338 if (left.eclass == ExprClass.Type) {
2339 Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2343 left = left.Resolve (ec);
2348 Constant lc = left as Constant;
2350 if (lc != null && lc.Type == TypeManager.bool_type &&
2351 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2352 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2354 // FIXME: resolve right expression as unreachable
2355 // right.Resolve (ec);
2357 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2361 right = right.Resolve (ec);
2365 eclass = ExprClass.Value;
2366 Constant rc = right as Constant;
2368 // The conversion rules are ignored in enum context but why
2369 if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2370 left = lc = EnumLiftUp (ec, lc, rc, loc);
2374 right = rc = EnumLiftUp (ec, rc, lc, loc);
2379 if (rc != null && lc != null) {
2380 int prev_e = Report.Errors;
2381 Expression e = ConstantFold.BinaryFold (
2382 ec, oper, lc, rc, loc);
2383 if (e != null || Report.Errors != prev_e)
2386 if ((oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) &&
2387 ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue))) {
2389 if ((ResolveOperator (ec)) == null) {
2390 Error_OperatorCannotBeApplied (left, right);
2399 // The result is a constant with side-effect
2400 return new SideEffectConstant (lc, right, loc);
2404 // Comparison warnings
2405 if ((oper & Operator.ComparisonMask) != 0) {
2406 if (left.Equals (right)) {
2407 Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2409 CheckUselessComparison (lc, right.Type);
2410 CheckUselessComparison (rc, left.Type);
2413 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2414 (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type) ||
2415 (left is NullLiteral && right.Type.IsValueType) || (right is NullLiteral && left.Type.IsValueType)))
2416 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2418 return DoResolveCore (ec, left, right);
2421 protected Expression DoResolveCore (EmitContext ec, Expression left_orig, Expression right_orig)
2423 Expression expr = ResolveOperator (ec);
2425 Error_OperatorCannotBeApplied (left_orig, right_orig);
2427 if (left == null || right == null)
2428 throw new InternalErrorException ("Invalid conversion");
2430 if (oper == Operator.BitwiseOr)
2431 CheckBitwiseOrOnSignExtended ();
2437 // D operator + (D x, D y)
2438 // D operator - (D x, D y)
2440 Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
2442 if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
2443 if ((RootContext.Version != LanguageVersion.ISO_1)) {
2444 Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2451 if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
2456 ArrayList args = new ArrayList (2);
2458 args = new ArrayList (2);
2459 args.Add (new Argument (left, Argument.AType.Expression));
2460 args.Add (new Argument (right, Argument.AType.Expression));
2462 if (oper == Operator.Addition) {
2463 if (TypeManager.delegate_combine_delegate_delegate == null) {
2464 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2465 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2468 method = TypeManager.delegate_combine_delegate_delegate;
2470 if (TypeManager.delegate_remove_delegate_delegate == null) {
2471 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2472 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2475 method = TypeManager.delegate_remove_delegate_delegate;
2478 return new BinaryDelegate (l, method, args);
2482 // Enumeration operators
2484 Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2487 // bool operator == (E x, E y);
2488 // bool operator != (E x, E y);
2489 // bool operator < (E x, E y);
2490 // bool operator > (E x, E y);
2491 // bool operator <= (E x, E y);
2492 // bool operator >= (E x, E y);
2494 // E operator & (E x, E y);
2495 // E operator | (E x, E y);
2496 // E operator ^ (E x, E y);
2498 // U operator - (E e, E f)
2499 // E operator - (E e, U x)
2501 // E operator + (U x, E e)
2502 // E operator + (E e, U x)
2504 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2505 (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
2508 Expression ltemp = left;
2509 Expression rtemp = right;
2510 Type underlying_type;
2512 if (TypeManager.IsEqual (ltype, rtype)) {
2513 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2515 if (left is Constant)
2516 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2518 left = EmptyCast.Create (left, underlying_type);
2520 if (right is Constant)
2521 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2523 right = EmptyCast.Create (right, underlying_type);
2525 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2526 Constant c = right as Constant;
2527 if (c == null || !c.IsDefaultValue)
2531 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2532 if (left is Constant)
2533 left = ((Constant) left).ConvertExplicitly (false, underlying_type);
2535 left = EmptyCast.Create (left, underlying_type);
2537 if (oper != Operator.Addition) {
2538 Constant c = left as Constant;
2539 if (c == null || !c.IsDefaultValue)
2543 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2544 if (right is Constant)
2545 right = ((Constant) right).ConvertExplicitly (false, underlying_type);
2547 right = EmptyCast.Create (right, underlying_type);
2553 // C# specification uses explicit cast syntax which means binary promotion
2554 // should happen, however it seems that csc does not do that
2556 if (!DoBinaryOperatorPromotion (ec)) {
2562 Type res_type = null;
2563 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2564 Type promoted_type = lenum ? left.Type : right.Type;
2565 enum_conversion = Convert.ExplicitNumericConversion (
2566 new EmptyExpression (promoted_type), underlying_type);
2568 if (oper == Operator.Subtraction && renum && lenum)
2569 res_type = underlying_type;
2570 else if (oper == Operator.Addition && renum)
2576 Expression expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2577 if (!is_compound || expr == null)
2581 // TODO: Need to corectly implemented Coumpound Assigment for all operators
2584 if (Convert.ImplicitConversionExists (ec, left, rtype))
2587 if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
2590 expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
2595 // 7.9.6 Reference type equality operators
2597 Binary ResolveOperatorEqualityRerefence (EmitContext ec, Type l, Type r)
2600 // operator != (object a, object b)
2601 // operator == (object a, object b)
2604 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2606 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2609 type = TypeManager.bool_type;
2610 GenericConstraints constraints;
2612 bool lgen = TypeManager.IsGenericParameter (l);
2614 if (TypeManager.IsEqual (l, r)) {
2617 // Only allow to compare same reference type parameter
2619 constraints = TypeManager.GetTypeParameterConstraints (l);
2620 if (constraints != null && constraints.IsReferenceType)
2626 if (l == TypeManager.anonymous_method_type)
2629 if (TypeManager.IsValueType (l))
2635 bool rgen = TypeManager.IsGenericParameter (r);
2638 // a, Both operands are reference-type values or the value null
2639 // b, One operand is a value of type T where T is a type-parameter and
2640 // the other operand is the value null. Furthermore T does not have the
2641 // value type constrain
2643 if (left is NullLiteral || right is NullLiteral) {
2645 constraints = TypeManager.GetTypeParameterConstraints (l);
2646 if (constraints != null && constraints.HasValueTypeConstraint)
2649 left = new BoxedCast (left, TypeManager.object_type);
2654 constraints = TypeManager.GetTypeParameterConstraints (r);
2655 if (constraints != null && constraints.HasValueTypeConstraint)
2658 right = new BoxedCast (right, TypeManager.object_type);
2664 // An interface is converted to the object before the
2665 // standard conversion is applied. It's not clear from the
2666 // standard but it looks like it works like that.
2669 constraints = TypeManager.GetTypeParameterConstraints (l);
2670 if (constraints == null || constraints.IsReferenceType)
2672 } else if (l.IsInterface) {
2673 l = TypeManager.object_type;
2674 } else if (l.IsValueType) {
2679 constraints = TypeManager.GetTypeParameterConstraints (r);
2680 if (constraints == null || constraints.IsReferenceType)
2682 } else if (r.IsInterface) {
2683 r = TypeManager.object_type;
2684 } else if (r.IsValueType) {
2689 const string ref_comparison = "Possible unintended reference comparison. " +
2690 "Consider casting the {0} side of the expression to `string' to compare the values";
2693 // A standard implicit conversion exists from the type of either
2694 // operand to the type of the other operand
2696 if (Convert.ImplicitReferenceConversionExists (left, r)) {
2697 if (l == TypeManager.string_type)
2698 Report.Warning (253, 2, loc, ref_comparison, "right");
2703 if (Convert.ImplicitReferenceConversionExists (right, l)) {
2704 if (r == TypeManager.string_type)
2705 Report.Warning (252, 2, loc, ref_comparison, "left");
2714 Expression ResolveOperatorPointer (EmitContext ec, Type l, Type r)
2717 // bool operator == (void* x, void* y);
2718 // bool operator != (void* x, void* y);
2719 // bool operator < (void* x, void* y);
2720 // bool operator > (void* x, void* y);
2721 // bool operator <= (void* x, void* y);
2722 // bool operator >= (void* x, void* y);
2724 if ((oper & Operator.ComparisonMask) != 0) {
2727 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
2734 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
2740 type = TypeManager.bool_type;
2744 if (pointer_operators == null)
2745 CreatePointerOperatorsTable ();
2747 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
2751 // Build-in operators method overloading
2753 protected virtual Expression ResolveOperatorPredefined (EmitContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
2755 PredefinedOperator best_operator = null;
2757 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
2759 foreach (PredefinedOperator po in operators) {
2760 if ((po.OperatorsMask & oper_mask) == 0)
2763 if (primitives_only) {
2764 if (!po.IsPrimitiveApplicable (l))
2767 if (!po.IsApplicable (ec, left, right))
2771 if (best_operator == null) {
2773 if (primitives_only)
2779 best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
2781 if (best_operator == null) {
2782 Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
2783 OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
2790 if (best_operator == null)
2793 Expression expr = best_operator.ConvertResult (ec, this);
2794 if (enum_type == null)
2798 // HACK: required by enum_conversion
2800 expr.Type = enum_type;
2801 return EmptyCast.Create (expr, enum_type);
2805 // Performs user-operator overloading
2807 protected virtual Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
2810 if (oper == Operator.LogicalAnd)
2811 user_oper = Operator.BitwiseAnd;
2812 else if (oper == Operator.LogicalOr)
2813 user_oper = Operator.BitwiseOr;
2817 string op = GetOperatorMetadataName (user_oper);
2819 MethodGroupExpr union;
2820 MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2821 if (!TypeManager.IsEqual (r, l)) {
2822 MethodGroupExpr right_operators = MemberLookup (
2823 ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
2824 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
2826 union = left_operators;
2831 ArrayList args = new ArrayList (2);
2832 Argument larg = new Argument (left);
2834 Argument rarg = new Argument (right);
2837 union = union.OverloadResolve (ec, ref args, true, loc);
2841 Expression oper_expr;
2843 // TODO: CreateExpressionTree is allocated every time
2844 if (user_oper != oper) {
2845 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
2846 oper == Operator.LogicalAnd, loc).Resolve (ec);
2848 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
2851 // This is used to check if a test 'x == null' can be optimized to a reference equals,
2852 // and not invoke user operator
2854 if ((oper & Operator.EqualityMask) != 0) {
2855 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
2856 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
2857 type = TypeManager.bool_type;
2858 if (left is NullLiteral || right is NullLiteral)
2859 oper_expr = ReducedExpression.Create (this, oper_expr).Resolve (ec);
2860 } else if (union.DeclaringType == TypeManager.delegate_type && l != r) {
2862 // Two System.Delegate(s) are never equal
2874 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2879 private void CheckUselessComparison (Constant c, Type type)
2881 if (c == null || !IsTypeIntegral (type)
2882 || c is StringConstant
2883 || c is BoolConstant
2884 || c is FloatConstant
2885 || c is DoubleConstant
2886 || c is DecimalConstant
2892 if (c is ULongConstant) {
2893 ulong uvalue = ((ULongConstant) c).Value;
2894 if (uvalue > long.MaxValue) {
2895 if (type == TypeManager.byte_type ||
2896 type == TypeManager.sbyte_type ||
2897 type == TypeManager.short_type ||
2898 type == TypeManager.ushort_type ||
2899 type == TypeManager.int32_type ||
2900 type == TypeManager.uint32_type ||
2901 type == TypeManager.int64_type ||
2902 type == TypeManager.char_type)
2903 WarnUselessComparison (type);
2906 value = (long) uvalue;
2908 else if (c is ByteConstant)
2909 value = ((ByteConstant) c).Value;
2910 else if (c is SByteConstant)
2911 value = ((SByteConstant) c).Value;
2912 else if (c is ShortConstant)
2913 value = ((ShortConstant) c).Value;
2914 else if (c is UShortConstant)
2915 value = ((UShortConstant) c).Value;
2916 else if (c is IntConstant)
2917 value = ((IntConstant) c).Value;
2918 else if (c is UIntConstant)
2919 value = ((UIntConstant) c).Value;
2920 else if (c is LongConstant)
2921 value = ((LongConstant) c).Value;
2922 else if (c is CharConstant)
2923 value = ((CharConstant)c).Value;
2928 if (IsValueOutOfRange (value, type))
2929 WarnUselessComparison (type);
2932 private bool IsValueOutOfRange (long value, Type type)
2934 if (IsTypeUnsigned (type) && value < 0)
2936 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2937 type == TypeManager.byte_type && value >= 0x100 ||
2938 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2939 type == TypeManager.ushort_type && value >= 0x10000 ||
2940 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2941 type == TypeManager.uint32_type && value >= 0x100000000;
2944 static bool IsBuildInEqualityOperator (Type t)
2946 return t == TypeManager.object_type || t == TypeManager.string_type ||
2947 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
2950 private static bool IsTypeIntegral (Type type)
2952 return type == TypeManager.uint64_type ||
2953 type == TypeManager.int64_type ||
2954 type == TypeManager.uint32_type ||
2955 type == TypeManager.int32_type ||
2956 type == TypeManager.ushort_type ||
2957 type == TypeManager.short_type ||
2958 type == TypeManager.sbyte_type ||
2959 type == TypeManager.byte_type ||
2960 type == TypeManager.char_type;
2963 private static bool IsTypeUnsigned (Type type)
2965 return type == TypeManager.uint64_type ||
2966 type == TypeManager.uint32_type ||
2967 type == TypeManager.ushort_type ||
2968 type == TypeManager.byte_type ||
2969 type == TypeManager.char_type;
2972 private void WarnUselessComparison (Type type)
2974 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}'",
2975 TypeManager.CSharpName (type));
2979 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2980 /// context of a conditional bool expression. This function will return
2981 /// false if it is was possible to use EmitBranchable, or true if it was.
2983 /// The expression's code is generated, and we will generate a branch to `target'
2984 /// if the resulting expression value is equal to isTrue
2986 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2988 ILGenerator ig = ec.ig;
2991 // This is more complicated than it looks, but its just to avoid
2992 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2993 // but on top of that we want for == and != to use a special path
2994 // if we are comparing against null
2996 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2997 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3000 // put the constant on the rhs, for simplicity
3002 if (left is Constant) {
3003 Expression swap = right;
3008 if (((Constant) right).IsZeroInteger) {
3009 left.EmitBranchable (ec, target, my_on_true);
3012 if (right.Type == TypeManager.bool_type) {
3013 // right is a boolean, and it's not 'false' => it is 'true'
3014 left.EmitBranchable (ec, target, !my_on_true);
3018 } else if (oper == Operator.LogicalAnd) {
3021 Label tests_end = ig.DefineLabel ();
3023 left.EmitBranchable (ec, tests_end, false);
3024 right.EmitBranchable (ec, target, true);
3025 ig.MarkLabel (tests_end);
3028 // This optimizes code like this
3029 // if (true && i > 4)
3031 if (!(left is Constant))
3032 left.EmitBranchable (ec, target, false);
3034 if (!(right is Constant))
3035 right.EmitBranchable (ec, target, false);
3040 } else if (oper == Operator.LogicalOr){
3042 left.EmitBranchable (ec, target, true);
3043 right.EmitBranchable (ec, target, true);
3046 Label tests_end = ig.DefineLabel ();
3047 left.EmitBranchable (ec, tests_end, true);
3048 right.EmitBranchable (ec, target, false);
3049 ig.MarkLabel (tests_end);
3054 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3055 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3056 oper == Operator.Equality || oper == Operator.Inequality)) {
3057 base.EmitBranchable (ec, target, on_true);
3065 bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
3068 case Operator.Equality:
3070 ig.Emit (OpCodes.Beq, target);
3072 ig.Emit (OpCodes.Bne_Un, target);
3075 case Operator.Inequality:
3077 ig.Emit (OpCodes.Bne_Un, target);
3079 ig.Emit (OpCodes.Beq, target);
3082 case Operator.LessThan:
3085 ig.Emit (OpCodes.Blt_Un, target);
3087 ig.Emit (OpCodes.Blt, target);
3090 ig.Emit (OpCodes.Bge_Un, target);
3092 ig.Emit (OpCodes.Bge, target);
3095 case Operator.GreaterThan:
3098 ig.Emit (OpCodes.Bgt_Un, target);
3100 ig.Emit (OpCodes.Bgt, target);
3103 ig.Emit (OpCodes.Ble_Un, target);
3105 ig.Emit (OpCodes.Ble, target);
3108 case Operator.LessThanOrEqual:
3111 ig.Emit (OpCodes.Ble_Un, target);
3113 ig.Emit (OpCodes.Ble, target);
3116 ig.Emit (OpCodes.Bgt_Un, target);
3118 ig.Emit (OpCodes.Bgt, target);
3122 case Operator.GreaterThanOrEqual:
3125 ig.Emit (OpCodes.Bge_Un, target);
3127 ig.Emit (OpCodes.Bge, target);
3130 ig.Emit (OpCodes.Blt_Un, target);
3132 ig.Emit (OpCodes.Blt, target);
3135 throw new InternalErrorException (oper.ToString ());
3139 public override void Emit (EmitContext ec)
3141 EmitOperator (ec, left.Type);
3144 protected virtual void EmitOperator (EmitContext ec, Type l)
3146 ILGenerator ig = ec.ig;
3149 // Handle short-circuit operators differently
3152 if ((oper & Operator.LogicalMask) != 0) {
3153 Label load_result = ig.DefineLabel ();
3154 Label end = ig.DefineLabel ();
3156 bool is_or = oper == Operator.LogicalOr;
3157 left.EmitBranchable (ec, load_result, is_or);
3159 ig.Emit (OpCodes.Br_S, end);
3161 ig.MarkLabel (load_result);
3162 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3170 // Optimize zero-based operations
3172 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3174 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3175 Constant rc = right as Constant;
3176 if (rc != null && rc.IsDefaultValue) {
3186 case Operator.Multiply:
3188 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3189 opcode = OpCodes.Mul_Ovf;
3190 else if (!IsFloat (l))
3191 opcode = OpCodes.Mul_Ovf_Un;
3193 opcode = OpCodes.Mul;
3195 opcode = OpCodes.Mul;
3199 case Operator.Division:
3201 opcode = OpCodes.Div_Un;
3203 opcode = OpCodes.Div;
3206 case Operator.Modulus:
3208 opcode = OpCodes.Rem_Un;
3210 opcode = OpCodes.Rem;
3213 case Operator.Addition:
3215 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3216 opcode = OpCodes.Add_Ovf;
3217 else if (!IsFloat (l))
3218 opcode = OpCodes.Add_Ovf_Un;
3220 opcode = OpCodes.Add;
3222 opcode = OpCodes.Add;
3225 case Operator.Subtraction:
3227 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3228 opcode = OpCodes.Sub_Ovf;
3229 else if (!IsFloat (l))
3230 opcode = OpCodes.Sub_Ovf_Un;
3232 opcode = OpCodes.Sub;
3234 opcode = OpCodes.Sub;
3237 case Operator.RightShift:
3239 opcode = OpCodes.Shr_Un;
3241 opcode = OpCodes.Shr;
3244 case Operator.LeftShift:
3245 opcode = OpCodes.Shl;
3248 case Operator.Equality:
3249 opcode = OpCodes.Ceq;
3252 case Operator.Inequality:
3253 ig.Emit (OpCodes.Ceq);
3254 ig.Emit (OpCodes.Ldc_I4_0);
3256 opcode = OpCodes.Ceq;
3259 case Operator.LessThan:
3261 opcode = OpCodes.Clt_Un;
3263 opcode = OpCodes.Clt;
3266 case Operator.GreaterThan:
3268 opcode = OpCodes.Cgt_Un;
3270 opcode = OpCodes.Cgt;
3273 case Operator.LessThanOrEqual:
3274 if (IsUnsigned (l) || IsFloat (l))
3275 ig.Emit (OpCodes.Cgt_Un);
3277 ig.Emit (OpCodes.Cgt);
3278 ig.Emit (OpCodes.Ldc_I4_0);
3280 opcode = OpCodes.Ceq;
3283 case Operator.GreaterThanOrEqual:
3284 if (IsUnsigned (l) || IsFloat (l))
3285 ig.Emit (OpCodes.Clt_Un);
3287 ig.Emit (OpCodes.Clt);
3289 ig.Emit (OpCodes.Ldc_I4_0);
3291 opcode = OpCodes.Ceq;
3294 case Operator.BitwiseOr:
3295 opcode = OpCodes.Or;
3298 case Operator.BitwiseAnd:
3299 opcode = OpCodes.And;
3302 case Operator.ExclusiveOr:
3303 opcode = OpCodes.Xor;
3307 throw new InternalErrorException (oper.ToString ());
3313 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3314 // expression because that would wrap lifted binary operation
3316 if (enum_conversion != null)
3317 enum_conversion.Emit (ec);
3320 public override void EmitSideEffect (EmitContext ec)
3322 if ((oper & Operator.LogicalMask) != 0 ||
3323 (ec.CheckState && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3324 base.EmitSideEffect (ec);
3326 left.EmitSideEffect (ec);
3327 right.EmitSideEffect (ec);
3331 protected override void CloneTo (CloneContext clonectx, Expression t)
3333 Binary target = (Binary) t;
3335 target.left = left.Clone (clonectx);
3336 target.right = right.Clone (clonectx);
3339 public override Expression CreateExpressionTree (EmitContext ec)
3341 return CreateExpressionTree (ec, null);
3344 Expression CreateExpressionTree (EmitContext ec, MethodGroupExpr method)
3347 bool lift_arg = false;
3350 case Operator.Addition:
3351 if (method == null && ec.CheckState && !IsFloat (type))
3352 method_name = "AddChecked";
3354 method_name = "Add";
3356 case Operator.BitwiseAnd:
3357 method_name = "And";
3359 case Operator.BitwiseOr:
3362 case Operator.Division:
3363 method_name = "Divide";
3365 case Operator.Equality:
3366 method_name = "Equal";
3369 case Operator.ExclusiveOr:
3370 method_name = "ExclusiveOr";
3372 case Operator.GreaterThan:
3373 method_name = "GreaterThan";
3376 case Operator.GreaterThanOrEqual:
3377 method_name = "GreaterThanOrEqual";
3380 case Operator.Inequality:
3381 method_name = "NotEqual";
3384 case Operator.LeftShift:
3385 method_name = "LeftShift";
3387 case Operator.LessThan:
3388 method_name = "LessThan";
3391 case Operator.LessThanOrEqual:
3392 method_name = "LessThanOrEqual";
3395 case Operator.LogicalAnd:
3396 method_name = "AndAlso";
3398 case Operator.LogicalOr:
3399 method_name = "OrElse";
3401 case Operator.Modulus:
3402 method_name = "Modulo";
3404 case Operator.Multiply:
3405 if (method == null && ec.CheckState && !IsFloat (type))
3406 method_name = "MultiplyChecked";
3408 method_name = "Multiply";
3410 case Operator.RightShift:
3411 method_name = "RightShift";
3413 case Operator.Subtraction:
3414 if (method == null && ec.CheckState && !IsFloat (type))
3415 method_name = "SubtractChecked";
3417 method_name = "Subtract";
3421 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3424 ArrayList args = new ArrayList (2);
3425 args.Add (new Argument (left.CreateExpressionTree (ec)));
3426 args.Add (new Argument (right.CreateExpressionTree (ec)));
3427 if (method != null) {
3429 args.Add (new Argument (new BoolConstant (false, loc)));
3431 args.Add (new Argument (method.CreateExpressionTree (ec)));
3434 return CreateExpressionFactoryCall (method_name, args);
3439 // Object created by Binary when the binary operator uses an method instead of being
3440 // a binary operation that maps to a CIL binary operation.
3442 public class BinaryMethod : Expression {
3443 public MethodBase method;
3444 public ArrayList Arguments;
3446 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3451 eclass = ExprClass.Value;
3454 public override Expression DoResolve (EmitContext ec)
3459 public override void Emit (EmitContext ec)
3461 ILGenerator ig = ec.ig;
3463 Invocation.EmitArguments (ec, Arguments, false, null);
3465 if (method is MethodInfo)
3466 ig.Emit (OpCodes.Call, (MethodInfo) method);
3468 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3473 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3474 // b, c, d... may be strings or objects.
3476 public class StringConcat : Expression {
3477 ArrayList arguments;
3479 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3482 type = TypeManager.string_type;
3483 eclass = ExprClass.Value;
3485 arguments = new ArrayList (2);
3490 public override Expression CreateExpressionTree (EmitContext ec)
3492 Argument arg = (Argument) arguments [0];
3493 return CreateExpressionAddCall (ec, arg, arg.Expr.CreateExpressionTree (ec), 1);
3497 // Creates nested calls tree from an array of arguments used for IL emit
3499 Expression CreateExpressionAddCall (EmitContext ec, Argument left, Expression left_etree, int pos)
3501 ArrayList concat_args = new ArrayList (2);
3502 ArrayList add_args = new ArrayList (3);
3504 concat_args.Add (left);
3505 add_args.Add (new Argument (left_etree));
3507 concat_args.Add (arguments [pos]);
3508 add_args.Add (new Argument (((Argument) arguments [pos]).Expr.CreateExpressionTree (ec)));
3510 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3514 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3518 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3520 Expression expr = CreateExpressionFactoryCall ("Add", add_args);
3521 if (++pos == arguments.Count)
3524 left = new Argument (new EmptyExpression (method.Type));
3525 return CreateExpressionAddCall (ec, left, expr, pos);
3528 public override Expression DoResolve (EmitContext ec)
3533 public void Append (EmitContext ec, Expression operand)
3538 StringConstant sc = operand as StringConstant;
3540 if (arguments.Count != 0) {
3541 Argument last_argument = (Argument) arguments [arguments.Count - 1];
3542 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3543 if (last_expr_constant != null) {
3544 last_argument.Expr = new StringConstant (
3545 last_expr_constant.Value + sc.Value, sc.Location);
3551 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3553 StringConcat concat_oper = operand as StringConcat;
3554 if (concat_oper != null) {
3555 arguments.AddRange (concat_oper.arguments);
3560 arguments.Add (new Argument (operand));
3563 Expression CreateConcatMemberExpression ()
3565 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3568 public override void Emit (EmitContext ec)
3570 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3571 concat = concat.Resolve (ec);
3578 // Object created with +/= on delegates
3580 public class BinaryDelegate : Expression {
3584 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3589 eclass = ExprClass.Value;
3592 public override Expression DoResolve (EmitContext ec)
3597 public override void Emit (EmitContext ec)
3599 ILGenerator ig = ec.ig;
3601 Invocation.EmitArguments (ec, args, false, null);
3603 ig.Emit (OpCodes.Call, (MethodInfo) method);
3604 ig.Emit (OpCodes.Castclass, type);
3607 public Expression Right {
3609 Argument arg = (Argument) args [1];
3614 public bool IsAddition {
3616 return method == TypeManager.delegate_combine_delegate_delegate;
3622 // User-defined conditional logical operator
3624 public class ConditionalLogicalOperator : UserOperatorCall {
3625 readonly bool is_and;
3628 public ConditionalLogicalOperator (MethodGroupExpr oper_method, ArrayList arguments,
3629 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3630 : base (oper_method, arguments, expr_tree, loc)
3632 this.is_and = is_and;
3635 public override Expression DoResolve (EmitContext ec)
3637 MethodInfo method = (MethodInfo)mg;
3638 type = TypeManager.TypeToCoreType (method.ReturnType);
3639 ParameterData pd = TypeManager.GetParameterData (method);
3640 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3641 Report.Error (217, loc,
3642 "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",
3643 TypeManager.CSharpSignature (method));
3647 Expression left_dup = new EmptyExpression (type);
3648 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3649 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3650 if (op_true == null || op_false == null) {
3651 Report.Error (218, loc,
3652 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3653 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3657 oper = is_and ? op_false : op_true;
3658 eclass = ExprClass.Value;
3662 public override void Emit (EmitContext ec)
3664 ILGenerator ig = ec.ig;
3665 Label end_target = ig.DefineLabel ();
3668 // Emit and duplicate left argument
3670 ((Argument)arguments [0]).Expr.Emit (ec);
3671 ig.Emit (OpCodes.Dup);
3672 arguments.RemoveAt (0);
3674 oper.EmitBranchable (ec, end_target, true);
3676 ig.MarkLabel (end_target);
3680 public class PointerArithmetic : Expression {
3681 Expression left, right;
3685 // We assume that `l' is always a pointer
3687 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3693 is_add = is_addition;
3696 public override Expression DoResolve (EmitContext ec)
3698 eclass = ExprClass.Variable;
3700 if (left.Type == TypeManager.void_ptr_type) {
3701 Error (242, "The operation in question is undefined on void pointers");
3708 public override void Emit (EmitContext ec)
3710 Type op_type = left.Type;
3711 ILGenerator ig = ec.ig;
3713 // It must be either array or fixed buffer
3714 Type element = TypeManager.HasElementType (op_type) ?
3715 element = TypeManager.GetElementType (op_type) :
3716 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3718 int size = GetTypeSize (element);
3719 Type rtype = right.Type;
3721 if (rtype.IsPointer){
3723 // handle (pointer - pointer)
3727 ig.Emit (OpCodes.Sub);
3731 ig.Emit (OpCodes.Sizeof, element);
3733 IntLiteral.EmitInt (ig, size);
3734 ig.Emit (OpCodes.Div);
3736 ig.Emit (OpCodes.Conv_I8);
3739 // handle + and - on (pointer op int)
3742 ig.Emit (OpCodes.Conv_I);
3744 Constant right_const = right as Constant;
3745 if (right_const != null && size != 0) {
3746 Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3754 ig.Emit (OpCodes.Sizeof, element);
3756 IntLiteral.EmitInt (ig, size);
3757 if (rtype == TypeManager.int64_type)
3758 ig.Emit (OpCodes.Conv_I8);
3759 else if (rtype == TypeManager.uint64_type)
3760 ig.Emit (OpCodes.Conv_U8);
3761 ig.Emit (OpCodes.Mul);
3765 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3766 ig.Emit (OpCodes.Conv_I);
3769 ig.Emit (OpCodes.Add);
3771 ig.Emit (OpCodes.Sub);
3777 /// Implements the ternary conditional operator (?:)
3779 public class Conditional : Expression {
3780 Expression expr, true_expr, false_expr;
3782 public Conditional (Expression expr, Expression true_expr, Expression false_expr)
3785 this.true_expr = true_expr;
3786 this.false_expr = false_expr;
3787 this.loc = expr.Location;
3790 public Expression Expr {
3796 public Expression TrueExpr {
3802 public Expression FalseExpr {
3808 public override Expression CreateExpressionTree (EmitContext ec)
3810 ArrayList args = new ArrayList (3);
3811 args.Add (new Argument (expr.CreateExpressionTree (ec)));
3812 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
3813 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
3814 return CreateExpressionFactoryCall ("Condition", args);
3817 public override Expression DoResolve (EmitContext ec)
3819 expr = expr.Resolve (ec);
3824 if (expr.Type != TypeManager.bool_type){
3825 expr = Expression.ResolveBoolean (
3832 Assign ass = expr as Assign;
3833 if (ass != null && ass.Source is Constant) {
3834 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3837 true_expr = true_expr.Resolve (ec);
3838 false_expr = false_expr.Resolve (ec);
3840 if (true_expr == null || false_expr == null)
3843 eclass = ExprClass.Value;
3844 if (true_expr.Type == false_expr.Type) {
3845 type = true_expr.Type;
3846 if (type == TypeManager.null_type) {
3847 // TODO: probably will have to implement ConditionalConstant
3848 // to call method without return constant as well
3849 Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3854 Type true_type = true_expr.Type;
3855 Type false_type = false_expr.Type;
3858 // First, if an implicit conversion exists from true_expr
3859 // to false_expr, then the result type is of type false_expr.Type
3861 conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
3864 // Check if both can convert implicitl to each other's type
3866 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
3868 "Can not compute type of conditional expression " +
3869 "as `" + TypeManager.CSharpName (true_expr.Type) +
3870 "' and `" + TypeManager.CSharpName (false_expr.Type) +
3871 "' convert implicitly to each other");
3876 } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
3880 Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3881 true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
3886 // Dead code optimalization
3887 if (expr is BoolConstant){
3888 BoolConstant bc = (BoolConstant) expr;
3890 Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
3891 return bc.Value ? true_expr : false_expr;
3897 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3902 public override void Emit (EmitContext ec)
3904 ILGenerator ig = ec.ig;
3905 Label false_target = ig.DefineLabel ();
3906 Label end_target = ig.DefineLabel ();
3908 expr.EmitBranchable (ec, false_target, false);
3909 true_expr.Emit (ec);
3911 if (type.IsInterface) {
3912 LocalBuilder temp = ec.GetTemporaryLocal (type);
3913 ig.Emit (OpCodes.Stloc, temp);
3914 ig.Emit (OpCodes.Ldloc, temp);
3915 ec.FreeTemporaryLocal (temp, type);
3918 ig.Emit (OpCodes.Br, end_target);
3919 ig.MarkLabel (false_target);
3920 false_expr.Emit (ec);
3921 ig.MarkLabel (end_target);
3924 protected override void CloneTo (CloneContext clonectx, Expression t)
3926 Conditional target = (Conditional) t;
3928 target.expr = expr.Clone (clonectx);
3929 target.true_expr = true_expr.Clone (clonectx);
3930 target.false_expr = false_expr.Clone (clonectx);
3934 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3936 LocalTemporary temp;
3938 public abstract Variable Variable {
3942 public abstract bool IsRef {
3946 public override void Emit (EmitContext ec)
3951 public override void EmitSideEffect (EmitContext ec)
3957 // This method is used by parameters that are references, that are
3958 // being passed as references: we only want to pass the pointer (that
3959 // is already stored in the parameter, not the address of the pointer,
3960 // and not the value of the variable).
3962 public void EmitLoad (EmitContext ec)
3964 Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3966 Variable.EmitInstance (ec);
3970 public void Emit (EmitContext ec, bool leave_copy)
3972 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3978 // If we are a reference, we loaded on the stack a pointer
3979 // Now lets load the real value
3981 LoadFromPtr (ec.ig, type);
3985 ec.ig.Emit (OpCodes.Dup);
3987 if (IsRef || Variable.NeedsTemporary) {
3988 temp = new LocalTemporary (Type);
3994 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3995 bool prepare_for_load)
3997 Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
4000 ILGenerator ig = ec.ig;
4001 prepared = prepare_for_load;
4003 Variable.EmitInstance (ec);
4004 if (prepare_for_load) {
4005 if (Variable.HasInstance)
4006 ig.Emit (OpCodes.Dup);
4014 // HACK: variable is already emitted when source is an initializer
4015 if (source is NewInitialize) {
4017 Variable.EmitInstance (ec);
4024 ig.Emit (OpCodes.Dup);
4025 if (IsRef || Variable.NeedsTemporary) {
4026 temp = new LocalTemporary (Type);
4032 StoreFromPtr (ig, type);
4034 Variable.EmitAssign (ec);
4042 public void AddressOf (EmitContext ec, AddressOp mode)
4044 Variable.EmitInstance (ec);
4045 Variable.EmitAddressOf (ec);
4052 public class LocalVariableReference : VariableReference, IVariable {
4053 public readonly string Name;
4055 public LocalInfo local_info;
4059 public LocalVariableReference (Block block, string name, Location l)
4064 eclass = ExprClass.Variable;
4068 // Setting `is_readonly' to false will allow you to create a writable
4069 // reference to a read-only variable. This is used by foreach and using.
4071 public LocalVariableReference (Block block, string name, Location l,
4072 LocalInfo local_info, bool is_readonly)
4073 : this (block, name, l)
4075 this.local_info = local_info;
4076 this.is_readonly = is_readonly;
4079 public VariableInfo VariableInfo {
4080 get { return local_info.VariableInfo; }
4083 public override bool IsRef {
4084 get { return false; }
4087 public bool IsReadOnly {
4088 get { return is_readonly; }
4091 public bool VerifyAssigned (EmitContext ec)
4093 VariableInfo variable_info = local_info.VariableInfo;
4094 return variable_info == null || variable_info.IsAssigned (ec, loc);
4097 void ResolveLocalInfo ()
4099 if (local_info == null) {
4100 local_info = Block.GetLocalInfo (Name);
4101 type = local_info.VariableType;
4102 is_readonly = local_info.ReadOnly;
4106 public override Expression CreateExpressionTree (EmitContext ec)
4108 ArrayList arg = new ArrayList (1);
4109 arg.Add (new Argument (this));
4110 return CreateExpressionFactoryCall ("Constant", arg);
4113 protected Expression DoResolveBase (EmitContext ec)
4115 type = local_info.VariableType;
4117 Expression e = Block.GetConstantExpression (Name);
4119 return e.Resolve (ec);
4121 if (!VerifyAssigned (ec))
4125 // If we are referencing a variable from the external block
4126 // flag it for capturing
4128 if (ec.MustCaptureVariable (local_info)) {
4129 if (local_info.AddressTaken){
4130 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
4134 if (!ec.IsInProbingMode)
4136 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
4137 variable = scope.AddLocal (local_info);
4138 type = variable.Type;
4145 public override Expression DoResolve (EmitContext ec)
4147 ResolveLocalInfo ();
4148 local_info.Used = true;
4150 if (type == null && local_info.Type is VarExpr) {
4151 local_info.VariableType = TypeManager.object_type;
4152 Error_VariableIsUsedBeforeItIsDeclared (Name);
4156 return DoResolveBase (ec);
4159 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4161 ResolveLocalInfo ();
4164 if (right_side == EmptyExpression.OutAccess)
4165 local_info.Used = true;
4167 // Infer implicitly typed local variable
4169 VarExpr ve = local_info.Type as VarExpr;
4171 if (!ve.InferType (ec, right_side))
4173 type = local_info.VariableType = ve.Type;
4180 if (right_side == EmptyExpression.OutAccess) {
4181 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4182 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4183 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4184 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4185 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4187 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4189 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4193 if (VariableInfo != null)
4194 VariableInfo.SetAssigned (ec);
4196 return DoResolveBase (ec);
4199 public bool VerifyFixed ()
4201 // A local Variable is always fixed.
4205 public override int GetHashCode ()
4207 return Name.GetHashCode ();
4210 public override bool Equals (object obj)
4212 LocalVariableReference lvr = obj as LocalVariableReference;
4216 return Name == lvr.Name && Block == lvr.Block;
4219 public override Variable Variable {
4220 get { return variable != null ? variable : local_info.Variable; }
4223 public override string ToString ()
4225 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4228 protected override void CloneTo (CloneContext clonectx, Expression t)
4230 LocalVariableReference target = (LocalVariableReference) t;
4232 target.Block = clonectx.LookupBlock (Block);
4233 if (local_info != null)
4234 target.local_info = clonectx.LookupVariable (local_info);
4239 /// This represents a reference to a parameter in the intermediate
4242 public class ParameterReference : VariableReference, IVariable {
4243 readonly ToplevelParameterInfo pi;
4244 readonly ToplevelBlock referenced;
4247 public bool is_ref, is_out;
4250 get { return is_out; }
4253 public override bool IsRef {
4254 get { return is_ref; }
4257 public string Name {
4258 get { return Parameter.Name; }
4261 public Parameter Parameter {
4262 get { return pi.Parameter; }
4265 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
4268 this.referenced = referenced;
4270 eclass = ExprClass.Variable;
4273 public VariableInfo VariableInfo {
4274 get { return pi.VariableInfo; }
4277 public override Variable Variable {
4278 get { return variable != null ? variable : Parameter.Variable; }
4281 public bool VerifyFixed ()
4283 // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
4284 return Parameter.ModFlags == Parameter.Modifier.NONE;
4287 public bool IsAssigned (EmitContext ec, Location loc)
4289 // HACK: Variables are not captured in probing mode
4290 if (ec.IsInProbingMode)
4293 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
4296 Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4300 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
4302 if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
4305 Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
4309 public void SetAssigned (EmitContext ec)
4311 if (is_out && ec.DoFlowAnalysis)
4312 ec.CurrentBranching.SetAssigned (VariableInfo);
4315 public void SetFieldAssigned (EmitContext ec, string field_name)
4317 if (is_out && ec.DoFlowAnalysis)
4318 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
4321 protected bool DoResolveBase (EmitContext ec)
4323 Parameter par = Parameter;
4324 if (!par.Resolve (ec)) {
4328 type = par.ParameterType;
4329 Parameter.Modifier mod = par.ModFlags;
4330 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
4331 is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
4332 eclass = ExprClass.Variable;
4334 AnonymousContainer am = ec.CurrentAnonymousMethod;
4338 ToplevelBlock declared = pi.Block;
4339 if (is_ref && declared != referenced) {
4340 Report.Error (1628, Location,
4341 "Cannot use ref or out parameter `{0}' inside an " +
4342 "anonymous method block", par.Name);
4346 if (!am.IsIterator && declared == referenced)
4349 // Don't capture aruments when the probing is on
4350 if (!ec.IsInProbingMode) {
4351 ScopeInfo scope = declared.CreateScopeInfo ();
4352 variable = scope.AddParameter (par, pi.Index);
4353 type = variable.Type;
4358 public override int GetHashCode ()
4360 return Name.GetHashCode ();
4363 public override bool Equals (object obj)
4365 ParameterReference pr = obj as ParameterReference;
4369 return Name == pr.Name && referenced == pr.referenced;
4372 public override Expression CreateExpressionTree (EmitContext ec)
4374 return Parameter.ExpressionTreeVariableReference ();
4378 // Notice that for ref/out parameters, the type exposed is not the
4379 // same type exposed externally.
4382 // externally we expose "int&"
4383 // here we expose "int".
4385 // We record this in "is_ref". This means that the type system can treat
4386 // the type as it is expected, but when we generate the code, we generate
4387 // the alternate kind of code.
4389 public override Expression DoResolve (EmitContext ec)
4391 if (!DoResolveBase (ec))
4394 if (is_out && ec.DoFlowAnalysis &&
4395 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4401 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4403 if (!DoResolveBase (ec))
4406 // HACK: parameters are not captured when probing is on
4407 if (!ec.IsInProbingMode)
4413 static public void EmitLdArg (ILGenerator ig, int x)
4417 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4418 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4419 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4420 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4421 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4424 ig.Emit (OpCodes.Ldarg, x);
4427 public override string ToString ()
4429 return "ParameterReference[" + Name + "]";
4434 /// Used for arguments to New(), Invocation()
4436 public class Argument {
4437 public enum AType : byte {
4444 public static readonly Argument[] Empty = new Argument [0];
4446 public readonly AType ArgType;
4447 public Expression Expr;
4449 public Argument (Expression expr, AType type)
4452 this.ArgType = type;
4455 public Argument (Expression expr)
4458 this.ArgType = AType.Expression;
4463 if (ArgType == AType.Ref || ArgType == AType.Out)
4464 return TypeManager.GetReferenceType (Expr.Type);
4470 public Parameter.Modifier Modifier
4475 return Parameter.Modifier.OUT;
4478 return Parameter.Modifier.REF;
4481 return Parameter.Modifier.NONE;
4486 public string GetSignatureForError ()
4488 if (Expr.eclass == ExprClass.MethodGroup)
4489 return Expr.ExprClassName;
4491 return Expr.GetSignatureForError ();
4494 public bool ResolveMethodGroup (EmitContext ec)
4496 SimpleName sn = Expr as SimpleName;
4498 Expr = sn.GetMethodGroup ();
4500 // FIXME: csc doesn't report any error if you try to use `ref' or
4501 // `out' in a delegate creation expression.
4502 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4509 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));
4614 return CreateExpressionFactoryCall ("Call", args);
4617 public override Expression DoResolve (EmitContext ec)
4619 // Don't resolve already resolved expression
4620 if (eclass != ExprClass.Invalid)
4623 Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4624 if (expr_resolved == null)
4627 mg = expr_resolved as MethodGroupExpr;
4629 Type expr_type = expr_resolved.Type;
4631 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4632 return (new DelegateInvocation (
4633 expr_resolved, Arguments, loc)).Resolve (ec);
4636 MemberExpr me = expr_resolved as MemberExpr;
4638 expr_resolved.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4642 mg = ec.TypeContainer.LookupExtensionMethod (me.Type, me.Name, loc);
4644 Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4645 expr_resolved.GetSignatureForError ());
4649 ((ExtensionMethodGroupExpr)mg).ExtensionExpression = me.InstanceExpression;
4653 // Next, evaluate all the expressions in the argument list
4655 if (Arguments != null && !arguments_resolved) {
4656 for (int i = 0; i < Arguments.Count; ++i)
4658 if (!((Argument)Arguments[i]).Resolve(ec, loc))
4663 mg = DoResolveOverload (ec);
4667 MethodInfo method = (MethodInfo)mg;
4668 if (method != null) {
4669 type = TypeManager.TypeToCoreType (method.ReturnType);
4671 // TODO: this is a copy of mg.ResolveMemberAccess method
4672 Expression iexpr = mg.InstanceExpression;
4673 if (method.IsStatic) {
4674 if (iexpr == null ||
4675 iexpr is This || iexpr is EmptyExpression ||
4676 mg.IdenticalTypeName) {
4677 mg.InstanceExpression = null;
4679 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4685 if (type.IsPointer){
4693 // Only base will allow this invocation to happen.
4695 if (mg.IsBase && method.IsAbstract){
4696 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4700 if (Arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == "Finalize") {
4702 Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4704 Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4708 if (IsSpecialMethodInvocation (method)) {
4712 if (mg.InstanceExpression != null)
4713 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
4715 eclass = ExprClass.Value;
4719 protected virtual MethodGroupExpr DoResolveOverload (EmitContext ec)
4721 return mg.OverloadResolve (ec, ref Arguments, false, loc);
4724 bool IsSpecialMethodInvocation (MethodBase method)
4726 if (!TypeManager.IsSpecialMethod (method))
4729 Report.SymbolRelatedToPreviousError (method);
4730 Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4731 TypeManager.CSharpSignature (method, true));
4737 /// Emits a list of resolved Arguments that are in the arguments
4740 /// The MethodBase argument might be null if the
4741 /// emission of the arguments is known not to contain
4742 /// a `params' field (for example in constructors or other routines
4743 /// that keep their arguments in this structure)
4745 /// if `dup_args' is true, a copy of the arguments will be left
4746 /// on the stack. If `dup_args' is true, you can specify `this_arg'
4747 /// which will be duplicated before any other args. Only EmitCall
4748 /// should be using this interface.
4750 public static void EmitArguments (EmitContext ec, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4752 if (arguments == null)
4755 int top = arguments.Count;
4756 LocalTemporary [] temps = null;
4758 if (dup_args && top != 0)
4759 temps = new LocalTemporary [top];
4761 int argument_index = 0;
4763 for (int i = 0; i < top; i++) {
4764 a = (Argument) arguments [argument_index++];
4767 ec.ig.Emit (OpCodes.Dup);
4768 (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4773 if (this_arg != null)
4776 for (int i = 0; i < top; i ++) {
4777 temps [i].Emit (ec);
4778 temps [i].Release (ec);
4783 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4785 ParameterData pd = TypeManager.GetParameterData (mb);
4787 if (arguments == null)
4788 return new Type [0];
4790 Argument a = (Argument) arguments [pd.Count - 1];
4791 Arglist list = (Arglist) a.Expr;
4793 return list.ArgumentTypes;
4797 /// This checks the ConditionalAttribute on the method
4799 public static bool IsMethodExcluded (MethodBase method)
4801 if (method.IsConstructor)
4804 method = TypeManager.DropGenericMethodArguments (method);
4805 if (method.DeclaringType.Module == CodeGen.Module.Builder) {
4806 IMethodData md = TypeManager.GetMethod (method);
4808 return md.IsExcluded ();
4810 // For some methods (generated by delegate class) GetMethod returns null
4811 // because they are not included in builder_to_method table
4815 return AttributeTester.IsConditionalMethodExcluded (method);
4819 /// is_base tells whether we want to force the use of the `call'
4820 /// opcode instead of using callvirt. Call is required to call
4821 /// a specific method, while callvirt will always use the most
4822 /// recent method in the vtable.
4824 /// is_static tells whether this is an invocation on a static method
4826 /// instance_expr is an expression that represents the instance
4827 /// it must be non-null if is_static is false.
4829 /// method is the method to invoke.
4831 /// Arguments is the list of arguments to pass to the method or constructor.
4833 public static void EmitCall (EmitContext ec, bool is_base,
4834 Expression instance_expr,
4835 MethodBase method, ArrayList Arguments, Location loc)
4837 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4840 // `dup_args' leaves an extra copy of the arguments on the stack
4841 // `omit_args' does not leave any arguments at all.
4842 // So, basically, you could make one call with `dup_args' set to true,
4843 // and then another with `omit_args' set to true, and the two calls
4844 // would have the same set of arguments. However, each argument would
4845 // only have been evaluated once.
4846 public static void EmitCall (EmitContext ec, bool is_base,
4847 Expression instance_expr,
4848 MethodBase method, ArrayList Arguments, Location loc,
4849 bool dup_args, bool omit_args)
4851 ILGenerator ig = ec.ig;
4852 bool struct_call = false;
4853 bool this_call = false;
4854 LocalTemporary this_arg = null;
4856 Type decl_type = method.DeclaringType;
4858 if (!ec.IsInObsoleteScope) {
4860 // This checks ObsoleteAttribute on the method and on the declaring type
4862 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4864 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4866 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4868 AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4872 if (IsMethodExcluded (method))
4875 bool is_static = method.IsStatic;
4877 if (instance_expr == EmptyExpression.Null) {
4878 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4882 this_call = instance_expr is This;
4883 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4887 // If this is ourselves, push "this"
4891 Type iexpr_type = instance_expr.Type;
4894 // Push the instance expression
4896 if (TypeManager.IsValueType (iexpr_type)) {
4898 // Special case: calls to a function declared in a
4899 // reference-type with a value-type argument need
4900 // to have their value boxed.
4901 if (decl_type.IsValueType ||
4902 TypeManager.IsGenericParameter (iexpr_type)) {
4904 // If the expression implements IMemoryLocation, then
4905 // we can optimize and use AddressOf on the
4908 // If not we have to use some temporary storage for
4910 if (instance_expr is IMemoryLocation) {
4911 ((IMemoryLocation)instance_expr).
4912 AddressOf (ec, AddressOp.LoadStore);
4914 LocalTemporary temp = new LocalTemporary (iexpr_type);
4915 instance_expr.Emit (ec);
4917 temp.AddressOf (ec, AddressOp.Load);
4920 // avoid the overhead of doing this all the time.
4922 t = TypeManager.GetReferenceType (iexpr_type);
4924 instance_expr.Emit (ec);
4925 ig.Emit (OpCodes.Box, instance_expr.Type);
4926 t = TypeManager.object_type;
4929 instance_expr.Emit (ec);
4930 t = instance_expr.Type;
4934 ig.Emit (OpCodes.Dup);
4935 if (Arguments != null && Arguments.Count != 0) {
4936 this_arg = new LocalTemporary (t);
4937 this_arg.Store (ec);
4944 EmitArguments (ec, Arguments, dup_args, this_arg);
4947 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4948 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4952 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4953 call_op = OpCodes.Call;
4955 call_op = OpCodes.Callvirt;
4957 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4958 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4959 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4966 // and DoFoo is not virtual, you can omit the callvirt,
4967 // because you don't need the null checking behavior.
4969 if (method is MethodInfo)
4970 ig.Emit (call_op, (MethodInfo) method);
4972 ig.Emit (call_op, (ConstructorInfo) method);
4975 public override void Emit (EmitContext ec)
4977 mg.EmitCall (ec, Arguments);
4980 public override void EmitStatement (EmitContext ec)
4985 // Pop the return value if there is one
4987 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4988 ec.ig.Emit (OpCodes.Pop);
4991 protected override void CloneTo (CloneContext clonectx, Expression t)
4993 Invocation target = (Invocation) t;
4995 if (Arguments != null) {
4996 target.Arguments = new ArrayList (Arguments.Count);
4997 foreach (Argument a in Arguments)
4998 target.Arguments.Add (a.Clone (clonectx));
5001 target.expr = expr.Clone (clonectx);
5005 public class InvocationOrCast : ExpressionStatement
5008 Expression argument;
5010 public InvocationOrCast (Expression expr, Expression argument)
5013 this.argument = argument;
5014 this.loc = expr.Location;
5017 public override Expression DoResolve (EmitContext ec)
5020 // First try to resolve it as a cast.
5022 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5023 if ((te != null) && (te.eclass == ExprClass.Type)) {
5024 Cast cast = new Cast (te, argument, loc);
5025 return cast.Resolve (ec);
5029 // This can either be a type or a delegate invocation.
5030 // Let's just resolve it and see what we'll get.
5032 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5037 // Ok, so it's a Cast.
5039 if (expr.eclass == ExprClass.Type) {
5040 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5041 return cast.Resolve (ec);
5045 // It's a delegate invocation.
5047 if (!TypeManager.IsDelegateType (expr.Type)) {
5048 Error (149, "Method name expected");
5052 ArrayList args = new ArrayList ();
5053 args.Add (new Argument (argument, Argument.AType.Expression));
5054 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5055 return invocation.Resolve (ec);
5058 public override ExpressionStatement ResolveStatement (EmitContext ec)
5061 // First try to resolve it as a cast.
5063 TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5064 if ((te != null) && (te.eclass == ExprClass.Type)) {
5065 Error_InvalidExpressionStatement ();
5070 // This can either be a type or a delegate invocation.
5071 // Let's just resolve it and see what we'll get.
5073 expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5074 if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5075 Error_InvalidExpressionStatement ();
5080 // It's a delegate invocation.
5082 if (!TypeManager.IsDelegateType (expr.Type)) {
5083 Error (149, "Method name expected");
5087 ArrayList args = new ArrayList ();
5088 args.Add (new Argument (argument, Argument.AType.Expression));
5089 DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5090 return invocation.ResolveStatement (ec);
5093 public override void Emit (EmitContext ec)
5095 throw new Exception ("Cannot happen");
5098 public override void EmitStatement (EmitContext ec)
5100 throw new Exception ("Cannot happen");
5103 protected override void CloneTo (CloneContext clonectx, Expression t)
5105 InvocationOrCast target = (InvocationOrCast) t;
5107 target.expr = expr.Clone (clonectx);
5108 target.argument = argument.Clone (clonectx);
5113 // This class is used to "disable" the code generation for the
5114 // temporary variable when initializing value types.
5116 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5117 public void AddressOf (EmitContext ec, AddressOp Mode)
5124 /// Implements the new expression
5126 public class New : ExpressionStatement, IMemoryLocation {
5127 ArrayList Arguments;
5130 // During bootstrap, it contains the RequestedType,
5131 // but if `type' is not null, it *might* contain a NewDelegate
5132 // (because of field multi-initialization)
5134 public Expression RequestedType;
5136 MethodGroupExpr method;
5139 // If set, the new expression is for a value_target, and
5140 // we will not leave anything on the stack.
5142 protected Expression value_target;
5143 protected bool value_target_set;
5144 bool is_type_parameter = false;
5146 public New (Expression requested_type, ArrayList arguments, Location l)
5148 RequestedType = requested_type;
5149 Arguments = arguments;
5153 public bool SetTargetVariable (Expression value)
5155 value_target = value;
5156 value_target_set = true;
5157 if (!(value_target is IMemoryLocation)){
5158 Error_UnexpectedKind (null, "variable", loc);
5165 // This function is used to disable the following code sequence for
5166 // value type initialization:
5168 // AddressOf (temporary)
5172 // Instead the provide will have provided us with the address on the
5173 // stack to store the results.
5175 static Expression MyEmptyExpression;
5177 public void DisableTemporaryValueType ()
5179 if (MyEmptyExpression == null)
5180 MyEmptyExpression = new EmptyAddressOf ();
5183 // To enable this, look into:
5184 // test-34 and test-89 and self bootstrapping.
5186 // For instance, we can avoid a copy by using `newobj'
5187 // instead of Call + Push-temp on value types.
5188 // value_target = MyEmptyExpression;
5193 /// Converts complex core type syntax like 'new int ()' to simple constant
5195 public static Constant Constantify (Type t)
5197 if (t == TypeManager.int32_type)
5198 return new IntConstant (0, Location.Null);
5199 if (t == TypeManager.uint32_type)
5200 return new UIntConstant (0, Location.Null);
5201 if (t == TypeManager.int64_type)
5202 return new LongConstant (0, Location.Null);
5203 if (t == TypeManager.uint64_type)
5204 return new ULongConstant (0, Location.Null);
5205 if (t == TypeManager.float_type)
5206 return new FloatConstant (0, Location.Null);
5207 if (t == TypeManager.double_type)
5208 return new DoubleConstant (0, Location.Null);
5209 if (t == TypeManager.short_type)
5210 return new ShortConstant (0, Location.Null);
5211 if (t == TypeManager.ushort_type)
5212 return new UShortConstant (0, Location.Null);
5213 if (t == TypeManager.sbyte_type)
5214 return new SByteConstant (0, Location.Null);
5215 if (t == TypeManager.byte_type)
5216 return new ByteConstant (0, Location.Null);
5217 if (t == TypeManager.char_type)
5218 return new CharConstant ('\0', Location.Null);
5219 if (t == TypeManager.bool_type)
5220 return new BoolConstant (false, Location.Null);
5221 if (t == TypeManager.decimal_type)
5222 return new DecimalConstant (0, Location.Null);
5223 if (TypeManager.IsEnumType (t))
5224 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5230 // Checks whether the type is an interface that has the
5231 // [ComImport, CoClass] attributes and must be treated
5234 public Expression CheckComImport (EmitContext ec)
5236 if (!type.IsInterface)
5240 // Turn the call into:
5241 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5243 Type real_class = AttributeTester.GetCoClassAttribute (type);
5244 if (real_class == null)
5247 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5248 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5249 return cast.Resolve (ec);
5252 public override Expression CreateExpressionTree (EmitContext ec)
5254 ArrayList args = Arguments == null ?
5255 new ArrayList (1) : new ArrayList (Arguments.Count + 1);
5257 if (method == null) {
5258 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5260 args.Add (new Argument (method.CreateExpressionTree (ec)));
5261 if (Arguments != null) {
5263 foreach (Argument a in Arguments) {
5264 expr = a.Expr.CreateExpressionTree (ec);
5266 args.Add (new Argument (expr));
5271 return CreateExpressionFactoryCall ("New", args);
5274 public override Expression DoResolve (EmitContext ec)
5277 // The New DoResolve might be called twice when initializing field
5278 // expressions (see EmitFieldInitializers, the call to
5279 // GetInitializerExpression will perform a resolve on the expression,
5280 // and later the assign will trigger another resolution
5282 // This leads to bugs (#37014)
5285 if (RequestedType is NewDelegate)
5286 return RequestedType;
5290 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5296 if (type == TypeManager.void_type) {
5297 Error_VoidInvalidInTheContext (loc);
5301 if (type.IsPointer) {
5302 Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5303 TypeManager.CSharpName (type));
5307 if (Arguments == null) {
5308 Expression c = Constantify (type);
5313 if (TypeManager.IsDelegateType (type)) {
5314 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5315 if (RequestedType != null)
5316 if (!(RequestedType is DelegateCreation))
5317 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5318 return RequestedType;
5322 if (type.IsGenericParameter) {
5323 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5325 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5326 Error (304, String.Format (
5327 "Cannot create an instance of the " +
5328 "variable type '{0}' because it " +
5329 "doesn't have the new() constraint",
5334 if ((Arguments != null) && (Arguments.Count != 0)) {
5335 Error (417, String.Format (
5336 "`{0}': cannot provide arguments " +
5337 "when creating an instance of a " +
5338 "variable type.", type));
5342 if (TypeManager.activator_create_instance == null) {
5343 Type activator_type = TypeManager.CoreLookupType ("System", "Activator", Kind.Class, true);
5344 if (activator_type != null) {
5345 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5346 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5350 is_type_parameter = true;
5351 eclass = ExprClass.Value;
5356 if (type.IsAbstract && type.IsSealed) {
5357 Report.SymbolRelatedToPreviousError (type);
5358 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5362 if (type.IsInterface || type.IsAbstract){
5363 if (!TypeManager.IsGenericType (type)) {
5364 RequestedType = CheckComImport (ec);
5365 if (RequestedType != null)
5366 return RequestedType;
5369 Report.SymbolRelatedToPreviousError (type);
5370 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5374 bool is_struct = type.IsValueType;
5375 eclass = ExprClass.Value;
5378 // SRE returns a match for .ctor () on structs (the object constructor),
5379 // so we have to manually ignore it.
5381 if (is_struct && Arguments == null)
5384 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5385 Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5386 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5388 if (Arguments != null){
5389 foreach (Argument a in Arguments){
5390 if (!a.Resolve (ec, loc))
5398 method = ml as MethodGroupExpr;
5399 if (method == null) {
5400 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5404 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5411 bool DoEmitTypeParameter (EmitContext ec)
5414 ILGenerator ig = ec.ig;
5415 // IMemoryLocation ml;
5417 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5418 new Type [] { type });
5420 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5421 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5422 ig.Emit (OpCodes.Call, ci);
5426 // Allow DoEmit() to be called multiple times.
5427 // We need to create a new LocalTemporary each time since
5428 // you can't share LocalBuilders among ILGeneators.
5429 LocalTemporary temp = new LocalTemporary (type);
5431 Label label_activator = ig.DefineLabel ();
5432 Label label_end = ig.DefineLabel ();
5434 temp.AddressOf (ec, AddressOp.Store);
5435 ig.Emit (OpCodes.Initobj, type);
5438 ig.Emit (OpCodes.Box, type);
5439 ig.Emit (OpCodes.Brfalse, label_activator);
5441 temp.AddressOf (ec, AddressOp.Store);
5442 ig.Emit (OpCodes.Initobj, type);
5444 ig.Emit (OpCodes.Br, label_end);
5446 ig.MarkLabel (label_activator);
5448 ig.Emit (OpCodes.Call, ci);
5449 ig.MarkLabel (label_end);
5452 throw new InternalErrorException ();
5457 // This DoEmit can be invoked in two contexts:
5458 // * As a mechanism that will leave a value on the stack (new object)
5459 // * As one that wont (init struct)
5461 // You can control whether a value is required on the stack by passing
5462 // need_value_on_stack. The code *might* leave a value on the stack
5463 // so it must be popped manually
5465 // If we are dealing with a ValueType, we have a few
5466 // situations to deal with:
5468 // * The target is a ValueType, and we have been provided
5469 // the instance (this is easy, we are being assigned).
5471 // * The target of New is being passed as an argument,
5472 // to a boxing operation or a function that takes a
5475 // In this case, we need to create a temporary variable
5476 // that is the argument of New.
5478 // Returns whether a value is left on the stack
5480 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5482 bool is_value_type = TypeManager.IsValueType (type);
5483 ILGenerator ig = ec.ig;
5488 // Allow DoEmit() to be called multiple times.
5489 // We need to create a new LocalTemporary each time since
5490 // you can't share LocalBuilders among ILGeneators.
5491 if (!value_target_set)
5492 value_target = new LocalTemporary (type);
5494 ml = (IMemoryLocation) value_target;
5495 ml.AddressOf (ec, AddressOp.Store);
5499 method.EmitArguments (ec, Arguments);
5503 ig.Emit (OpCodes.Initobj, type);
5505 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5506 if (need_value_on_stack){
5507 value_target.Emit (ec);
5512 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5517 public override void Emit (EmitContext ec)
5519 if (is_type_parameter)
5520 DoEmitTypeParameter (ec);
5525 public override void EmitStatement (EmitContext ec)
5527 bool value_on_stack;
5529 if (is_type_parameter)
5530 value_on_stack = DoEmitTypeParameter (ec);
5532 value_on_stack = DoEmit (ec, false);
5535 ec.ig.Emit (OpCodes.Pop);
5539 public virtual bool HasInitializer {
5545 public void AddressOf (EmitContext ec, AddressOp Mode)
5547 if (is_type_parameter) {
5548 LocalTemporary temp = new LocalTemporary (type);
5549 DoEmitTypeParameter (ec);
5551 temp.AddressOf (ec, Mode);
5555 if (!type.IsValueType){
5557 // We throw an exception. So far, I believe we only need to support
5559 // foreach (int j in new StructType ())
5562 throw new Exception ("AddressOf should not be used for classes");
5565 if (!value_target_set)
5566 value_target = new LocalTemporary (type);
5567 IMemoryLocation ml = (IMemoryLocation) value_target;
5569 ml.AddressOf (ec, AddressOp.Store);
5570 if (method == null) {
5571 ec.ig.Emit (OpCodes.Initobj, type);
5573 method.EmitArguments (ec, Arguments);
5574 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5577 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5580 protected override void CloneTo (CloneContext clonectx, Expression t)
5582 New target = (New) t;
5584 target.RequestedType = RequestedType.Clone (clonectx);
5585 if (Arguments != null){
5586 target.Arguments = new ArrayList ();
5587 foreach (Argument a in Arguments){
5588 target.Arguments.Add (a.Clone (clonectx));
5595 /// 14.5.10.2: Represents an array creation expression.
5599 /// There are two possible scenarios here: one is an array creation
5600 /// expression that specifies the dimensions and optionally the
5601 /// initialization data and the other which does not need dimensions
5602 /// specified but where initialization data is mandatory.
5604 public class ArrayCreation : Expression {
5605 FullNamedExpression requested_base_type;
5606 ArrayList initializers;
5609 // The list of Argument types.
5610 // This is used to construct the `newarray' or constructor signature
5612 protected ArrayList arguments;
5614 protected Type array_element_type;
5615 bool expect_initializers = false;
5616 int num_arguments = 0;
5617 protected int dimensions;
5618 protected readonly string rank;
5620 protected ArrayList array_data;
5624 // The number of constants in array initializers
5625 int const_initializers_count;
5626 bool only_constant_initializers;
5628 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5630 this.requested_base_type = requested_base_type;
5631 this.initializers = initializers;
5635 arguments = new ArrayList ();
5637 foreach (Expression e in exprs) {
5638 arguments.Add (new Argument (e, Argument.AType.Expression));
5643 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5645 this.requested_base_type = requested_base_type;
5646 this.initializers = initializers;
5650 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5652 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5654 //dimensions = tmp.Length - 1;
5655 expect_initializers = true;
5658 void Error_IncorrectArrayInitializer ()
5660 Error (178, "Invalid rank specifier: expected `,' or `]'");
5663 protected override void Error_NegativeArrayIndex (Location loc)
5665 Report.Error (248, loc, "Cannot create an array with a negative size");
5668 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5670 if (specified_dims) {
5671 Argument a = (Argument) arguments [idx];
5673 if (!a.Resolve (ec, loc))
5676 Constant c = a.Expr as Constant;
5678 c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5682 Report.Error (150, a.Expr.Location, "A constant value is expected");
5686 int value = (int) c.GetValue ();
5688 if (value != probe.Count) {
5689 Error_IncorrectArrayInitializer ();
5693 bounds [idx] = value;
5696 int child_bounds = -1;
5697 only_constant_initializers = true;
5698 for (int i = 0; i < probe.Count; ++i) {
5699 object o = probe [i];
5700 if (o is ArrayList) {
5701 ArrayList sub_probe = o as ArrayList;
5702 int current_bounds = sub_probe.Count;
5704 if (child_bounds == -1)
5705 child_bounds = current_bounds;
5707 else if (child_bounds != current_bounds){
5708 Error_IncorrectArrayInitializer ();
5711 if (idx + 1 >= dimensions){
5712 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5716 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5720 if (child_bounds != -1){
5721 Error_IncorrectArrayInitializer ();
5725 Expression element = ResolveArrayElement (ec, (Expression) o);
5726 if (element == null)
5729 // Initializers with the default values can be ignored
5730 Constant c = element as Constant;
5732 if (c.IsDefaultInitializer (array_element_type)) {
5736 ++const_initializers_count;
5739 only_constant_initializers = false;
5742 array_data.Add (element);
5749 public override Expression CreateExpressionTree (EmitContext ec)
5753 if (dimensions != 1) {
5754 if (initializers != null) {
5755 Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5759 args = new ArrayList (arguments.Count + 1);
5760 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5761 foreach (Argument a in arguments)
5762 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
5764 return CreateExpressionFactoryCall ("NewArrayBounds", args);
5767 args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
5768 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5769 if (array_data != null) {
5770 foreach (Expression e in array_data)
5771 args.Add (new Argument (e.CreateExpressionTree (ec)));
5774 return CreateExpressionFactoryCall ("NewArrayInit", args);
5777 public void UpdateIndices ()
5780 for (ArrayList probe = initializers; probe != null;) {
5781 if (probe.Count > 0 && probe [0] is ArrayList) {
5782 Expression e = new IntConstant (probe.Count, Location.Null);
5783 arguments.Add (new Argument (e, Argument.AType.Expression));
5785 bounds [i++] = probe.Count;
5787 probe = (ArrayList) probe [0];
5790 Expression e = new IntConstant (probe.Count, Location.Null);
5791 arguments.Add (new Argument (e, Argument.AType.Expression));
5793 bounds [i++] = probe.Count;
5800 Expression first_emit;
5801 LocalTemporary first_emit_temp;
5803 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5805 element = element.Resolve (ec);
5806 if (element == null)
5809 if (element is CompoundAssign.Helper) {
5810 if (first_emit != null)
5811 throw new InternalErrorException ("Can only handle one mutator at a time");
5812 first_emit = element;
5813 element = first_emit_temp = new LocalTemporary (element.Type);
5816 return Convert.ImplicitConversionRequired (
5817 ec, element, array_element_type, loc);
5820 protected bool ResolveInitializers (EmitContext ec)
5822 if (initializers == null) {
5823 return !expect_initializers;
5827 // We use this to store all the date values in the order in which we
5828 // will need to store them in the byte blob later
5830 array_data = new ArrayList ();
5831 bounds = new System.Collections.Specialized.HybridDictionary ();
5833 if (arguments != null)
5834 return CheckIndices (ec, initializers, 0, true);
5836 arguments = new ArrayList ();
5838 if (!CheckIndices (ec, initializers, 0, false))
5847 // Resolved the type of the array
5849 bool ResolveArrayType (EmitContext ec)
5851 if (requested_base_type == null) {
5852 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5856 StringBuilder array_qualifier = new StringBuilder (rank);
5859 // `In the first form allocates an array instace of the type that results
5860 // from deleting each of the individual expression from the expression list'
5862 if (num_arguments > 0) {
5863 array_qualifier.Append ("[");
5864 for (int i = num_arguments-1; i > 0; i--)
5865 array_qualifier.Append (",");
5866 array_qualifier.Append ("]");
5872 TypeExpr array_type_expr;
5873 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5874 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5875 if (array_type_expr == null)
5878 type = array_type_expr.Type;
5879 array_element_type = TypeManager.GetElementType (type);
5880 dimensions = type.GetArrayRank ();
5885 public override Expression DoResolve (EmitContext ec)
5890 if (!ResolveArrayType (ec))
5893 if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5894 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5895 TypeManager.CSharpName (array_element_type));
5899 // First step is to validate the initializers and fill
5900 // in any missing bits
5902 if (!ResolveInitializers (ec))
5905 if (arguments.Count != dimensions) {
5906 Error_IncorrectArrayInitializer ();
5909 foreach (Argument a in arguments){
5910 if (!a.Resolve (ec, loc))
5913 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
5916 eclass = ExprClass.Value;
5920 MethodInfo GetArrayMethod (int arguments)
5922 ModuleBuilder mb = CodeGen.Module.Builder;
5924 Type[] arg_types = new Type[arguments];
5925 for (int i = 0; i < arguments; i++)
5926 arg_types[i] = TypeManager.int32_type;
5928 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5932 Report.Error (-6, "New invocation: Can not find a constructor for " +
5933 "this argument list");
5940 byte [] MakeByteBlob ()
5945 int count = array_data.Count;
5947 if (TypeManager.IsEnumType (array_element_type))
5948 array_element_type = TypeManager.GetEnumUnderlyingType (array_element_type);
5950 factor = GetTypeSize (array_element_type);
5952 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5954 data = new byte [(count * factor + 3) & ~3];
5957 for (int i = 0; i < count; ++i) {
5958 object v = array_data [i];
5960 if (v is EnumConstant)
5961 v = ((EnumConstant) v).Child;
5963 if (v is Constant && !(v is StringConstant))
5964 v = ((Constant) v).GetValue ();
5970 if (array_element_type == TypeManager.int64_type){
5971 if (!(v is Expression)){
5972 long val = (long) v;
5974 for (int j = 0; j < factor; ++j) {
5975 data [idx + j] = (byte) (val & 0xFF);
5979 } else if (array_element_type == TypeManager.uint64_type){
5980 if (!(v is Expression)){
5981 ulong val = (ulong) v;
5983 for (int j = 0; j < factor; ++j) {
5984 data [idx + j] = (byte) (val & 0xFF);
5988 } else if (array_element_type == TypeManager.float_type) {
5989 if (!(v is Expression)){
5990 element = BitConverter.GetBytes ((float) v);
5992 for (int j = 0; j < factor; ++j)
5993 data [idx + j] = element [j];
5994 if (!BitConverter.IsLittleEndian)
5995 System.Array.Reverse (data, idx, 4);
5997 } else if (array_element_type == TypeManager.double_type) {
5998 if (!(v is Expression)){
5999 element = BitConverter.GetBytes ((double) v);
6001 for (int j = 0; j < factor; ++j)
6002 data [idx + j] = element [j];
6004 // FIXME: Handle the ARM float format.
6005 if (!BitConverter.IsLittleEndian)
6006 System.Array.Reverse (data, idx, 8);
6008 } else if (array_element_type == TypeManager.char_type){
6009 if (!(v is Expression)){
6010 int val = (int) ((char) v);
6012 data [idx] = (byte) (val & 0xff);
6013 data [idx+1] = (byte) (val >> 8);
6015 } else if (array_element_type == TypeManager.short_type){
6016 if (!(v is Expression)){
6017 int val = (int) ((short) v);
6019 data [idx] = (byte) (val & 0xff);
6020 data [idx+1] = (byte) (val >> 8);
6022 } else if (array_element_type == TypeManager.ushort_type){
6023 if (!(v is Expression)){
6024 int val = (int) ((ushort) v);
6026 data [idx] = (byte) (val & 0xff);
6027 data [idx+1] = (byte) (val >> 8);
6029 } else if (array_element_type == TypeManager.int32_type) {
6030 if (!(v is Expression)){
6033 data [idx] = (byte) (val & 0xff);
6034 data [idx+1] = (byte) ((val >> 8) & 0xff);
6035 data [idx+2] = (byte) ((val >> 16) & 0xff);
6036 data [idx+3] = (byte) (val >> 24);
6038 } else if (array_element_type == TypeManager.uint32_type) {
6039 if (!(v is Expression)){
6040 uint val = (uint) v;
6042 data [idx] = (byte) (val & 0xff);
6043 data [idx+1] = (byte) ((val >> 8) & 0xff);
6044 data [idx+2] = (byte) ((val >> 16) & 0xff);
6045 data [idx+3] = (byte) (val >> 24);
6047 } else if (array_element_type == TypeManager.sbyte_type) {
6048 if (!(v is Expression)){
6049 sbyte val = (sbyte) v;
6050 data [idx] = (byte) val;
6052 } else if (array_element_type == TypeManager.byte_type) {
6053 if (!(v is Expression)){
6054 byte val = (byte) v;
6055 data [idx] = (byte) val;
6057 } else if (array_element_type == TypeManager.bool_type) {
6058 if (!(v is Expression)){
6059 bool val = (bool) v;
6060 data [idx] = (byte) (val ? 1 : 0);
6062 } else if (array_element_type == TypeManager.decimal_type){
6063 if (!(v is Expression)){
6064 int [] bits = Decimal.GetBits ((decimal) v);
6067 // FIXME: For some reason, this doesn't work on the MS runtime.
6068 int [] nbits = new int [4];
6069 nbits [0] = bits [3];
6070 nbits [1] = bits [2];
6071 nbits [2] = bits [0];
6072 nbits [3] = bits [1];
6074 for (int j = 0; j < 4; j++){
6075 data [p++] = (byte) (nbits [j] & 0xff);
6076 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6077 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6078 data [p++] = (byte) (nbits [j] >> 24);
6082 throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
6091 // Emits the initializers for the array
6093 void EmitStaticInitializers (EmitContext ec)
6095 // FIXME: This should go to Resolve !
6096 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6097 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6098 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6099 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6100 if (TypeManager.void_initializearray_array_fieldhandle == null)
6105 // First, the static data
6108 ILGenerator ig = ec.ig;
6110 byte [] data = MakeByteBlob ();
6112 fb = RootContext.MakeStaticData (data);
6114 ig.Emit (OpCodes.Dup);
6115 ig.Emit (OpCodes.Ldtoken, fb);
6116 ig.Emit (OpCodes.Call,
6117 TypeManager.void_initializearray_array_fieldhandle);
6121 // Emits pieces of the array that can not be computed at compile
6122 // time (variables and string locations).
6124 // This always expect the top value on the stack to be the array
6126 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6128 ILGenerator ig = ec.ig;
6129 int dims = bounds.Count;
6130 int [] current_pos = new int [dims];
6132 MethodInfo set = null;
6135 Type [] args = new Type [dims + 1];
6137 for (int j = 0; j < dims; j++)
6138 args [j] = TypeManager.int32_type;
6139 args [dims] = array_element_type;
6141 set = CodeGen.Module.Builder.GetArrayMethod (
6143 CallingConventions.HasThis | CallingConventions.Standard,
6144 TypeManager.void_type, args);
6147 for (int i = 0; i < array_data.Count; i++){
6149 Expression e = (Expression)array_data [i];
6151 // Constant can be initialized via StaticInitializer
6152 if (e != null && !(!emitConstants && e is Constant)) {
6153 Type etype = e.Type;
6155 ig.Emit (OpCodes.Dup);
6157 for (int idx = 0; idx < dims; idx++)
6158 IntConstant.EmitInt (ig, current_pos [idx]);
6161 // If we are dealing with a struct, get the
6162 // address of it, so we can store it.
6164 if ((dims == 1) && etype.IsValueType &&
6165 (!TypeManager.IsBuiltinOrEnum (etype) ||
6166 etype == TypeManager.decimal_type)) {
6171 // Let new know that we are providing
6172 // the address where to store the results
6174 n.DisableTemporaryValueType ();
6177 ig.Emit (OpCodes.Ldelema, etype);
6183 bool is_stobj, has_type_arg;
6184 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6186 ig.Emit (OpCodes.Stobj, etype);
6187 else if (has_type_arg)
6188 ig.Emit (op, etype);
6192 ig.Emit (OpCodes.Call, set);
6199 for (int j = dims - 1; j >= 0; j--){
6201 if (current_pos [j] < (int) bounds [j])
6203 current_pos [j] = 0;
6208 public override void Emit (EmitContext ec)
6210 ILGenerator ig = ec.ig;
6212 if (first_emit != null) {
6213 first_emit.Emit (ec);
6214 first_emit_temp.Store (ec);
6217 foreach (Argument a in arguments)
6220 if (arguments.Count == 1)
6221 ig.Emit (OpCodes.Newarr, array_element_type);
6223 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6226 if (initializers == null)
6229 // Emit static initializer for arrays which have contain more than 4 items and
6230 // the static initializer will initialize at least 25% of array values.
6231 // NOTE: const_initializers_count does not contain default constant values.
6232 if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6233 TypeManager.IsPrimitiveType (array_element_type)) {
6234 EmitStaticInitializers (ec);
6236 if (!only_constant_initializers)
6237 EmitDynamicInitializers (ec, false);
6239 EmitDynamicInitializers (ec, true);
6242 if (first_emit_temp != null)
6243 first_emit_temp.Release (ec);
6246 public override bool GetAttributableValue (Type value_type, out object value)
6248 if (arguments.Count != 1) {
6249 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6250 return base.GetAttributableValue (null, out value);
6253 if (array_data == null) {
6254 Constant c = (Constant)((Argument)arguments [0]).Expr;
6255 if (c.IsDefaultValue) {
6256 value = Array.CreateInstance (array_element_type, 0);
6259 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6260 return base.GetAttributableValue (null, out value);
6263 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6264 object element_value;
6265 for (int i = 0; i < ret.Length; ++i)
6267 Expression e = (Expression)array_data [i];
6269 // Is null when an initializer is optimized (value == predefined value)
6273 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6277 ret.SetValue (element_value, i);
6283 protected override void CloneTo (CloneContext clonectx, Expression t)
6285 ArrayCreation target = (ArrayCreation) t;
6287 if (requested_base_type != null)
6288 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6290 if (arguments != null){
6291 target.arguments = new ArrayList (arguments.Count);
6292 foreach (Argument a in arguments)
6293 target.arguments.Add (a.Clone (clonectx));
6296 if (initializers != null){
6297 target.initializers = new ArrayList (initializers.Count);
6298 foreach (object initializer in initializers)
6299 if (initializer is ArrayList) {
6300 ArrayList this_al = (ArrayList)initializer;
6301 ArrayList al = new ArrayList (this_al.Count);
6302 target.initializers.Add (al);
6303 foreach (Expression e in this_al)
6304 al.Add (e.Clone (clonectx));
6306 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6313 // Represents an implicitly typed array epxression
6315 public class ImplicitlyTypedArrayCreation : ArrayCreation
6317 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6318 : base (null, rank, initializers, loc)
6320 if (RootContext.Version <= LanguageVersion.ISO_2)
6321 Report.FeatureIsNotAvailable (loc, "implicitly typed arrays");
6323 if (rank.Length > 2) {
6324 while (rank [++dimensions] == ',');
6330 public override Expression DoResolve (EmitContext ec)
6335 if (!ResolveInitializers (ec))
6338 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6339 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6340 arguments.Count != dimensions) {
6341 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6346 // At this point we found common base type for all initializer elements
6347 // but we have to be sure that all static initializer elements are of
6350 UnifyInitializerElement (ec);
6352 type = TypeManager.GetConstructedType (array_element_type, rank);
6353 eclass = ExprClass.Value;
6358 // Converts static initializer only
6360 void UnifyInitializerElement (EmitContext ec)
6362 for (int i = 0; i < array_data.Count; ++i) {
6363 Expression e = (Expression)array_data[i];
6365 array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6369 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6371 element = element.Resolve (ec);
6372 if (element == null)
6375 if (array_element_type == null) {
6376 array_element_type = element.Type;
6380 if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6384 if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6385 array_element_type = element.Type;
6389 element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6394 public sealed class CompilerGeneratedThis : This
6396 public static This Instance = new CompilerGeneratedThis ();
6398 private CompilerGeneratedThis ()
6399 : base (Location.Null)
6403 public override Expression DoResolve (EmitContext ec)
6405 eclass = ExprClass.Variable;
6406 type = ec.ContainerType;
6407 variable = new SimpleThis (type);
6413 /// Represents the `this' construct
6416 public class This : VariableReference, IVariable
6419 VariableInfo variable_info;
6420 protected Variable variable;
6423 public This (Block block, Location loc)
6429 public This (Location loc)
6434 public VariableInfo VariableInfo {
6435 get { return variable_info; }
6438 public bool VerifyFixed ()
6440 return !TypeManager.IsValueType (Type);
6443 public override bool IsRef {
6444 get { return is_struct; }
6447 public override Variable Variable {
6448 get { return variable; }
6451 public bool ResolveBase (EmitContext ec)
6453 eclass = ExprClass.Variable;
6455 if (ec.TypeContainer.CurrentType != null)
6456 type = ec.TypeContainer.CurrentType;
6458 type = ec.ContainerType;
6460 is_struct = ec.TypeContainer is Struct;
6463 Error (26, "Keyword `this' is not valid in a static property, " +
6464 "static method, or static field initializer");
6468 if (block != null) {
6469 if (block.Toplevel.ThisVariable != null)
6470 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6472 AnonymousContainer am = ec.CurrentAnonymousMethod;
6473 if (is_struct && (am != null) && !am.IsIterator) {
6474 Report.Error (1673, loc, "Anonymous methods inside structs " +
6475 "cannot access instance members of `this'. " +
6476 "Consider copying `this' to a local variable " +
6477 "outside the anonymous method and using the " +
6481 RootScopeInfo host = block.Toplevel.RootScope;
6482 if ((host != null) && !ec.IsConstructor &&
6483 (!is_struct || host.IsIterator)) {
6484 variable = host.CaptureThis ();
6485 type = variable.Type;
6490 if (variable == null)
6491 variable = new SimpleThis (type);
6497 // Called from Invocation to check if the invocation is correct
6499 public override void CheckMarshalByRefAccess (EmitContext ec)
6501 if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6502 !variable_info.IsAssigned (ec)) {
6503 Error (188, "The `this' object cannot be used before all of its " +
6504 "fields are assigned to");
6505 variable_info.SetAssigned (ec);
6509 public override Expression CreateExpressionTree (EmitContext ec)
6511 ArrayList args = new ArrayList (2);
6512 args.Add (new Argument (this));
6513 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6514 return CreateExpressionFactoryCall ("Constant", args);
6517 public override Expression DoResolve (EmitContext ec)
6519 if (!ResolveBase (ec))
6523 if (ec.IsInFieldInitializer) {
6524 Error (27, "Keyword `this' is not available in the current context");
6531 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6533 if (!ResolveBase (ec))
6536 if (variable_info != null)
6537 variable_info.SetAssigned (ec);
6539 if (ec.TypeContainer is Class){
6540 Error (1604, "Cannot assign to 'this' because it is read-only");
6546 public override int GetHashCode()
6548 return block.GetHashCode ();
6551 public override bool Equals (object obj)
6553 This t = obj as This;
6557 return block == t.block;
6560 protected class SimpleThis : Variable
6564 public SimpleThis (Type type)
6569 public override Type Type {
6570 get { return type; }
6573 public override bool HasInstance {
6574 get { return false; }
6577 public override bool NeedsTemporary {
6578 get { return false; }
6581 public override void EmitInstance (EmitContext ec)
6586 public override void Emit (EmitContext ec)
6588 ec.ig.Emit (OpCodes.Ldarg_0);
6591 public override void EmitAssign (EmitContext ec)
6593 throw new InvalidOperationException ();
6596 public override void EmitAddressOf (EmitContext ec)
6598 ec.ig.Emit (OpCodes.Ldarg_0);
6602 protected override void CloneTo (CloneContext clonectx, Expression t)
6604 This target = (This) t;
6606 target.block = clonectx.LookupBlock (block);
6611 /// Represents the `__arglist' construct
6613 public class ArglistAccess : Expression
6615 public ArglistAccess (Location loc)
6620 public override Expression DoResolve (EmitContext ec)
6622 eclass = ExprClass.Variable;
6623 type = TypeManager.runtime_argument_handle_type;
6625 if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
6627 Error (190, "The __arglist construct is valid only within " +
6628 "a variable argument method");
6635 public override void Emit (EmitContext ec)
6637 ec.ig.Emit (OpCodes.Arglist);
6640 protected override void CloneTo (CloneContext clonectx, Expression target)
6647 /// Represents the `__arglist (....)' construct
6649 public class Arglist : Expression
6651 Argument[] Arguments;
6653 public Arglist (Location loc)
6654 : this (Argument.Empty, loc)
6658 public Arglist (Argument[] args, Location l)
6664 public Type[] ArgumentTypes {
6666 Type[] retval = new Type [Arguments.Length];
6667 for (int i = 0; i < Arguments.Length; i++)
6668 retval [i] = Arguments [i].Type;
6673 public override Expression CreateExpressionTree (EmitContext ec)
6675 Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6679 public override Expression DoResolve (EmitContext ec)
6681 eclass = ExprClass.Variable;
6682 type = TypeManager.runtime_argument_handle_type;
6684 foreach (Argument arg in Arguments) {
6685 if (!arg.Resolve (ec, loc))
6692 public override void Emit (EmitContext ec)
6694 foreach (Argument arg in Arguments)
6698 protected override void CloneTo (CloneContext clonectx, Expression t)
6700 Arglist target = (Arglist) t;
6702 target.Arguments = new Argument [Arguments.Length];
6703 for (int i = 0; i < Arguments.Length; i++)
6704 target.Arguments [i] = Arguments [i].Clone (clonectx);
6709 // This produces the value that renders an instance, used by the iterators code
6711 public class ProxyInstance : Expression, IMemoryLocation {
6712 public override Expression DoResolve (EmitContext ec)
6714 eclass = ExprClass.Variable;
6715 type = ec.ContainerType;
6719 public override void Emit (EmitContext ec)
6721 ec.ig.Emit (OpCodes.Ldarg_0);
6725 public void AddressOf (EmitContext ec, AddressOp mode)
6727 ec.ig.Emit (OpCodes.Ldarg_0);
6732 /// Implements the typeof operator
6734 public class TypeOf : Expression {
6735 Expression QueriedType;
6736 protected Type typearg;
6738 public TypeOf (Expression queried_type, Location l)
6740 QueriedType = queried_type;
6744 public override Expression CreateExpressionTree (EmitContext ec)
6746 ArrayList args = new ArrayList (2);
6747 args.Add (new Argument (this));
6748 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6749 return CreateExpressionFactoryCall ("Constant", args);
6752 public override Expression DoResolve (EmitContext ec)
6754 if (eclass != ExprClass.Invalid)
6757 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6761 typearg = texpr.Type;
6763 if (typearg == TypeManager.void_type) {
6764 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6768 if (typearg.IsPointer && !ec.InUnsafe){
6773 type = TypeManager.type_type;
6775 return DoResolveBase ();
6778 protected Expression DoResolveBase ()
6780 if (TypeManager.system_type_get_type_from_handle == null) {
6781 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6782 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6785 // Even though what is returned is a type object, it's treated as a value by the compiler.
6786 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6787 eclass = ExprClass.Value;
6791 public override void Emit (EmitContext ec)
6793 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6794 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6797 public override bool GetAttributableValue (Type value_type, out object value)
6799 if (TypeManager.ContainsGenericParameters (typearg) &&
6800 !TypeManager.IsGenericTypeDefinition (typearg)) {
6801 Report.SymbolRelatedToPreviousError (typearg);
6802 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6803 TypeManager.CSharpName (typearg));
6808 if (value_type == TypeManager.object_type) {
6809 value = (object)typearg;
6816 public Type TypeArgument
6824 protected override void CloneTo (CloneContext clonectx, Expression t)
6826 TypeOf target = (TypeOf) t;
6827 if (QueriedType != null)
6828 target.QueriedType = QueriedType.Clone (clonectx);
6833 /// Implements the `typeof (void)' operator
6835 public class TypeOfVoid : TypeOf {
6836 public TypeOfVoid (Location l) : base (null, l)
6841 public override Expression DoResolve (EmitContext ec)
6843 type = TypeManager.type_type;
6844 typearg = TypeManager.void_type;
6846 return DoResolveBase ();
6850 class TypeOfMethodInfo : TypeOfMethod
6852 public TypeOfMethodInfo (MethodBase method, Location loc)
6853 : base (method, loc)
6857 public override Expression DoResolve (EmitContext ec)
6859 type = typeof (MethodInfo);
6860 return base.DoResolve (ec);
6863 public override void Emit (EmitContext ec)
6865 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) method);
6867 ec.ig.Emit (OpCodes.Castclass, type);
6871 class TypeOfConstructorInfo : TypeOfMethod
6873 public TypeOfConstructorInfo (MethodBase method, Location loc)
6874 : base (method, loc)
6878 public override Expression DoResolve (EmitContext ec)
6880 type = typeof (ConstructorInfo);
6881 return base.DoResolve (ec);
6884 public override void Emit (EmitContext ec)
6886 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) method);
6888 ec.ig.Emit (OpCodes.Castclass, type);
6892 abstract class TypeOfMethod : Expression
6894 protected readonly MethodBase method;
6896 protected TypeOfMethod (MethodBase method, Location loc)
6898 this.method = method;
6902 public override Expression CreateExpressionTree (EmitContext ec)
6904 ArrayList args = new ArrayList (2);
6905 args.Add (new Argument (this));
6906 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6907 return CreateExpressionFactoryCall ("Constant", args);
6910 public override Expression DoResolve (EmitContext ec)
6912 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6913 MethodInfo mi = is_generic ?
6914 TypeManager.methodbase_get_type_from_handle_generic :
6915 TypeManager.methodbase_get_type_from_handle;
6918 Type t = TypeManager.CoreLookupType ("System.Reflection", "MethodBase", Kind.Class, true);
6919 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeMethodHandle", Kind.Class, true);
6921 if (t == null || handle_type == null)
6924 mi = TypeManager.GetPredefinedMethod (t, "GetMethodFromHandle", loc,
6926 new Type[] { handle_type, TypeManager.runtime_handle_type } :
6927 new Type[] { handle_type } );
6930 TypeManager.methodbase_get_type_from_handle_generic = mi;
6932 TypeManager.methodbase_get_type_from_handle = mi;
6935 eclass = ExprClass.Value;
6939 public override void Emit (EmitContext ec)
6941 bool is_generic = TypeManager.IsGenericType (method.DeclaringType);
6944 mi = TypeManager.methodbase_get_type_from_handle_generic;
6945 ec.ig.Emit (OpCodes.Ldtoken, method.DeclaringType);
6947 mi = TypeManager.methodbase_get_type_from_handle;
6950 ec.ig.Emit (OpCodes.Call, mi);
6954 internal class TypeOfField : Expression
6956 readonly FieldInfo field;
6958 public TypeOfField (FieldInfo field, Location loc)
6964 public override Expression DoResolve (EmitContext ec)
6966 if (TypeManager.fieldinfo_get_field_from_handle == null) {
6967 Type t = TypeManager.CoreLookupType ("System.Reflection", "FieldInfo", Kind.Class, true);
6968 Type handle_type = TypeManager.CoreLookupType ("System", "RuntimeFieldHandle", Kind.Class, true);
6970 if (t != null && handle_type != null)
6971 TypeManager.fieldinfo_get_field_from_handle = TypeManager.GetPredefinedMethod (t,
6972 "GetFieldFromHandle", loc, handle_type);
6975 type = typeof (FieldInfo);
6976 eclass = ExprClass.Value;
6980 public override void Emit (EmitContext ec)
6982 ec.ig.Emit (OpCodes.Ldtoken, field);
6983 ec.ig.Emit (OpCodes.Call, TypeManager.fieldinfo_get_field_from_handle);
6988 /// Implements the sizeof expression
6990 public class SizeOf : Expression {
6991 readonly Expression QueriedType;
6994 public SizeOf (Expression queried_type, Location l)
6996 this.QueriedType = queried_type;
7000 public override Expression DoResolve (EmitContext ec)
7002 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7006 type_queried = texpr.Type;
7007 if (TypeManager.IsEnumType (type_queried))
7008 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7010 if (type_queried == TypeManager.void_type) {
7011 Expression.Error_VoidInvalidInTheContext (loc);
7015 int size_of = GetTypeSize (type_queried);
7017 return new IntConstant (size_of, loc);
7020 if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7025 Report.Error (233, loc,
7026 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7027 TypeManager.CSharpName (type_queried));
7030 type = TypeManager.int32_type;
7031 eclass = ExprClass.Value;
7035 public override void Emit (EmitContext ec)
7037 int size = GetTypeSize (type_queried);
7040 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7042 IntConstant.EmitInt (ec.ig, size);
7045 protected override void CloneTo (CloneContext clonectx, Expression t)
7051 /// Implements the qualified-alias-member (::) expression.
7053 public class QualifiedAliasMember : MemberAccess
7055 readonly string alias;
7057 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7058 : base (null, identifier, targs, l)
7063 public QualifiedAliasMember (string alias, string identifier, Location l)
7064 : base (null, identifier, l)
7069 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7071 if (alias == "global") {
7072 expr = RootNamespace.Global;
7073 return base.ResolveAsTypeStep (ec, silent);
7076 int errors = Report.Errors;
7077 expr = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7079 if (errors == Report.Errors)
7080 Report.Error (432, loc, "Alias `{0}' not found", alias);
7084 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7088 if (expr.eclass == ExprClass.Type) {
7090 Report.Error (431, loc,
7091 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7099 public override Expression DoResolve (EmitContext ec)
7101 return ResolveAsTypeStep (ec, false);
7104 protected override void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7106 Report.Error (687, loc,
7107 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7108 GetSignatureForError ());
7111 public override string GetSignatureForError ()
7114 if (targs != null) {
7115 name = TypeManager.RemoveGenericArity (Name) + "<" +
7116 targs.GetSignatureForError () + ">";
7119 return alias + "::" + name;
7122 protected override void CloneTo (CloneContext clonectx, Expression t)
7129 /// Implements the member access expression
7131 public class MemberAccess : ATypeNameExpression {
7132 protected Expression expr;
7134 public MemberAccess (Expression expr, string id)
7135 : base (id, expr.Location)
7140 public MemberAccess (Expression expr, string identifier, Location loc)
7141 : base (identifier, loc)
7146 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7147 : base (identifier, args, loc)
7152 // TODO: this method has very poor performace for Enum fields and
7153 // probably for other constants as well
7154 Expression DoResolve (EmitContext ec, Expression right_side)
7157 throw new Exception ();
7160 // Resolve the expression with flow analysis turned off, we'll do the definite
7161 // assignment checks later. This is because we don't know yet what the expression
7162 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7163 // definite assignment check on the actual field and not on the whole struct.
7166 SimpleName original = expr as SimpleName;
7167 Expression expr_resolved = expr.Resolve (ec,
7168 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7169 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7171 if (expr_resolved == null)
7174 string LookupIdentifier = MemberName.MakeName (Name, targs);
7176 if (expr_resolved is Namespace) {
7177 Namespace ns = (Namespace) expr_resolved;
7178 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7180 if ((retval != null) && (targs != null))
7181 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (ec, false);
7185 ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Name);
7189 Type expr_type = expr_resolved.Type;
7190 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7191 expr_resolved is NullLiteral || expr_type == TypeManager.anonymous_method_type) {
7192 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7196 Constant c = expr_resolved as Constant;
7197 if (c != null && c.GetValue () == null) {
7198 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7199 "System.NullReferenceException");
7202 if (targs != null) {
7203 if (!targs.Resolve (ec))
7207 Expression member_lookup;
7208 member_lookup = MemberLookup (
7209 ec.ContainerType, expr_type, expr_type, Name, loc);
7211 if ((member_lookup == null) && (targs != null)) {
7212 member_lookup = MemberLookup (
7213 ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7216 if (member_lookup == null) {
7217 ExprClass expr_eclass = expr_resolved.eclass;
7220 // Extension methods are not allowed on all expression types
7222 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7223 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7224 expr_eclass == ExprClass.EventAccess) {
7225 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (expr_type, Name, loc);
7226 if (ex_method_lookup != null) {
7227 ex_method_lookup.ExtensionExpression = expr_resolved;
7229 if (targs != null) {
7230 ex_method_lookup.SetTypeArguments (targs);
7233 return ex_method_lookup.DoResolve (ec);
7237 expr = expr_resolved;
7238 Error_MemberLookupFailed (
7239 ec.ContainerType, expr_type, expr_type, Name, null,
7240 AllMemberTypes, AllBindingFlags);
7244 TypeExpr texpr = member_lookup as TypeExpr;
7245 if (texpr != null) {
7246 if (!(expr_resolved is TypeExpr) &&
7247 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7248 Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7249 Name, member_lookup.GetSignatureForError ());
7253 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7254 Report.SymbolRelatedToPreviousError (member_lookup.Type);
7255 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7260 ConstructedType ct = expr_resolved as ConstructedType;
7263 // When looking up a nested type in a generic instance
7264 // via reflection, we always get a generic type definition
7265 // and not a generic instance - so we have to do this here.
7267 // See gtest-172-lib.cs and gtest-172.cs for an example.
7269 ct = new ConstructedType (
7270 member_lookup.Type, ct.TypeArguments, loc);
7272 return ct.ResolveAsTypeStep (ec, false);
7275 return member_lookup;
7278 MemberExpr me = (MemberExpr) member_lookup;
7279 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7283 if (targs != null) {
7284 me.SetTypeArguments (targs);
7287 if (original != null && !TypeManager.IsValueType (expr_type)) {
7288 if (me.IsInstance) {
7289 LocalVariableReference var = expr_resolved as LocalVariableReference;
7290 if (var != null && !var.VerifyAssigned (ec))
7295 // The following DoResolve/DoResolveLValue will do the definite assignment
7298 if (right_side != null)
7299 return me.DoResolveLValue (ec, right_side);
7301 return me.DoResolve (ec);
7304 public override Expression DoResolve (EmitContext ec)
7306 return DoResolve (ec, null);
7309 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7311 return DoResolve (ec, right_side);
7314 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7316 return ResolveNamespaceOrType (ec, silent);
7319 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7321 FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7323 if (new_expr == null)
7326 string LookupIdentifier = MemberName.MakeName (Name, targs);
7328 if (new_expr is Namespace) {
7329 Namespace ns = (Namespace) new_expr;
7330 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7332 if ((retval != null) && (targs != null))
7333 retval = new ConstructedType (retval, targs, loc).ResolveAsTypeStep (rc, false);
7335 if (!silent && retval == null)
7336 ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7340 TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7341 if (tnew_expr == null)
7344 Type expr_type = tnew_expr.Type;
7346 if (expr_type.IsPointer){
7347 Error (23, "The `.' operator can not be applied to pointer operands (" +
7348 TypeManager.CSharpName (expr_type) + ")");
7352 Expression member_lookup = MemberLookup (
7353 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7354 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7355 if (member_lookup == null) {
7359 Error_IdentifierNotFound (rc, new_expr, LookupIdentifier);
7363 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7368 TypeArguments the_args = targs;
7369 Type declaring_type = texpr.Type.DeclaringType;
7370 if (TypeManager.HasGenericArguments (declaring_type)) {
7371 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7372 expr_type = expr_type.BaseType;
7375 TypeArguments new_args = new TypeArguments (loc);
7376 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7377 new_args.Add (new TypeExpression (decl, loc));
7380 new_args.Add (targs);
7382 the_args = new_args;
7385 if (the_args != null) {
7386 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7387 return ctype.ResolveAsTypeStep (rc, false);
7394 protected virtual void Error_IdentifierNotFound (IResolveContext rc, FullNamedExpression expr_type, string identifier)
7396 Expression member_lookup = MemberLookup (
7397 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7398 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7400 if (member_lookup != null) {
7401 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7402 if (expr_type == null)
7405 Namespace.Error_TypeArgumentsCannotBeUsed (expr_type.Type, loc);
7409 member_lookup = MemberLookup (
7410 rc.DeclContainer.TypeBuilder, expr_type.Type, expr_type.Type, identifier,
7411 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7413 if (member_lookup == null) {
7414 Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7415 Name, expr_type.GetSignatureForError ());
7417 // TODO: Report.SymbolRelatedToPreviousError
7418 member_lookup.Error_UnexpectedKind (null, "type", loc);
7422 protected override void Error_TypeDoesNotContainDefinition (Type type, string name)
7424 if (RootContext.Version > LanguageVersion.ISO_2 &&
7425 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7426 Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7427 "extension method `{1}' of type `{0}' could be found " +
7428 "(are you missing a using directive or an assembly reference?)",
7429 TypeManager.CSharpName (type), name);
7433 base.Error_TypeDoesNotContainDefinition (type, name);
7436 public override string GetSignatureForError ()
7438 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7441 protected override void CloneTo (CloneContext clonectx, Expression t)
7443 MemberAccess target = (MemberAccess) t;
7445 target.expr = expr.Clone (clonectx);
7450 /// Implements checked expressions
7452 public class CheckedExpr : Expression {
7454 public Expression Expr;
7456 public CheckedExpr (Expression e, Location l)
7462 public override Expression CreateExpressionTree (EmitContext ec)
7464 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7465 return Expr.CreateExpressionTree (ec);
7468 public override Expression DoResolve (EmitContext ec)
7470 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7471 Expr = Expr.Resolve (ec);
7476 if (Expr is Constant)
7479 eclass = Expr.eclass;
7484 public override void Emit (EmitContext ec)
7486 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7490 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7492 using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7493 Expr.EmitBranchable (ec, target, on_true);
7496 protected override void CloneTo (CloneContext clonectx, Expression t)
7498 CheckedExpr target = (CheckedExpr) t;
7500 target.Expr = Expr.Clone (clonectx);
7505 /// Implements the unchecked expression
7507 public class UnCheckedExpr : Expression {
7509 public Expression Expr;
7511 public UnCheckedExpr (Expression e, Location l)
7517 public override Expression CreateExpressionTree (EmitContext ec)
7519 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7520 return Expr.CreateExpressionTree (ec);
7523 public override Expression DoResolve (EmitContext ec)
7525 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7526 Expr = Expr.Resolve (ec);
7531 if (Expr is Constant)
7534 eclass = Expr.eclass;
7539 public override void Emit (EmitContext ec)
7541 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7545 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7547 using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7548 Expr.EmitBranchable (ec, target, on_true);
7551 protected override void CloneTo (CloneContext clonectx, Expression t)
7553 UnCheckedExpr target = (UnCheckedExpr) t;
7555 target.Expr = Expr.Clone (clonectx);
7560 /// An Element Access expression.
7562 /// During semantic analysis these are transformed into
7563 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7565 public class ElementAccess : Expression {
7566 public ArrayList Arguments;
7567 public Expression Expr;
7569 public ElementAccess (Expression e, ArrayList e_list)
7578 Arguments = new ArrayList ();
7579 foreach (Expression tmp in e_list)
7580 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7584 bool CommonResolve (EmitContext ec)
7586 Expr = Expr.Resolve (ec);
7588 if (Arguments == null)
7591 foreach (Argument a in Arguments){
7592 if (!a.Resolve (ec, loc))
7596 return Expr != null;
7599 public override Expression CreateExpressionTree (EmitContext ec)
7601 ArrayList args = new ArrayList (Arguments.Count + 1);
7602 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
7603 foreach (Argument a in Arguments)
7604 args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
7606 return CreateExpressionFactoryCall ("ArrayIndex", args);
7609 Expression MakePointerAccess (EmitContext ec, Type t)
7611 if (t == TypeManager.void_ptr_type){
7612 Error (242, "The array index operation is not valid on void pointers");
7615 if (Arguments.Count != 1){
7616 Error (196, "A pointer must be indexed by only one value");
7621 p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7624 return new Indirection (p, loc).Resolve (ec);
7627 public override Expression DoResolve (EmitContext ec)
7629 if (!CommonResolve (ec))
7633 // We perform some simple tests, and then to "split" the emit and store
7634 // code we create an instance of a different class, and return that.
7636 // I am experimenting with this pattern.
7640 if (t == TypeManager.array_type){
7641 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7646 return (new ArrayAccess (this, loc)).Resolve (ec);
7648 return MakePointerAccess (ec, t);
7650 FieldExpr fe = Expr as FieldExpr;
7652 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7654 return MakePointerAccess (ec, ff.ElementType);
7657 return (new IndexerAccess (this, loc)).Resolve (ec);
7660 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7662 if (!CommonResolve (ec))
7667 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7670 return MakePointerAccess (ec, type);
7672 if (Expr.eclass != ExprClass.Variable && type.IsValueType)
7673 Error_CannotModifyIntermediateExpressionValue (ec);
7675 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7678 public override void Emit (EmitContext ec)
7680 throw new Exception ("Should never be reached");
7683 public override string GetSignatureForError ()
7685 return Expr.GetSignatureForError ();
7688 protected override void CloneTo (CloneContext clonectx, Expression t)
7690 ElementAccess target = (ElementAccess) t;
7692 target.Expr = Expr.Clone (clonectx);
7693 target.Arguments = new ArrayList (Arguments.Count);
7694 foreach (Argument a in Arguments)
7695 target.Arguments.Add (a.Clone (clonectx));
7700 /// Implements array access
7702 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7704 // Points to our "data" repository
7708 LocalTemporary temp;
7712 public ArrayAccess (ElementAccess ea_data, Location l)
7715 eclass = ExprClass.Variable;
7719 public override Expression CreateExpressionTree (EmitContext ec)
7721 return ea.CreateExpressionTree (ec);
7724 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7726 return DoResolve (ec);
7729 public override Expression DoResolve (EmitContext ec)
7732 ExprClass eclass = ea.Expr.eclass;
7734 // As long as the type is valid
7735 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7736 eclass == ExprClass.Value)) {
7737 ea.Expr.Error_UnexpectedKind ("variable or value");
7742 Type t = ea.Expr.Type;
7743 int rank = ea.Arguments.Count;
7744 if (t.GetArrayRank () != rank) {
7745 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7746 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7750 if (rank != 1 && TypeManager.int_getlength_int == null) {
7751 TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
7752 TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
7755 type = TypeManager.GetElementType (t);
7756 if (type.IsPointer && !ec.InUnsafe) {
7757 UnsafeError (ea.Location);
7761 foreach (Argument a in ea.Arguments) {
7762 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7765 eclass = ExprClass.Variable;
7771 /// Emits the right opcode to load an object of Type `t'
7772 /// from an array of T
7774 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7777 MethodInfo get = FetchGetMethod ();
7778 ig.Emit (OpCodes.Call, get);
7782 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7783 ig.Emit (OpCodes.Ldelem_U1);
7784 else if (type == TypeManager.sbyte_type)
7785 ig.Emit (OpCodes.Ldelem_I1);
7786 else if (type == TypeManager.short_type)
7787 ig.Emit (OpCodes.Ldelem_I2);
7788 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7789 ig.Emit (OpCodes.Ldelem_U2);
7790 else if (type == TypeManager.int32_type)
7791 ig.Emit (OpCodes.Ldelem_I4);
7792 else if (type == TypeManager.uint32_type)
7793 ig.Emit (OpCodes.Ldelem_U4);
7794 else if (type == TypeManager.uint64_type)
7795 ig.Emit (OpCodes.Ldelem_I8);
7796 else if (type == TypeManager.int64_type)
7797 ig.Emit (OpCodes.Ldelem_I8);
7798 else if (type == TypeManager.float_type)
7799 ig.Emit (OpCodes.Ldelem_R4);
7800 else if (type == TypeManager.double_type)
7801 ig.Emit (OpCodes.Ldelem_R8);
7802 else if (type == TypeManager.intptr_type)
7803 ig.Emit (OpCodes.Ldelem_I);
7804 else if (TypeManager.IsEnumType (type)){
7805 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
7806 } else if (type.IsValueType){
7807 ig.Emit (OpCodes.Ldelema, type);
7808 ig.Emit (OpCodes.Ldobj, type);
7810 } else if (type.IsGenericParameter) {
7811 ig.Emit (OpCodes.Ldelem, type);
7813 } else if (type.IsPointer)
7814 ig.Emit (OpCodes.Ldelem_I);
7816 ig.Emit (OpCodes.Ldelem_Ref);
7819 protected override void Error_NegativeArrayIndex (Location loc)
7821 Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
7825 /// Returns the right opcode to store an object of Type `t'
7826 /// from an array of T.
7828 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7830 //Console.WriteLine (new System.Diagnostics.StackTrace ());
7831 has_type_arg = false; is_stobj = false;
7832 t = TypeManager.TypeToCoreType (t);
7833 if (TypeManager.IsEnumType (t))
7834 t = TypeManager.GetEnumUnderlyingType (t);
7835 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7836 t == TypeManager.bool_type)
7837 return OpCodes.Stelem_I1;
7838 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7839 t == TypeManager.char_type)
7840 return OpCodes.Stelem_I2;
7841 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7842 return OpCodes.Stelem_I4;
7843 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7844 return OpCodes.Stelem_I8;
7845 else if (t == TypeManager.float_type)
7846 return OpCodes.Stelem_R4;
7847 else if (t == TypeManager.double_type)
7848 return OpCodes.Stelem_R8;
7849 else if (t == TypeManager.intptr_type) {
7850 has_type_arg = true;
7852 return OpCodes.Stobj;
7853 } else if (t.IsValueType) {
7854 has_type_arg = true;
7856 return OpCodes.Stobj;
7858 } else if (t.IsGenericParameter) {
7859 has_type_arg = true;
7860 return OpCodes.Stelem;
7863 } else if (t.IsPointer)
7864 return OpCodes.Stelem_I;
7866 return OpCodes.Stelem_Ref;
7869 MethodInfo FetchGetMethod ()
7871 ModuleBuilder mb = CodeGen.Module.Builder;
7872 int arg_count = ea.Arguments.Count;
7873 Type [] args = new Type [arg_count];
7876 for (int i = 0; i < arg_count; i++){
7877 //args [i++] = a.Type;
7878 args [i] = TypeManager.int32_type;
7881 get = mb.GetArrayMethod (
7882 ea.Expr.Type, "Get",
7883 CallingConventions.HasThis |
7884 CallingConventions.Standard,
7890 MethodInfo FetchAddressMethod ()
7892 ModuleBuilder mb = CodeGen.Module.Builder;
7893 int arg_count = ea.Arguments.Count;
7894 Type [] args = new Type [arg_count];
7898 ret_type = TypeManager.GetReferenceType (type);
7900 for (int i = 0; i < arg_count; i++){
7901 //args [i++] = a.Type;
7902 args [i] = TypeManager.int32_type;
7905 address = mb.GetArrayMethod (
7906 ea.Expr.Type, "Address",
7907 CallingConventions.HasThis |
7908 CallingConventions.Standard,
7915 // Load the array arguments into the stack.
7917 void LoadArrayAndArguments (EmitContext ec)
7921 for (int i = 0; i < ea.Arguments.Count; ++i) {
7922 ((Argument)ea.Arguments [i]).Emit (ec);
7926 public void Emit (EmitContext ec, bool leave_copy)
7928 int rank = ea.Expr.Type.GetArrayRank ();
7929 ILGenerator ig = ec.ig;
7932 LoadFromPtr (ig, this.type);
7934 LoadArrayAndArguments (ec);
7935 EmitLoadOpcode (ig, type, rank);
7939 ig.Emit (OpCodes.Dup);
7940 temp = new LocalTemporary (this.type);
7945 public override void Emit (EmitContext ec)
7950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7952 int rank = ea.Expr.Type.GetArrayRank ();
7953 ILGenerator ig = ec.ig;
7954 Type t = source.Type;
7955 prepared = prepare_for_load;
7958 AddressOf (ec, AddressOp.LoadStore);
7959 ec.ig.Emit (OpCodes.Dup);
7961 LoadArrayAndArguments (ec);
7965 bool is_stobj, has_type_arg;
7966 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7970 // The stobj opcode used by value types will need
7971 // an address on the stack, not really an array/array
7975 ig.Emit (OpCodes.Ldelema, t);
7980 ec.ig.Emit (OpCodes.Dup);
7981 temp = new LocalTemporary (this.type);
7986 StoreFromPtr (ig, t);
7988 ig.Emit (OpCodes.Stobj, t);
7989 else if (has_type_arg)
7996 ec.ig.Emit (OpCodes.Dup);
7997 temp = new LocalTemporary (this.type);
8002 StoreFromPtr (ig, t);
8004 int arg_count = ea.Arguments.Count;
8005 Type [] args = new Type [arg_count + 1];
8006 for (int i = 0; i < arg_count; i++) {
8007 //args [i++] = a.Type;
8008 args [i] = TypeManager.int32_type;
8010 args [arg_count] = type;
8012 MethodInfo set = CodeGen.Module.Builder.GetArrayMethod (
8013 ea.Expr.Type, "Set",
8014 CallingConventions.HasThis |
8015 CallingConventions.Standard,
8016 TypeManager.void_type, args);
8018 ig.Emit (OpCodes.Call, set);
8028 public void AddressOf (EmitContext ec, AddressOp mode)
8030 int rank = ea.Expr.Type.GetArrayRank ();
8031 ILGenerator ig = ec.ig;
8033 LoadArrayAndArguments (ec);
8036 ig.Emit (OpCodes.Ldelema, type);
8038 MethodInfo address = FetchAddressMethod ();
8039 ig.Emit (OpCodes.Call, address);
8043 public void EmitGetLength (EmitContext ec, int dim)
8045 int rank = ea.Expr.Type.GetArrayRank ();
8046 ILGenerator ig = ec.ig;
8050 ig.Emit (OpCodes.Ldlen);
8051 ig.Emit (OpCodes.Conv_I4);
8053 IntLiteral.EmitInt (ig, dim);
8054 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8060 /// Expressions that represent an indexer call.
8062 public class IndexerAccess : Expression, IAssignMethod
8064 class IndexerMethodGroupExpr : MethodGroupExpr
8066 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8069 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8072 public override string Name {
8078 protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
8081 // Here is the trick, decrease number of arguments by 1 when only
8082 // available property method is setter. This makes overload resolution
8083 // work correctly for indexers.
8086 if (method.Name [0] == 'g')
8087 return parameters.Count;
8089 return parameters.Count - 1;
8095 // Contains either property getter or setter
8096 public ArrayList Methods;
8097 public ArrayList Properties;
8103 void Append (Type caller_type, MemberInfo [] mi)
8108 foreach (PropertyInfo property in mi) {
8109 MethodInfo accessor = property.GetGetMethod (true);
8110 if (accessor == null)
8111 accessor = property.GetSetMethod (true);
8113 if (Methods == null) {
8114 Methods = new ArrayList ();
8115 Properties = new ArrayList ();
8118 Methods.Add (accessor);
8119 Properties.Add (property);
8123 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8125 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8127 return TypeManager.MemberLookup (
8128 caller_type, caller_type, lookup_type, MemberTypes.Property,
8129 BindingFlags.Public | BindingFlags.Instance |
8130 BindingFlags.DeclaredOnly, p_name, null);
8133 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8135 Indexers ix = new Indexers ();
8138 if (lookup_type.IsGenericParameter) {
8139 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8143 if (gc.HasClassConstraint)
8144 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8146 Type[] ifaces = gc.InterfaceConstraints;
8147 foreach (Type itype in ifaces)
8148 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8154 Type copy = lookup_type;
8155 while (copy != TypeManager.object_type && copy != null){
8156 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8157 copy = copy.BaseType;
8160 if (lookup_type.IsInterface) {
8161 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8162 if (ifaces != null) {
8163 foreach (Type itype in ifaces)
8164 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8179 // Points to our "data" repository
8181 MethodInfo get, set;
8182 bool is_base_indexer;
8184 LocalTemporary temp;
8185 LocalTemporary prepared_value;
8186 Expression set_expr;
8188 protected Type indexer_type;
8189 protected Type current_type;
8190 protected Expression instance_expr;
8191 protected ArrayList arguments;
8193 public IndexerAccess (ElementAccess ea, Location loc)
8194 : this (ea.Expr, false, loc)
8196 this.arguments = ea.Arguments;
8199 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8202 this.instance_expr = instance_expr;
8203 this.is_base_indexer = is_base_indexer;
8204 this.eclass = ExprClass.Value;
8208 static string GetAccessorName (AccessorType at)
8210 if (at == AccessorType.Set)
8213 if (at == AccessorType.Get)
8216 throw new NotImplementedException (at.ToString ());
8219 protected virtual bool CommonResolve (EmitContext ec)
8221 indexer_type = instance_expr.Type;
8222 current_type = ec.ContainerType;
8227 public override Expression DoResolve (EmitContext ec)
8229 return ResolveAccessor (ec, AccessorType.Get);
8232 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8234 if (right_side == EmptyExpression.OutAccess) {
8235 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8236 GetSignatureForError ());
8240 // if the indexer returns a value type, and we try to set a field in it
8241 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8242 Error_CannotModifyIntermediateExpressionValue (ec);
8245 Expression e = ResolveAccessor (ec, AccessorType.Set);
8249 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8253 Expression ResolveAccessor (EmitContext ec, AccessorType accessorType)
8255 if (!CommonResolve (ec))
8258 Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8259 if (ilist.Methods == null) {
8260 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8261 TypeManager.CSharpName (indexer_type));
8265 MethodGroupExpr mg = new IndexerMethodGroupExpr (ilist, loc);
8266 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8270 MethodInfo mi = (MethodInfo) mg;
8271 PropertyInfo pi = null;
8272 for (int i = 0; i < ilist.Methods.Count; ++i) {
8273 if (ilist.Methods [i] == mi) {
8274 pi = (PropertyInfo) ilist.Properties [i];
8279 type = TypeManager.TypeToCoreType (pi.PropertyType);
8280 if (type.IsPointer && !ec.InUnsafe)
8283 MethodInfo accessor;
8284 if (accessorType == AccessorType.Get) {
8285 accessor = get = pi.GetGetMethod (true);
8287 accessor = set = pi.GetSetMethod (true);
8288 if (accessor == null && pi.GetGetMethod (true) != null) {
8289 Report.SymbolRelatedToPreviousError (pi);
8290 Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8291 TypeManager.GetFullNameSignature (pi));
8296 if (accessor == null) {
8297 Report.SymbolRelatedToPreviousError (pi);
8298 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8299 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8304 // Only base will allow this invocation to happen.
8306 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8307 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (pi));
8310 bool must_do_cs1540_check;
8311 if (!IsAccessorAccessible (ec.ContainerType, accessor, out must_do_cs1540_check)) {
8313 set = pi.GetSetMethod (true);
8315 get = pi.GetGetMethod (true);
8317 if (set != null && get != null &&
8318 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8319 Report.SymbolRelatedToPreviousError (accessor);
8320 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8321 TypeManager.GetFullNameSignature (pi), GetAccessorName (accessorType));
8323 Report.SymbolRelatedToPreviousError (pi);
8324 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi));
8328 instance_expr.CheckMarshalByRefAccess (ec);
8329 eclass = ExprClass.IndexerAccess;
8333 public void Emit (EmitContext ec, bool leave_copy)
8336 prepared_value.Emit (ec);
8338 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8339 arguments, loc, false, false);
8343 ec.ig.Emit (OpCodes.Dup);
8344 temp = new LocalTemporary (Type);
8350 // source is ignored, because we already have a copy of it from the
8351 // LValue resolution and we have already constructed a pre-cached
8352 // version of the arguments (ea.set_arguments);
8354 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8356 prepared = prepare_for_load;
8357 Expression value = set_expr;
8360 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8361 arguments, loc, true, false);
8363 prepared_value = new LocalTemporary (type);
8364 prepared_value.Store (ec);
8366 prepared_value.Release (ec);
8369 ec.ig.Emit (OpCodes.Dup);
8370 temp = new LocalTemporary (Type);
8373 } else if (leave_copy) {
8374 temp = new LocalTemporary (Type);
8380 arguments.Add (new Argument (value, Argument.AType.Expression));
8381 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8389 public override void Emit (EmitContext ec)
8394 public override string GetSignatureForError ()
8396 return TypeManager.CSharpSignature (get != null ? get : set, false);
8399 protected override void CloneTo (CloneContext clonectx, Expression t)
8401 IndexerAccess target = (IndexerAccess) t;
8403 if (arguments != null){
8404 target.arguments = new ArrayList ();
8405 foreach (Argument a in arguments)
8406 target.arguments.Add (a.Clone (clonectx));
8408 if (instance_expr != null)
8409 target.instance_expr = instance_expr.Clone (clonectx);
8414 /// The base operator for method names
8416 public class BaseAccess : Expression {
8417 public readonly string Identifier;
8420 public BaseAccess (string member, Location l)
8422 this.Identifier = member;
8426 public BaseAccess (string member, TypeArguments args, Location l)
8432 public override Expression DoResolve (EmitContext ec)
8434 Expression c = CommonResolve (ec);
8440 // MethodGroups use this opportunity to flag an error on lacking ()
8442 if (!(c is MethodGroupExpr))
8443 return c.Resolve (ec);
8447 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8449 Expression c = CommonResolve (ec);
8455 // MethodGroups use this opportunity to flag an error on lacking ()
8457 if (! (c is MethodGroupExpr))
8458 return c.DoResolveLValue (ec, right_side);
8463 Expression CommonResolve (EmitContext ec)
8465 Expression member_lookup;
8466 Type current_type = ec.ContainerType;
8467 Type base_type = current_type.BaseType;
8470 Error (1511, "Keyword `base' is not available in a static method");
8474 if (ec.IsInFieldInitializer){
8475 Error (1512, "Keyword `base' is not available in the current context");
8479 member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8480 AllMemberTypes, AllBindingFlags, loc);
8481 if (member_lookup == null) {
8482 Error_MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier,
8483 null, AllMemberTypes, AllBindingFlags);
8490 left = new TypeExpression (base_type, loc);
8492 left = ec.GetThis (loc);
8494 MemberExpr me = (MemberExpr) member_lookup;
8495 me = me.ResolveMemberAccess (ec, left, loc, null);
8502 me.SetTypeArguments (args);
8508 public override void Emit (EmitContext ec)
8510 throw new Exception ("Should never be called");
8513 protected override void CloneTo (CloneContext clonectx, Expression t)
8515 BaseAccess target = (BaseAccess) t;
8518 target.args = args.Clone ();
8523 /// The base indexer operator
8525 public class BaseIndexerAccess : IndexerAccess {
8526 public BaseIndexerAccess (ArrayList args, Location loc)
8527 : base (null, true, loc)
8529 arguments = new ArrayList ();
8530 foreach (Expression tmp in args)
8531 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8534 protected override bool CommonResolve (EmitContext ec)
8536 instance_expr = ec.GetThis (loc);
8538 current_type = ec.ContainerType.BaseType;
8539 indexer_type = current_type;
8541 foreach (Argument a in arguments){
8542 if (!a.Resolve (ec, loc))
8551 /// This class exists solely to pass the Type around and to be a dummy
8552 /// that can be passed to the conversion functions (this is used by
8553 /// foreach implementation to typecast the object return value from
8554 /// get_Current into the proper type. All code has been generated and
8555 /// we only care about the side effect conversions to be performed
8557 /// This is also now used as a placeholder where a no-action expression
8558 /// is needed (the `New' class).
8560 public class EmptyExpression : Expression {
8561 public static readonly EmptyExpression Null = new EmptyExpression ();
8563 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8564 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8565 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8567 static EmptyExpression temp = new EmptyExpression ();
8568 public static EmptyExpression Grab ()
8570 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8575 public static void Release (EmptyExpression e)
8580 // TODO: should be protected
8581 public EmptyExpression ()
8583 type = TypeManager.object_type;
8584 eclass = ExprClass.Value;
8585 loc = Location.Null;
8588 public EmptyExpression (Type t)
8591 eclass = ExprClass.Value;
8592 loc = Location.Null;
8595 public override Expression DoResolve (EmitContext ec)
8600 public override void Emit (EmitContext ec)
8602 // nothing, as we only exist to not do anything.
8605 public override void EmitSideEffect (EmitContext ec)
8610 // This is just because we might want to reuse this bad boy
8611 // instead of creating gazillions of EmptyExpressions.
8612 // (CanImplicitConversion uses it)
8614 public void SetType (Type t)
8621 // Empty statement expression
8623 public sealed class EmptyExpressionStatement : ExpressionStatement
8625 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8627 private EmptyExpressionStatement ()
8629 type = TypeManager.object_type;
8630 eclass = ExprClass.Value;
8631 loc = Location.Null;
8634 public override void EmitStatement (EmitContext ec)
8639 public override Expression DoResolve (EmitContext ec)
8644 public override void Emit (EmitContext ec)
8650 public class UserCast : Expression {
8654 public UserCast (MethodInfo method, Expression source, Location l)
8656 this.method = method;
8657 this.source = source;
8658 type = TypeManager.TypeToCoreType (method.ReturnType);
8659 eclass = ExprClass.Value;
8663 public Expression Source {
8669 public override Expression CreateExpressionTree (EmitContext ec)
8671 ArrayList args = new ArrayList (2);
8672 args.Add (new Argument (source.CreateExpressionTree (ec)));
8673 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8674 args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
8675 return CreateExpressionFactoryCall ("Convert", args);
8678 public override Expression DoResolve (EmitContext ec)
8681 // We are born fully resolved
8686 public override void Emit (EmitContext ec)
8689 ec.ig.Emit (OpCodes.Call, method);
8694 // This class is used to "construct" the type during a typecast
8695 // operation. Since the Type.GetType class in .NET can parse
8696 // the type specification, we just use this to construct the type
8697 // one bit at a time.
8699 public class ComposedCast : TypeExpr {
8700 FullNamedExpression left;
8703 public ComposedCast (FullNamedExpression left, string dim)
8704 : this (left, dim, left.Location)
8708 public ComposedCast (FullNamedExpression left, string dim, Location l)
8715 public Expression RemoveNullable ()
8717 if (dim.EndsWith ("?")) {
8718 dim = dim.Substring (0, dim.Length - 1);
8719 if (dim.Length == 0)
8726 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8728 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8732 Type ltype = lexpr.Type;
8733 if ((ltype == TypeManager.void_type) && (dim != "*")) {
8734 Error_VoidInvalidInTheContext (loc);
8739 if ((dim.Length > 0) && (dim [0] == '?')) {
8740 TypeExpr nullable = new Nullable.NullableType (left, loc);
8742 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8743 return nullable.ResolveAsTypeTerminal (ec, false);
8747 if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8750 if (dim != "" && dim [0] == '[' &&
8751 (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8752 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8757 type = TypeManager.GetConstructedType (ltype, dim);
8762 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8764 if (type.IsPointer && !ec.IsInUnsafeScope){
8769 eclass = ExprClass.Type;
8773 public override string GetSignatureForError ()
8775 return left.GetSignatureForError () + dim;
8778 protected override void CloneTo (CloneContext clonectx, Expression t)
8780 ComposedCast target = (ComposedCast) t;
8782 target.left = (FullNamedExpression)left.Clone (clonectx);
8786 public class FixedBufferPtr : Expression {
8789 public FixedBufferPtr (Expression array, Type array_type, Location l)
8794 type = TypeManager.GetPointerType (array_type);
8795 eclass = ExprClass.Value;
8798 public override void Emit(EmitContext ec)
8803 public override Expression DoResolve (EmitContext ec)
8806 // We are born fully resolved
8814 // This class is used to represent the address of an array, used
8815 // only by the Fixed statement, this generates "&a [0]" construct
8816 // for fixed (char *pa = a)
8818 public class ArrayPtr : FixedBufferPtr {
8821 public ArrayPtr (Expression array, Type array_type, Location l):
8822 base (array, array_type, l)
8824 this.array_type = array_type;
8827 public override void Emit (EmitContext ec)
8831 ILGenerator ig = ec.ig;
8832 IntLiteral.EmitInt (ig, 0);
8833 ig.Emit (OpCodes.Ldelema, array_type);
8838 // Encapsulates a conversion rules required for array indexes
8840 public class ArrayIndexCast : Expression
8844 public ArrayIndexCast (Expression expr)
8847 this.loc = expr.Location;
8850 public override Expression CreateExpressionTree (EmitContext ec)
8852 ArrayList args = new ArrayList (2);
8853 args.Add (new Argument (expr.CreateExpressionTree (ec)));
8854 args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
8855 return CreateExpressionFactoryCall ("ConvertChecked", args);
8858 public override Expression DoResolve (EmitContext ec)
8861 eclass = expr.eclass;
8865 public override void Emit (EmitContext ec)
8869 if (type == TypeManager.int32_type)
8872 if (type == TypeManager.uint32_type)
8873 ec.ig.Emit (OpCodes.Conv_U);
8874 else if (type == TypeManager.int64_type)
8875 ec.ig.Emit (OpCodes.Conv_Ovf_I);
8876 else if (type == TypeManager.uint64_type)
8877 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
8879 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
8884 // Used by the fixed statement
8886 public class StringPtr : Expression {
8889 public StringPtr (LocalBuilder b, Location l)
8892 eclass = ExprClass.Value;
8893 type = TypeManager.char_ptr_type;
8897 public override Expression DoResolve (EmitContext ec)
8899 // This should never be invoked, we are born in fully
8900 // initialized state.
8905 public override void Emit (EmitContext ec)
8907 if (TypeManager.int_get_offset_to_string_data == null) {
8908 // TODO: Move to resolve !!
8909 TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
8910 TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
8913 ILGenerator ig = ec.ig;
8915 ig.Emit (OpCodes.Ldloc, b);
8916 ig.Emit (OpCodes.Conv_I);
8917 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8918 ig.Emit (OpCodes.Add);
8923 // Implements the `stackalloc' keyword
8925 public class StackAlloc : Expression {
8930 public StackAlloc (Expression type, Expression count, Location l)
8937 public override Expression DoResolve (EmitContext ec)
8939 count = count.Resolve (ec);
8943 if (count.Type != TypeManager.int32_type){
8944 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8949 Constant c = count as Constant;
8950 if (c != null && c.IsNegative) {
8951 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8955 if (ec.InCatch || ec.InFinally) {
8956 Error (255, "Cannot use stackalloc in finally or catch");
8960 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8966 if (!TypeManager.VerifyUnManaged (otype, loc))
8969 type = TypeManager.GetPointerType (otype);
8970 eclass = ExprClass.Value;
8975 public override void Emit (EmitContext ec)
8977 int size = GetTypeSize (otype);
8978 ILGenerator ig = ec.ig;
8981 ig.Emit (OpCodes.Sizeof, otype);
8983 IntConstant.EmitInt (ig, size);
8985 ig.Emit (OpCodes.Mul);
8986 ig.Emit (OpCodes.Localloc);
8989 protected override void CloneTo (CloneContext clonectx, Expression t)
8991 StackAlloc target = (StackAlloc) t;
8992 target.count = count.Clone (clonectx);
8993 target.t = t.Clone (clonectx);
8998 // An object initializer expression
9000 public class ElementInitializer : Assign
9002 public readonly string Name;
9004 public ElementInitializer (string name, Expression initializer, Location loc)
9005 : base (null, initializer, loc)
9010 protected override void CloneTo (CloneContext clonectx, Expression t)
9012 ElementInitializer target = (ElementInitializer) t;
9013 target.source = source.Clone (clonectx);
9016 public override Expression CreateExpressionTree (EmitContext ec)
9018 ArrayList args = new ArrayList (2);
9019 FieldExpr fe = target as FieldExpr;
9021 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9023 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9025 args.Add (new Argument (source.CreateExpressionTree (ec)));
9026 return CreateExpressionFactoryCall (
9027 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9031 public override Expression DoResolve (EmitContext ec)
9034 return EmptyExpressionStatement.Instance;
9036 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9037 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9043 me.InstanceExpression = ec.CurrentInitializerVariable;
9045 if (source is CollectionOrObjectInitializers) {
9046 Expression previous = ec.CurrentInitializerVariable;
9047 ec.CurrentInitializerVariable = target;
9048 source = source.Resolve (ec);
9049 ec.CurrentInitializerVariable = previous;
9053 eclass = source.eclass;
9058 Expression expr = base.DoResolve (ec);
9063 // Ignore field initializers with default value
9065 Constant c = source as Constant;
9066 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9067 return EmptyExpressionStatement.Instance;
9072 protected override Expression Error_MemberLookupFailed (MemberInfo[] members)
9074 MemberInfo member = members [0];
9075 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9076 Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9077 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9079 Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9080 TypeManager.GetFullNameSignature (member));
9085 public override void EmitStatement (EmitContext ec)
9087 if (source is CollectionOrObjectInitializers)
9090 base.EmitStatement (ec);
9095 // A collection initializer expression
9097 public class CollectionElementInitializer : Invocation
9099 public class ElementInitializerArgument : Argument
9101 public ElementInitializerArgument (Expression e)
9107 public CollectionElementInitializer (Expression argument)
9108 : base (null, new ArrayList (1), true)
9110 Arguments.Add (argument);
9111 this.loc = argument.Location;
9114 public CollectionElementInitializer (ArrayList arguments, Location loc)
9115 : base (null, arguments, true)
9120 public override Expression CreateExpressionTree (EmitContext ec)
9122 ArrayList args = new ArrayList (2);
9123 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9125 ArrayList expr_initializers = new ArrayList (Arguments.Count);
9126 foreach (Argument a in Arguments)
9127 expr_initializers.Add (a.Expr.CreateExpressionTree (ec));
9129 args.Add (new Argument (new ArrayCreation (
9130 CreateExpressionTypeExpression (loc), "[]", expr_initializers, loc)));
9131 return CreateExpressionFactoryCall ("ElementInit", args);
9134 protected override void CloneTo (CloneContext clonectx, Expression t)
9136 CollectionElementInitializer target = (CollectionElementInitializer) t;
9138 target.Arguments = new ArrayList (Arguments.Count);
9139 foreach (Expression e in Arguments)
9140 target.Arguments.Add (e.Clone (clonectx));
9143 public override Expression DoResolve (EmitContext ec)
9145 if (eclass != ExprClass.Invalid)
9148 // TODO: We could call a constructor which takes element count argument,
9149 // for known types like List<T>, Dictionary<T, U>
9151 for (int i = 0; i < Arguments.Count; ++i) {
9152 Expression expr = ((Expression) Arguments [i]).Resolve (ec);
9156 Arguments [i] = new ElementInitializerArgument (expr);
9159 base.expr = new MemberAccess (ec.CurrentInitializerVariable, "Add", loc);
9161 return base.DoResolve (ec);
9166 // A block of object or collection initializers
9168 public class CollectionOrObjectInitializers : ExpressionStatement
9170 ArrayList initializers;
9172 public static readonly CollectionOrObjectInitializers Empty =
9173 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9175 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9177 this.initializers = initializers;
9181 public bool IsEmpty {
9183 return initializers.Count == 0;
9187 public bool IsCollectionInitializer {
9189 return type == typeof (CollectionOrObjectInitializers);
9193 protected override void CloneTo (CloneContext clonectx, Expression target)
9195 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9197 t.initializers = new ArrayList (initializers.Count);
9198 foreach (Expression e in initializers)
9199 t.initializers.Add (e.Clone (clonectx));
9202 public override Expression CreateExpressionTree (EmitContext ec)
9204 ArrayList expr_initializers = new ArrayList (initializers.Count);
9205 foreach (Expression e in initializers) {
9206 Expression expr = e.CreateExpressionTree (ec);
9208 expr_initializers.Add (expr);
9211 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9214 public override Expression DoResolve (EmitContext ec)
9216 if (eclass != ExprClass.Invalid)
9219 bool is_elements_initialization = false;
9220 ArrayList element_names = null;
9221 for (int i = 0; i < initializers.Count; ++i) {
9222 Expression initializer = (Expression) initializers [i];
9223 ElementInitializer element_initializer = initializer as ElementInitializer;
9226 if (element_initializer != null) {
9227 is_elements_initialization = true;
9228 element_names = new ArrayList (initializers.Count);
9229 element_names.Add (element_initializer.Name);
9231 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type,
9232 TypeManager.ienumerable_type)) {
9233 Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9234 "object initializer because type `{1}' does not implement `{2}' interface",
9235 ec.CurrentInitializerVariable.GetSignatureForError (),
9236 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9237 TypeManager.CSharpName (TypeManager.ienumerable_type));
9242 if (is_elements_initialization == (element_initializer == null)) {
9243 Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9244 is_elements_initialization ? "object initializer" : "collection initializer");
9248 if (is_elements_initialization) {
9249 if (element_names.Contains (element_initializer.Name)) {
9250 Report.Error (1912, element_initializer.Location,
9251 "An object initializer includes more than one member `{0}' initialization",
9252 element_initializer.Name);
9254 element_names.Add (element_initializer.Name);
9259 Expression e = initializer.Resolve (ec);
9260 if (e == EmptyExpressionStatement.Instance)
9261 initializers.RemoveAt (i--);
9263 initializers [i] = e;
9266 type = is_elements_initialization ? typeof (ElementInitializer) : typeof (CollectionOrObjectInitializers);
9267 eclass = ExprClass.Variable;
9271 public override void Emit (EmitContext ec)
9276 public override void EmitStatement (EmitContext ec)
9278 foreach (ExpressionStatement e in initializers)
9279 e.EmitStatement (ec);
9284 // New expression with element/object initializers
9286 public class NewInitialize : New
9289 // This class serves as a proxy for variable initializer target instances.
9290 // A real variable is assigned later when we resolve left side of an
9293 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9295 NewInitialize new_instance;
9297 public InitializerTargetExpression (NewInitialize newInstance)
9299 this.type = newInstance.type;
9300 this.loc = newInstance.loc;
9301 this.eclass = newInstance.eclass;
9302 this.new_instance = newInstance;
9305 public override Expression CreateExpressionTree (EmitContext ec)
9307 // Should not be reached
9308 throw new NotSupportedException ();
9311 public override Expression DoResolve (EmitContext ec)
9316 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
9321 public override void Emit (EmitContext ec)
9323 new_instance.value_target.Emit (ec);
9326 #region IMemoryLocation Members
9328 public void AddressOf (EmitContext ec, AddressOp mode)
9330 ((IMemoryLocation)new_instance.value_target).AddressOf (ec, mode);
9336 CollectionOrObjectInitializers initializers;
9338 public NewInitialize (Expression requested_type, ArrayList arguments, CollectionOrObjectInitializers initializers, Location l)
9339 : base (requested_type, arguments, l)
9341 this.initializers = initializers;
9344 protected override void CloneTo (CloneContext clonectx, Expression t)
9346 base.CloneTo (clonectx, t);
9348 NewInitialize target = (NewInitialize) t;
9349 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9352 public override Expression CreateExpressionTree (EmitContext ec)
9354 ArrayList args = new ArrayList (2);
9355 args.Add (new Argument (base.CreateExpressionTree (ec)));
9356 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9358 return CreateExpressionFactoryCall (
9359 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9363 public override Expression DoResolve (EmitContext ec)
9365 if (eclass != ExprClass.Invalid)
9368 Expression e = base.DoResolve (ec);
9372 // Empty initializer can be optimized to simple new
9373 if (initializers.IsEmpty)
9376 Expression previous = ec.CurrentInitializerVariable;
9377 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9378 initializers.Resolve (ec);
9379 ec.CurrentInitializerVariable = previous;
9383 public override void Emit (EmitContext ec)
9388 // If target is a value, let's use it
9390 VariableReference variable = value_target as VariableReference;
9391 if (variable != null) {
9393 StoreFromPtr (ec.ig, type);
9395 variable.Variable.EmitAssign (ec);
9397 if (value_target == null || value_target_set)
9398 value_target = new LocalTemporary (type);
9400 ((LocalTemporary) value_target).Store (ec);
9403 initializers.Emit (ec);
9405 if (variable == null)
9406 value_target.Emit (ec);
9409 public override void EmitStatement (EmitContext ec)
9411 if (initializers.IsEmpty) {
9412 base.EmitStatement (ec);
9418 if (value_target == null) {
9419 LocalTemporary variable = new LocalTemporary (type);
9420 variable.Store (ec);
9421 value_target = variable;
9424 initializers.EmitStatement (ec);
9427 public override bool HasInitializer {
9429 return !initializers.IsEmpty;
9434 public class AnonymousTypeDeclaration : Expression
9436 ArrayList parameters;
9437 readonly TypeContainer parent;
9438 static readonly ArrayList EmptyParameters = new ArrayList (0);
9440 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
9442 this.parameters = parameters;
9443 this.parent = parent;
9447 protected override void CloneTo (CloneContext clonectx, Expression target)
9449 if (parameters == null)
9452 AnonymousTypeDeclaration t = (AnonymousTypeDeclaration) target;
9453 t.parameters = new ArrayList (parameters.Count);
9454 foreach (AnonymousTypeParameter atp in parameters)
9455 t.parameters.Add (atp.Clone (clonectx));
9458 AnonymousTypeClass CreateAnonymousType (ArrayList parameters)
9460 AnonymousTypeClass type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
9464 type = AnonymousTypeClass.Create (parent, parameters, loc);
9469 type.DefineMembers ();
9473 RootContext.ToplevelTypes.AddAnonymousType (type);
9477 public override Expression DoResolve (EmitContext ec)
9479 AnonymousTypeClass anonymous_type;
9481 if (parameters == null) {
9482 anonymous_type = CreateAnonymousType (EmptyParameters);
9483 return new New (new TypeExpression (anonymous_type.TypeBuilder, loc),
9484 null, loc).Resolve (ec);
9488 ArrayList arguments = new ArrayList (parameters.Count);
9489 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9490 for (int i = 0; i < parameters.Count; ++i) {
9491 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9497 arguments.Add (new Argument (e));
9498 t_args [i] = new TypeExpression (e.Type, e.Location);
9504 anonymous_type = CreateAnonymousType (parameters);
9505 if (anonymous_type == null)
9508 ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
9509 new TypeArguments (loc, t_args), loc);
9511 return new New (te, arguments, loc).Resolve (ec);
9514 public override void Emit (EmitContext ec)
9516 throw new InternalErrorException ("Should not be reached");
9520 public class AnonymousTypeParameter : Expression
9522 public readonly string Name;
9523 Expression initializer;
9525 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9529 this.initializer = initializer;
9532 public AnonymousTypeParameter (Parameter parameter)
9534 this.Name = parameter.Name;
9535 this.loc = parameter.Location;
9536 this.initializer = new SimpleName (Name, loc);
9539 protected override void CloneTo (CloneContext clonectx, Expression target)
9541 AnonymousTypeParameter t = (AnonymousTypeParameter) target;
9542 t.initializer = initializer.Clone (clonectx);
9545 public override bool Equals (object o)
9547 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9548 return other != null && Name == other.Name;
9551 public override int GetHashCode ()
9553 return Name.GetHashCode ();
9556 public override Expression DoResolve (EmitContext ec)
9558 Expression e = initializer.Resolve (ec);
9563 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9564 type == TypeManager.anonymous_method_type || type.IsPointer) {
9565 Error_InvalidInitializer (e);
9572 protected virtual void Error_InvalidInitializer (Expression initializer)
9574 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
9575 Name, initializer.GetSignatureForError ());
9578 public override void Emit (EmitContext ec)
9580 throw new InternalErrorException ("Should not be reached");