2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
15 using System.Collections;
16 using System.Collections.Generic;
17 using System.Reflection;
18 using System.Reflection.Emit;
23 using SLE = System.Linq.Expressions;
27 // This is an user operator expression, automatically created during
30 public class UserOperatorCall : Expression {
31 public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
33 protected readonly Arguments arguments;
34 protected readonly MethodGroupExpr mg;
35 readonly ExpressionTreeExpression expr_tree;
37 public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
40 this.arguments = args;
41 this.expr_tree = expr_tree;
43 type = TypeManager.TypeToCoreType (((MethodInfo) mg).ReturnType);
44 eclass = ExprClass.Value;
48 public override Expression CreateExpressionTree (ResolveContext ec)
50 if (expr_tree != null)
51 return expr_tree (ec, mg);
53 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
54 new NullLiteral (loc),
55 mg.CreateExpressionTree (ec));
57 return CreateExpressionFactoryCall (ec, "Call", args);
60 protected override void CloneTo (CloneContext context, Expression target)
65 protected override Expression DoResolve (ResolveContext ec)
68 // We are born fully resolved
73 public override void Emit (EmitContext ec)
75 mg.EmitCall (ec, arguments);
79 public override SLE.Expression MakeExpression (BuilderContext ctx)
81 return SLE.Expression.Call ((MethodInfo) mg, Arguments.MakeExpression (arguments, ctx));
85 public MethodGroupExpr Method {
89 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
91 arguments.MutateHoistedGenericType (storey);
92 mg.MutateHoistedGenericType (storey);
96 public class ParenthesizedExpression : ShimExpression
98 public ParenthesizedExpression (Expression expr)
104 protected override Expression DoResolve (ResolveContext ec)
106 return expr.Resolve (ec);
109 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
111 return expr.DoResolveLValue (ec, right_side);
116 // Unary implements unary expressions.
118 public class Unary : Expression
120 public enum Operator : byte {
121 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
125 static Type [] [] predefined_operators;
127 public readonly Operator Oper;
128 public Expression Expr;
129 Expression enum_conversion;
131 public Unary (Operator op, Expression expr)
139 // This routine will attempt to simplify the unary expression when the
140 // argument is a constant.
142 Constant TryReduceConstant (ResolveContext ec, Constant e)
144 if (e is EmptyConstantCast)
145 return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
147 if (e is SideEffectConstant) {
148 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
149 return r == null ? null : new SideEffectConstant (r, e, r.Location);
152 Type expr_type = e.Type;
155 case Operator.UnaryPlus:
156 // Unary numeric promotions
157 if (expr_type == TypeManager.byte_type)
158 return new IntConstant (((ByteConstant)e).Value, e.Location);
159 if (expr_type == TypeManager.sbyte_type)
160 return new IntConstant (((SByteConstant)e).Value, e.Location);
161 if (expr_type == TypeManager.short_type)
162 return new IntConstant (((ShortConstant)e).Value, e.Location);
163 if (expr_type == TypeManager.ushort_type)
164 return new IntConstant (((UShortConstant)e).Value, e.Location);
165 if (expr_type == TypeManager.char_type)
166 return new IntConstant (((CharConstant)e).Value, e.Location);
168 // Predefined operators
169 if (expr_type == TypeManager.int32_type || expr_type == TypeManager.uint32_type ||
170 expr_type == TypeManager.int64_type || expr_type == TypeManager.uint64_type ||
171 expr_type == TypeManager.float_type || expr_type == TypeManager.double_type ||
172 expr_type == TypeManager.decimal_type) {
178 case Operator.UnaryNegation:
179 // Unary numeric promotions
180 if (expr_type == TypeManager.byte_type)
181 return new IntConstant (-((ByteConstant)e).Value, e.Location);
182 if (expr_type == TypeManager.sbyte_type)
183 return new IntConstant (-((SByteConstant)e).Value, e.Location);
184 if (expr_type == TypeManager.short_type)
185 return new IntConstant (-((ShortConstant)e).Value, e.Location);
186 if (expr_type == TypeManager.ushort_type)
187 return new IntConstant (-((UShortConstant)e).Value, e.Location);
188 if (expr_type == TypeManager.char_type)
189 return new IntConstant (-((CharConstant)e).Value, e.Location);
191 // Predefined operators
192 if (expr_type == TypeManager.int32_type) {
193 int value = ((IntConstant)e).Value;
194 if (value == int.MinValue) {
195 if (ec.ConstantCheckState) {
196 ConstantFold.Error_CompileTimeOverflow (ec, loc);
201 return new IntConstant (-value, e.Location);
203 if (expr_type == TypeManager.int64_type) {
204 long value = ((LongConstant)e).Value;
205 if (value == long.MinValue) {
206 if (ec.ConstantCheckState) {
207 ConstantFold.Error_CompileTimeOverflow (ec, loc);
212 return new LongConstant (-value, e.Location);
215 if (expr_type == TypeManager.uint32_type) {
216 UIntLiteral uil = e as UIntLiteral;
218 if (uil.Value == 2147483648)
219 return new IntLiteral (int.MinValue, e.Location);
220 return new LongLiteral (-uil.Value, e.Location);
222 return new LongConstant (-((UIntConstant)e).Value, e.Location);
225 if (expr_type == TypeManager.uint64_type) {
226 ULongLiteral ull = e as ULongLiteral;
227 if (ull != null && ull.Value == 9223372036854775808)
228 return new LongLiteral (long.MinValue, e.Location);
232 if (expr_type == TypeManager.float_type) {
233 FloatLiteral fl = e as FloatLiteral;
234 // For better error reporting
236 return new FloatLiteral (-fl.Value, e.Location);
238 return new FloatConstant (-((FloatConstant)e).Value, e.Location);
240 if (expr_type == TypeManager.double_type) {
241 DoubleLiteral dl = e as DoubleLiteral;
242 // For better error reporting
244 return new DoubleLiteral (-dl.Value, e.Location);
246 return new DoubleConstant (-((DoubleConstant)e).Value, e.Location);
248 if (expr_type == TypeManager.decimal_type)
249 return new DecimalConstant (-((DecimalConstant)e).Value, e.Location);
253 case Operator.LogicalNot:
254 if (expr_type != TypeManager.bool_type)
257 bool b = (bool)e.GetValue ();
258 return new BoolConstant (!b, e.Location);
260 case Operator.OnesComplement:
261 // Unary numeric promotions
262 if (expr_type == TypeManager.byte_type)
263 return new IntConstant (~((ByteConstant)e).Value, e.Location);
264 if (expr_type == TypeManager.sbyte_type)
265 return new IntConstant (~((SByteConstant)e).Value, e.Location);
266 if (expr_type == TypeManager.short_type)
267 return new IntConstant (~((ShortConstant)e).Value, e.Location);
268 if (expr_type == TypeManager.ushort_type)
269 return new IntConstant (~((UShortConstant)e).Value, e.Location);
270 if (expr_type == TypeManager.char_type)
271 return new IntConstant (~((CharConstant)e).Value, e.Location);
273 // Predefined operators
274 if (expr_type == TypeManager.int32_type)
275 return new IntConstant (~((IntConstant)e).Value, e.Location);
276 if (expr_type == TypeManager.uint32_type)
277 return new UIntConstant (~((UIntConstant)e).Value, e.Location);
278 if (expr_type == TypeManager.int64_type)
279 return new LongConstant (~((LongConstant)e).Value, e.Location);
280 if (expr_type == TypeManager.uint64_type){
281 return new ULongConstant (~((ULongConstant)e).Value, e.Location);
283 if (e is EnumConstant) {
284 e = TryReduceConstant (ec, ((EnumConstant)e).Child);
286 e = new EnumConstant (e, expr_type);
291 throw new Exception ("Can not constant fold: " + Oper.ToString());
294 protected Expression ResolveOperator (ResolveContext ec, Expression expr)
296 eclass = ExprClass.Value;
298 if (predefined_operators == null)
299 CreatePredefinedOperatorsTable ();
301 Type expr_type = expr.Type;
302 Expression best_expr;
305 // Primitive types first
307 if (TypeManager.IsPrimitiveType (expr_type)) {
308 best_expr = ResolvePrimitivePredefinedType (expr);
309 if (best_expr == null)
312 type = best_expr.Type;
318 // E operator ~(E x);
320 if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
321 return ResolveEnumOperator (ec, expr);
323 return ResolveUserType (ec, expr);
326 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
328 Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
329 Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
330 if (best_expr == null)
334 enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
336 return EmptyCast.Create (this, type);
339 public override Expression CreateExpressionTree (ResolveContext ec)
341 return CreateExpressionTree (ec, null);
344 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
348 case Operator.AddressOf:
349 Error_PointerInsideExpressionTree (ec);
351 case Operator.UnaryNegation:
352 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
353 method_name = "NegateChecked";
355 method_name = "Negate";
357 case Operator.OnesComplement:
358 case Operator.LogicalNot:
361 case Operator.UnaryPlus:
362 method_name = "UnaryPlus";
365 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
368 Arguments args = new Arguments (2);
369 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
371 args.Add (new Argument (user_op.CreateExpressionTree (ec)));
372 return CreateExpressionFactoryCall (ec, method_name, args);
375 static void CreatePredefinedOperatorsTable ()
377 predefined_operators = new Type [(int) Operator.TOP] [];
380 // 7.6.1 Unary plus operator
382 predefined_operators [(int) Operator.UnaryPlus] = new Type [] {
383 TypeManager.int32_type, TypeManager.uint32_type,
384 TypeManager.int64_type, TypeManager.uint64_type,
385 TypeManager.float_type, TypeManager.double_type,
386 TypeManager.decimal_type
390 // 7.6.2 Unary minus operator
392 predefined_operators [(int) Operator.UnaryNegation] = new Type [] {
393 TypeManager.int32_type,
394 TypeManager.int64_type,
395 TypeManager.float_type, TypeManager.double_type,
396 TypeManager.decimal_type
400 // 7.6.3 Logical negation operator
402 predefined_operators [(int) Operator.LogicalNot] = new Type [] {
403 TypeManager.bool_type
407 // 7.6.4 Bitwise complement operator
409 predefined_operators [(int) Operator.OnesComplement] = new Type [] {
410 TypeManager.int32_type, TypeManager.uint32_type,
411 TypeManager.int64_type, TypeManager.uint64_type
416 // Unary numeric promotions
418 static Expression DoNumericPromotion (Operator op, Expression expr)
420 Type expr_type = expr.Type;
421 if ((op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) &&
422 expr_type == TypeManager.byte_type || expr_type == TypeManager.sbyte_type ||
423 expr_type == TypeManager.short_type || expr_type == TypeManager.ushort_type ||
424 expr_type == TypeManager.char_type)
425 return Convert.ImplicitNumericConversion (expr, TypeManager.int32_type);
427 if (op == Operator.UnaryNegation && expr_type == TypeManager.uint32_type)
428 return Convert.ImplicitNumericConversion (expr, TypeManager.int64_type);
433 protected override Expression DoResolve (ResolveContext ec)
435 if (Oper == Operator.AddressOf) {
436 return ResolveAddressOf (ec);
439 Expr = Expr.Resolve (ec);
443 if (TypeManager.IsDynamicType (Expr.Type)) {
444 Arguments args = new Arguments (1);
445 args.Add (new Argument (Expr));
446 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
449 if (TypeManager.IsNullableType (Expr.Type))
450 return new Nullable.LiftedUnaryOperator (Oper, Expr).Resolve (ec);
453 // Attempt to use a constant folding operation.
455 Constant cexpr = Expr as Constant;
457 cexpr = TryReduceConstant (ec, cexpr);
459 return cexpr.Resolve (ec);
462 Expression expr = ResolveOperator (ec, Expr);
464 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
467 // Reduce unary operator on predefined types
469 if (expr == this && Oper == Operator.UnaryPlus)
475 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
480 public override void Emit (EmitContext ec)
482 EmitOperator (ec, type);
485 protected void EmitOperator (EmitContext ec, Type type)
487 ILGenerator ig = ec.ig;
490 case Operator.UnaryPlus:
494 case Operator.UnaryNegation:
495 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
496 ig.Emit (OpCodes.Ldc_I4_0);
497 if (type == TypeManager.int64_type)
498 ig.Emit (OpCodes.Conv_U8);
500 ig.Emit (OpCodes.Sub_Ovf);
503 ig.Emit (OpCodes.Neg);
508 case Operator.LogicalNot:
510 ig.Emit (OpCodes.Ldc_I4_0);
511 ig.Emit (OpCodes.Ceq);
514 case Operator.OnesComplement:
516 ig.Emit (OpCodes.Not);
519 case Operator.AddressOf:
520 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
524 throw new Exception ("This should not happen: Operator = "
529 // Same trick as in Binary expression
531 if (enum_conversion != null)
532 enum_conversion.Emit (ec);
535 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
537 if (Oper == Operator.LogicalNot)
538 Expr.EmitBranchable (ec, target, !on_true);
540 base.EmitBranchable (ec, target, on_true);
543 public override void EmitSideEffect (EmitContext ec)
545 Expr.EmitSideEffect (ec);
548 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Location loc, string oper, Type t)
550 ec.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
551 oper, TypeManager.CSharpName (t));
555 // Converts operator to System.Linq.Expressions.ExpressionType enum name
557 string GetOperatorExpressionTypeName ()
560 case Operator.OnesComplement:
561 return "OnesComplement";
562 case Operator.LogicalNot:
564 case Operator.UnaryNegation:
566 case Operator.UnaryPlus:
569 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
573 static bool IsFloat (Type t)
575 return t == TypeManager.float_type || t == TypeManager.double_type;
579 // Returns a stringified representation of the Operator
581 public static string OperName (Operator oper)
584 case Operator.UnaryPlus:
586 case Operator.UnaryNegation:
588 case Operator.LogicalNot:
590 case Operator.OnesComplement:
592 case Operator.AddressOf:
596 throw new NotImplementedException (oper.ToString ());
600 public override SLE.Expression MakeExpression (BuilderContext ctx)
602 var expr = Expr.MakeExpression (ctx);
603 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
606 case Operator.UnaryNegation:
607 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
608 case Operator.LogicalNot:
609 return SLE.Expression.Not (expr);
610 case Operator.OnesComplement:
611 return SLE.Expression.OnesComplement (expr);
613 throw new NotImplementedException (Oper.ToString ());
618 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
620 type = storey.MutateType (type);
621 Expr.MutateHoistedGenericType (storey);
624 Expression ResolveAddressOf (ResolveContext ec)
627 UnsafeError (ec, loc);
629 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
630 if (Expr == null || Expr.eclass != ExprClass.Variable) {
631 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
635 if (!TypeManager.VerifyUnmanaged (ec.Compiler, Expr.Type, loc)) {
639 IVariableReference vr = Expr as IVariableReference;
642 VariableInfo vi = vr.VariableInfo;
644 if (vi.LocalInfo != null)
645 vi.LocalInfo.Used = true;
648 // A variable is considered definitely assigned if you take its address.
653 is_fixed = vr.IsFixed;
654 vr.SetHasAddressTaken ();
657 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
660 IFixedExpression fe = Expr as IFixedExpression;
661 is_fixed = fe != null && fe.IsFixed;
664 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
665 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
668 type = TypeManager.GetPointerType (Expr.Type);
669 eclass = ExprClass.Value;
673 Expression ResolvePrimitivePredefinedType (Expression expr)
675 expr = DoNumericPromotion (Oper, expr);
676 Type expr_type = expr.Type;
677 Type[] predefined = predefined_operators [(int) Oper];
678 foreach (Type t in predefined) {
686 // Perform user-operator overload resolution
688 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
690 CSharp.Operator.OpType op_type;
692 case Operator.LogicalNot:
693 op_type = CSharp.Operator.OpType.LogicalNot; break;
694 case Operator.OnesComplement:
695 op_type = CSharp.Operator.OpType.OnesComplement; break;
696 case Operator.UnaryNegation:
697 op_type = CSharp.Operator.OpType.UnaryNegation; break;
698 case Operator.UnaryPlus:
699 op_type = CSharp.Operator.OpType.UnaryPlus; break;
701 throw new InternalErrorException (Oper.ToString ());
704 string op_name = CSharp.Operator.GetMetadataName (op_type);
705 MethodGroupExpr user_op = MemberLookup (ec.Compiler, ec.CurrentType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
709 Arguments args = new Arguments (1);
710 args.Add (new Argument (expr));
711 user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
716 Expr = args [0].Expr;
717 return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
721 // Unary user type overload resolution
723 Expression ResolveUserType (ResolveContext ec, Expression expr)
725 Expression best_expr = ResolveUserOperator (ec, expr);
726 if (best_expr != null)
729 Type[] predefined = predefined_operators [(int) Oper];
730 foreach (Type t in predefined) {
731 Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
732 if (oper_expr == null)
736 // decimal type is predefined but has user-operators
738 if (oper_expr.Type == TypeManager.decimal_type)
739 oper_expr = ResolveUserType (ec, oper_expr);
741 oper_expr = ResolvePrimitivePredefinedType (oper_expr);
743 if (oper_expr == null)
746 if (best_expr == null) {
747 best_expr = oper_expr;
751 int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
753 ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
754 OperName (Oper), TypeManager.CSharpName (expr.Type));
759 best_expr = oper_expr;
762 if (best_expr == null)
766 // HACK: Decimal user-operator is included in standard operators
768 if (best_expr.Type == TypeManager.decimal_type)
772 type = best_expr.Type;
776 protected override void CloneTo (CloneContext clonectx, Expression t)
778 Unary target = (Unary) t;
780 target.Expr = Expr.Clone (clonectx);
785 // Unary operators are turned into Indirection expressions
786 // after semantic analysis (this is so we can take the address
787 // of an indirection).
789 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
791 LocalTemporary temporary;
794 public Indirection (Expression expr, Location l)
800 public override Expression CreateExpressionTree (ResolveContext ec)
802 Error_PointerInsideExpressionTree (ec);
806 protected override void CloneTo (CloneContext clonectx, Expression t)
808 Indirection target = (Indirection) t;
809 target.expr = expr.Clone (clonectx);
812 public override void Emit (EmitContext ec)
817 LoadFromPtr (ec.ig, Type);
820 public void Emit (EmitContext ec, bool leave_copy)
824 ec.ig.Emit (OpCodes.Dup);
825 temporary = new LocalTemporary (expr.Type);
826 temporary.Store (ec);
830 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
832 prepared = prepare_for_load;
836 if (prepare_for_load)
837 ec.ig.Emit (OpCodes.Dup);
841 ec.ig.Emit (OpCodes.Dup);
842 temporary = new LocalTemporary (expr.Type);
843 temporary.Store (ec);
846 StoreFromPtr (ec.ig, type);
848 if (temporary != null) {
850 temporary.Release (ec);
854 public void AddressOf (EmitContext ec, AddressOp Mode)
859 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
861 return DoResolve (ec);
864 protected override Expression DoResolve (ResolveContext ec)
866 expr = expr.Resolve (ec);
871 UnsafeError (ec, loc);
873 if (!expr.Type.IsPointer) {
874 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
878 if (expr.Type == TypeManager.void_ptr_type) {
879 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
883 type = TypeManager.GetElementType (expr.Type);
884 eclass = ExprClass.Variable;
888 public bool IsFixed {
892 public override string ToString ()
894 return "*(" + expr + ")";
899 /// Unary Mutator expressions (pre and post ++ and --)
903 /// UnaryMutator implements ++ and -- expressions. It derives from
904 /// ExpressionStatement becuase the pre/post increment/decrement
905 /// operators can be used in a statement context.
907 /// FIXME: Idea, we could split this up in two classes, one simpler
908 /// for the common case, and one with the extra fields for more complex
909 /// classes (indexers require temporary access; overloaded require method)
912 public class UnaryMutator : ExpressionStatement
914 class DynamicPostMutator : Expression, IAssignMethod
919 public DynamicPostMutator (Expression expr)
922 this.type = expr.Type;
923 this.loc = expr.Location;
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 throw new NotImplementedException ("ET");
931 protected override Expression DoResolve (ResolveContext rc)
933 eclass = expr.eclass;
937 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
939 expr.DoResolveLValue (ec, right_side);
940 return DoResolve (ec);
943 public override void Emit (EmitContext ec)
948 public void Emit (EmitContext ec, bool leave_copy)
950 throw new NotImplementedException ();
954 // Emits target assignment using unmodified source value
956 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
959 // Allocate temporary variable to keep original value before it's modified
961 temp = new LocalTemporary (type);
965 ((IAssignMethod) expr).EmitAssign (ec, source, false, prepare_for_load);
976 public enum Mode : byte {
983 PreDecrement = IsDecrement,
984 PostIncrement = IsPost,
985 PostDecrement = IsPost | IsDecrement
989 bool is_expr, recurse;
993 // Holds the real operation
994 Expression operation;
996 public UnaryMutator (Mode m, Expression e)
1003 public override Expression CreateExpressionTree (ResolveContext ec)
1005 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1008 protected override Expression DoResolve (ResolveContext ec)
1010 expr = expr.Resolve (ec);
1015 if (TypeManager.IsDynamicType (expr.Type)) {
1017 // Handle postfix unary operators using local
1018 // temporary variable
1020 if ((mode & Mode.IsPost) != 0)
1021 expr = new DynamicPostMutator (expr);
1023 Arguments args = new Arguments (1);
1024 args.Add (new Argument (expr));
1025 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1028 if (TypeManager.IsNullableType (expr.Type))
1029 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1031 eclass = ExprClass.Value;
1033 return ResolveOperator (ec);
1036 void EmitCode (EmitContext ec, bool is_expr)
1039 this.is_expr = is_expr;
1040 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1043 public override void Emit (EmitContext ec)
1046 // We use recurse to allow ourselfs to be the source
1047 // of an assignment. This little hack prevents us from
1048 // having to allocate another expression
1051 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1053 operation.Emit (ec);
1059 EmitCode (ec, true);
1062 public override void EmitStatement (EmitContext ec)
1064 EmitCode (ec, false);
1068 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1070 string GetOperatorExpressionTypeName ()
1072 return IsDecrement ? "Decrement" : "Increment";
1076 get { return (mode & Mode.IsDecrement) != 0; }
1080 // Returns whether an object of type `t' can be incremented
1081 // or decremented with add/sub (ie, basically whether we can
1082 // use pre-post incr-decr operations on it, but it is not a
1083 // System.Decimal, which we require operator overloading to catch)
1085 static bool IsPredefinedOperator (Type t)
1087 return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
1088 TypeManager.IsEnumType (t) ||
1089 t.IsPointer && t != TypeManager.void_ptr_type;
1093 public override SLE.Expression MakeExpression (BuilderContext ctx)
1095 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1096 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1097 return SLE.Expression.Assign (target, source);
1101 protected override void CloneTo (CloneContext clonectx, Expression t)
1103 UnaryMutator target = (UnaryMutator) t;
1105 target.expr = expr.Clone (clonectx);
1108 Expression ResolveOperator (ResolveContext ec)
1110 if (expr is RuntimeValueExpression) {
1113 // Use itself at the top of the stack
1114 operation = new EmptyExpression (type);
1118 // The operand of the prefix/postfix increment decrement operators
1119 // should be an expression that is classified as a variable,
1120 // a property access or an indexer access
1122 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1123 expr = expr.ResolveLValue (ec, expr);
1125 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1129 // 1. Check predefined types
1131 if (IsPredefinedOperator (type)) {
1132 // TODO: Move to IntConstant once I get rid of int32_type
1133 var one = new IntConstant (1, loc);
1135 // TODO: Cache this based on type when using EmptyExpression in
1137 Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1138 operation = new Binary (op, operation, one);
1139 operation = operation.Resolve (ec);
1140 if (operation != null && operation.Type != type)
1141 operation = Convert.ExplicitNumericConversion (operation, type);
1147 // Step 2: Perform Operator Overload location
1153 op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
1155 op_name = Operator.GetMetadataName (Operator.OpType.Increment);
1157 mg = MemberLookup (ec.Compiler, ec.CurrentType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
1160 Arguments args = new Arguments (1);
1161 args.Add (new Argument (expr));
1162 mg = mg.OverloadResolve (ec, ref args, false, loc);
1166 args[0].Expr = operation;
1167 operation = new UserOperatorCall (mg, args, null, loc);
1168 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1172 string name = IsDecrement ?
1173 Operator.GetName (Operator.OpType.Decrement) :
1174 Operator.GetName (Operator.OpType.Increment);
1176 Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
1182 /// Base class for the `Is' and `As' classes.
1186 /// FIXME: Split this in two, and we get to save the `Operator' Oper
1189 public abstract class Probe : Expression {
1190 public Expression ProbeType;
1191 protected Expression expr;
1192 protected TypeExpr probe_type_expr;
1194 public Probe (Expression expr, Expression probe_type, Location l)
1196 ProbeType = probe_type;
1201 public Expression Expr {
1207 protected override Expression DoResolve (ResolveContext ec)
1209 probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false);
1210 if (probe_type_expr == null)
1213 expr = expr.Resolve (ec);
1217 if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1218 ec.Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
1222 if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
1223 ec.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1228 if (expr.Type == InternalType.AnonymousMethod) {
1229 ec.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression or anonymous method",
1237 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1239 expr.MutateHoistedGenericType (storey);
1240 probe_type_expr.MutateHoistedGenericType (storey);
1243 protected abstract string OperatorName { get; }
1245 protected override void CloneTo (CloneContext clonectx, Expression t)
1247 Probe target = (Probe) t;
1249 target.expr = expr.Clone (clonectx);
1250 target.ProbeType = ProbeType.Clone (clonectx);
1256 /// Implementation of the `is' operator.
1258 public class Is : Probe {
1259 Nullable.Unwrap expr_unwrap;
1261 public Is (Expression expr, Expression probe_type, Location l)
1262 : base (expr, probe_type, l)
1266 public override Expression CreateExpressionTree (ResolveContext ec)
1268 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1269 expr.CreateExpressionTree (ec),
1270 new TypeOf (probe_type_expr, loc));
1272 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1275 public override void Emit (EmitContext ec)
1277 ILGenerator ig = ec.ig;
1278 if (expr_unwrap != null) {
1279 expr_unwrap.EmitCheck (ec);
1284 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1285 ig.Emit (OpCodes.Ldnull);
1286 ig.Emit (OpCodes.Cgt_Un);
1289 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1291 ILGenerator ig = ec.ig;
1292 if (expr_unwrap != null) {
1293 expr_unwrap.EmitCheck (ec);
1296 ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
1298 ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1301 Expression CreateConstantResult (ResolveContext ec, bool result)
1304 ec.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1305 TypeManager.CSharpName (probe_type_expr.Type));
1307 ec.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1308 TypeManager.CSharpName (probe_type_expr.Type));
1310 return ReducedExpression.Create (new BoolConstant (result, loc).Resolve (ec), this);
1313 protected override Expression DoResolve (ResolveContext ec)
1315 if (base.DoResolve (ec) == null)
1319 bool d_is_nullable = false;
1322 // If E is a method group or the null literal, or if the type of E is a reference
1323 // type or a nullable type and the value of E is null, the result is false
1325 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1326 return CreateConstantResult (ec, false);
1328 if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
1329 d = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (d) [0]);
1330 d_is_nullable = true;
1333 type = TypeManager.bool_type;
1334 eclass = ExprClass.Value;
1335 Type t = probe_type_expr.Type;
1336 bool t_is_nullable = false;
1337 if (TypeManager.IsNullableType (t) && !TypeManager.ContainsGenericParameters (t)) {
1338 t = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (t) [0]);
1339 t_is_nullable = true;
1342 if (TypeManager.IsStruct (t)) {
1345 // D and T are the same value types but D can be null
1347 if (d_is_nullable && !t_is_nullable) {
1348 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1353 // The result is true if D and T are the same value types
1355 return CreateConstantResult (ec, true);
1358 if (TypeManager.IsGenericParameter (d))
1359 return ResolveGenericParameter (ec, t, d);
1362 // An unboxing conversion exists
1364 if (Convert.ExplicitReferenceConversionExists (d, t))
1367 if (TypeManager.IsGenericParameter (t))
1368 return ResolveGenericParameter (ec, d, t);
1370 if (TypeManager.IsStruct (d)) {
1372 if (Convert.ImplicitBoxingConversionExists (expr, t, out temp))
1373 return CreateConstantResult (ec, true);
1375 if (TypeManager.IsGenericParameter (d))
1376 return ResolveGenericParameter (ec, t, d);
1378 if (TypeManager.ContainsGenericParameters (d))
1381 if (Convert.ImplicitReferenceConversionExists (expr, t) ||
1382 Convert.ExplicitReferenceConversionExists (d, t)) {
1388 return CreateConstantResult (ec, false);
1391 Expression ResolveGenericParameter (ResolveContext ec, Type d, Type t)
1393 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1394 if (constraints != null) {
1395 if (constraints.IsReferenceType && TypeManager.IsStruct (d))
1396 return CreateConstantResult (ec, false);
1399 if (TypeManager.IsGenericParameter (expr.Type)) {
1400 if (constraints != null && constraints.IsValueType && expr.Type == t)
1401 return CreateConstantResult (ec, true);
1403 expr = new BoxedCast (expr, d);
1409 protected override string OperatorName {
1410 get { return "is"; }
1415 /// Implementation of the `as' operator.
1417 public class As : Probe {
1419 Expression resolved_type;
1421 public As (Expression expr, Expression probe_type, Location l)
1422 : base (expr, probe_type, l)
1426 public override Expression CreateExpressionTree (ResolveContext ec)
1428 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1429 expr.CreateExpressionTree (ec),
1430 new TypeOf (probe_type_expr, loc));
1432 return CreateExpressionFactoryCall (ec, "TypeAs", args);
1435 public override void Emit (EmitContext ec)
1437 ILGenerator ig = ec.ig;
1442 ig.Emit (OpCodes.Isinst, type);
1444 if (TypeManager.IsGenericParameter (type) || TypeManager.IsNullableType (type))
1445 ig.Emit (OpCodes.Unbox_Any, type);
1448 protected override Expression DoResolve (ResolveContext ec)
1450 if (resolved_type == null) {
1451 resolved_type = base.DoResolve (ec);
1453 if (resolved_type == null)
1457 type = probe_type_expr.Type;
1458 eclass = ExprClass.Value;
1459 Type etype = expr.Type;
1461 if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
1462 if (TypeManager.IsGenericParameter (type)) {
1463 ec.Report.Error (413, loc,
1464 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
1465 probe_type_expr.GetSignatureForError ());
1467 ec.Report.Error (77, loc,
1468 "The `as' operator cannot be used with a non-nullable value type `{0}'",
1469 TypeManager.CSharpName (type));
1474 if (expr.IsNull && TypeManager.IsNullableType (type)) {
1475 return Nullable.LiftedNull.CreateFromExpression (ec, this);
1478 Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
1485 if (Convert.ExplicitReferenceConversionExists (etype, type)){
1486 if (TypeManager.IsGenericParameter (etype))
1487 expr = new BoxedCast (expr, etype);
1493 if (TypeManager.ContainsGenericParameters (etype) ||
1494 TypeManager.ContainsGenericParameters (type)) {
1495 expr = new BoxedCast (expr, etype);
1500 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
1501 TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
1506 protected override string OperatorName {
1507 get { return "as"; }
1510 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1512 type = storey.MutateType (type);
1513 base.MutateHoistedGenericType (storey);
1516 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1518 return expr.GetAttributableValue (ec, value_type, out value);
1523 /// This represents a typecast in the source language.
1525 /// FIXME: Cast expressions have an unusual set of parsing
1526 /// rules, we need to figure those out.
1528 public class Cast : ShimExpression {
1529 Expression target_type;
1531 public Cast (Expression cast_type, Expression expr)
1532 : this (cast_type, expr, cast_type.Location)
1536 public Cast (Expression cast_type, Expression expr, Location loc)
1539 this.target_type = cast_type;
1543 public Expression TargetType {
1544 get { return target_type; }
1547 protected override Expression DoResolve (ResolveContext ec)
1549 expr = expr.Resolve (ec);
1553 TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false);
1559 if (type.IsAbstract && type.IsSealed) {
1560 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type));
1564 eclass = ExprClass.Value;
1566 Constant c = expr as Constant;
1568 c = c.TryReduce (ec, type, loc);
1573 if (type.IsPointer && !ec.IsUnsafe) {
1574 UnsafeError (ec, loc);
1575 } else if (TypeManager.IsDynamicType (expr.Type)) {
1576 Arguments arg = new Arguments (1);
1577 arg.Add (new Argument (expr));
1578 return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
1581 expr = Convert.ExplicitConversion (ec, expr, type, loc);
1585 protected override void CloneTo (CloneContext clonectx, Expression t)
1587 Cast target = (Cast) t;
1589 target.target_type = target_type.Clone (clonectx);
1590 target.expr = expr.Clone (clonectx);
1594 public class ImplicitCast : ShimExpression
1598 public ImplicitCast (Expression expr, Type target, bool arrayAccess)
1601 this.loc = expr.Location;
1603 this.arrayAccess = arrayAccess;
1606 protected override Expression DoResolve (ResolveContext ec)
1608 expr = expr.Resolve (ec);
1613 expr = ConvertExpressionToArrayIndex (ec, expr);
1615 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
1622 // C# 2.0 Default value expression
1624 public class DefaultValueExpression : Expression
1628 public DefaultValueExpression (Expression expr, Location loc)
1634 public override Expression CreateExpressionTree (ResolveContext ec)
1636 Arguments args = new Arguments (2);
1637 args.Add (new Argument (this));
1638 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1639 return CreateExpressionFactoryCall (ec, "Constant", args);
1642 protected override Expression DoResolve (ResolveContext ec)
1644 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec, false);
1650 if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
1651 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
1655 return new NullLiteral (Location).ConvertImplicitly (ec, type);
1657 if (TypeManager.IsReferenceType (type))
1658 return new NullConstant (type, loc);
1660 Constant c = New.Constantify (type);
1662 return c.Resolve (ec);
1664 eclass = ExprClass.Variable;
1668 public override void Emit (EmitContext ec)
1670 LocalTemporary temp_storage = new LocalTemporary(type);
1672 temp_storage.AddressOf(ec, AddressOp.LoadStore);
1673 ec.ig.Emit(OpCodes.Initobj, type);
1674 temp_storage.Emit(ec);
1677 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1679 type = storey.MutateType (type);
1682 protected override void CloneTo (CloneContext clonectx, Expression t)
1684 DefaultValueExpression target = (DefaultValueExpression) t;
1686 target.expr = expr.Clone (clonectx);
1691 /// Binary operators
1693 public class Binary : Expression, IDynamicBinder
1696 protected class PredefinedOperator {
1697 protected readonly Type left;
1698 protected readonly Type right;
1699 public readonly Operator OperatorsMask;
1700 public Type ReturnType;
1702 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask)
1703 : this (ltype, rtype, op_mask, ltype)
1707 public PredefinedOperator (Type type, Operator op_mask, Type return_type)
1708 : this (type, type, op_mask, return_type)
1712 public PredefinedOperator (Type type, Operator op_mask)
1713 : this (type, type, op_mask, type)
1717 public PredefinedOperator (Type ltype, Type rtype, Operator op_mask, Type return_type)
1719 if ((op_mask & Operator.ValuesOnlyMask) != 0)
1720 throw new InternalErrorException ("Only masked values can be used");
1724 this.OperatorsMask = op_mask;
1725 this.ReturnType = return_type;
1728 public virtual Expression ConvertResult (ResolveContext ec, Binary b)
1730 b.type = ReturnType;
1732 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1733 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1736 // A user operators does not support multiple user conversions, but decimal type
1737 // is considered to be predefined type therefore we apply predefined operators rules
1738 // and then look for decimal user-operator implementation
1740 if (left == TypeManager.decimal_type)
1741 return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
1746 public bool IsPrimitiveApplicable (Type ltype, Type rtype)
1749 // We are dealing with primitive types only
1751 return left == ltype && ltype == rtype;
1754 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1756 if (TypeManager.IsEqual (left, lexpr.Type) &&
1757 TypeManager.IsEqual (right, rexpr.Type))
1760 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
1761 Convert.ImplicitConversionExists (ec, rexpr, right);
1764 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
1767 if (left != null && best_operator.left != null) {
1768 result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
1772 // When second arguments are same as the first one, the result is same
1774 if (right != null && (left != right || best_operator.left != best_operator.right)) {
1775 result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
1778 if (result == 0 || result > 2)
1781 return result == 1 ? best_operator : this;
1785 class PredefinedStringOperator : PredefinedOperator {
1786 public PredefinedStringOperator (Type type, Operator op_mask)
1787 : base (type, op_mask, type)
1789 ReturnType = TypeManager.string_type;
1792 public PredefinedStringOperator (Type ltype, Type rtype, Operator op_mask)
1793 : base (ltype, rtype, op_mask)
1795 ReturnType = TypeManager.string_type;
1798 public override Expression ConvertResult (ResolveContext ec, Binary b)
1801 // Use original expression for nullable arguments
1803 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
1805 b.left = unwrap.Original;
1807 unwrap = b.right as Nullable.Unwrap;
1809 b.right = unwrap.Original;
1811 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1812 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
1815 // Start a new concat expression using converted expression
1817 return StringConcat.Create (ec, b.left, b.right, b.loc);
1821 class PredefinedShiftOperator : PredefinedOperator {
1822 public PredefinedShiftOperator (Type ltype, Operator op_mask) :
1823 base (ltype, TypeManager.int32_type, op_mask)
1827 public override Expression ConvertResult (ResolveContext ec, Binary b)
1829 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
1831 Expression expr_tree_expr = Convert.ImplicitConversion (ec, b.right, TypeManager.int32_type, b.right.Location);
1833 int right_mask = left == TypeManager.int32_type || left == TypeManager.uint32_type ? 0x1f : 0x3f;
1836 // b = b.left >> b.right & (0x1f|0x3f)
1838 b.right = new Binary (Operator.BitwiseAnd,
1839 b.right, new IntConstant (right_mask, b.right.Location)).Resolve (ec);
1842 // Expression tree representation does not use & mask
1844 b.right = ReducedExpression.Create (b.right, expr_tree_expr);
1845 b.type = ReturnType;
1850 class PredefinedPointerOperator : PredefinedOperator {
1851 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask)
1852 : base (ltype, rtype, op_mask)
1856 public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
1857 : base (ltype, rtype, op_mask, retType)
1861 public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
1862 : base (type, op_mask, return_type)
1866 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
1869 if (!lexpr.Type.IsPointer)
1872 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
1876 if (right == null) {
1877 if (!rexpr.Type.IsPointer)
1880 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
1887 public override Expression ConvertResult (ResolveContext ec, Binary b)
1890 b.left = EmptyCast.Create (b.left, left);
1891 } else if (right != null) {
1892 b.right = EmptyCast.Create (b.right, right);
1895 Type r_type = ReturnType;
1896 Expression left_arg, right_arg;
1897 if (r_type == null) {
1900 right_arg = b.right;
1901 r_type = b.left.Type;
1905 r_type = b.right.Type;
1909 right_arg = b.right;
1912 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
1917 public enum Operator {
1918 Multiply = 0 | ArithmeticMask,
1919 Division = 1 | ArithmeticMask,
1920 Modulus = 2 | ArithmeticMask,
1921 Addition = 3 | ArithmeticMask | AdditionMask,
1922 Subtraction = 4 | ArithmeticMask | SubtractionMask,
1924 LeftShift = 5 | ShiftMask,
1925 RightShift = 6 | ShiftMask,
1927 LessThan = 7 | ComparisonMask | RelationalMask,
1928 GreaterThan = 8 | ComparisonMask | RelationalMask,
1929 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
1930 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
1931 Equality = 11 | ComparisonMask | EqualityMask,
1932 Inequality = 12 | ComparisonMask | EqualityMask,
1934 BitwiseAnd = 13 | BitwiseMask,
1935 ExclusiveOr = 14 | BitwiseMask,
1936 BitwiseOr = 15 | BitwiseMask,
1938 LogicalAnd = 16 | LogicalMask,
1939 LogicalOr = 17 | LogicalMask,
1944 ValuesOnlyMask = ArithmeticMask - 1,
1945 ArithmeticMask = 1 << 5,
1947 ComparisonMask = 1 << 7,
1948 EqualityMask = 1 << 8,
1949 BitwiseMask = 1 << 9,
1950 LogicalMask = 1 << 10,
1951 AdditionMask = 1 << 11,
1952 SubtractionMask = 1 << 12,
1953 RelationalMask = 1 << 13
1956 readonly Operator oper;
1957 protected Expression left, right;
1958 readonly bool is_compound;
1959 Expression enum_conversion;
1961 static PredefinedOperator [] standard_operators;
1962 static PredefinedOperator [] pointer_operators;
1964 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
1965 : this (oper, left, right)
1967 this.is_compound = isCompound;
1970 public Binary (Operator oper, Expression left, Expression right)
1975 this.loc = left.Location;
1978 public Operator Oper {
1985 /// Returns a stringified representation of the Operator
1987 string OperName (Operator oper)
1991 case Operator.Multiply:
1994 case Operator.Division:
1997 case Operator.Modulus:
2000 case Operator.Addition:
2003 case Operator.Subtraction:
2006 case Operator.LeftShift:
2009 case Operator.RightShift:
2012 case Operator.LessThan:
2015 case Operator.GreaterThan:
2018 case Operator.LessThanOrEqual:
2021 case Operator.GreaterThanOrEqual:
2024 case Operator.Equality:
2027 case Operator.Inequality:
2030 case Operator.BitwiseAnd:
2033 case Operator.BitwiseOr:
2036 case Operator.ExclusiveOr:
2039 case Operator.LogicalOr:
2042 case Operator.LogicalAnd:
2046 s = oper.ToString ();
2056 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
2058 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
2061 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
2064 l = TypeManager.CSharpName (left.Type);
2065 r = TypeManager.CSharpName (right.Type);
2067 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
2071 protected void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
2073 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
2077 // Converts operator to System.Linq.Expressions.ExpressionType enum name
2079 string GetOperatorExpressionTypeName ()
2082 case Operator.Addition:
2083 return is_compound ? "AddAssign" : "Add";
2084 case Operator.BitwiseAnd:
2085 return is_compound ? "AndAssign" : "And";
2086 case Operator.BitwiseOr:
2087 return is_compound ? "OrAssign" : "Or";
2088 case Operator.Division:
2089 return is_compound ? "DivideAssign" : "Divide";
2090 case Operator.ExclusiveOr:
2091 return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
2092 case Operator.Equality:
2094 case Operator.GreaterThan:
2095 return "GreaterThan";
2096 case Operator.GreaterThanOrEqual:
2097 return "GreaterThanOrEqual";
2098 case Operator.Inequality:
2100 case Operator.LeftShift:
2101 return is_compound ? "LeftShiftAssign" : "LeftShift";
2102 case Operator.LessThan:
2104 case Operator.LessThanOrEqual:
2105 return "LessThanOrEqual";
2106 case Operator.LogicalAnd:
2108 case Operator.LogicalOr:
2110 case Operator.Modulus:
2111 return is_compound ? "ModuloAssign" : "Modulo";
2112 case Operator.Multiply:
2113 return is_compound ? "MultiplyAssign" : "Multiply";
2114 case Operator.RightShift:
2115 return is_compound ? "RightShiftAssign" : "RightShift";
2116 case Operator.Subtraction:
2117 return is_compound ? "SubtractAssign" : "Subtract";
2119 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
2123 static string GetOperatorMetadataName (Operator op)
2125 CSharp.Operator.OpType op_type;
2127 case Operator.Addition:
2128 op_type = CSharp.Operator.OpType.Addition; break;
2129 case Operator.BitwiseAnd:
2130 op_type = CSharp.Operator.OpType.BitwiseAnd; break;
2131 case Operator.BitwiseOr:
2132 op_type = CSharp.Operator.OpType.BitwiseOr; break;
2133 case Operator.Division:
2134 op_type = CSharp.Operator.OpType.Division; break;
2135 case Operator.Equality:
2136 op_type = CSharp.Operator.OpType.Equality; break;
2137 case Operator.ExclusiveOr:
2138 op_type = CSharp.Operator.OpType.ExclusiveOr; break;
2139 case Operator.GreaterThan:
2140 op_type = CSharp.Operator.OpType.GreaterThan; break;
2141 case Operator.GreaterThanOrEqual:
2142 op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
2143 case Operator.Inequality:
2144 op_type = CSharp.Operator.OpType.Inequality; break;
2145 case Operator.LeftShift:
2146 op_type = CSharp.Operator.OpType.LeftShift; break;
2147 case Operator.LessThan:
2148 op_type = CSharp.Operator.OpType.LessThan; break;
2149 case Operator.LessThanOrEqual:
2150 op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
2151 case Operator.Modulus:
2152 op_type = CSharp.Operator.OpType.Modulus; break;
2153 case Operator.Multiply:
2154 op_type = CSharp.Operator.OpType.Multiply; break;
2155 case Operator.RightShift:
2156 op_type = CSharp.Operator.OpType.RightShift; break;
2157 case Operator.Subtraction:
2158 op_type = CSharp.Operator.OpType.Subtraction; break;
2160 throw new InternalErrorException (op.ToString ());
2163 return CSharp.Operator.GetMetadataName (op_type);
2166 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
2169 ILGenerator ig = ec.ig;
2172 case Operator.Multiply:
2173 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2174 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2175 opcode = OpCodes.Mul_Ovf;
2176 else if (!IsFloat (l))
2177 opcode = OpCodes.Mul_Ovf_Un;
2179 opcode = OpCodes.Mul;
2181 opcode = OpCodes.Mul;
2185 case Operator.Division:
2187 opcode = OpCodes.Div_Un;
2189 opcode = OpCodes.Div;
2192 case Operator.Modulus:
2194 opcode = OpCodes.Rem_Un;
2196 opcode = OpCodes.Rem;
2199 case Operator.Addition:
2200 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2201 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2202 opcode = OpCodes.Add_Ovf;
2203 else if (!IsFloat (l))
2204 opcode = OpCodes.Add_Ovf_Un;
2206 opcode = OpCodes.Add;
2208 opcode = OpCodes.Add;
2211 case Operator.Subtraction:
2212 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
2213 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2214 opcode = OpCodes.Sub_Ovf;
2215 else if (!IsFloat (l))
2216 opcode = OpCodes.Sub_Ovf_Un;
2218 opcode = OpCodes.Sub;
2220 opcode = OpCodes.Sub;
2223 case Operator.RightShift:
2225 opcode = OpCodes.Shr_Un;
2227 opcode = OpCodes.Shr;
2230 case Operator.LeftShift:
2231 opcode = OpCodes.Shl;
2234 case Operator.Equality:
2235 opcode = OpCodes.Ceq;
2238 case Operator.Inequality:
2239 ig.Emit (OpCodes.Ceq);
2240 ig.Emit (OpCodes.Ldc_I4_0);
2242 opcode = OpCodes.Ceq;
2245 case Operator.LessThan:
2247 opcode = OpCodes.Clt_Un;
2249 opcode = OpCodes.Clt;
2252 case Operator.GreaterThan:
2254 opcode = OpCodes.Cgt_Un;
2256 opcode = OpCodes.Cgt;
2259 case Operator.LessThanOrEqual:
2260 if (IsUnsigned (l) || IsFloat (l))
2261 ig.Emit (OpCodes.Cgt_Un);
2263 ig.Emit (OpCodes.Cgt);
2264 ig.Emit (OpCodes.Ldc_I4_0);
2266 opcode = OpCodes.Ceq;
2269 case Operator.GreaterThanOrEqual:
2270 if (IsUnsigned (l) || IsFloat (l))
2271 ig.Emit (OpCodes.Clt_Un);
2273 ig.Emit (OpCodes.Clt);
2275 ig.Emit (OpCodes.Ldc_I4_0);
2277 opcode = OpCodes.Ceq;
2280 case Operator.BitwiseOr:
2281 opcode = OpCodes.Or;
2284 case Operator.BitwiseAnd:
2285 opcode = OpCodes.And;
2288 case Operator.ExclusiveOr:
2289 opcode = OpCodes.Xor;
2293 throw new InternalErrorException (oper.ToString ());
2299 static bool IsUnsigned (Type t)
2304 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2305 t == TypeManager.ushort_type || t == TypeManager.byte_type);
2308 static bool IsFloat (Type t)
2310 return t == TypeManager.float_type || t == TypeManager.double_type;
2313 Expression ResolveOperator (ResolveContext ec)
2316 Type r = right.Type;
2318 bool primitives_only = false;
2320 if (standard_operators == null)
2321 CreateStandardOperatorsTable ();
2324 // Handles predefined primitive types
2326 if (TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r)) {
2327 if ((oper & Operator.ShiftMask) == 0) {
2328 if (l != TypeManager.bool_type && !DoBinaryOperatorPromotion (ec))
2331 primitives_only = true;
2335 if (l.IsPointer || r.IsPointer)
2336 return ResolveOperatorPointer (ec, l, r);
2339 bool lenum = TypeManager.IsEnumType (l);
2340 bool renum = TypeManager.IsEnumType (r);
2341 if (lenum || renum) {
2342 expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
2344 // TODO: Can this be ambiguous
2350 if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
2351 (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
2353 expr = ResolveOperatorDelegate (ec, l, r);
2355 // TODO: Can this be ambiguous
2361 expr = ResolveUserOperator (ec, l, r);
2365 // Predefined reference types equality
2366 if ((oper & Operator.EqualityMask) != 0) {
2367 expr = ResolveOperatorEqualityRerefence (ec, l, r);
2373 return ResolveOperatorPredefined (ec, standard_operators, primitives_only, null);
2376 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
2377 // if 'left' is not an enumeration constant, create one from the type of 'right'
2378 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right, Location loc)
2381 case Operator.BitwiseOr:
2382 case Operator.BitwiseAnd:
2383 case Operator.ExclusiveOr:
2384 case Operator.Equality:
2385 case Operator.Inequality:
2386 case Operator.LessThan:
2387 case Operator.LessThanOrEqual:
2388 case Operator.GreaterThan:
2389 case Operator.GreaterThanOrEqual:
2390 if (TypeManager.IsEnumType (left.Type))
2393 if (left.IsZeroInteger)
2394 return left.TryReduce (ec, right.Type, loc);
2398 case Operator.Addition:
2399 case Operator.Subtraction:
2402 case Operator.Multiply:
2403 case Operator.Division:
2404 case Operator.Modulus:
2405 case Operator.LeftShift:
2406 case Operator.RightShift:
2407 if (TypeManager.IsEnumType (right.Type) || TypeManager.IsEnumType (left.Type))
2411 Error_OperatorCannotBeApplied (ec, this.left, this.right);
2416 // The `|' operator used on types which were extended is dangerous
2418 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
2420 OpcodeCast lcast = left as OpcodeCast;
2421 if (lcast != null) {
2422 if (IsUnsigned (lcast.UnderlyingType))
2426 OpcodeCast rcast = right as OpcodeCast;
2427 if (rcast != null) {
2428 if (IsUnsigned (rcast.UnderlyingType))
2432 if (lcast == null && rcast == null)
2435 // FIXME: consider constants
2437 ec.Report.Warning (675, 3, loc,
2438 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
2439 TypeManager.CSharpName (lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType));
2442 static void CreatePointerOperatorsTable ()
2444 ArrayList temp = new ArrayList ();
2447 // Pointer arithmetic:
2449 // T* operator + (T* x, int y); T* operator - (T* x, int y);
2450 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
2451 // T* operator + (T* x, long y); T* operator - (T* x, long y);
2452 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
2454 temp.Add (new PredefinedPointerOperator (null, TypeManager.int32_type, Operator.AdditionMask | Operator.SubtractionMask));
2455 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint32_type, Operator.AdditionMask | Operator.SubtractionMask));
2456 temp.Add (new PredefinedPointerOperator (null, TypeManager.int64_type, Operator.AdditionMask | Operator.SubtractionMask));
2457 temp.Add (new PredefinedPointerOperator (null, TypeManager.uint64_type, Operator.AdditionMask | Operator.SubtractionMask));
2460 // T* operator + (int y, T* x);
2461 // T* operator + (uint y, T *x);
2462 // T* operator + (long y, T *x);
2463 // T* operator + (ulong y, T *x);
2465 temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
2466 temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
2467 temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
2468 temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
2471 // long operator - (T* x, T *y)
2473 temp.Add (new PredefinedPointerOperator (null, Operator.SubtractionMask, TypeManager.int64_type));
2475 pointer_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2478 static void CreateStandardOperatorsTable ()
2480 ArrayList temp = new ArrayList ();
2481 Type bool_type = TypeManager.bool_type;
2483 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2484 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2485 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2486 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
2487 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
2488 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
2489 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
2491 temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
2492 temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
2493 temp.Add (new PredefinedOperator (TypeManager.int64_type, Operator.ComparisonMask, bool_type));
2494 temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
2495 temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
2496 temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
2497 temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
2499 temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
2501 temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
2502 temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
2503 temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
2505 temp.Add (new PredefinedOperator (bool_type,
2506 Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type));
2508 temp.Add (new PredefinedShiftOperator (TypeManager.int32_type, Operator.ShiftMask));
2509 temp.Add (new PredefinedShiftOperator (TypeManager.uint32_type, Operator.ShiftMask));
2510 temp.Add (new PredefinedShiftOperator (TypeManager.int64_type, Operator.ShiftMask));
2511 temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
2513 standard_operators = (PredefinedOperator []) temp.ToArray (typeof (PredefinedOperator));
2517 // Rules used during binary numeric promotion
2519 static bool DoNumericPromotion (ResolveContext rc, ref Expression prim_expr, ref Expression second_expr, Type type)
2524 Constant c = prim_expr as Constant;
2526 temp = c.ConvertImplicitly (rc, type);
2533 if (type == TypeManager.uint32_type) {
2534 etype = prim_expr.Type;
2535 if (etype == TypeManager.int32_type || etype == TypeManager.short_type || etype == TypeManager.sbyte_type) {
2536 type = TypeManager.int64_type;
2538 if (type != second_expr.Type) {
2539 c = second_expr as Constant;
2541 temp = c.ConvertImplicitly (rc, type);
2543 temp = Convert.ImplicitNumericConversion (second_expr, type);
2549 } else if (type == TypeManager.uint64_type) {
2551 // A compile-time error occurs if the other operand is of type sbyte, short, int, or long
2553 if (type == TypeManager.int32_type || type == TypeManager.int64_type ||
2554 type == TypeManager.sbyte_type || type == TypeManager.sbyte_type)
2558 temp = Convert.ImplicitNumericConversion (prim_expr, type);
2567 // 7.2.6.2 Binary numeric promotions
2569 public bool DoBinaryOperatorPromotion (ResolveContext ec)
2571 Type ltype = left.Type;
2572 Type rtype = right.Type;
2575 foreach (Type t in ConstantFold.binary_promotions) {
2577 return t == rtype || DoNumericPromotion (ec, ref right, ref left, t);
2580 return t == ltype || DoNumericPromotion (ec, ref left, ref right, t);
2583 Type int32 = TypeManager.int32_type;
2584 if (ltype != int32) {
2585 Constant c = left as Constant;
2587 temp = c.ConvertImplicitly (ec, int32);
2589 temp = Convert.ImplicitNumericConversion (left, int32);
2596 if (rtype != int32) {
2597 Constant c = right as Constant;
2599 temp = c.ConvertImplicitly (ec, int32);
2601 temp = Convert.ImplicitNumericConversion (right, int32);
2611 protected override Expression DoResolve (ResolveContext ec)
2616 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2617 left = ((ParenthesizedExpression) left).Expr;
2618 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2622 if (left.eclass == ExprClass.Type) {
2623 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
2627 left = left.Resolve (ec);
2632 Constant lc = left as Constant;
2634 if (lc != null && lc.Type == TypeManager.bool_type &&
2635 ((oper == Operator.LogicalAnd && lc.IsDefaultValue) ||
2636 (oper == Operator.LogicalOr && !lc.IsDefaultValue))) {
2638 // FIXME: resolve right expression as unreachable
2639 // right.Resolve (ec);
2641 ec.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2645 right = right.Resolve (ec);
2649 eclass = ExprClass.Value;
2650 Constant rc = right as Constant;
2652 // The conversion rules are ignored in enum context but why
2653 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) {
2654 lc = EnumLiftUp (ec, lc, rc, loc);
2656 rc = EnumLiftUp (ec, rc, lc, loc);
2659 if (rc != null && lc != null) {
2660 int prev_e = ec.Report.Errors;
2661 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
2665 if (e != null || ec.Report.Errors != prev_e)
2669 // Comparison warnings
2670 if ((oper & Operator.ComparisonMask) != 0) {
2671 if (left.Equals (right)) {
2672 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
2674 CheckUselessComparison (ec, lc, right.Type);
2675 CheckUselessComparison (ec, rc, left.Type);
2678 if (TypeManager.IsDynamicType (left.Type) || TypeManager.IsDynamicType (right.Type)) {
2679 Arguments args = new Arguments (2);
2680 args.Add (new Argument (left));
2681 args.Add (new Argument (right));
2682 return new DynamicExpressionStatement (this, args, loc).Resolve (ec);
2685 if (RootContext.Version >= LanguageVersion.ISO_2 &&
2686 ((TypeManager.IsNullableType (left.Type) && (right is NullLiteral || TypeManager.IsNullableType (right.Type) || TypeManager.IsValueType (right.Type))) ||
2687 (TypeManager.IsValueType (left.Type) && right is NullLiteral) ||
2688 (TypeManager.IsNullableType (right.Type) && (left is NullLiteral || TypeManager.IsNullableType (left.Type) || TypeManager.IsValueType (left.Type))) ||
2689 (TypeManager.IsValueType (right.Type) && left is NullLiteral)))
2690 return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
2692 return DoResolveCore (ec, left, right);
2695 protected Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
2697 Expression expr = ResolveOperator (ec);
2699 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
2701 if (left == null || right == null)
2702 throw new InternalErrorException ("Invalid conversion");
2704 if (oper == Operator.BitwiseOr)
2705 CheckBitwiseOrOnSignExtended (ec);
2711 public override SLE.Expression MakeExpression (BuilderContext ctx)
2713 var le = left.MakeExpression (ctx);
2714 var re = right.MakeExpression (ctx);
2715 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
2718 case Operator.Addition:
2719 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
2720 case Operator.BitwiseAnd:
2721 return SLE.Expression.And (le, re);
2722 case Operator.BitwiseOr:
2723 return SLE.Expression.Or (le, re);
2724 case Operator.Division:
2725 return SLE.Expression.Divide (le, re);
2726 case Operator.Equality:
2727 return SLE.Expression.Equal (le, re);
2728 case Operator.ExclusiveOr:
2729 return SLE.Expression.ExclusiveOr (le, re);
2730 case Operator.GreaterThan:
2731 return SLE.Expression.GreaterThan (le, re);
2732 case Operator.GreaterThanOrEqual:
2733 return SLE.Expression.GreaterThanOrEqual (le, re);
2734 case Operator.Inequality:
2735 return SLE.Expression.NotEqual (le, re);
2736 case Operator.LeftShift:
2737 return SLE.Expression.LeftShift (le, re);
2738 case Operator.LessThan:
2739 return SLE.Expression.LessThan (le, re);
2740 case Operator.LessThanOrEqual:
2741 return SLE.Expression.LessThanOrEqual (le, re);
2742 case Operator.LogicalAnd:
2743 return SLE.Expression.AndAlso (le, re);
2744 case Operator.LogicalOr:
2745 return SLE.Expression.OrElse (le, re);
2746 case Operator.Modulus:
2747 return SLE.Expression.Modulo (le, re);
2748 case Operator.Multiply:
2749 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
2750 case Operator.RightShift:
2751 return SLE.Expression.RightShift (le, re);
2752 case Operator.Subtraction:
2753 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
2755 throw new NotImplementedException (oper.ToString ());
2760 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2762 left.MutateHoistedGenericType (storey);
2763 right.MutateHoistedGenericType (storey);
2767 // D operator + (D x, D y)
2768 // D operator - (D x, D y)
2769 // bool operator == (D x, D y)
2770 // bool operator != (D x, D y)
2772 Expression ResolveOperatorDelegate (ResolveContext ec, Type l, Type r)
2774 bool is_equality = (oper & Operator.EqualityMask) != 0;
2775 if (!TypeManager.IsEqual (l, r) && !TypeManager.IsVariantOf (r, l)) {
2777 if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
2778 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2783 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
2784 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
2795 // Resolve delegate equality as a user operator
2798 return ResolveUserOperator (ec, l, r);
2801 Arguments args = new Arguments (2);
2802 args.Add (new Argument (left));
2803 args.Add (new Argument (right));
2805 if (oper == Operator.Addition) {
2806 if (TypeManager.delegate_combine_delegate_delegate == null) {
2807 TypeManager.delegate_combine_delegate_delegate = TypeManager.GetPredefinedMethod (
2808 TypeManager.delegate_type, "Combine", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2811 method = TypeManager.delegate_combine_delegate_delegate;
2813 if (TypeManager.delegate_remove_delegate_delegate == null) {
2814 TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
2815 TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
2818 method = TypeManager.delegate_remove_delegate_delegate;
2821 MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
2822 mg = mg.OverloadResolve (ec, ref args, false, loc);
2824 return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
2828 // Enumeration operators
2830 Expression ResolveOperatorEnum (ResolveContext ec, bool lenum, bool renum, Type ltype, Type rtype)
2833 // bool operator == (E x, E y);
2834 // bool operator != (E x, E y);
2835 // bool operator < (E x, E y);
2836 // bool operator > (E x, E y);
2837 // bool operator <= (E x, E y);
2838 // bool operator >= (E x, E y);
2840 // E operator & (E x, E y);
2841 // E operator | (E x, E y);
2842 // E operator ^ (E x, E y);
2844 // U operator - (E e, E f)
2845 // E operator - (E e, U x)
2847 // E operator + (U x, E e)
2848 // E operator + (E e, U x)
2850 if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
2851 (oper == Operator.Subtraction && lenum) ||
2852 (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
2855 Expression ltemp = left;
2856 Expression rtemp = right;
2857 Type underlying_type;
2860 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
2862 expr = Convert.ImplicitConversion (ec, left, rtype, loc);
2868 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2876 if (TypeManager.IsEqual (ltype, rtype)) {
2877 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2879 if (left is Constant)
2880 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2882 left = EmptyCast.Create (left, underlying_type);
2884 if (right is Constant)
2885 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2887 right = EmptyCast.Create (right, underlying_type);
2889 underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
2891 if (oper != Operator.Subtraction && oper != Operator.Addition) {
2892 Constant c = right as Constant;
2893 if (c == null || !c.IsDefaultValue)
2896 if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
2899 right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
2902 if (left is Constant)
2903 left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
2905 left = EmptyCast.Create (left, underlying_type);
2908 underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
2910 if (oper != Operator.Addition) {
2911 Constant c = left as Constant;
2912 if (c == null || !c.IsDefaultValue)
2915 if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
2918 left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
2921 if (right is Constant)
2922 right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
2924 right = EmptyCast.Create (right, underlying_type);
2931 // C# specification uses explicit cast syntax which means binary promotion
2932 // should happen, however it seems that csc does not do that
2934 if (!DoBinaryOperatorPromotion (ec)) {
2940 Type res_type = null;
2941 if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
2942 Type promoted_type = lenum ? left.Type : right.Type;
2943 enum_conversion = Convert.ExplicitNumericConversion (
2944 new EmptyExpression (promoted_type), underlying_type);
2946 if (oper == Operator.Subtraction && renum && lenum)
2947 res_type = underlying_type;
2948 else if (oper == Operator.Addition && renum)
2954 expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
2955 if (!is_compound || expr == null)
2963 // If the return type of the selected operator is implicitly convertible to the type of x
2965 if (Convert.ImplicitConversionExists (ec, expr, ltype))
2969 // Otherwise, if the selected operator is a predefined operator, if the return type of the
2970 // selected operator is explicitly convertible to the type of x, and if y is implicitly
2971 // convertible to the type of x or the operator is a shift operator, then the operation
2972 // is evaluated as x = (T)(x op y), where T is the type of x
2974 expr = Convert.ExplicitConversion (ec, expr, ltype, loc);
2978 if (Convert.ImplicitConversionExists (ec, ltemp, ltype))
2985 // 7.9.6 Reference type equality operators
2987 Binary ResolveOperatorEqualityRerefence (ResolveContext ec, Type l, Type r)
2990 // operator != (object a, object b)
2991 // operator == (object a, object b)
2994 // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
2996 if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
2999 type = TypeManager.bool_type;
3000 GenericConstraints constraints;
3002 bool lgen = TypeManager.IsGenericParameter (l);
3004 if (TypeManager.IsEqual (l, r)) {
3007 // Only allow to compare same reference type parameter
3009 if (TypeManager.IsReferenceType (l)) {
3010 left = new BoxedCast (left, TypeManager.object_type);
3011 right = new BoxedCast (right, TypeManager.object_type);
3018 if (l == InternalType.AnonymousMethod)
3021 if (TypeManager.IsValueType (l))
3027 bool rgen = TypeManager.IsGenericParameter (r);
3030 // a, Both operands are reference-type values or the value null
3031 // b, One operand is a value of type T where T is a type-parameter and
3032 // the other operand is the value null. Furthermore T does not have the
3033 // value type constrain
3035 if (left is NullLiteral || right is NullLiteral) {
3037 constraints = TypeManager.GetTypeParameterConstraints (l);
3038 if (constraints != null && constraints.HasValueTypeConstraint)
3041 left = new BoxedCast (left, TypeManager.object_type);
3046 constraints = TypeManager.GetTypeParameterConstraints (r);
3047 if (constraints != null && constraints.HasValueTypeConstraint)
3050 right = new BoxedCast (right, TypeManager.object_type);
3056 // An interface is converted to the object before the
3057 // standard conversion is applied. It's not clear from the
3058 // standard but it looks like it works like that.
3061 if (!TypeManager.IsReferenceType (l))
3064 l = TypeManager.object_type;
3065 left = new BoxedCast (left, l);
3066 } else if (l.IsInterface) {
3067 l = TypeManager.object_type;
3068 } else if (TypeManager.IsStruct (l)) {
3073 if (!TypeManager.IsReferenceType (r))
3076 r = TypeManager.object_type;
3077 right = new BoxedCast (right, r);
3078 } else if (r.IsInterface) {
3079 r = TypeManager.object_type;
3080 } else if (TypeManager.IsStruct (r)) {
3085 const string ref_comparison = "Possible unintended reference comparison. " +
3086 "Consider casting the {0} side of the expression to `string' to compare the values";
3089 // A standard implicit conversion exists from the type of either
3090 // operand to the type of the other operand
3092 if (Convert.ImplicitReferenceConversionExists (left, r)) {
3093 if (l == TypeManager.string_type)
3094 ec.Report.Warning (253, 2, loc, ref_comparison, "right");
3099 if (Convert.ImplicitReferenceConversionExists (right, l)) {
3100 if (r == TypeManager.string_type)
3101 ec.Report.Warning (252, 2, loc, ref_comparison, "left");
3110 Expression ResolveOperatorPointer (ResolveContext ec, Type l, Type r)
3113 // bool operator == (void* x, void* y);
3114 // bool operator != (void* x, void* y);
3115 // bool operator < (void* x, void* y);
3116 // bool operator > (void* x, void* y);
3117 // bool operator <= (void* x, void* y);
3118 // bool operator >= (void* x, void* y);
3120 if ((oper & Operator.ComparisonMask) != 0) {
3123 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
3130 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
3136 type = TypeManager.bool_type;
3140 if (pointer_operators == null)
3141 CreatePointerOperatorsTable ();
3143 return ResolveOperatorPredefined (ec, pointer_operators, false, null);
3147 // Build-in operators method overloading
3149 protected virtual Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only, Type enum_type)
3151 PredefinedOperator best_operator = null;
3153 Type r = right.Type;
3154 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
3156 foreach (PredefinedOperator po in operators) {
3157 if ((po.OperatorsMask & oper_mask) == 0)
3160 if (primitives_only) {
3161 if (!po.IsPrimitiveApplicable (l, r))
3164 if (!po.IsApplicable (ec, left, right))
3168 if (best_operator == null) {
3170 if (primitives_only)
3176 best_operator = po.ResolveBetterOperator (ec, best_operator);
3178 if (best_operator == null) {
3179 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
3180 OperName (oper), TypeManager.CSharpName (l), TypeManager.CSharpName (r));
3187 if (best_operator == null)
3190 Expression expr = best_operator.ConvertResult (ec, this);
3193 // Optimize &/&& constant expressions with 0 value
3195 if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
3196 Constant rc = right as Constant;
3197 Constant lc = left as Constant;
3198 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
3200 // The result is a constant with side-effect
3202 Constant side_effect = rc == null ?
3203 new SideEffectConstant (lc, right, loc) :
3204 new SideEffectConstant (rc, left, loc);
3206 return ReducedExpression.Create (side_effect.Resolve (ec), expr);
3210 if (enum_type == null)
3214 // HACK: required by enum_conversion
3216 expr.Type = enum_type;
3217 return EmptyCast.Create (expr, enum_type);
3221 // Performs user-operator overloading
3223 protected virtual Expression ResolveUserOperator (ResolveContext ec, Type l, Type r)
3226 if (oper == Operator.LogicalAnd)
3227 user_oper = Operator.BitwiseAnd;
3228 else if (oper == Operator.LogicalOr)
3229 user_oper = Operator.BitwiseOr;
3233 string op = GetOperatorMetadataName (user_oper);
3235 MethodGroupExpr left_operators = MemberLookup (ec.Compiler, ec.CurrentType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3236 MethodGroupExpr right_operators = null;
3238 if (!TypeManager.IsEqual (r, l)) {
3239 right_operators = MemberLookup (ec.Compiler, ec.CurrentType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
3240 if (right_operators == null && left_operators == null)
3242 } else if (left_operators == null) {
3246 Arguments args = new Arguments (2);
3247 Argument larg = new Argument (left);
3249 Argument rarg = new Argument (right);
3252 MethodGroupExpr union;
3255 // User-defined operator implementations always take precedence
3256 // over predefined operator implementations
3258 if (left_operators != null && right_operators != null) {
3259 if (IsPredefinedUserOperator (l, user_oper)) {
3260 union = right_operators.OverloadResolve (ec, ref args, true, loc);
3262 union = left_operators;
3263 } else if (IsPredefinedUserOperator (r, user_oper)) {
3264 union = left_operators.OverloadResolve (ec, ref args, true, loc);
3266 union = right_operators;
3268 union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
3270 } else if (left_operators != null) {
3271 union = left_operators;
3273 union = right_operators;
3276 union = union.OverloadResolve (ec, ref args, true, loc);
3280 Expression oper_expr;
3282 // TODO: CreateExpressionTree is allocated every time
3283 if (user_oper != oper) {
3284 oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
3285 oper == Operator.LogicalAnd, loc).Resolve (ec);
3287 oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
3290 // This is used to check if a test 'x == null' can be optimized to a reference equals,
3291 // and not invoke user operator
3293 if ((oper & Operator.EqualityMask) != 0) {
3294 if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
3295 (right is NullLiteral && IsBuildInEqualityOperator (l))) {
3296 type = TypeManager.bool_type;
3297 if (left is NullLiteral || right is NullLiteral)
3298 oper_expr = ReducedExpression.Create (this, oper_expr);
3299 } else if (l != r) {
3300 MethodInfo mi = (MethodInfo) union;
3303 // Two System.Delegate(s) are never equal
3305 if (mi.DeclaringType == TypeManager.multicast_delegate_type)
3316 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3321 private void CheckUselessComparison (ResolveContext ec, Constant c, Type type)
3323 if (c == null || !IsTypeIntegral (type)
3324 || c is StringConstant
3325 || c is BoolConstant
3326 || c is FloatConstant
3327 || c is DoubleConstant
3328 || c is DecimalConstant
3334 if (c is ULongConstant) {
3335 ulong uvalue = ((ULongConstant) c).Value;
3336 if (uvalue > long.MaxValue) {
3337 if (type == TypeManager.byte_type ||
3338 type == TypeManager.sbyte_type ||
3339 type == TypeManager.short_type ||
3340 type == TypeManager.ushort_type ||
3341 type == TypeManager.int32_type ||
3342 type == TypeManager.uint32_type ||
3343 type == TypeManager.int64_type ||
3344 type == TypeManager.char_type)
3345 WarnUselessComparison (ec, type);
3348 value = (long) uvalue;
3350 else if (c is ByteConstant)
3351 value = ((ByteConstant) c).Value;
3352 else if (c is SByteConstant)
3353 value = ((SByteConstant) c).Value;
3354 else if (c is ShortConstant)
3355 value = ((ShortConstant) c).Value;
3356 else if (c is UShortConstant)
3357 value = ((UShortConstant) c).Value;
3358 else if (c is IntConstant)
3359 value = ((IntConstant) c).Value;
3360 else if (c is UIntConstant)
3361 value = ((UIntConstant) c).Value;
3362 else if (c is LongConstant)
3363 value = ((LongConstant) c).Value;
3364 else if (c is CharConstant)
3365 value = ((CharConstant)c).Value;
3370 if (IsValueOutOfRange (value, type))
3371 WarnUselessComparison (ec, type);
3374 static bool IsValueOutOfRange (long value, Type type)
3376 if (IsTypeUnsigned (type) && value < 0)
3378 return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
3379 type == TypeManager.byte_type && value >= 0x100 ||
3380 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
3381 type == TypeManager.ushort_type && value >= 0x10000 ||
3382 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
3383 type == TypeManager.uint32_type && value >= 0x100000000;
3386 static bool IsBuildInEqualityOperator (Type t)
3388 return t == TypeManager.object_type || t == TypeManager.string_type ||
3389 t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
3392 static bool IsPredefinedUserOperator (Type t, Operator op)
3395 // Some predefined types have user operators
3397 return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
3400 private static bool IsTypeIntegral (Type type)
3402 return type == TypeManager.uint64_type ||
3403 type == TypeManager.int64_type ||
3404 type == TypeManager.uint32_type ||
3405 type == TypeManager.int32_type ||
3406 type == TypeManager.ushort_type ||
3407 type == TypeManager.short_type ||
3408 type == TypeManager.sbyte_type ||
3409 type == TypeManager.byte_type ||
3410 type == TypeManager.char_type;
3413 private static bool IsTypeUnsigned (Type type)
3415 return type == TypeManager.uint64_type ||
3416 type == TypeManager.uint32_type ||
3417 type == TypeManager.ushort_type ||
3418 type == TypeManager.byte_type ||
3419 type == TypeManager.char_type;
3422 private void WarnUselessComparison (ResolveContext ec, Type type)
3424 ec.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}'",
3425 TypeManager.CSharpName (type));
3429 /// EmitBranchable is called from Statement.EmitBoolExpression in the
3430 /// context of a conditional bool expression. This function will return
3431 /// false if it is was possible to use EmitBranchable, or true if it was.
3433 /// The expression's code is generated, and we will generate a branch to `target'
3434 /// if the resulting expression value is equal to isTrue
3436 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
3438 ILGenerator ig = ec.ig;
3441 // This is more complicated than it looks, but its just to avoid
3442 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
3443 // but on top of that we want for == and != to use a special path
3444 // if we are comparing against null
3446 if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
3447 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
3450 // put the constant on the rhs, for simplicity
3452 if (left is Constant) {
3453 Expression swap = right;
3458 if (((Constant) right).IsZeroInteger) {
3459 left.EmitBranchable (ec, target, my_on_true);
3462 if (right.Type == TypeManager.bool_type) {
3463 // right is a boolean, and it's not 'false' => it is 'true'
3464 left.EmitBranchable (ec, target, !my_on_true);
3468 } else if (oper == Operator.LogicalAnd) {
3471 Label tests_end = ig.DefineLabel ();
3473 left.EmitBranchable (ec, tests_end, false);
3474 right.EmitBranchable (ec, target, true);
3475 ig.MarkLabel (tests_end);
3478 // This optimizes code like this
3479 // if (true && i > 4)
3481 if (!(left is Constant))
3482 left.EmitBranchable (ec, target, false);
3484 if (!(right is Constant))
3485 right.EmitBranchable (ec, target, false);
3490 } else if (oper == Operator.LogicalOr){
3492 left.EmitBranchable (ec, target, true);
3493 right.EmitBranchable (ec, target, true);
3496 Label tests_end = ig.DefineLabel ();
3497 left.EmitBranchable (ec, tests_end, true);
3498 right.EmitBranchable (ec, target, false);
3499 ig.MarkLabel (tests_end);
3504 } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
3505 oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
3506 oper == Operator.Equality || oper == Operator.Inequality)) {
3507 base.EmitBranchable (ec, target, on_true);
3515 bool is_float = IsFloat (t);
3516 bool is_unsigned = is_float || IsUnsigned (t);
3519 case Operator.Equality:
3521 ig.Emit (OpCodes.Beq, target);
3523 ig.Emit (OpCodes.Bne_Un, target);
3526 case Operator.Inequality:
3528 ig.Emit (OpCodes.Bne_Un, target);
3530 ig.Emit (OpCodes.Beq, target);
3533 case Operator.LessThan:
3535 if (is_unsigned && !is_float)
3536 ig.Emit (OpCodes.Blt_Un, target);
3538 ig.Emit (OpCodes.Blt, target);
3541 ig.Emit (OpCodes.Bge_Un, target);
3543 ig.Emit (OpCodes.Bge, target);
3546 case Operator.GreaterThan:
3548 if (is_unsigned && !is_float)
3549 ig.Emit (OpCodes.Bgt_Un, target);
3551 ig.Emit (OpCodes.Bgt, target);
3554 ig.Emit (OpCodes.Ble_Un, target);
3556 ig.Emit (OpCodes.Ble, target);
3559 case Operator.LessThanOrEqual:
3561 if (is_unsigned && !is_float)
3562 ig.Emit (OpCodes.Ble_Un, target);
3564 ig.Emit (OpCodes.Ble, target);
3567 ig.Emit (OpCodes.Bgt_Un, target);
3569 ig.Emit (OpCodes.Bgt, target);
3573 case Operator.GreaterThanOrEqual:
3575 if (is_unsigned && !is_float)
3576 ig.Emit (OpCodes.Bge_Un, target);
3578 ig.Emit (OpCodes.Bge, target);
3581 ig.Emit (OpCodes.Blt_Un, target);
3583 ig.Emit (OpCodes.Blt, target);
3586 throw new InternalErrorException (oper.ToString ());
3590 public override void Emit (EmitContext ec)
3592 EmitOperator (ec, left.Type);
3595 protected virtual void EmitOperator (EmitContext ec, Type l)
3597 ILGenerator ig = ec.ig;
3600 // Handle short-circuit operators differently
3603 if ((oper & Operator.LogicalMask) != 0) {
3604 Label load_result = ig.DefineLabel ();
3605 Label end = ig.DefineLabel ();
3607 bool is_or = oper == Operator.LogicalOr;
3608 left.EmitBranchable (ec, load_result, is_or);
3610 ig.Emit (OpCodes.Br_S, end);
3612 ig.MarkLabel (load_result);
3613 ig.Emit (is_or ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
3621 // Optimize zero-based operations
3623 // TODO: Implement more optimizations, but it should probably go to PredefinedOperators
3625 if ((oper & Operator.ShiftMask) != 0 || oper == Operator.Addition || oper == Operator.Subtraction) {
3626 Constant rc = right as Constant;
3627 if (rc != null && rc.IsDefaultValue) {
3633 EmitOperatorOpcode (ec, oper, l);
3636 // Nullable enum could require underlying type cast and we cannot simply wrap binary
3637 // expression because that would wrap lifted binary operation
3639 if (enum_conversion != null)
3640 enum_conversion.Emit (ec);
3643 public override void EmitSideEffect (EmitContext ec)
3645 if ((oper & Operator.LogicalMask) != 0 ||
3646 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
3647 base.EmitSideEffect (ec);
3649 left.EmitSideEffect (ec);
3650 right.EmitSideEffect (ec);
3654 protected override void CloneTo (CloneContext clonectx, Expression t)
3656 Binary target = (Binary) t;
3658 target.left = left.Clone (clonectx);
3659 target.right = right.Clone (clonectx);
3662 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
3664 Arguments binder_args = new Arguments (3);
3666 MemberAccess sle = new MemberAccess (new MemberAccess (
3667 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
3669 CSharpBinderFlags flags = 0;
3670 if (ec.HasSet (ResolveContext.Options.CheckedScope))
3671 flags = CSharpBinderFlags.CheckedContext;
3673 if ((oper & Operator.LogicalMask) != 0)
3674 flags |= CSharpBinderFlags.BinaryOperationLogical;
3676 binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
3677 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
3678 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (ec), loc)));
3680 return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
3683 public override Expression CreateExpressionTree (ResolveContext ec)
3685 return CreateExpressionTree (ec, null);
3688 Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
3691 bool lift_arg = false;
3694 case Operator.Addition:
3695 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3696 method_name = "AddChecked";
3698 method_name = "Add";
3700 case Operator.BitwiseAnd:
3701 method_name = "And";
3703 case Operator.BitwiseOr:
3706 case Operator.Division:
3707 method_name = "Divide";
3709 case Operator.Equality:
3710 method_name = "Equal";
3713 case Operator.ExclusiveOr:
3714 method_name = "ExclusiveOr";
3716 case Operator.GreaterThan:
3717 method_name = "GreaterThan";
3720 case Operator.GreaterThanOrEqual:
3721 method_name = "GreaterThanOrEqual";
3724 case Operator.Inequality:
3725 method_name = "NotEqual";
3728 case Operator.LeftShift:
3729 method_name = "LeftShift";
3731 case Operator.LessThan:
3732 method_name = "LessThan";
3735 case Operator.LessThanOrEqual:
3736 method_name = "LessThanOrEqual";
3739 case Operator.LogicalAnd:
3740 method_name = "AndAlso";
3742 case Operator.LogicalOr:
3743 method_name = "OrElse";
3745 case Operator.Modulus:
3746 method_name = "Modulo";
3748 case Operator.Multiply:
3749 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3750 method_name = "MultiplyChecked";
3752 method_name = "Multiply";
3754 case Operator.RightShift:
3755 method_name = "RightShift";
3757 case Operator.Subtraction:
3758 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
3759 method_name = "SubtractChecked";
3761 method_name = "Subtract";
3765 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
3768 Arguments args = new Arguments (2);
3769 args.Add (new Argument (left.CreateExpressionTree (ec)));
3770 args.Add (new Argument (right.CreateExpressionTree (ec)));
3771 if (method != null) {
3773 args.Add (new Argument (new BoolConstant (false, loc)));
3775 args.Add (new Argument (method.CreateExpressionTree (ec)));
3778 return CreateExpressionFactoryCall (ec, method_name, args);
3783 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3784 // b, c, d... may be strings or objects.
3786 public class StringConcat : Expression {
3787 Arguments arguments;
3789 public StringConcat (Expression left, Expression right, Location loc)
3792 type = TypeManager.string_type;
3793 eclass = ExprClass.Value;
3795 arguments = new Arguments (2);
3798 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
3800 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
3801 throw new ArgumentException ();
3803 var s = new StringConcat (left, right, loc);
3804 s.Append (rc, left);
3805 s.Append (rc, right);
3809 public override Expression CreateExpressionTree (ResolveContext ec)
3811 Argument arg = arguments [0];
3812 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
3816 // Creates nested calls tree from an array of arguments used for IL emit
3818 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
3820 Arguments concat_args = new Arguments (2);
3821 Arguments add_args = new Arguments (3);
3823 concat_args.Add (left);
3824 add_args.Add (new Argument (left_etree));
3826 concat_args.Add (arguments [pos]);
3827 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
3829 MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
3833 method = method.OverloadResolve (ec, ref concat_args, false, loc);
3837 add_args.Add (new Argument (method.CreateExpressionTree (ec)));
3839 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
3840 if (++pos == arguments.Count)
3843 left = new Argument (new EmptyExpression (((MethodInfo)method).ReturnType));
3844 return CreateExpressionAddCall (ec, left, expr, pos);
3847 protected override Expression DoResolve (ResolveContext ec)
3852 void Append (ResolveContext rc, Expression operand)
3857 StringConstant sc = operand as StringConstant;
3859 if (arguments.Count != 0) {
3860 Argument last_argument = arguments [arguments.Count - 1];
3861 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
3862 if (last_expr_constant != null) {
3863 last_argument.Expr = new StringConstant (
3864 last_expr_constant.Value + sc.Value, sc.Location).Resolve (rc);
3870 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
3872 StringConcat concat_oper = operand as StringConcat;
3873 if (concat_oper != null) {
3874 arguments.AddRange (concat_oper.arguments);
3879 arguments.Add (new Argument (operand));
3882 Expression CreateConcatMemberExpression ()
3884 return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
3887 public override void Emit (EmitContext ec)
3889 Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
3890 concat = concat.Resolve (new ResolveContext (ec.MemberContext));
3896 public override SLE.Expression MakeExpression (BuilderContext ctx)
3898 if (arguments.Count != 2)
3899 throw new NotImplementedException ("arguments.Count != 2");
3901 var concat = TypeManager.string_type.GetMethod ("Concat", new[] { typeof (object), typeof (object) });
3902 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
3906 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3908 arguments.MutateHoistedGenericType (storey);
3913 // User-defined conditional logical operator
3915 public class ConditionalLogicalOperator : UserOperatorCall {
3916 readonly bool is_and;
3919 public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
3920 ExpressionTreeExpression expr_tree, bool is_and, Location loc)
3921 : base (oper_method, arguments, expr_tree, loc)
3923 this.is_and = is_and;
3924 eclass = ExprClass.Unresolved;
3927 protected override Expression DoResolve (ResolveContext ec)
3929 MethodInfo method = (MethodInfo)mg;
3930 type = TypeManager.TypeToCoreType (method.ReturnType);
3931 AParametersCollection pd = TypeManager.GetParameterData (method);
3932 if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
3933 ec.Report.Error (217, loc,
3934 "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",
3935 TypeManager.CSharpSignature (method));
3939 Expression left_dup = new EmptyExpression (type);
3940 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
3941 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
3942 if (op_true == null || op_false == null) {
3943 ec.Report.Error (218, loc,
3944 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
3945 TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
3949 oper = is_and ? op_false : op_true;
3950 eclass = ExprClass.Value;
3954 public override void Emit (EmitContext ec)
3956 ILGenerator ig = ec.ig;
3957 Label end_target = ig.DefineLabel ();
3960 // Emit and duplicate left argument
3962 arguments [0].Expr.Emit (ec);
3963 ig.Emit (OpCodes.Dup);
3964 arguments.RemoveAt (0);
3966 oper.EmitBranchable (ec, end_target, true);
3968 ig.MarkLabel (end_target);
3972 public class PointerArithmetic : Expression {
3973 Expression left, right;
3977 // We assume that `l' is always a pointer
3979 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
3988 public override Expression CreateExpressionTree (ResolveContext ec)
3990 Error_PointerInsideExpressionTree (ec);
3994 protected override Expression DoResolve (ResolveContext ec)
3996 eclass = ExprClass.Variable;
3998 if (left.Type == TypeManager.void_ptr_type) {
3999 ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
4006 public override void Emit (EmitContext ec)
4008 Type op_type = left.Type;
4009 ILGenerator ig = ec.ig;
4011 // It must be either array or fixed buffer
4013 if (TypeManager.HasElementType (op_type)) {
4014 element = TypeManager.GetElementType (op_type);
4016 FieldExpr fe = left as FieldExpr;
4018 element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
4023 int size = GetTypeSize (element);
4024 Type rtype = right.Type;
4026 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
4028 // handle (pointer - pointer)
4032 ig.Emit (OpCodes.Sub);
4036 ig.Emit (OpCodes.Sizeof, element);
4038 IntLiteral.EmitInt (ig, size);
4039 ig.Emit (OpCodes.Div);
4041 ig.Emit (OpCodes.Conv_I8);
4044 // handle + and - on (pointer op int)
4046 Constant left_const = left as Constant;
4047 if (left_const != null) {
4049 // Optimize ((T*)null) pointer operations
4051 if (left_const.IsDefaultValue) {
4052 left = EmptyExpression.Null;
4060 Constant right_const = right as Constant;
4061 if (right_const != null) {
4063 // Optimize 0-based arithmetic
4065 if (right_const.IsDefaultValue)
4069 // TODO: Should be the checks resolve context sensitive?
4070 ResolveContext rc = new ResolveContext (ec.MemberContext);
4071 right = ConstantFold.BinaryFold (rc, Binary.Operator.Multiply, new IntConstant (size, right.Location).Resolve (rc), right_const, loc);
4075 ig.Emit (OpCodes.Sizeof, element);
4076 right = EmptyExpression.Null;
4081 if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
4082 rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
4083 ig.Emit (OpCodes.Conv_I);
4084 } else if (rtype == TypeManager.uint32_type) {
4085 ig.Emit (OpCodes.Conv_U);
4088 if (right_const == null && size != 1){
4090 ig.Emit (OpCodes.Sizeof, element);
4092 IntLiteral.EmitInt (ig, size);
4093 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
4094 ig.Emit (OpCodes.Conv_I8);
4096 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
4099 if (left_const == null) {
4100 if (rtype == TypeManager.int64_type)
4101 ig.Emit (OpCodes.Conv_I);
4102 else if (rtype == TypeManager.uint64_type)
4103 ig.Emit (OpCodes.Conv_U);
4105 Binary.EmitOperatorOpcode (ec, op, op_type);
4112 // A boolean-expression is an expression that yields a result
4115 public class BooleanExpression : ShimExpression
4117 public BooleanExpression (Expression expr)
4120 this.loc = expr.Location;
4123 public override Expression CreateExpressionTree (ResolveContext ec)
4125 // TODO: We should emit IsTrue (v4) instead of direct user operator
4126 // call but that would break csc compatibility
4127 return base.CreateExpressionTree (ec);
4130 protected override Expression DoResolve (ResolveContext ec)
4132 // A boolean-expression is required to be of a type
4133 // that can be implicitly converted to bool or of
4134 // a type that implements operator true
4136 expr = expr.Resolve (ec);
4140 Assign ass = expr as Assign;
4141 if (ass != null && ass.Source is Constant) {
4142 ec.Report.Warning (665, 3, loc,
4143 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
4146 if (expr.Type == TypeManager.bool_type)
4149 if (TypeManager.IsDynamicType (expr.Type)) {
4150 Arguments args = new Arguments (1);
4151 args.Add (new Argument (expr));
4152 return new DynamicUnaryConversion ("IsTrue", args, loc).Resolve (ec);
4155 type = TypeManager.bool_type;
4156 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
4157 if (converted != null)
4161 // If no implicit conversion to bool exists, try using `operator true'
4163 converted = GetOperatorTrue (ec, expr, loc);
4164 if (converted == null) {
4165 expr.Error_ValueCannotBeConverted (ec, loc, type, false);
4174 /// Implements the ternary conditional operator (?:)
4176 public class Conditional : Expression {
4177 Expression expr, true_expr, false_expr;
4179 public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
4182 this.true_expr = true_expr;
4183 this.false_expr = false_expr;
4184 this.loc = expr.Location;
4187 public Expression Expr {
4193 public Expression TrueExpr {
4199 public Expression FalseExpr {
4205 public override Expression CreateExpressionTree (ResolveContext ec)
4207 Arguments args = new Arguments (3);
4208 args.Add (new Argument (expr.CreateExpressionTree (ec)));
4209 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
4210 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
4211 return CreateExpressionFactoryCall (ec, "Condition", args);
4214 protected override Expression DoResolve (ResolveContext ec)
4216 expr = expr.Resolve (ec);
4217 true_expr = true_expr.Resolve (ec);
4218 false_expr = false_expr.Resolve (ec);
4220 if (true_expr == null || false_expr == null || expr == null)
4223 eclass = ExprClass.Value;
4224 Type true_type = true_expr.Type;
4225 Type false_type = false_expr.Type;
4229 // First, if an implicit conversion exists from true_expr
4230 // to false_expr, then the result type is of type false_expr.Type
4232 if (!TypeManager.IsEqual (true_type, false_type)) {
4233 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
4236 // Check if both can convert implicitl to each other's type
4238 if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
4239 ec.Report.Error (172, loc,
4240 "Can not compute type of conditional expression " +
4241 "as `" + TypeManager.CSharpName (true_expr.Type) +
4242 "' and `" + TypeManager.CSharpName (false_expr.Type) +
4243 "' convert implicitly to each other");
4248 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
4251 ec.Report.Error (173, loc,
4252 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
4253 TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
4258 // Dead code optimalization
4259 Constant c = expr as Constant;
4261 bool is_false = c.IsDefaultValue;
4262 ec.Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
4263 return ReducedExpression.Create (is_false ? false_expr : true_expr, this);
4269 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4271 expr.MutateHoistedGenericType (storey);
4272 true_expr.MutateHoistedGenericType (storey);
4273 false_expr.MutateHoistedGenericType (storey);
4274 type = storey.MutateType (type);
4277 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
4282 public override void Emit (EmitContext ec)
4284 ILGenerator ig = ec.ig;
4285 Label false_target = ig.DefineLabel ();
4286 Label end_target = ig.DefineLabel ();
4288 expr.EmitBranchable (ec, false_target, false);
4289 true_expr.Emit (ec);
4291 if (type.IsInterface) {
4292 LocalBuilder temp = ec.GetTemporaryLocal (type);
4293 ig.Emit (OpCodes.Stloc, temp);
4294 ig.Emit (OpCodes.Ldloc, temp);
4295 ec.FreeTemporaryLocal (temp, type);
4298 ig.Emit (OpCodes.Br, end_target);
4299 ig.MarkLabel (false_target);
4300 false_expr.Emit (ec);
4301 ig.MarkLabel (end_target);
4304 protected override void CloneTo (CloneContext clonectx, Expression t)
4306 Conditional target = (Conditional) t;
4308 target.expr = expr.Clone (clonectx);
4309 target.true_expr = true_expr.Clone (clonectx);
4310 target.false_expr = false_expr.Clone (clonectx);
4314 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
4315 LocalTemporary temp;
4318 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
4319 public abstract bool IsFixed { get; }
4320 public abstract bool IsRef { get; }
4321 public abstract string Name { get; }
4322 public abstract void SetHasAddressTaken ();
4325 // Variable IL data, it has to be protected to encapsulate hoisted variables
4327 protected abstract ILocalVariable Variable { get; }
4330 // Variable flow-analysis data
4332 public abstract VariableInfo VariableInfo { get; }
4335 public void AddressOf (EmitContext ec, AddressOp mode)
4337 HoistedVariable hv = GetHoistedVariable (ec);
4339 hv.AddressOf (ec, mode);
4343 Variable.EmitAddressOf (ec);
4346 public HoistedVariable GetHoistedVariable (ResolveContext rc)
4348 return GetHoistedVariable (rc.CurrentAnonymousMethod);
4351 public HoistedVariable GetHoistedVariable (EmitContext ec)
4353 return GetHoistedVariable (ec.CurrentAnonymousMethod);
4356 public override string GetSignatureForError ()
4361 public override void Emit (EmitContext ec)
4366 public override void EmitSideEffect (EmitContext ec)
4372 // This method is used by parameters that are references, that are
4373 // being passed as references: we only want to pass the pointer (that
4374 // is already stored in the parameter, not the address of the pointer,
4375 // and not the value of the variable).
4377 public void EmitLoad (EmitContext ec)
4382 public void Emit (EmitContext ec, bool leave_copy)
4384 Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
4386 HoistedVariable hv = GetHoistedVariable (ec);
4388 hv.Emit (ec, leave_copy);
4396 // If we are a reference, we loaded on the stack a pointer
4397 // Now lets load the real value
4399 LoadFromPtr (ec.ig, type);
4403 ec.ig.Emit (OpCodes.Dup);
4406 temp = new LocalTemporary (Type);
4412 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
4413 bool prepare_for_load)
4415 HoistedVariable hv = GetHoistedVariable (ec);
4417 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
4421 New n_source = source as New;
4422 if (n_source != null) {
4423 if (!n_source.Emit (ec, this)) {
4436 ec.ig.Emit (OpCodes.Dup);
4438 temp = new LocalTemporary (Type);
4444 StoreFromPtr (ec.ig, type);
4446 Variable.EmitAssign (ec);
4454 public bool IsHoisted {
4455 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
4458 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4460 type = storey.MutateType (type);
4467 public class LocalVariableReference : VariableReference {
4468 readonly string name;
4470 public LocalInfo local_info;
4473 public LocalVariableReference (Block block, string name, Location l)
4481 // Setting `is_readonly' to false will allow you to create a writable
4482 // reference to a read-only variable. This is used by foreach and using.
4484 public LocalVariableReference (Block block, string name, Location l,
4485 LocalInfo local_info, bool is_readonly)
4486 : this (block, name, l)
4488 this.local_info = local_info;
4489 this.is_readonly = is_readonly;
4492 public override VariableInfo VariableInfo {
4493 get { return local_info.VariableInfo; }
4496 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4498 return local_info.HoistedVariant;
4502 // A local variable is always fixed
4504 public override bool IsFixed {
4505 get { return true; }
4508 public override bool IsRef {
4509 get { return false; }
4512 public bool IsReadOnly {
4513 get { return is_readonly; }
4516 public override string Name {
4517 get { return name; }
4520 public bool VerifyAssigned (ResolveContext ec)
4522 VariableInfo variable_info = local_info.VariableInfo;
4523 return variable_info == null || variable_info.IsAssigned (ec, loc);
4526 void ResolveLocalInfo ()
4528 if (local_info == null) {
4529 local_info = Block.GetLocalInfo (Name);
4530 type = local_info.VariableType;
4531 is_readonly = local_info.ReadOnly;
4535 public override void SetHasAddressTaken ()
4537 local_info.AddressTaken = true;
4540 public override Expression CreateExpressionTree (ResolveContext ec)
4542 HoistedVariable hv = GetHoistedVariable (ec);
4544 return hv.CreateExpressionTree ();
4546 Arguments arg = new Arguments (1);
4547 arg.Add (new Argument (this));
4548 return CreateExpressionFactoryCall (ec, "Constant", arg);
4551 Expression DoResolveBase (ResolveContext ec)
4553 Expression e = Block.GetConstantExpression (Name);
4555 return e.Resolve (ec);
4557 VerifyAssigned (ec);
4560 // If we are referencing a variable from the external block
4561 // flag it for capturing
4563 if (ec.MustCaptureVariable (local_info)) {
4564 if (local_info.AddressTaken)
4565 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4567 if (ec.IsVariableCapturingRequired) {
4568 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
4569 storey.CaptureLocalVariable (ec, local_info);
4573 eclass = ExprClass.Variable;
4574 type = local_info.VariableType;
4578 protected override Expression DoResolve (ResolveContext ec)
4580 ResolveLocalInfo ();
4581 local_info.Used = true;
4583 if (type == null && local_info.Type is VarExpr) {
4584 local_info.VariableType = TypeManager.object_type;
4585 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
4589 return DoResolveBase (ec);
4592 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4594 ResolveLocalInfo ();
4597 if (right_side == EmptyExpression.OutAccess.Instance)
4598 local_info.Used = true;
4600 // Infer implicitly typed local variable
4602 VarExpr ve = local_info.Type as VarExpr;
4604 if (!ve.InferType (ec, right_side))
4606 type = local_info.VariableType = ve.Type;
4613 if (right_side == EmptyExpression.OutAccess.Instance) {
4614 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
4615 } else if (right_side == EmptyExpression.LValueMemberAccess) {
4616 code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
4617 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
4618 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
4619 } else if (right_side == EmptyExpression.UnaryAddress) {
4620 code = 459; msg = "Cannot take the address of {1} `{0}'";
4622 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
4624 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
4625 } else if (VariableInfo != null) {
4626 VariableInfo.SetAssigned (ec);
4629 return DoResolveBase (ec);
4632 public override int GetHashCode ()
4634 return Name.GetHashCode ();
4637 public override bool Equals (object obj)
4639 LocalVariableReference lvr = obj as LocalVariableReference;
4643 return Name == lvr.Name && Block == lvr.Block;
4646 protected override ILocalVariable Variable {
4647 get { return local_info; }
4650 public override string ToString ()
4652 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
4655 protected override void CloneTo (CloneContext clonectx, Expression t)
4657 LocalVariableReference target = (LocalVariableReference) t;
4659 target.Block = clonectx.LookupBlock (Block);
4660 if (local_info != null)
4661 target.local_info = clonectx.LookupVariable (local_info);
4666 /// This represents a reference to a parameter in the intermediate
4669 public class ParameterReference : VariableReference {
4670 readonly ToplevelParameterInfo pi;
4672 public ParameterReference (ToplevelParameterInfo pi, Location loc)
4678 public override bool IsRef {
4679 get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
4682 bool HasOutModifier {
4683 get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
4686 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
4688 return pi.Parameter.HoistedVariant;
4692 // A ref or out parameter is classified as a moveable variable, even
4693 // if the argument given for the parameter is a fixed variable
4695 public override bool IsFixed {
4696 get { return !IsRef; }
4699 public override string Name {
4700 get { return Parameter.Name; }
4703 public Parameter Parameter {
4704 get { return pi.Parameter; }
4707 public override VariableInfo VariableInfo {
4708 get { return pi.VariableInfo; }
4711 protected override ILocalVariable Variable {
4712 get { return Parameter; }
4715 public bool IsAssigned (ResolveContext ec, Location loc)
4717 // HACK: Variables are not captured in probing mode
4718 if (ec.IsInProbingMode)
4721 if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
4724 ec.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
4728 public override void SetHasAddressTaken ()
4730 Parameter.HasAddressTaken = true;
4733 void SetAssigned (ResolveContext ec)
4735 if (HasOutModifier && ec.DoFlowAnalysis)
4736 ec.CurrentBranching.SetAssigned (VariableInfo);
4739 bool DoResolveBase (ResolveContext ec)
4741 type = pi.ParameterType;
4742 eclass = ExprClass.Variable;
4744 AnonymousExpression am = ec.CurrentAnonymousMethod;
4748 Block b = ec.CurrentBlock;
4751 IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
4752 for (int i = 0; i < p.Length; ++i) {
4753 if (p [i] != Parameter)
4757 // Don't capture local parameters
4759 if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
4763 ec.Report.Error (1628, loc,
4764 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
4765 Name, am.ContainerType);
4768 if (pi.Parameter.HasAddressTaken)
4769 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
4771 if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
4772 AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
4773 storey.CaptureParameter (ec, this);
4785 public override int GetHashCode ()
4787 return Name.GetHashCode ();
4790 public override bool Equals (object obj)
4792 ParameterReference pr = obj as ParameterReference;
4796 return Name == pr.Name;
4799 protected override void CloneTo (CloneContext clonectx, Expression target)
4804 public override Expression CreateExpressionTree (ResolveContext ec)
4806 HoistedVariable hv = GetHoistedVariable (ec);
4808 return hv.CreateExpressionTree ();
4810 return Parameter.ExpressionTreeVariableReference ();
4814 // Notice that for ref/out parameters, the type exposed is not the
4815 // same type exposed externally.
4818 // externally we expose "int&"
4819 // here we expose "int".
4821 // We record this in "is_ref". This means that the type system can treat
4822 // the type as it is expected, but when we generate the code, we generate
4823 // the alternate kind of code.
4825 protected override Expression DoResolve (ResolveContext ec)
4827 if (!DoResolveBase (ec))
4830 // HACK: Variables are not captured in probing mode
4831 if (ec.IsInProbingMode)
4834 if (HasOutModifier && ec.DoFlowAnalysis &&
4835 (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
4841 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4843 if (!DoResolveBase (ec))
4846 // HACK: parameters are not captured when probing is on
4847 if (!ec.IsInProbingMode)
4853 static public void EmitLdArg (ILGenerator ig, int x)
4856 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4857 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4858 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4859 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4861 if (x > byte.MaxValue)
4862 ig.Emit (OpCodes.Ldarg, x);
4864 ig.Emit (OpCodes.Ldarg_S, (byte) x);
4871 /// Invocation of methods or delegates.
4873 public class Invocation : ExpressionStatement
4875 protected Arguments arguments;
4876 protected Expression expr;
4877 protected MethodGroupExpr mg;
4878 bool arguments_resolved;
4881 // arguments is an ArrayList, but we do not want to typecast,
4882 // as it might be null.
4884 public Invocation (Expression expr, Arguments arguments)
4886 SimpleName sn = expr as SimpleName;
4888 this.expr = sn.GetMethodGroup ();
4892 this.arguments = arguments;
4894 loc = expr.Location;
4897 public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
4898 : this (expr, arguments)
4900 this.arguments_resolved = arguments_resolved;
4903 public override Expression CreateExpressionTree (ResolveContext ec)
4905 Expression instance = mg.IsInstance ?
4906 mg.InstanceExpression.CreateExpressionTree (ec) :
4907 new NullLiteral (loc);
4909 var args = Arguments.CreateForExpressionTree (ec, arguments,
4911 mg.CreateExpressionTree (ec));
4914 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
4916 return CreateExpressionFactoryCall (ec, "Call", args);
4919 protected override Expression DoResolve (ResolveContext ec)
4921 Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4922 if (member_expr == null)
4926 // Next, evaluate all the expressions in the argument list
4928 bool dynamic_arg = false;
4929 if (arguments != null && !arguments_resolved)
4930 arguments.Resolve (ec, out dynamic_arg);
4932 Type expr_type = member_expr.Type;
4933 mg = member_expr as MethodGroupExpr;
4935 bool dynamic_member = TypeManager.IsDynamicType (expr_type);
4937 if (!dynamic_member) {
4938 Expression invoke = null;
4941 if (expr_type != null && TypeManager.IsDelegateType (expr_type)) {
4942 invoke = new DelegateInvocation (member_expr, arguments, loc);
4943 invoke = invoke.Resolve (ec);
4944 if (invoke == null || !dynamic_arg)
4947 MemberExpr me = member_expr as MemberExpr;
4949 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
4953 mg = ec.LookupExtensionMethod (me.Type, me.Name, loc);
4955 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
4956 member_expr.GetSignatureForError ());
4960 ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
4964 if (invoke == null) {
4965 mg = DoResolveOverload (ec);
4971 if (dynamic_arg || dynamic_member)
4972 return DoResolveDynamic (ec, member_expr);
4974 MethodInfo method = (MethodInfo)mg;
4975 if (method != null) {
4976 type = TypeManager.TypeToCoreType (method.ReturnType);
4978 // TODO: this is a copy of mg.ResolveMemberAccess method
4979 Expression iexpr = mg.InstanceExpression;
4980 if (method.IsStatic) {
4981 if (iexpr == null ||
4982 iexpr is This || iexpr is EmptyExpression ||
4983 mg.IdenticalTypeName) {
4984 mg.InstanceExpression = null;
4986 MemberExpr.error176 (ec, loc, mg.GetSignatureForError ());
4990 if (iexpr == null || iexpr == EmptyExpression.Null) {
4991 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4997 // Only base will allow this invocation to happen.
4999 if (mg.IsBase && method.IsAbstract){
5000 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
5004 if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
5006 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5008 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5012 IsSpecialMethodInvocation (ec, method, loc);
5014 if (mg.InstanceExpression != null)
5015 mg.InstanceExpression.CheckMarshalByRefAccess (ec);
5017 eclass = ExprClass.Value;
5021 Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
5024 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
5026 args = dmb.Arguments;
5027 if (arguments != null)
5028 args.AddRange (arguments);
5029 } else if (mg == null) {
5030 if (arguments == null)
5031 args = new Arguments (1);
5035 args.Insert (0, new Argument (memberExpr));
5039 ec.Report.Error (1971, loc,
5040 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
5047 if (mg.IsStatic != mg.IsInstance) {
5049 args = new Arguments (1);
5052 args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
5054 MemberAccess ma = expr as MemberAccess;
5056 args.Insert (0, new Argument (ma.Left.Resolve (ec)));
5058 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
5063 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
5066 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
5068 return mg.OverloadResolve (ec, ref arguments, false, loc);
5071 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodBase method, Location loc)
5073 if (!TypeManager.IsSpecialMethod (method))
5076 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
5079 ec.Report.SymbolRelatedToPreviousError (method);
5080 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5081 TypeManager.CSharpSignature (method, true));
5086 static Type[] GetVarargsTypes (MethodBase mb, Arguments arguments)
5088 AParametersCollection pd = TypeManager.GetParameterData (mb);
5090 Argument a = arguments [pd.Count - 1];
5091 Arglist list = (Arglist) a.Expr;
5093 return list.ArgumentTypes;
5097 /// This checks the ConditionalAttribute on the method
5099 public static bool IsMethodExcluded (MethodBase method, Location loc)
5101 if (method.IsConstructor)
5104 method = TypeManager.DropGenericMethodArguments (method);
5105 if (TypeManager.IsBeingCompiled (method)) {
5106 IMethodData md = TypeManager.GetMethod (method);
5108 return md.IsExcluded ();
5110 // For some methods (generated by delegate class) GetMethod returns null
5111 // because they are not included in builder_to_method table
5115 return AttributeTester.IsConditionalMethodExcluded (method, loc);
5119 /// is_base tells whether we want to force the use of the `call'
5120 /// opcode instead of using callvirt. Call is required to call
5121 /// a specific method, while callvirt will always use the most
5122 /// recent method in the vtable.
5124 /// is_static tells whether this is an invocation on a static method
5126 /// instance_expr is an expression that represents the instance
5127 /// it must be non-null if is_static is false.
5129 /// method is the method to invoke.
5131 /// Arguments is the list of arguments to pass to the method or constructor.
5133 public static void EmitCall (EmitContext ec, bool is_base,
5134 Expression instance_expr,
5135 MethodBase method, Arguments Arguments, Location loc)
5137 EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
5140 // `dup_args' leaves an extra copy of the arguments on the stack
5141 // `omit_args' does not leave any arguments at all.
5142 // So, basically, you could make one call with `dup_args' set to true,
5143 // and then another with `omit_args' set to true, and the two calls
5144 // would have the same set of arguments. However, each argument would
5145 // only have been evaluated once.
5146 public static void EmitCall (EmitContext ec, bool is_base,
5147 Expression instance_expr,
5148 MethodBase method, Arguments Arguments, Location loc,
5149 bool dup_args, bool omit_args)
5151 ILGenerator ig = ec.ig;
5152 bool struct_call = false;
5153 bool this_call = false;
5154 LocalTemporary this_arg = null;
5156 Type decl_type = method.DeclaringType;
5158 if (IsMethodExcluded (method, loc))
5161 bool is_static = method.IsStatic;
5163 this_call = instance_expr is This;
5164 if (TypeManager.IsStruct (decl_type) || TypeManager.IsEnumType (decl_type))
5168 // If this is ourselves, push "this"
5172 Type iexpr_type = instance_expr.Type;
5175 // Push the instance expression
5177 if (TypeManager.IsValueType (iexpr_type) || TypeManager.IsGenericParameter (iexpr_type)) {
5179 // Special case: calls to a function declared in a
5180 // reference-type with a value-type argument need
5181 // to have their value boxed.
5182 if (TypeManager.IsStruct (decl_type) ||
5183 TypeManager.IsGenericParameter (iexpr_type)) {
5185 // If the expression implements IMemoryLocation, then
5186 // we can optimize and use AddressOf on the
5189 // If not we have to use some temporary storage for
5191 if (instance_expr is IMemoryLocation) {
5192 ((IMemoryLocation)instance_expr).
5193 AddressOf (ec, AddressOp.LoadStore);
5195 LocalTemporary temp = new LocalTemporary (iexpr_type);
5196 instance_expr.Emit (ec);
5198 temp.AddressOf (ec, AddressOp.Load);
5201 // avoid the overhead of doing this all the time.
5203 t = TypeManager.GetReferenceType (iexpr_type);
5205 instance_expr.Emit (ec);
5207 // FIXME: should use instance_expr is IMemoryLocation + constraint.
5208 // to help JIT to produce better code
5209 ig.Emit (OpCodes.Box, instance_expr.Type);
5210 t = TypeManager.object_type;
5213 instance_expr.Emit (ec);
5214 t = instance_expr.Type;
5218 ig.Emit (OpCodes.Dup);
5219 if (Arguments != null && Arguments.Count != 0) {
5220 this_arg = new LocalTemporary (t);
5221 this_arg.Store (ec);
5227 if (!omit_args && Arguments != null)
5228 Arguments.Emit (ec, dup_args, this_arg);
5231 if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) {
5232 call_op = OpCodes.Call;
5234 call_op = OpCodes.Callvirt;
5236 if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5237 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5240 if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5241 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5242 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5249 // and DoFoo is not virtual, you can omit the callvirt,
5250 // because you don't need the null checking behavior.
5252 if (method is MethodInfo)
5253 ig.Emit (call_op, (MethodInfo) method);
5255 ig.Emit (call_op, (ConstructorInfo) method);
5258 public override void Emit (EmitContext ec)
5260 mg.EmitCall (ec, arguments);
5263 public override void EmitStatement (EmitContext ec)
5268 // Pop the return value if there is one
5270 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
5271 ec.ig.Emit (OpCodes.Pop);
5274 protected override void CloneTo (CloneContext clonectx, Expression t)
5276 Invocation target = (Invocation) t;
5278 if (arguments != null)
5279 target.arguments = arguments.Clone (clonectx);
5281 target.expr = expr.Clone (clonectx);
5285 public override SLE.Expression MakeExpression (BuilderContext ctx)
5287 return MakeExpression (ctx, mg.InstanceExpression, (MethodInfo) mg, arguments);
5290 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodInfo mi, Arguments args)
5292 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
5293 return SLE.Expression.Call (instance_expr, mi, Arguments.MakeExpression (args, ctx));
5297 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5299 mg.MutateHoistedGenericType (storey);
5300 type = storey.MutateType (type);
5301 if (arguments != null) {
5302 arguments.MutateHoistedGenericType (storey);
5308 /// Implements the new expression
5310 public class New : ExpressionStatement, IMemoryLocation {
5311 protected Arguments Arguments;
5314 // During bootstrap, it contains the RequestedType,
5315 // but if `type' is not null, it *might* contain a NewDelegate
5316 // (because of field multi-initialization)
5318 protected Expression RequestedType;
5320 protected MethodGroupExpr method;
5322 bool is_type_parameter;
5324 public New (Expression requested_type, Arguments arguments, Location l)
5326 RequestedType = requested_type;
5327 Arguments = arguments;
5332 /// Converts complex core type syntax like 'new int ()' to simple constant
5334 public static Constant Constantify (Type t)
5336 if (t == TypeManager.int32_type)
5337 return new IntConstant (0, Location.Null);
5338 if (t == TypeManager.uint32_type)
5339 return new UIntConstant (0, Location.Null);
5340 if (t == TypeManager.int64_type)
5341 return new LongConstant (0, Location.Null);
5342 if (t == TypeManager.uint64_type)
5343 return new ULongConstant (0, Location.Null);
5344 if (t == TypeManager.float_type)
5345 return new FloatConstant (0, Location.Null);
5346 if (t == TypeManager.double_type)
5347 return new DoubleConstant (0, Location.Null);
5348 if (t == TypeManager.short_type)
5349 return new ShortConstant (0, Location.Null);
5350 if (t == TypeManager.ushort_type)
5351 return new UShortConstant (0, Location.Null);
5352 if (t == TypeManager.sbyte_type)
5353 return new SByteConstant (0, Location.Null);
5354 if (t == TypeManager.byte_type)
5355 return new ByteConstant (0, Location.Null);
5356 if (t == TypeManager.char_type)
5357 return new CharConstant ('\0', Location.Null);
5358 if (t == TypeManager.bool_type)
5359 return new BoolConstant (false, Location.Null);
5360 if (t == TypeManager.decimal_type)
5361 return new DecimalConstant (0, Location.Null);
5362 if (TypeManager.IsEnumType (t))
5363 return new EnumConstant (Constantify (TypeManager.GetEnumUnderlyingType (t)), t);
5364 if (TypeManager.IsNullableType (t))
5365 return Nullable.LiftedNull.Create (t, Location.Null);
5371 // Checks whether the type is an interface that has the
5372 // [ComImport, CoClass] attributes and must be treated
5375 public Expression CheckComImport (ResolveContext ec)
5377 if (!type.IsInterface)
5381 // Turn the call into:
5382 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5384 Type real_class = AttributeTester.GetCoClassAttribute (type);
5385 if (real_class == null)
5388 New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5389 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5390 return cast.Resolve (ec);
5393 public override Expression CreateExpressionTree (ResolveContext ec)
5396 if (method == null) {
5397 args = new Arguments (1);
5398 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
5400 args = Arguments.CreateForExpressionTree (ec,
5402 method.CreateExpressionTree (ec));
5405 return CreateExpressionFactoryCall (ec, "New", args);
5408 protected override Expression DoResolve (ResolveContext ec)
5411 // The New DoResolve might be called twice when initializing field
5412 // expressions (see EmitFieldInitializers, the call to
5413 // GetInitializerExpression will perform a resolve on the expression,
5414 // and later the assign will trigger another resolution
5416 // This leads to bugs (#37014)
5419 if (RequestedType is NewDelegate)
5420 return RequestedType;
5424 TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5430 if (type.IsPointer) {
5431 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
5432 TypeManager.CSharpName (type));
5436 if (Arguments == null) {
5437 Constant c = Constantify (type);
5439 return ReducedExpression.Create (c.Resolve (ec), this);
5442 if (TypeManager.IsDelegateType (type)) {
5443 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5446 if (TypeManager.IsGenericParameter (type)) {
5447 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5449 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5450 ec.Report.Error (304, loc,
5451 "Cannot create an instance of the variable type '{0}' because it doesn't have the new() constraint",
5452 TypeManager.CSharpName (type));
5456 if ((Arguments != null) && (Arguments.Count != 0)) {
5457 ec.Report.Error (417, loc,
5458 "`{0}': cannot provide arguments when creating an instance of a variable type",
5459 TypeManager.CSharpName (type));
5463 if (TypeManager.activator_create_instance == null) {
5464 Type activator_type = TypeManager.CoreLookupType (ec.Compiler, "System", "Activator", Kind.Class, true);
5465 if (activator_type != null) {
5466 TypeManager.activator_create_instance = TypeManager.GetPredefinedMethod (
5467 activator_type, "CreateInstance", loc, Type.EmptyTypes);
5471 is_type_parameter = true;
5472 eclass = ExprClass.Value;
5476 if (type.IsAbstract && type.IsSealed) {
5477 ec.Report.SymbolRelatedToPreviousError (type);
5478 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5482 if (type.IsInterface || type.IsAbstract){
5483 if (!TypeManager.IsGenericType (type)) {
5484 RequestedType = CheckComImport (ec);
5485 if (RequestedType != null)
5486 return RequestedType;
5489 ec.Report.SymbolRelatedToPreviousError (type);
5490 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5494 bool is_struct = TypeManager.IsStruct (type);
5495 eclass = ExprClass.Value;
5498 // SRE returns a match for .ctor () on structs (the object constructor),
5499 // so we have to manually ignore it.
5501 if (is_struct && Arguments == null)
5504 // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5505 Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName,
5506 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5509 if (Arguments != null) {
5510 Arguments.Resolve (ec, out dynamic);
5518 method = ml as MethodGroupExpr;
5519 if (method == null) {
5520 ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
5524 method = method.OverloadResolve (ec, ref Arguments, false, loc);
5529 Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
5530 return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
5536 bool DoEmitTypeParameter (EmitContext ec)
5538 ILGenerator ig = ec.ig;
5540 MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5541 new Type [] { type });
5543 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5544 if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5545 ig.Emit (OpCodes.Call, ci);
5549 // Allow DoEmit() to be called multiple times.
5550 // We need to create a new LocalTemporary each time since
5551 // you can't share LocalBuilders among ILGeneators.
5552 LocalTemporary temp = new LocalTemporary (type);
5554 Label label_activator = ig.DefineLabel ();
5555 Label label_end = ig.DefineLabel ();
5557 temp.AddressOf (ec, AddressOp.Store);
5558 ig.Emit (OpCodes.Initobj, type);
5561 ig.Emit (OpCodes.Box, type);
5562 ig.Emit (OpCodes.Brfalse, label_activator);
5564 temp.AddressOf (ec, AddressOp.Store);
5565 ig.Emit (OpCodes.Initobj, type);
5567 ig.Emit (OpCodes.Br_S, label_end);
5569 ig.MarkLabel (label_activator);
5571 ig.Emit (OpCodes.Call, ci);
5572 ig.MarkLabel (label_end);
5577 // This Emit can be invoked in two contexts:
5578 // * As a mechanism that will leave a value on the stack (new object)
5579 // * As one that wont (init struct)
5581 // If we are dealing with a ValueType, we have a few
5582 // situations to deal with:
5584 // * The target is a ValueType, and we have been provided
5585 // the instance (this is easy, we are being assigned).
5587 // * The target of New is being passed as an argument,
5588 // to a boxing operation or a function that takes a
5591 // In this case, we need to create a temporary variable
5592 // that is the argument of New.
5594 // Returns whether a value is left on the stack
5596 // *** Implementation note ***
5598 // To benefit from this optimization, each assignable expression
5599 // has to manually cast to New and call this Emit.
5601 // TODO: It's worth to implement it for arrays and fields
5603 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
5605 bool is_value_type = TypeManager.IsValueType (type);
5606 ILGenerator ig = ec.ig;
5607 VariableReference vr = target as VariableReference;
5609 if (target != null && is_value_type && (vr != null || method == null)) {
5610 target.AddressOf (ec, AddressOp.Store);
5611 } else if (vr != null && vr.IsRef) {
5615 if (Arguments != null)
5616 Arguments.Emit (ec);
5618 if (is_value_type) {
5619 if (method == null) {
5620 ig.Emit (OpCodes.Initobj, type);
5625 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5630 if (is_type_parameter)
5631 return DoEmitTypeParameter (ec);
5633 ConstructorInfo ci = (ConstructorInfo) method;
5635 if (TypeManager.IsGenericType (type) && type.IsGenericTypeDefinition)
5636 ci = TypeBuilder.GetConstructor (type, ci);
5639 ig.Emit (OpCodes.Newobj, ci);
5643 public override void Emit (EmitContext ec)
5645 LocalTemporary v = null;
5646 if (method == null && TypeManager.IsValueType (type)) {
5647 // TODO: Use temporary variable from pool
5648 v = new LocalTemporary (type);
5655 public override void EmitStatement (EmitContext ec)
5657 LocalTemporary v = null;
5658 if (method == null && TypeManager.IsValueType (type)) {
5659 // TODO: Use temporary variable from pool
5660 v = new LocalTemporary (type);
5664 ec.ig.Emit (OpCodes.Pop);
5667 public virtual bool HasInitializer {
5673 public void AddressOf (EmitContext ec, AddressOp mode)
5675 EmitAddressOf (ec, mode);
5678 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
5680 LocalTemporary value_target = new LocalTemporary (type);
5682 if (is_type_parameter) {
5683 DoEmitTypeParameter (ec);
5684 value_target.Store (ec);
5685 value_target.AddressOf (ec, mode);
5686 return value_target;
5689 if (!TypeManager.IsStruct (type)){
5691 // We throw an exception. So far, I believe we only need to support
5693 // foreach (int j in new StructType ())
5696 throw new Exception ("AddressOf should not be used for classes");
5699 value_target.AddressOf (ec, AddressOp.Store);
5701 if (method == null) {
5702 ec.ig.Emit (OpCodes.Initobj, type);
5704 if (Arguments != null)
5705 Arguments.Emit (ec);
5707 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5710 value_target.AddressOf (ec, mode);
5711 return value_target;
5714 protected override void CloneTo (CloneContext clonectx, Expression t)
5716 New target = (New) t;
5718 target.RequestedType = RequestedType.Clone (clonectx);
5719 if (Arguments != null){
5720 target.Arguments = Arguments.Clone (clonectx);
5725 public override SLE.Expression MakeExpression (BuilderContext ctx)
5727 return SLE.Expression.New ((ConstructorInfo) method, Arguments.MakeExpression (Arguments, ctx));
5731 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5733 if (method != null) {
5734 method.MutateHoistedGenericType (storey);
5735 if (Arguments != null) {
5736 Arguments.MutateHoistedGenericType (storey);
5740 type = storey.MutateType (type);
5745 /// 14.5.10.2: Represents an array creation expression.
5749 /// There are two possible scenarios here: one is an array creation
5750 /// expression that specifies the dimensions and optionally the
5751 /// initialization data and the other which does not need dimensions
5752 /// specified but where initialization data is mandatory.
5754 public class ArrayCreation : Expression {
5755 FullNamedExpression requested_base_type;
5756 ArrayList initializers;
5759 // The list of Argument types.
5760 // This is used to construct the `newarray' or constructor signature
5762 protected ArrayList arguments;
5764 protected Type array_element_type;
5765 bool expect_initializers = false;
5766 int num_arguments = 0;
5767 protected int dimensions;
5768 protected readonly string rank;
5769 Expression first_emit;
5770 LocalTemporary first_emit_temp;
5772 protected List<Expression> array_data;
5776 // The number of constants in array initializers
5777 int const_initializers_count;
5778 bool only_constant_initializers;
5780 public ArrayCreation (FullNamedExpression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5782 this.requested_base_type = requested_base_type;
5783 this.initializers = initializers;
5787 arguments = new ArrayList (exprs.Count);
5789 foreach (Expression e in exprs) {
5795 public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayList initializers, Location l)
5797 this.requested_base_type = requested_base_type;
5798 this.initializers = initializers;
5802 //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5804 //string tmp = rank.Substring (rank.LastIndexOf ('['));
5806 //dimensions = tmp.Length - 1;
5807 expect_initializers = true;
5810 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
5812 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
5815 bool CheckIndices (ResolveContext ec, ArrayList probe, int idx, bool specified_dims, int child_bounds)
5817 if (specified_dims) {
5818 Expression a = (Expression) arguments [idx];
5823 Constant c = a as Constant;
5825 c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Location);
5829 ec.Report.Error (150, a.Location, "A constant value is expected");
5833 int value = (int) c.GetValue ();
5835 if (value != probe.Count) {
5836 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value);
5840 bounds [idx] = value;
5843 only_constant_initializers = true;
5844 for (int i = 0; i < probe.Count; ++i) {
5845 object o = probe [i];
5846 if (o is ArrayList) {
5847 ArrayList sub_probe = o as ArrayList;
5848 if (idx + 1 >= dimensions){
5849 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5853 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
5856 } else if (child_bounds > 1) {
5857 ec.Report.Error (846, ((Expression) o).Location, "A nested array initializer was expected");
5859 Expression element = ResolveArrayElement (ec, (Expression) o);
5860 if (element == null)
5863 // Initializers with the default values can be ignored
5864 Constant c = element as Constant;
5866 if (c.IsDefaultInitializer (array_element_type)) {
5870 ++const_initializers_count;
5873 only_constant_initializers = false;
5876 array_data.Add (element);
5883 public override Expression CreateExpressionTree (ResolveContext ec)
5887 if (array_data == null) {
5888 args = new Arguments (arguments.Count + 1);
5889 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5890 foreach (Expression a in arguments)
5891 args.Add (new Argument (a.CreateExpressionTree (ec)));
5893 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
5896 if (dimensions > 1) {
5897 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
5901 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
5902 args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
5903 if (array_data != null) {
5904 for (int i = 0; i < array_data.Count; ++i) {
5905 Expression e = array_data [i];
5907 e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
5909 args.Add (new Argument (e.CreateExpressionTree (ec)));
5913 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
5916 public void UpdateIndices ()
5919 for (ArrayList probe = initializers; probe != null;) {
5920 if (probe.Count > 0 && probe [0] is ArrayList) {
5921 Expression e = new IntConstant (probe.Count, Location.Null);
5924 bounds [i++] = probe.Count;
5926 probe = (ArrayList) probe [0];
5929 Expression e = new IntConstant (probe.Count, Location.Null);
5932 bounds [i++] = probe.Count;
5938 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
5940 element = element.Resolve (ec);
5941 if (element == null)
5944 if (element is CompoundAssign.TargetExpression) {
5945 if (first_emit != null)
5946 throw new InternalErrorException ("Can only handle one mutator at a time");
5947 first_emit = element;
5948 element = first_emit_temp = new LocalTemporary (element.Type);
5951 return Convert.ImplicitConversionRequired (
5952 ec, element, array_element_type, loc);
5955 protected bool ResolveInitializers (ResolveContext ec)
5957 if (initializers == null) {
5958 return !expect_initializers;
5962 // We use this to store all the date values in the order in which we
5963 // will need to store them in the byte blob later
5965 array_data = new List<Expression> ();
5966 bounds = new System.Collections.Specialized.HybridDictionary ();
5968 if (arguments != null)
5969 return CheckIndices (ec, initializers, 0, true, dimensions);
5971 arguments = new ArrayList ();
5973 if (!CheckIndices (ec, initializers, 0, false, dimensions))
5982 // Resolved the type of the array
5984 bool ResolveArrayType (ResolveContext ec)
5986 if (requested_base_type == null) {
5987 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5991 if (requested_base_type is VarExpr) {
5992 ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
5996 StringBuilder array_qualifier = new StringBuilder (rank);
5999 // `In the first form allocates an array instace of the type that results
6000 // from deleting each of the individual expression from the expression list'
6002 if (num_arguments > 0) {
6003 array_qualifier.Append ("[");
6004 for (int i = num_arguments-1; i > 0; i--)
6005 array_qualifier.Append (",");
6006 array_qualifier.Append ("]");
6012 TypeExpr array_type_expr;
6013 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6014 array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6015 if (array_type_expr == null)
6018 type = array_type_expr.Type;
6019 array_element_type = TypeManager.GetElementType (type);
6020 dimensions = type.GetArrayRank ();
6025 protected override Expression DoResolve (ResolveContext ec)
6030 if (!ResolveArrayType (ec))
6034 // First step is to validate the initializers and fill
6035 // in any missing bits
6037 if (!ResolveInitializers (ec))
6040 for (int i = 0; i < arguments.Count; ++i) {
6041 Expression e = ((Expression) arguments[i]).Resolve (ec);
6045 arguments [i] = ConvertExpressionToArrayIndex (ec, e);
6048 eclass = ExprClass.Value;
6052 MethodInfo GetArrayMethod (EmitContext ec, int arguments)
6054 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
6056 Type[] arg_types = new Type[arguments];
6057 for (int i = 0; i < arguments; i++)
6058 arg_types[i] = TypeManager.int32_type;
6060 MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6064 ec.Report.Error (-6, "New invocation: Can not find a constructor for " +
6065 "this argument list");
6072 byte [] MakeByteBlob ()
6077 int count = array_data.Count;
6079 Type element_type = array_element_type;
6080 if (TypeManager.IsEnumType (element_type))
6081 element_type = TypeManager.GetEnumUnderlyingType (element_type);
6083 factor = GetTypeSize (element_type);
6085 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
6087 data = new byte [(count * factor + 3) & ~3];
6090 for (int i = 0; i < count; ++i) {
6091 object v = array_data [i];
6093 if (v is EnumConstant)
6094 v = ((EnumConstant) v).Child;
6096 if (v is Constant && !(v is StringConstant))
6097 v = ((Constant) v).GetValue ();
6103 if (element_type == TypeManager.int64_type){
6104 if (!(v is Expression)){
6105 long val = (long) v;
6107 for (int j = 0; j < factor; ++j) {
6108 data [idx + j] = (byte) (val & 0xFF);
6112 } else if (element_type == TypeManager.uint64_type){
6113 if (!(v is Expression)){
6114 ulong val = (ulong) v;
6116 for (int j = 0; j < factor; ++j) {
6117 data [idx + j] = (byte) (val & 0xFF);
6121 } else if (element_type == TypeManager.float_type) {
6122 if (!(v is Expression)){
6123 element = BitConverter.GetBytes ((float) v);
6125 for (int j = 0; j < factor; ++j)
6126 data [idx + j] = element [j];
6127 if (!BitConverter.IsLittleEndian)
6128 System.Array.Reverse (data, idx, 4);
6130 } else if (element_type == TypeManager.double_type) {
6131 if (!(v is Expression)){
6132 element = BitConverter.GetBytes ((double) v);
6134 for (int j = 0; j < factor; ++j)
6135 data [idx + j] = element [j];
6137 // FIXME: Handle the ARM float format.
6138 if (!BitConverter.IsLittleEndian)
6139 System.Array.Reverse (data, idx, 8);
6141 } else if (element_type == TypeManager.char_type){
6142 if (!(v is Expression)){
6143 int val = (int) ((char) v);
6145 data [idx] = (byte) (val & 0xff);
6146 data [idx+1] = (byte) (val >> 8);
6148 } else if (element_type == TypeManager.short_type){
6149 if (!(v is Expression)){
6150 int val = (int) ((short) v);
6152 data [idx] = (byte) (val & 0xff);
6153 data [idx+1] = (byte) (val >> 8);
6155 } else if (element_type == TypeManager.ushort_type){
6156 if (!(v is Expression)){
6157 int val = (int) ((ushort) v);
6159 data [idx] = (byte) (val & 0xff);
6160 data [idx+1] = (byte) (val >> 8);
6162 } else if (element_type == TypeManager.int32_type) {
6163 if (!(v is Expression)){
6166 data [idx] = (byte) (val & 0xff);
6167 data [idx+1] = (byte) ((val >> 8) & 0xff);
6168 data [idx+2] = (byte) ((val >> 16) & 0xff);
6169 data [idx+3] = (byte) (val >> 24);
6171 } else if (element_type == TypeManager.uint32_type) {
6172 if (!(v is Expression)){
6173 uint val = (uint) v;
6175 data [idx] = (byte) (val & 0xff);
6176 data [idx+1] = (byte) ((val >> 8) & 0xff);
6177 data [idx+2] = (byte) ((val >> 16) & 0xff);
6178 data [idx+3] = (byte) (val >> 24);
6180 } else if (element_type == TypeManager.sbyte_type) {
6181 if (!(v is Expression)){
6182 sbyte val = (sbyte) v;
6183 data [idx] = (byte) val;
6185 } else if (element_type == TypeManager.byte_type) {
6186 if (!(v is Expression)){
6187 byte val = (byte) v;
6188 data [idx] = (byte) val;
6190 } else if (element_type == TypeManager.bool_type) {
6191 if (!(v is Expression)){
6192 bool val = (bool) v;
6193 data [idx] = (byte) (val ? 1 : 0);
6195 } else if (element_type == TypeManager.decimal_type){
6196 if (!(v is Expression)){
6197 int [] bits = Decimal.GetBits ((decimal) v);
6200 // FIXME: For some reason, this doesn't work on the MS runtime.
6201 int [] nbits = new int [4];
6202 nbits [0] = bits [3];
6203 nbits [1] = bits [2];
6204 nbits [2] = bits [0];
6205 nbits [3] = bits [1];
6207 for (int j = 0; j < 4; j++){
6208 data [p++] = (byte) (nbits [j] & 0xff);
6209 data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6210 data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6211 data [p++] = (byte) (nbits [j] >> 24);
6215 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
6225 public override SLE.Expression MakeExpression (BuilderContext ctx)
6227 var initializers = new SLE.Expression [array_data.Count];
6228 for (var i = 0; i < initializers.Length; i++) {
6229 if (array_data [i] == null)
6230 initializers [i] = SLE.Expression.Default (array_element_type);
6232 initializers [i] = array_data [i].MakeExpression (ctx);
6235 return SLE.Expression.NewArrayInit (array_element_type, initializers);
6239 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6241 array_element_type = storey.MutateType (array_element_type);
6242 type = storey.MutateType (type);
6243 if (arguments != null) {
6244 foreach (Expression e in arguments)
6245 e.MutateHoistedGenericType (storey);
6248 if (array_data != null) {
6249 foreach (Expression e in array_data) {
6250 // Don't mutate values optimized away
6254 e.MutateHoistedGenericType (storey);
6260 // Emits the initializers for the array
6262 void EmitStaticInitializers (EmitContext ec)
6264 // FIXME: This should go to Resolve !
6265 if (TypeManager.void_initializearray_array_fieldhandle == null) {
6266 TypeManager.void_initializearray_array_fieldhandle = TypeManager.GetPredefinedMethod (
6267 TypeManager.runtime_helpers_type, "InitializeArray", loc,
6268 TypeManager.array_type, TypeManager.runtime_field_handle_type);
6269 if (TypeManager.void_initializearray_array_fieldhandle == null)
6274 // First, the static data
6277 ILGenerator ig = ec.ig;
6279 byte [] data = MakeByteBlob ();
6281 fb = RootContext.MakeStaticData (data);
6283 ig.Emit (OpCodes.Dup);
6284 ig.Emit (OpCodes.Ldtoken, fb);
6285 ig.Emit (OpCodes.Call,
6286 TypeManager.void_initializearray_array_fieldhandle);
6290 // Emits pieces of the array that can not be computed at compile
6291 // time (variables and string locations).
6293 // This always expect the top value on the stack to be the array
6295 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6297 ILGenerator ig = ec.ig;
6298 int dims = bounds.Count;
6299 int [] current_pos = new int [dims];
6301 MethodInfo set = null;
6304 Type [] args = new Type [dims + 1];
6306 for (int j = 0; j < dims; j++)
6307 args [j] = TypeManager.int32_type;
6308 args [dims] = array_element_type;
6310 set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
6312 CallingConventions.HasThis | CallingConventions.Standard,
6313 TypeManager.void_type, args);
6316 for (int i = 0; i < array_data.Count; i++){
6318 Expression e = (Expression)array_data [i];
6320 // Constant can be initialized via StaticInitializer
6321 if (e != null && !(!emitConstants && e is Constant)) {
6322 Type etype = e.Type;
6324 ig.Emit (OpCodes.Dup);
6326 for (int idx = 0; idx < dims; idx++)
6327 IntConstant.EmitInt (ig, current_pos [idx]);
6330 // If we are dealing with a struct, get the
6331 // address of it, so we can store it.
6333 if ((dims == 1) && TypeManager.IsStruct (etype) &&
6334 (!TypeManager.IsBuiltinOrEnum (etype) ||
6335 etype == TypeManager.decimal_type)) {
6337 ig.Emit (OpCodes.Ldelema, etype);
6343 bool is_stobj, has_type_arg;
6344 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6346 ig.Emit (OpCodes.Stobj, etype);
6347 else if (has_type_arg)
6348 ig.Emit (op, etype);
6352 ig.Emit (OpCodes.Call, set);
6359 for (int j = dims - 1; j >= 0; j--){
6361 if (current_pos [j] < (int) bounds [j])
6363 current_pos [j] = 0;
6368 public override void Emit (EmitContext ec)
6370 ILGenerator ig = ec.ig;
6372 if (first_emit != null) {
6373 first_emit.Emit (ec);
6374 first_emit_temp.Store (ec);
6377 foreach (Expression e in arguments)
6380 if (arguments.Count == 1)
6381 ig.Emit (OpCodes.Newarr, TypeManager.TypeToReflectionType (array_element_type));
6383 ig.Emit (OpCodes.Newobj, GetArrayMethod (ec, arguments.Count));
6386 if (initializers == null)
6389 // Emit static initializer for arrays which have contain more than 2 items and
6390 // the static initializer will initialize at least 25% of array values.
6391 // NOTE: const_initializers_count does not contain default constant values.
6392 if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
6393 (TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
6394 EmitStaticInitializers (ec);
6396 if (!only_constant_initializers)
6397 EmitDynamicInitializers (ec, false);
6399 EmitDynamicInitializers (ec, true);
6402 if (first_emit_temp != null)
6403 first_emit_temp.Release (ec);
6406 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6408 if (arguments.Count != 1) {
6409 // ec.Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6410 return base.GetAttributableValue (ec, null, out value);
6413 if (array_data == null) {
6414 Expression arg = (Expression) arguments[0];
6416 if (arg.GetAttributableValue (ec, arg.Type, out arg_value) && arg_value is int && (int)arg_value == 0) {
6417 value = Array.CreateInstance (array_element_type, 0);
6421 // ec.Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6422 return base.GetAttributableValue (ec, null, out value);
6425 Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6426 object element_value;
6427 for (int i = 0; i < ret.Length; ++i)
6429 Expression e = (Expression)array_data [i];
6431 // Is null when an initializer is optimized (value == predefined value)
6435 if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
6439 ret.SetValue (element_value, i);
6445 protected override void CloneTo (CloneContext clonectx, Expression t)
6447 ArrayCreation target = (ArrayCreation) t;
6449 if (requested_base_type != null)
6450 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
6452 if (arguments != null){
6453 target.arguments = new ArrayList (arguments.Count);
6454 foreach (Expression e in arguments)
6455 target.arguments.Add (e.Clone (clonectx));
6458 if (initializers != null){
6459 target.initializers = new ArrayList (initializers.Count);
6460 foreach (object initializer in initializers)
6461 if (initializer is ArrayList) {
6462 ArrayList this_al = (ArrayList)initializer;
6463 ArrayList al = new ArrayList (this_al.Count);
6464 target.initializers.Add (al);
6465 foreach (Expression e in this_al)
6466 al.Add (e.Clone (clonectx));
6468 target.initializers.Add (((Expression)initializer).Clone (clonectx));
6475 // Represents an implicitly typed array epxression
6477 public class ImplicitlyTypedArrayCreation : ArrayCreation
6479 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6480 : base (null, rank, initializers, loc)
6482 if (rank.Length > 2) {
6483 while (rank [++dimensions] == ',');
6489 protected override Expression DoResolve (ResolveContext ec)
6494 if (!ResolveInitializers (ec))
6497 if (array_element_type == null || array_element_type == TypeManager.null_type ||
6498 array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
6499 array_element_type == InternalType.MethodGroup ||
6500 arguments.Count != dimensions) {
6501 Error_NoBestType (ec);
6506 // At this point we found common base type for all initializer elements
6507 // but we have to be sure that all static initializer elements are of
6510 UnifyInitializerElement (ec);
6512 type = TypeManager.GetConstructedType (array_element_type, rank);
6513 eclass = ExprClass.Value;
6517 void Error_NoBestType (ResolveContext ec)
6519 ec.Report.Error (826, loc,
6520 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6524 // Converts static initializer only
6526 void UnifyInitializerElement (ResolveContext ec)
6528 for (int i = 0; i < array_data.Count; ++i) {
6529 Expression e = (Expression)array_data[i];
6531 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
6535 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
6537 element = element.Resolve (ec);
6538 if (element == null)
6541 if (array_element_type == null) {
6542 if (element.Type != TypeManager.null_type)
6543 array_element_type = element.Type;
6548 if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
6552 if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
6553 array_element_type = element.Type;
6557 Error_NoBestType (ec);
6562 public sealed class CompilerGeneratedThis : This
6564 public static This Instance = new CompilerGeneratedThis ();
6566 private CompilerGeneratedThis ()
6567 : base (Location.Null)
6571 public CompilerGeneratedThis (Type type, Location loc)
6577 protected override Expression DoResolve (ResolveContext ec)
6579 eclass = ExprClass.Variable;
6581 type = ec.CurrentType;
6583 is_struct = type.IsValueType;
6587 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6594 /// Represents the `this' construct
6597 public class This : VariableReference
6599 sealed class ThisVariable : ILocalVariable
6601 public static readonly ILocalVariable Instance = new ThisVariable ();
6603 public void Emit (EmitContext ec)
6605 ec.ig.Emit (OpCodes.Ldarg_0);
6608 public void EmitAssign (EmitContext ec)
6610 throw new InvalidOperationException ();
6613 public void EmitAddressOf (EmitContext ec)
6615 ec.ig.Emit (OpCodes.Ldarg_0);
6620 VariableInfo variable_info;
6621 protected bool is_struct;
6623 public This (Block block, Location loc)
6629 public This (Location loc)
6634 public override VariableInfo VariableInfo {
6635 get { return variable_info; }
6638 public override bool IsFixed {
6639 get { return false; }
6642 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6647 AnonymousMethodStorey storey = ae.Storey;
6648 while (storey != null) {
6649 AnonymousMethodStorey temp = storey.Parent as AnonymousMethodStorey;
6651 return storey.HoistedThis;
6659 public override bool IsRef {
6660 get { return is_struct; }
6663 protected override ILocalVariable Variable {
6664 get { return ThisVariable.Instance; }
6667 public static bool IsThisAvailable (ResolveContext ec)
6669 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
6672 if (ec.CurrentAnonymousMethod == null)
6675 if (ec.CurrentType.IsValueType && ec.CurrentIterator == null)
6681 public bool ResolveBase (ResolveContext ec)
6683 eclass = ExprClass.Variable;
6684 type = ec.CurrentType;
6686 if (!IsThisAvailable (ec)) {
6687 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
6688 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6689 } else if (ec.CurrentAnonymousMethod != null) {
6690 ec.Report.Error (1673, loc,
6691 "Anonymous methods inside structs cannot access instance members of `this'. " +
6692 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
6694 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
6698 is_struct = type.IsValueType;
6700 if (block != null) {
6701 if (block.Toplevel.ThisVariable != null)
6702 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6704 AnonymousExpression am = ec.CurrentAnonymousMethod;
6705 if (am != null && ec.IsVariableCapturingRequired) {
6706 am.SetHasThisAccess ();
6714 // Called from Invocation to check if the invocation is correct
6716 public override void CheckMarshalByRefAccess (ResolveContext ec)
6718 if ((variable_info != null) && !(TypeManager.IsStruct (type) && ec.OmitStructFlowAnalysis) &&
6719 !variable_info.IsAssigned (ec)) {
6720 ec.Report.Error (188, loc,
6721 "The `this' object cannot be used before all of its fields are assigned to");
6722 variable_info.SetAssigned (ec);
6726 public override Expression CreateExpressionTree (ResolveContext ec)
6728 Arguments args = new Arguments (1);
6729 args.Add (new Argument (this));
6731 // Use typeless constant for ldarg.0 to save some
6732 // space and avoid problems with anonymous stories
6733 return CreateExpressionFactoryCall (ec, "Constant", args);
6736 protected override Expression DoResolve (ResolveContext ec)
6742 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6744 if (!ResolveBase (ec))
6747 if (variable_info != null)
6748 variable_info.SetAssigned (ec);
6750 if (ec.CurrentType.IsClass){
6751 if (right_side == EmptyExpression.UnaryAddress)
6752 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
6753 else if (right_side == EmptyExpression.OutAccess.Instance)
6754 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
6756 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
6762 public override int GetHashCode()
6764 return block.GetHashCode ();
6767 public override string Name {
6768 get { return "this"; }
6771 public override bool Equals (object obj)
6773 This t = obj as This;
6777 return block == t.block;
6780 protected override void CloneTo (CloneContext clonectx, Expression t)
6782 This target = (This) t;
6784 target.block = clonectx.LookupBlock (block);
6787 public override void SetHasAddressTaken ()
6794 /// Represents the `__arglist' construct
6796 public class ArglistAccess : Expression
6798 public ArglistAccess (Location loc)
6803 public override Expression CreateExpressionTree (ResolveContext ec)
6805 throw new NotSupportedException ("ET");
6808 protected override Expression DoResolve (ResolveContext ec)
6810 eclass = ExprClass.Variable;
6811 type = TypeManager.runtime_argument_handle_type;
6813 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
6814 ec.Report.Error (190, loc,
6815 "The __arglist construct is valid only within a variable argument method");
6821 public override void Emit (EmitContext ec)
6823 ec.ig.Emit (OpCodes.Arglist);
6826 protected override void CloneTo (CloneContext clonectx, Expression target)
6833 /// Represents the `__arglist (....)' construct
6835 class Arglist : Expression
6837 Arguments Arguments;
6839 public Arglist (Location loc)
6844 public Arglist (Arguments args, Location l)
6850 public Type[] ArgumentTypes {
6852 if (Arguments == null)
6853 return Type.EmptyTypes;
6855 Type[] retval = new Type [Arguments.Count];
6856 for (int i = 0; i < retval.Length; i++)
6857 retval [i] = Arguments [i].Expr.Type;
6863 public override Expression CreateExpressionTree (ResolveContext ec)
6865 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
6869 protected override Expression DoResolve (ResolveContext ec)
6871 eclass = ExprClass.Variable;
6872 type = InternalType.Arglist;
6873 if (Arguments != null) {
6874 bool dynamic; // Can be ignored as there is always only 1 overload
6875 Arguments.Resolve (ec, out dynamic);
6881 public override void Emit (EmitContext ec)
6883 if (Arguments != null)
6884 Arguments.Emit (ec);
6887 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6889 if (Arguments != null)
6890 Arguments.MutateHoistedGenericType (storey);
6893 protected override void CloneTo (CloneContext clonectx, Expression t)
6895 Arglist target = (Arglist) t;
6897 if (Arguments != null)
6898 target.Arguments = Arguments.Clone (clonectx);
6903 /// Implements the typeof operator
6905 public class TypeOf : Expression {
6906 Expression QueriedType;
6907 protected Type typearg;
6909 public TypeOf (Expression queried_type, Location l)
6911 QueriedType = queried_type;
6915 public override Expression CreateExpressionTree (ResolveContext ec)
6917 Arguments args = new Arguments (2);
6918 args.Add (new Argument (this));
6919 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
6920 return CreateExpressionFactoryCall (ec, "Constant", args);
6923 protected override Expression DoResolve (ResolveContext ec)
6925 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6929 typearg = texpr.Type;
6931 if (typearg == TypeManager.void_type) {
6932 ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6933 } else if (typearg.IsPointer && !ec.IsUnsafe){
6934 UnsafeError (ec, loc);
6935 } else if (texpr is DynamicTypeExpr) {
6936 ec.Report.Error (1962, QueriedType.Location,
6937 "The typeof operator cannot be used on the dynamic type");
6940 type = TypeManager.type_type;
6942 return DoResolveBase ();
6945 protected Expression DoResolveBase ()
6947 if (TypeManager.system_type_get_type_from_handle == null) {
6948 TypeManager.system_type_get_type_from_handle = TypeManager.GetPredefinedMethod (
6949 TypeManager.type_type, "GetTypeFromHandle", loc, TypeManager.runtime_handle_type);
6952 // Even though what is returned is a type object, it's treated as a value by the compiler.
6953 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6954 eclass = ExprClass.Value;
6958 public override void Emit (EmitContext ec)
6960 ec.ig.Emit (OpCodes.Ldtoken, TypeManager.TypeToReflectionType (typearg));
6961 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6964 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
6966 if (TypeManager.ContainsGenericParameters (typearg) &&
6967 !TypeManager.IsGenericTypeDefinition (typearg)) {
6968 ec.Report.SymbolRelatedToPreviousError (typearg);
6969 ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6970 TypeManager.CSharpName (typearg));
6975 if (value_type == TypeManager.object_type) {
6976 value = (object)typearg;
6983 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
6985 typearg = storey.MutateType (typearg);
6988 public Type TypeArgument {
6994 protected override void CloneTo (CloneContext clonectx, Expression t)
6996 TypeOf target = (TypeOf) t;
6997 if (QueriedType != null)
6998 target.QueriedType = QueriedType.Clone (clonectx);
7003 /// Implements the `typeof (void)' operator
7005 public class TypeOfVoid : TypeOf {
7006 public TypeOfVoid (Location l) : base (null, l)
7011 protected override Expression DoResolve (ResolveContext ec)
7013 type = TypeManager.type_type;
7014 typearg = TypeManager.void_type;
7016 return DoResolveBase ();
7020 class TypeOfMethod : TypeOfMember
7022 public TypeOfMethod (MethodBase method, Location loc)
7023 : base (method, loc)
7027 protected override Expression DoResolve (ResolveContext ec)
7029 if (member is MethodInfo) {
7030 type = TypeManager.methodinfo_type;
7032 type = TypeManager.methodinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "MethodInfo", Kind.Class, true);
7034 type = TypeManager.ctorinfo_type;
7036 type = TypeManager.ctorinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", "ConstructorInfo", Kind.Class, true);
7039 return base.DoResolve (ec);
7042 public override void Emit (EmitContext ec)
7044 if (member is ConstructorInfo)
7045 ec.ig.Emit (OpCodes.Ldtoken, (ConstructorInfo) member);
7047 ec.ig.Emit (OpCodes.Ldtoken, (MethodInfo) member);
7050 ec.ig.Emit (OpCodes.Castclass, type);
7053 protected override string GetMethodName {
7054 get { return "GetMethodFromHandle"; }
7057 protected override string RuntimeHandleName {
7058 get { return "RuntimeMethodHandle"; }
7061 protected override MethodInfo TypeFromHandle {
7063 return TypeManager.methodbase_get_type_from_handle;
7066 TypeManager.methodbase_get_type_from_handle = value;
7070 protected override MethodInfo TypeFromHandleGeneric {
7072 return TypeManager.methodbase_get_type_from_handle_generic;
7075 TypeManager.methodbase_get_type_from_handle_generic = value;
7079 protected override string TypeName {
7080 get { return "MethodBase"; }
7084 abstract class TypeOfMember : Expression
7086 protected readonly MemberInfo member;
7088 protected TypeOfMember (MemberInfo member, Location loc)
7090 this.member = member;
7094 public override Expression CreateExpressionTree (ResolveContext ec)
7096 Arguments args = new Arguments (2);
7097 args.Add (new Argument (this));
7098 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
7099 return CreateExpressionFactoryCall (ec, "Constant", args);
7102 protected override Expression DoResolve (ResolveContext ec)
7104 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7105 MethodInfo mi = is_generic ? TypeFromHandleGeneric : TypeFromHandle;
7108 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7109 Type handle_type = TypeManager.CoreLookupType (ec.Compiler, "System", RuntimeHandleName, Kind.Class, true);
7111 if (t == null || handle_type == null)
7114 mi = TypeManager.GetPredefinedMethod (t, GetMethodName, loc,
7116 new Type[] { handle_type, TypeManager.runtime_handle_type } :
7117 new Type[] { handle_type } );
7120 TypeFromHandleGeneric = mi;
7122 TypeFromHandle = mi;
7125 eclass = ExprClass.Value;
7129 public override void Emit (EmitContext ec)
7131 bool is_generic = TypeManager.IsGenericType (member.DeclaringType);
7134 mi = TypeFromHandleGeneric;
7135 ec.ig.Emit (OpCodes.Ldtoken, member.DeclaringType);
7137 mi = TypeFromHandle;
7140 ec.ig.Emit (OpCodes.Call, mi);
7143 protected abstract string GetMethodName { get; }
7144 protected abstract string RuntimeHandleName { get; }
7145 protected abstract MethodInfo TypeFromHandle { get; set; }
7146 protected abstract MethodInfo TypeFromHandleGeneric { get; set; }
7147 protected abstract string TypeName { get; }
7150 class TypeOfField : TypeOfMember
7152 public TypeOfField (FieldInfo field, Location loc)
7157 protected override Expression DoResolve (ResolveContext ec)
7159 if (TypeManager.fieldinfo_type == null)
7160 TypeManager.fieldinfo_type = TypeManager.CoreLookupType (ec.Compiler, "System.Reflection", TypeName, Kind.Class, true);
7162 type = TypeManager.fieldinfo_type;
7163 return base.DoResolve (ec);
7166 public override void Emit (EmitContext ec)
7168 ec.ig.Emit (OpCodes.Ldtoken, (FieldInfo) member);
7172 protected override string GetMethodName {
7173 get { return "GetFieldFromHandle"; }
7176 protected override string RuntimeHandleName {
7177 get { return "RuntimeFieldHandle"; }
7180 protected override MethodInfo TypeFromHandle {
7182 return TypeManager.fieldinfo_get_field_from_handle;
7185 TypeManager.fieldinfo_get_field_from_handle = value;
7189 protected override MethodInfo TypeFromHandleGeneric {
7191 return TypeManager.fieldinfo_get_field_from_handle_generic;
7194 TypeManager.fieldinfo_get_field_from_handle_generic = value;
7198 protected override string TypeName {
7199 get { return "FieldInfo"; }
7204 /// Implements the sizeof expression
7206 public class SizeOf : Expression {
7207 readonly Expression QueriedType;
7210 public SizeOf (Expression queried_type, Location l)
7212 this.QueriedType = queried_type;
7216 public override Expression CreateExpressionTree (ResolveContext ec)
7218 Error_PointerInsideExpressionTree (ec);
7222 protected override Expression DoResolve (ResolveContext ec)
7224 TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7228 type_queried = texpr.Type;
7229 if (TypeManager.IsEnumType (type_queried))
7230 type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
7232 int size_of = GetTypeSize (type_queried);
7234 return new IntConstant (size_of, loc).Resolve (ec);
7237 if (!TypeManager.VerifyUnmanaged (ec.Compiler, type_queried, loc)){
7242 ec.Report.Error (233, loc,
7243 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
7244 TypeManager.CSharpName (type_queried));
7247 type = TypeManager.int32_type;
7248 eclass = ExprClass.Value;
7252 public override void Emit (EmitContext ec)
7254 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7257 protected override void CloneTo (CloneContext clonectx, Expression t)
7263 /// Implements the qualified-alias-member (::) expression.
7265 public class QualifiedAliasMember : MemberAccess
7267 readonly string alias;
7268 public static readonly string GlobalAlias = "global";
7270 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
7271 : base (null, identifier, targs, l)
7276 public QualifiedAliasMember (string alias, string identifier, Location l)
7277 : base (null, identifier, l)
7282 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7284 if (alias == GlobalAlias) {
7285 expr = GlobalRootNamespace.Instance;
7286 return base.ResolveAsTypeStep (ec, silent);
7289 int errors = ec.Compiler.Report.Errors;
7290 expr = ec.LookupNamespaceAlias (alias);
7292 if (errors == ec.Compiler.Report.Errors)
7293 ec.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
7297 FullNamedExpression fne = base.ResolveAsTypeStep (ec, silent);
7301 if (expr.eclass == ExprClass.Type) {
7303 ec.Compiler.Report.Error (431, loc,
7304 "Alias `{0}' cannot be used with '::' since it denotes a type. Consider replacing '::' with '.'", alias);
7312 protected override Expression DoResolve (ResolveContext ec)
7314 return ResolveAsTypeStep (ec, false);
7317 protected override void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7319 rc.Compiler.Report.Error (687, loc,
7320 "A namespace alias qualifier `{0}' did not resolve to a namespace or a type",
7321 GetSignatureForError ());
7324 public override string GetSignatureForError ()
7327 if (targs != null) {
7328 name = TypeManager.RemoveGenericArity (Name) + "<" +
7329 targs.GetSignatureForError () + ">";
7332 return alias + "::" + name;
7335 protected override void CloneTo (CloneContext clonectx, Expression t)
7342 /// Implements the member access expression
7344 public class MemberAccess : ATypeNameExpression {
7345 protected Expression expr;
7347 public MemberAccess (Expression expr, string id)
7348 : base (id, expr.Location)
7353 public MemberAccess (Expression expr, string identifier, Location loc)
7354 : base (identifier, loc)
7359 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7360 : base (identifier, args, loc)
7365 Expression DoResolve (ResolveContext ec, Expression right_side)
7368 throw new Exception ();
7371 // Resolve the expression with flow analysis turned off, we'll do the definite
7372 // assignment checks later. This is because we don't know yet what the expression
7373 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7374 // definite assignment check on the actual field and not on the whole struct.
7377 SimpleName original = expr as SimpleName;
7378 Expression expr_resolved;
7379 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
7380 expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.Intermediate);
7383 if (expr_resolved == null)
7386 string LookupIdentifier = MemberName.MakeName (Name, targs);
7388 Namespace ns = expr_resolved as Namespace;
7390 FullNamedExpression retval = ns.Lookup (ec.Compiler, LookupIdentifier, loc);
7393 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, ec);
7394 else if (targs != null)
7395 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
7400 Type expr_type = expr_resolved.Type;
7401 if (TypeManager.IsDynamicType (expr_type)) {
7402 Arguments args = new Arguments (1);
7403 args.Add (new Argument (expr_resolved.Resolve (ec)));
7404 expr = new DynamicMemberBinder (Name, args, loc);
7405 if (right_side != null)
7406 return expr.DoResolveLValue (ec, right_side);
7408 return expr.Resolve (ec);
7411 if (expr_type.IsPointer || expr_type == TypeManager.void_type ||
7412 expr_type == TypeManager.null_type || expr_type == InternalType.AnonymousMethod) {
7413 Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
7417 Constant c = expr_resolved as Constant;
7418 if (c != null && c.GetValue () == null) {
7419 ec.Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7420 "System.NullReferenceException");
7423 if (targs != null) {
7424 if (!targs.Resolve (ec))
7428 Expression member_lookup;
7429 member_lookup = MemberLookup (ec.Compiler,
7430 ec.CurrentType, expr_type, expr_type, Name, loc);
7432 if (member_lookup == null && targs != null) {
7433 member_lookup = MemberLookup (ec.Compiler,
7434 ec.CurrentType, expr_type, expr_type, LookupIdentifier, loc);
7437 if (member_lookup == null) {
7438 ExprClass expr_eclass = expr_resolved.eclass;
7441 // Extension methods are not allowed on all expression types
7443 if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
7444 expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
7445 expr_eclass == ExprClass.EventAccess) {
7446 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
7447 if (ex_method_lookup != null) {
7448 ex_method_lookup.ExtensionExpression = expr_resolved;
7450 if (targs != null) {
7451 ex_method_lookup.SetTypeArguments (ec, targs);
7454 return ex_method_lookup.Resolve (ec);
7458 expr = expr_resolved;
7459 member_lookup = Error_MemberLookupFailed (ec,
7460 ec.CurrentType, expr_type, expr_type, Name, null,
7461 AllMemberTypes, AllBindingFlags);
7462 if (member_lookup == null)
7466 TypeExpr texpr = member_lookup as TypeExpr;
7467 if (texpr != null) {
7468 if (!(expr_resolved is TypeExpr) &&
7469 (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
7470 ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7471 Name, member_lookup.GetSignatureForError ());
7475 if (!texpr.CheckAccessLevel (ec.MemberContext)) {
7476 ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
7477 ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
7481 GenericTypeExpr ct = expr_resolved as GenericTypeExpr;
7484 // When looking up a nested type in a generic instance
7485 // via reflection, we always get a generic type definition
7486 // and not a generic instance - so we have to do this here.
7488 // See gtest-172-lib.cs and gtest-172.cs for an example.
7491 TypeArguments nested_targs;
7492 if (HasTypeArguments) {
7493 nested_targs = ct.TypeArguments.Clone ();
7494 nested_targs.Add (targs);
7496 nested_targs = ct.TypeArguments;
7499 ct = new GenericTypeExpr (member_lookup.Type, nested_targs, loc);
7501 return ct.ResolveAsTypeStep (ec, false);
7504 return member_lookup;
7507 MemberExpr me = (MemberExpr) member_lookup;
7508 me = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
7512 if (targs != null) {
7513 me.SetTypeArguments (ec, targs);
7516 if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
7517 if (me.IsInstance) {
7518 LocalVariableReference var = expr_resolved as LocalVariableReference;
7519 if (var != null && !var.VerifyAssigned (ec))
7524 // The following DoResolve/DoResolveLValue will do the definite assignment
7527 if (right_side != null)
7528 return me.DoResolveLValue (ec, right_side);
7530 return me.Resolve (ec);
7533 protected override Expression DoResolve (ResolveContext ec)
7535 return DoResolve (ec, null);
7538 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7540 return DoResolve (ec, right_side);
7543 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
7545 return ResolveNamespaceOrType (ec, silent);
7548 public FullNamedExpression ResolveNamespaceOrType (IMemberContext rc, bool silent)
7550 FullNamedExpression expr_resolved = expr.ResolveAsTypeStep (rc, silent);
7552 if (expr_resolved == null)
7555 string LookupIdentifier = MemberName.MakeName (Name, targs);
7557 Namespace ns = expr_resolved as Namespace;
7559 FullNamedExpression retval = ns.Lookup (rc.Compiler, LookupIdentifier, loc);
7561 if (retval == null && !silent)
7562 ns.Error_NamespaceDoesNotExist (loc, LookupIdentifier, rc);
7563 else if (targs != null)
7564 retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (rc, silent);
7569 TypeExpr tnew_expr = expr_resolved.ResolveAsTypeTerminal (rc, false);
7570 if (tnew_expr == null)
7573 Type expr_type = tnew_expr.Type;
7574 if (TypeManager.IsGenericParameter (expr_type)) {
7575 rc.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
7576 tnew_expr.GetSignatureForError ());
7580 Expression member_lookup = MemberLookup (rc.Compiler,
7581 rc.CurrentType, expr_type, expr_type, LookupIdentifier,
7582 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7583 if (member_lookup == null) {
7587 Error_IdentifierNotFound (rc, expr_resolved, LookupIdentifier);
7591 TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7595 TypeArguments the_args = targs;
7596 Type declaring_type = texpr.Type.DeclaringType;
7597 if (TypeManager.HasGenericArguments (declaring_type) && !TypeManager.IsGenericTypeDefinition (expr_type)) {
7598 while (!TypeManager.IsEqual (TypeManager.DropGenericTypeArguments (expr_type), declaring_type)) {
7599 expr_type = expr_type.BaseType;
7602 TypeArguments new_args = new TypeArguments ();
7603 foreach (Type decl in TypeManager.GetTypeArguments (expr_type))
7604 new_args.Add (new TypeExpression (TypeManager.TypeToCoreType (decl), loc));
7607 new_args.Add (targs);
7609 the_args = new_args;
7612 if (the_args != null) {
7613 GenericTypeExpr ctype = new GenericTypeExpr (texpr.Type, the_args, loc);
7614 return ctype.ResolveAsTypeStep (rc, false);
7620 protected virtual void Error_IdentifierNotFound (IMemberContext rc, FullNamedExpression expr_type, string identifier)
7622 Expression member_lookup = MemberLookup (rc.Compiler,
7623 rc.CurrentType, expr_type.Type, expr_type.Type, SimpleName.RemoveGenericArity (identifier),
7624 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7626 if (member_lookup != null) {
7627 expr_type = member_lookup.ResolveAsTypeTerminal (rc, false);
7628 if (expr_type == null)
7631 expr_type.Error_TypeArgumentsCannotBeUsed (rc.Compiler.Report, loc);
7635 member_lookup = MemberLookup (rc.Compiler,
7636 rc.CurrentType, expr_type.Type, expr_type.Type, identifier,
7637 MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7639 if (member_lookup == null) {
7640 rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7641 Name, expr_type.GetSignatureForError ());
7643 // TODO: Report.SymbolRelatedToPreviousError
7644 member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
7648 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
7650 if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
7651 ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
7652 ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
7653 "extension method `{1}' of type `{0}' could be found " +
7654 "(are you missing a using directive or an assembly reference?)",
7655 TypeManager.CSharpName (type), name);
7659 base.Error_TypeDoesNotContainDefinition (ec, type, name);
7662 public override string GetSignatureForError ()
7664 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
7667 public Expression Left {
7673 protected override void CloneTo (CloneContext clonectx, Expression t)
7675 MemberAccess target = (MemberAccess) t;
7677 target.expr = expr.Clone (clonectx);
7682 /// Implements checked expressions
7684 public class CheckedExpr : Expression {
7686 public Expression Expr;
7688 public CheckedExpr (Expression e, Location l)
7694 public override Expression CreateExpressionTree (ResolveContext ec)
7696 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7697 return Expr.CreateExpressionTree (ec);
7700 protected override Expression DoResolve (ResolveContext ec)
7702 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
7703 Expr = Expr.Resolve (ec);
7708 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7711 eclass = Expr.eclass;
7716 public override void Emit (EmitContext ec)
7718 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7722 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7724 using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
7725 Expr.EmitBranchable (ec, target, on_true);
7729 public override SLE.Expression MakeExpression (BuilderContext ctx)
7731 using (ctx.With (BuilderContext.Options.AllCheckStateFlags, true)) {
7732 return Expr.MakeExpression (ctx);
7737 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7739 Expr.MutateHoistedGenericType (storey);
7742 protected override void CloneTo (CloneContext clonectx, Expression t)
7744 CheckedExpr target = (CheckedExpr) t;
7746 target.Expr = Expr.Clone (clonectx);
7751 /// Implements the unchecked expression
7753 public class UnCheckedExpr : Expression {
7755 public Expression Expr;
7757 public UnCheckedExpr (Expression e, Location l)
7763 public override Expression CreateExpressionTree (ResolveContext ec)
7765 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7766 return Expr.CreateExpressionTree (ec);
7769 protected override Expression DoResolve (ResolveContext ec)
7771 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
7772 Expr = Expr.Resolve (ec);
7777 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
7780 eclass = Expr.eclass;
7785 public override void Emit (EmitContext ec)
7787 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7791 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
7793 using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
7794 Expr.EmitBranchable (ec, target, on_true);
7797 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
7799 Expr.MutateHoistedGenericType (storey);
7802 protected override void CloneTo (CloneContext clonectx, Expression t)
7804 UnCheckedExpr target = (UnCheckedExpr) t;
7806 target.Expr = Expr.Clone (clonectx);
7811 /// An Element Access expression.
7813 /// During semantic analysis these are transformed into
7814 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
7816 public class ElementAccess : Expression {
7817 public Arguments Arguments;
7818 public Expression Expr;
7820 public ElementAccess (Expression e, Arguments args)
7824 this.Arguments = args;
7827 public override Expression CreateExpressionTree (ResolveContext ec)
7829 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
7830 Expr.CreateExpressionTree (ec));
7832 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
7835 Expression MakePointerAccess (ResolveContext ec, Type t)
7837 if (Arguments.Count != 1){
7838 ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
7842 if (Arguments [0] is NamedArgument)
7843 Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
7845 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
7846 return new Indirection (p, loc).Resolve (ec);
7849 protected override Expression DoResolve (ResolveContext ec)
7851 Expr = Expr.Resolve (ec);
7856 // We perform some simple tests, and then to "split" the emit and store
7857 // code we create an instance of a different class, and return that.
7859 // I am experimenting with this pattern.
7863 if (t == TypeManager.array_type){
7864 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7869 return (new ArrayAccess (this, loc)).Resolve (ec);
7871 return MakePointerAccess (ec, t);
7873 FieldExpr fe = Expr as FieldExpr;
7875 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7877 return MakePointerAccess (ec, ff.ElementType);
7880 return (new IndexerAccess (this, loc)).Resolve (ec);
7883 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7885 Expr = Expr.Resolve (ec);
7891 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7894 return MakePointerAccess (ec, type);
7896 if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
7897 Error_CannotModifyIntermediateExpressionValue (ec);
7899 return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7902 public override void Emit (EmitContext ec)
7904 throw new Exception ("Should never be reached");
7907 public static void Error_NamedArgument (NamedArgument na, Report Report)
7909 Report.Error (1742, na.Name.Location, "An element access expression cannot use named argument");
7912 public override string GetSignatureForError ()
7914 return Expr.GetSignatureForError ();
7917 protected override void CloneTo (CloneContext clonectx, Expression t)
7919 ElementAccess target = (ElementAccess) t;
7921 target.Expr = Expr.Clone (clonectx);
7922 if (Arguments != null)
7923 target.Arguments = Arguments.Clone (clonectx);
7928 /// Implements array access
7930 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
7932 // Points to our "data" repository
7936 LocalTemporary temp;
7940 public ArrayAccess (ElementAccess ea_data, Location l)
7946 public override Expression CreateExpressionTree (ResolveContext ec)
7948 return ea.CreateExpressionTree (ec);
7951 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7953 return DoResolve (ec);
7956 protected override Expression DoResolve (ResolveContext ec)
7958 // dynamic is used per argument in ConvertExpressionToArrayIndex case
7960 ea.Arguments.Resolve (ec, out dynamic);
7962 Type t = ea.Expr.Type;
7963 int rank = ea.Arguments.Count;
7964 if (t.GetArrayRank () != rank) {
7965 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7966 ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7970 type = TypeManager.GetElementType (t);
7971 if (type.IsPointer && !ec.IsUnsafe) {
7972 UnsafeError (ec, ea.Location);
7975 foreach (Argument a in ea.Arguments) {
7976 if (a is NamedArgument)
7977 ElementAccess.Error_NamedArgument ((NamedArgument) a, ec.Report);
7979 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
7982 eclass = ExprClass.Variable;
7988 /// Emits the right opcode to load an object of Type `t'
7989 /// from an array of T
7991 void EmitLoadOpcode (ILGenerator ig, Type type, int rank)
7994 MethodInfo get = FetchGetMethod ();
7995 ig.Emit (OpCodes.Call, get);
7999 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
8000 ig.Emit (OpCodes.Ldelem_U1);
8001 else if (type == TypeManager.sbyte_type)
8002 ig.Emit (OpCodes.Ldelem_I1);
8003 else if (type == TypeManager.short_type)
8004 ig.Emit (OpCodes.Ldelem_I2);
8005 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
8006 ig.Emit (OpCodes.Ldelem_U2);
8007 else if (type == TypeManager.int32_type)
8008 ig.Emit (OpCodes.Ldelem_I4);
8009 else if (type == TypeManager.uint32_type)
8010 ig.Emit (OpCodes.Ldelem_U4);
8011 else if (type == TypeManager.uint64_type)
8012 ig.Emit (OpCodes.Ldelem_I8);
8013 else if (type == TypeManager.int64_type)
8014 ig.Emit (OpCodes.Ldelem_I8);
8015 else if (type == TypeManager.float_type)
8016 ig.Emit (OpCodes.Ldelem_R4);
8017 else if (type == TypeManager.double_type)
8018 ig.Emit (OpCodes.Ldelem_R8);
8019 else if (type == TypeManager.intptr_type)
8020 ig.Emit (OpCodes.Ldelem_I);
8021 else if (TypeManager.IsEnumType (type)){
8022 EmitLoadOpcode (ig, TypeManager.GetEnumUnderlyingType (type), rank);
8023 } else if (TypeManager.IsStruct (type)){
8024 ig.Emit (OpCodes.Ldelema, type);
8025 ig.Emit (OpCodes.Ldobj, type);
8026 } else if (type.IsGenericParameter) {
8027 ig.Emit (OpCodes.Ldelem, type);
8028 } else if (type.IsPointer)
8029 ig.Emit (OpCodes.Ldelem_I);
8031 ig.Emit (OpCodes.Ldelem_Ref);
8034 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8036 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
8040 /// Returns the right opcode to store an object of Type `t'
8041 /// from an array of T.
8043 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
8045 has_type_arg = false; is_stobj = false;
8046 t = TypeManager.TypeToCoreType (t);
8047 if (TypeManager.IsEnumType (t))
8048 t = TypeManager.GetEnumUnderlyingType (t);
8049 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
8050 t == TypeManager.bool_type)
8051 return OpCodes.Stelem_I1;
8052 else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
8053 t == TypeManager.char_type)
8054 return OpCodes.Stelem_I2;
8055 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
8056 return OpCodes.Stelem_I4;
8057 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
8058 return OpCodes.Stelem_I8;
8059 else if (t == TypeManager.float_type)
8060 return OpCodes.Stelem_R4;
8061 else if (t == TypeManager.double_type)
8062 return OpCodes.Stelem_R8;
8063 else if (t == TypeManager.intptr_type) {
8064 has_type_arg = true;
8066 return OpCodes.Stobj;
8067 } else if (TypeManager.IsStruct (t)) {
8068 has_type_arg = true;
8070 return OpCodes.Stobj;
8071 } else if (t.IsGenericParameter) {
8072 has_type_arg = true;
8073 return OpCodes.Stelem;
8074 } else if (t.IsPointer)
8075 return OpCodes.Stelem_I;
8077 return OpCodes.Stelem_Ref;
8080 MethodInfo FetchGetMethod ()
8082 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8083 int arg_count = ea.Arguments.Count;
8084 Type [] args = new Type [arg_count];
8087 for (int i = 0; i < arg_count; i++){
8088 //args [i++] = a.Type;
8089 args [i] = TypeManager.int32_type;
8092 get = mb.GetArrayMethod (
8093 ea.Expr.Type, "Get",
8094 CallingConventions.HasThis |
8095 CallingConventions.Standard,
8101 MethodInfo FetchAddressMethod ()
8103 ModuleBuilder mb = RootContext.ToplevelTypes.Builder;
8104 int arg_count = ea.Arguments.Count;
8105 Type [] args = new Type [arg_count];
8109 ret_type = TypeManager.GetReferenceType (type);
8111 for (int i = 0; i < arg_count; i++){
8112 //args [i++] = a.Type;
8113 args [i] = TypeManager.int32_type;
8116 address = mb.GetArrayMethod (
8117 ea.Expr.Type, "Address",
8118 CallingConventions.HasThis |
8119 CallingConventions.Standard,
8126 // Load the array arguments into the stack.
8128 void LoadArrayAndArguments (EmitContext ec)
8132 for (int i = 0; i < ea.Arguments.Count; ++i) {
8133 ea.Arguments [i].Emit (ec);
8137 public void Emit (EmitContext ec, bool leave_copy)
8139 int rank = ea.Expr.Type.GetArrayRank ();
8140 ILGenerator ig = ec.ig;
8143 LoadFromPtr (ig, this.type);
8145 LoadArrayAndArguments (ec);
8146 EmitLoadOpcode (ig, type, rank);
8150 ig.Emit (OpCodes.Dup);
8151 temp = new LocalTemporary (this.type);
8156 public override void Emit (EmitContext ec)
8161 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8163 int rank = ea.Expr.Type.GetArrayRank ();
8164 ILGenerator ig = ec.ig;
8165 Type t = source.Type;
8166 prepared = prepare_for_load;
8169 AddressOf (ec, AddressOp.LoadStore);
8170 ec.ig.Emit (OpCodes.Dup);
8172 LoadArrayAndArguments (ec);
8176 bool is_stobj, has_type_arg;
8177 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
8181 // The stobj opcode used by value types will need
8182 // an address on the stack, not really an array/array
8186 ig.Emit (OpCodes.Ldelema, t);
8191 ec.ig.Emit (OpCodes.Dup);
8192 temp = new LocalTemporary (this.type);
8197 StoreFromPtr (ig, t);
8199 ig.Emit (OpCodes.Stobj, t);
8200 else if (has_type_arg)
8207 ec.ig.Emit (OpCodes.Dup);
8208 temp = new LocalTemporary (this.type);
8213 StoreFromPtr (ig, t);
8215 int arg_count = ea.Arguments.Count;
8216 Type [] args = new Type [arg_count + 1];
8217 for (int i = 0; i < arg_count; i++) {
8218 //args [i++] = a.Type;
8219 args [i] = TypeManager.int32_type;
8221 args [arg_count] = type;
8223 MethodInfo set = RootContext.ToplevelTypes.Builder.GetArrayMethod (
8224 ea.Expr.Type, "Set",
8225 CallingConventions.HasThis |
8226 CallingConventions.Standard,
8227 TypeManager.void_type, args);
8229 ig.Emit (OpCodes.Call, set);
8239 public void EmitNew (EmitContext ec, New source, bool leave_copy)
8241 if (!source.Emit (ec, this)) {
8243 throw new NotImplementedException ();
8248 throw new NotImplementedException ();
8251 public void AddressOf (EmitContext ec, AddressOp mode)
8253 int rank = ea.Expr.Type.GetArrayRank ();
8254 ILGenerator ig = ec.ig;
8256 LoadArrayAndArguments (ec);
8259 ig.Emit (OpCodes.Ldelema, type);
8261 MethodInfo address = FetchAddressMethod ();
8262 ig.Emit (OpCodes.Call, address);
8267 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8269 return SLE.Expression.ArrayAccess (
8270 ea.Expr.MakeExpression (ctx),
8271 Arguments.MakeExpression (ea.Arguments, ctx));
8274 public override SLE.Expression MakeExpression (BuilderContext ctx)
8276 return SLE.Expression.ArrayIndex (
8277 ea.Expr.MakeExpression (ctx),
8278 Arguments.MakeExpression (ea.Arguments, ctx));
8282 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8284 type = storey.MutateType (type);
8285 ea.Expr.Type = storey.MutateType (ea.Expr.Type);
8290 /// Expressions that represent an indexer call.
8292 public class IndexerAccess : Expression, IDynamicAssign
8294 class IndexerMethodGroupExpr : MethodGroupExpr
8296 public IndexerMethodGroupExpr (Indexers indexers, Location loc)
8299 Methods = (MethodBase []) indexers.Methods.ToArray (typeof (MethodBase));
8302 public override string Name {
8308 protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
8311 // Here is the trick, decrease number of arguments by 1 when only
8312 // available property method is setter. This makes overload resolution
8313 // work correctly for indexers.
8316 if (method.Name [0] == 'g')
8317 return parameters.Count;
8319 return parameters.Count - 1;
8325 // Contains either property getter or setter
8326 public ArrayList Methods;
8327 public ArrayList Properties;
8333 void Append (Type caller_type, MemberInfo [] mi)
8338 foreach (PropertyInfo property in mi) {
8339 MethodInfo accessor = property.GetGetMethod (true);
8340 if (accessor == null)
8341 accessor = property.GetSetMethod (true);
8343 if (Methods == null) {
8344 Methods = new ArrayList ();
8345 Properties = new ArrayList ();
8348 Methods.Add (accessor);
8349 Properties.Add (property);
8353 static MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8355 string p_name = TypeManager.IndexerPropertyName (lookup_type);
8357 return TypeManager.MemberLookup (
8358 caller_type, caller_type, lookup_type, MemberTypes.Property,
8359 BindingFlags.Public | BindingFlags.Instance |
8360 BindingFlags.DeclaredOnly, p_name, null);
8363 public static Indexers GetIndexersForType (Type caller_type, Type lookup_type)
8365 Indexers ix = new Indexers ();
8367 if (TypeManager.IsGenericParameter (lookup_type)) {
8368 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8372 if (gc.HasClassConstraint) {
8373 Type class_contraint = gc.ClassConstraint;
8374 while (class_contraint != TypeManager.object_type && class_contraint != null) {
8375 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, class_contraint));
8376 class_contraint = class_contraint.BaseType;
8380 Type[] ifaces = gc.InterfaceConstraints;
8381 foreach (Type itype in ifaces)
8382 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8387 Type copy = lookup_type;
8388 while (copy != TypeManager.object_type && copy != null){
8389 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8390 copy = copy.BaseType;
8393 if (lookup_type.IsInterface) {
8394 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8395 if (ifaces != null) {
8396 foreach (Type itype in ifaces)
8397 ix.Append (caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8406 // Points to our "data" repository
8408 MethodInfo get, set;
8409 bool is_base_indexer;
8411 LocalTemporary temp;
8412 LocalTemporary prepared_value;
8413 Expression set_expr;
8415 protected Type indexer_type;
8416 protected Type current_type;
8417 protected Expression instance_expr;
8418 protected Arguments arguments;
8420 public IndexerAccess (ElementAccess ea, Location loc)
8421 : this (ea.Expr, false, loc)
8423 this.arguments = ea.Arguments;
8426 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8429 this.instance_expr = instance_expr;
8430 this.is_base_indexer = is_base_indexer;
8434 static string GetAccessorName (bool isSet)
8436 return isSet ? "set" : "get";
8439 public override Expression CreateExpressionTree (ResolveContext ec)
8441 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
8442 instance_expr.CreateExpressionTree (ec),
8443 new TypeOfMethod (get, loc));
8445 return CreateExpressionFactoryCall (ec, "Call", args);
8448 protected virtual void CommonResolve (ResolveContext ec)
8450 indexer_type = instance_expr.Type;
8451 current_type = ec.CurrentType;
8454 protected override Expression DoResolve (ResolveContext ec)
8456 return ResolveAccessor (ec, null);
8459 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8461 if (right_side == EmptyExpression.OutAccess.Instance) {
8462 right_side.DoResolveLValue (ec, this);
8466 // if the indexer returns a value type, and we try to set a field in it
8467 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8468 Error_CannotModifyIntermediateExpressionValue (ec);
8471 return ResolveAccessor (ec, right_side);
8474 Expression ResolveAccessor (ResolveContext ec, Expression right_side)
8482 arguments.Resolve (ec, out dynamic);
8484 if (TypeManager.IsDynamicType (indexer_type)) {
8489 ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8490 if (ilist.Methods == null) {
8491 ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8492 TypeManager.CSharpName (indexer_type));
8496 mg = new IndexerMethodGroupExpr (ilist, loc);
8497 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
8503 Arguments args = new Arguments (arguments.Count + 1);
8504 if (is_base_indexer) {
8505 ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
8507 args.Add (new Argument (instance_expr));
8509 args.AddRange (arguments);
8511 var expr = new DynamicIndexBinder (args, loc);
8512 if (right_side != null)
8513 return expr.ResolveLValue (ec, right_side);
8515 return expr.Resolve (ec);
8518 MethodInfo mi = (MethodInfo) mg;
8519 PropertyInfo pi = null;
8520 for (int i = 0; i < ilist.Methods.Count; ++i) {
8521 if (ilist.Methods [i] == mi) {
8522 pi = (PropertyInfo) ilist.Properties [i];
8527 type = TypeManager.TypeToCoreType (pi.PropertyType);
8528 if (type.IsPointer && !ec.IsUnsafe)
8529 UnsafeError (ec, loc);
8531 MethodInfo accessor;
8532 if (right_side == null) {
8533 accessor = get = pi.GetGetMethod (true);
8535 accessor = set = pi.GetSetMethod (true);
8536 if (accessor == null && pi.GetGetMethod (true) != null) {
8537 ec.Report.SymbolRelatedToPreviousError (pi);
8538 ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
8539 TypeManager.GetFullNameSignature (pi));
8543 set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
8546 if (accessor == null) {
8547 ec.Report.SymbolRelatedToPreviousError (pi);
8548 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
8549 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8554 // Only base will allow this invocation to happen.
8556 if (accessor.IsAbstract && this is BaseIndexerAccess) {
8557 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (pi));
8560 bool must_do_cs1540_check;
8561 if (!IsAccessorAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
8563 set = pi.GetSetMethod (true);
8565 get = pi.GetGetMethod (true);
8567 if (set != null && get != null &&
8568 (set.Attributes & MethodAttributes.MemberAccessMask) != (get.Attributes & MethodAttributes.MemberAccessMask)) {
8569 ec.Report.SymbolRelatedToPreviousError (accessor);
8570 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
8571 TypeManager.GetFullNameSignature (pi), GetAccessorName (right_side != null));
8573 ec.Report.SymbolRelatedToPreviousError (pi);
8574 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (pi), ec.Report);
8578 instance_expr.CheckMarshalByRefAccess (ec);
8579 eclass = ExprClass.IndexerAccess;
8583 public override void Emit (EmitContext ec)
8588 public void Emit (EmitContext ec, bool leave_copy)
8591 prepared_value.Emit (ec);
8593 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8594 arguments, loc, false, false);
8598 ec.ig.Emit (OpCodes.Dup);
8599 temp = new LocalTemporary (Type);
8605 // source is ignored, because we already have a copy of it from the
8606 // LValue resolution and we have already constructed a pre-cached
8607 // version of the arguments (ea.set_arguments);
8609 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8611 prepared = prepare_for_load;
8612 Expression value = set_expr;
8615 Invocation.EmitCall (ec, is_base_indexer, instance_expr, get,
8616 arguments, loc, true, false);
8618 prepared_value = new LocalTemporary (type);
8619 prepared_value.Store (ec);
8621 prepared_value.Release (ec);
8624 ec.ig.Emit (OpCodes.Dup);
8625 temp = new LocalTemporary (Type);
8628 } else if (leave_copy) {
8629 temp = new LocalTemporary (Type);
8636 arguments.Add (new Argument (value));
8638 Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, arguments, loc, false, prepared);
8646 public override string GetSignatureForError ()
8648 return TypeManager.CSharpSignature (get != null ? get : set, false);
8652 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
8654 var value = new[] { set_expr.MakeExpression (ctx) };
8655 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
8657 return SLE.Expression.Block (
8658 SLE.Expression.Call (instance_expr.MakeExpression (ctx), set, args),
8662 public override SLE.Expression MakeExpression (BuilderContext ctx)
8664 var args = Arguments.MakeExpression (arguments, ctx);
8665 return SLE.Expression.Call (instance_expr.MakeExpression (ctx), get, args);
8669 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
8672 get = storey.MutateGenericMethod (get);
8674 set = storey.MutateGenericMethod (set);
8676 instance_expr.MutateHoistedGenericType (storey);
8677 if (arguments != null)
8678 arguments.MutateHoistedGenericType (storey);
8680 type = storey.MutateType (type);
8683 protected override void CloneTo (CloneContext clonectx, Expression t)
8685 IndexerAccess target = (IndexerAccess) t;
8687 if (arguments != null)
8688 target.arguments = arguments.Clone (clonectx);
8690 if (instance_expr != null)
8691 target.instance_expr = instance_expr.Clone (clonectx);
8696 /// The base operator for method names
8698 public class BaseAccess : Expression {
8699 public readonly string Identifier;
8702 public BaseAccess (string member, Location l)
8704 this.Identifier = member;
8708 public BaseAccess (string member, TypeArguments args, Location l)
8714 public override Expression CreateExpressionTree (ResolveContext ec)
8716 throw new NotSupportedException ("ET");
8719 protected override Expression DoResolve (ResolveContext ec)
8721 Expression c = CommonResolve (ec);
8727 // MethodGroups use this opportunity to flag an error on lacking ()
8729 if (!(c is MethodGroupExpr))
8730 return c.Resolve (ec);
8734 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8736 Expression c = CommonResolve (ec);
8742 // MethodGroups use this opportunity to flag an error on lacking ()
8744 if (! (c is MethodGroupExpr))
8745 return c.DoResolveLValue (ec, right_side);
8750 Expression CommonResolve (ResolveContext ec)
8752 Expression member_lookup;
8753 Type current_type = ec.CurrentType;
8754 Type base_type = current_type.BaseType;
8756 if (!This.IsThisAvailable (ec)) {
8758 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
8760 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
8765 member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier,
8766 AllMemberTypes, AllBindingFlags, loc);
8767 if (member_lookup == null) {
8768 Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier,
8769 null, AllMemberTypes, AllBindingFlags);
8776 left = new TypeExpression (base_type, loc);
8778 left = ec.GetThis (loc);
8780 MemberExpr me = member_lookup as MemberExpr;
8782 if (member_lookup is TypeExpression){
8783 ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
8784 Identifier, member_lookup.GetSignatureForError ());
8786 ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
8787 Identifier, member_lookup.ExprClassName);
8793 me = me.ResolveMemberAccess (ec, left, loc, null);
8800 me.SetTypeArguments (ec, args);
8806 public override void Emit (EmitContext ec)
8808 throw new Exception ("Should never be called");
8811 protected override void CloneTo (CloneContext clonectx, Expression t)
8813 BaseAccess target = (BaseAccess) t;
8816 target.args = args.Clone ();
8821 /// The base indexer operator
8823 public class BaseIndexerAccess : IndexerAccess {
8824 public BaseIndexerAccess (Arguments args, Location loc)
8825 : base (null, true, loc)
8827 this.arguments = args;
8830 protected override void CommonResolve (ResolveContext ec)
8832 instance_expr = ec.GetThis (loc);
8834 current_type = ec.CurrentType.BaseType;
8835 indexer_type = current_type;
8838 public override Expression CreateExpressionTree (ResolveContext ec)
8840 MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
8841 return base.CreateExpressionTree (ec);
8846 /// This class exists solely to pass the Type around and to be a dummy
8847 /// that can be passed to the conversion functions (this is used by
8848 /// foreach implementation to typecast the object return value from
8849 /// get_Current into the proper type. All code has been generated and
8850 /// we only care about the side effect conversions to be performed
8852 /// This is also now used as a placeholder where a no-action expression
8853 /// is needed (the `New' class).
8855 public class EmptyExpression : Expression {
8856 public static readonly Expression Null = new EmptyExpression ();
8858 public class OutAccess : EmptyExpression
8860 public static readonly OutAccess Instance = new OutAccess ();
8862 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8864 rc.Report.Error (206, right_side.Location,
8865 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
8871 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8872 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8873 public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
8875 static EmptyExpression temp = new EmptyExpression ();
8876 public static EmptyExpression Grab ()
8878 EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8883 public static void Release (EmptyExpression e)
8890 // FIXME: Don't set to object
8891 type = TypeManager.object_type;
8892 eclass = ExprClass.Value;
8893 loc = Location.Null;
8896 public EmptyExpression (Type t)
8899 eclass = ExprClass.Value;
8900 loc = Location.Null;
8903 public override Expression CreateExpressionTree (ResolveContext ec)
8905 throw new NotSupportedException ("ET");
8908 protected override Expression DoResolve (ResolveContext ec)
8913 public override void Emit (EmitContext ec)
8915 // nothing, as we only exist to not do anything.
8918 public override void EmitSideEffect (EmitContext ec)
8923 // This is just because we might want to reuse this bad boy
8924 // instead of creating gazillions of EmptyExpressions.
8925 // (CanImplicitConversion uses it)
8927 public void SetType (Type t)
8934 // Empty statement expression
8936 public sealed class EmptyExpressionStatement : ExpressionStatement
8938 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
8940 private EmptyExpressionStatement ()
8942 loc = Location.Null;
8945 public override Expression CreateExpressionTree (ResolveContext ec)
8950 public override void EmitStatement (EmitContext ec)
8955 protected override Expression DoResolve (ResolveContext ec)
8957 eclass = ExprClass.Value;
8958 type = TypeManager.object_type;
8962 public override void Emit (EmitContext ec)
8968 public class UserCast : Expression {
8972 public UserCast (MethodInfo method, Expression source, Location l)
8974 this.method = method;
8975 this.source = source;
8976 type = TypeManager.TypeToCoreType (method.ReturnType);
8980 public Expression Source {
8986 public override Expression CreateExpressionTree (ResolveContext ec)
8988 Arguments args = new Arguments (3);
8989 args.Add (new Argument (source.CreateExpressionTree (ec)));
8990 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
8991 args.Add (new Argument (new TypeOfMethod (method, loc)));
8992 return CreateExpressionFactoryCall (ec, "Convert", args);
8995 protected override Expression DoResolve (ResolveContext ec)
8997 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
8999 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
9001 eclass = ExprClass.Value;
9005 public override void Emit (EmitContext ec)
9008 ec.ig.Emit (OpCodes.Call, method);
9011 public override string GetSignatureForError ()
9013 return TypeManager.CSharpSignature (method);
9017 public override SLE.Expression MakeExpression (BuilderContext ctx)
9019 return SLE.Expression.Convert (source.MakeExpression (ctx), type, method);
9023 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9025 source.MutateHoistedGenericType (storey);
9026 method = storey.MutateGenericMethod (method);
9031 // This class is used to "construct" the type during a typecast
9032 // operation. Since the Type.GetType class in .NET can parse
9033 // the type specification, we just use this to construct the type
9034 // one bit at a time.
9036 public class ComposedCast : TypeExpr {
9037 FullNamedExpression left;
9040 public ComposedCast (FullNamedExpression left, string dim)
9041 : this (left, dim, left.Location)
9045 public ComposedCast (FullNamedExpression left, string dim, Location l)
9052 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
9054 TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
9058 Type ltype = lexpr.Type;
9059 if ((dim.Length > 0) && (dim [0] == '?')) {
9060 TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
9062 nullable = new ComposedCast (nullable, dim.Substring (1), loc);
9063 return nullable.ResolveAsTypeTerminal (ec, false);
9066 if (dim == "*" && !TypeManager.VerifyUnmanaged (ec.Compiler, ltype, loc))
9069 if (dim.Length != 0 && dim [0] == '[') {
9070 if (TypeManager.IsSpecialType (ltype)) {
9071 ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
9075 if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
9076 ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
9077 ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
9078 TypeManager.CSharpName (ltype));
9083 type = TypeManager.GetConstructedType (ltype, dim);
9088 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
9090 if (type.IsPointer && !ec.IsUnsafe){
9091 UnsafeError (ec.Compiler.Report, loc);
9094 eclass = ExprClass.Type;
9098 public override string GetSignatureForError ()
9100 return left.GetSignatureForError () + dim;
9103 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
9105 return ResolveAsBaseTerminal (ec, silent);
9109 public class FixedBufferPtr : Expression {
9112 public FixedBufferPtr (Expression array, Type array_type, Location l)
9117 type = TypeManager.GetPointerType (array_type);
9118 eclass = ExprClass.Value;
9121 public override Expression CreateExpressionTree (ResolveContext ec)
9123 Error_PointerInsideExpressionTree (ec);
9127 public override void Emit(EmitContext ec)
9132 protected override Expression DoResolve (ResolveContext ec)
9135 // We are born fully resolved
9143 // This class is used to represent the address of an array, used
9144 // only by the Fixed statement, this generates "&a [0]" construct
9145 // for fixed (char *pa = a)
9147 public class ArrayPtr : FixedBufferPtr {
9150 public ArrayPtr (Expression array, Type array_type, Location l):
9151 base (array, array_type, l)
9153 this.array_type = array_type;
9156 public override void Emit (EmitContext ec)
9160 ILGenerator ig = ec.ig;
9161 IntLiteral.EmitInt (ig, 0);
9162 ig.Emit (OpCodes.Ldelema, array_type);
9167 // Encapsulates a conversion rules required for array indexes
9169 public class ArrayIndexCast : TypeCast
9171 public ArrayIndexCast (Expression expr)
9172 : base (expr, TypeManager.int32_type)
9174 if (expr.Type == TypeManager.int32_type)
9175 throw new ArgumentException ("unnecessary array index conversion");
9178 public override Expression CreateExpressionTree (ResolveContext ec)
9180 using (ec.Set (ResolveContext.Options.CheckedScope)) {
9181 return base.CreateExpressionTree (ec);
9185 public override void Emit (EmitContext ec)
9189 var expr_type = child.Type;
9191 if (expr_type == TypeManager.uint32_type)
9192 ec.ig.Emit (OpCodes.Conv_U);
9193 else if (expr_type == TypeManager.int64_type)
9194 ec.ig.Emit (OpCodes.Conv_Ovf_I);
9195 else if (expr_type == TypeManager.uint64_type)
9196 ec.ig.Emit (OpCodes.Conv_Ovf_I_Un);
9198 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
9201 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
9203 return child.GetAttributableValue (ec, value_type, out value);
9208 // Implements the `stackalloc' keyword
9210 public class StackAlloc : Expression {
9215 public StackAlloc (Expression type, Expression count, Location l)
9222 public override Expression CreateExpressionTree (ResolveContext ec)
9224 throw new NotSupportedException ("ET");
9227 protected override Expression DoResolve (ResolveContext ec)
9229 count = count.Resolve (ec);
9233 if (count.Type != TypeManager.uint32_type){
9234 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
9239 Constant c = count as Constant;
9240 if (c != null && c.IsNegative) {
9241 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
9244 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
9245 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
9248 TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
9254 if (!TypeManager.VerifyUnmanaged (ec.Compiler, otype, loc))
9257 type = TypeManager.GetPointerType (otype);
9258 eclass = ExprClass.Value;
9263 public override void Emit (EmitContext ec)
9265 int size = GetTypeSize (otype);
9266 ILGenerator ig = ec.ig;
9271 ig.Emit (OpCodes.Sizeof, otype);
9273 IntConstant.EmitInt (ig, size);
9275 ig.Emit (OpCodes.Mul_Ovf_Un);
9276 ig.Emit (OpCodes.Localloc);
9279 protected override void CloneTo (CloneContext clonectx, Expression t)
9281 StackAlloc target = (StackAlloc) t;
9282 target.count = count.Clone (clonectx);
9283 target.t = t.Clone (clonectx);
9288 // An object initializer expression
9290 public class ElementInitializer : Assign
9292 public readonly string Name;
9294 public ElementInitializer (string name, Expression initializer, Location loc)
9295 : base (null, initializer, loc)
9300 protected override void CloneTo (CloneContext clonectx, Expression t)
9302 ElementInitializer target = (ElementInitializer) t;
9303 target.source = source.Clone (clonectx);
9306 public override Expression CreateExpressionTree (ResolveContext ec)
9308 Arguments args = new Arguments (2);
9309 FieldExpr fe = target as FieldExpr;
9311 args.Add (new Argument (fe.CreateTypeOfExpression ()));
9313 args.Add (new Argument (((PropertyExpr)target).CreateSetterTypeOfExpression ()));
9315 args.Add (new Argument (source.CreateExpressionTree (ec)));
9316 return CreateExpressionFactoryCall (ec,
9317 source is CollectionOrObjectInitializers ? "ListBind" : "Bind",
9321 protected override Expression DoResolve (ResolveContext ec)
9324 return EmptyExpressionStatement.Instance;
9326 MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
9327 Name, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr;
9333 me.InstanceExpression = ec.CurrentInitializerVariable;
9335 if (source is CollectionOrObjectInitializers) {
9336 Expression previous = ec.CurrentInitializerVariable;
9337 ec.CurrentInitializerVariable = target;
9338 source = source.Resolve (ec);
9339 ec.CurrentInitializerVariable = previous;
9343 eclass = source.eclass;
9348 Expression expr = base.DoResolve (ec);
9353 // Ignore field initializers with default value
9355 Constant c = source as Constant;
9356 if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
9357 return EmptyExpressionStatement.Instance.Resolve (ec);
9362 protected override Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
9364 MemberInfo member = members [0];
9365 if (member.MemberType != MemberTypes.Property && member.MemberType != MemberTypes.Field)
9366 ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
9367 "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
9369 ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
9370 TypeManager.GetFullNameSignature (member));
9375 public override void EmitStatement (EmitContext ec)
9377 if (source is CollectionOrObjectInitializers)
9380 base.EmitStatement (ec);
9385 // A collection initializer expression
9387 class CollectionElementInitializer : Invocation
9389 public class ElementInitializerArgument : Argument
9391 public ElementInitializerArgument (Expression e)
9397 sealed class AddMemberAccess : MemberAccess
9399 public AddMemberAccess (Expression expr, Location loc)
9400 : base (expr, "Add", loc)
9404 protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
9406 if (TypeManager.HasElementType (type))
9409 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9413 public CollectionElementInitializer (Expression argument)
9414 : base (null, new Arguments (1))
9416 base.arguments.Add (new ElementInitializerArgument (argument));
9417 this.loc = argument.Location;
9420 public CollectionElementInitializer (ArrayList arguments, Location loc)
9421 : base (null, new Arguments (arguments.Count))
9423 foreach (Expression e in arguments)
9424 base.arguments.Add (new ElementInitializerArgument (e));
9429 public override Expression CreateExpressionTree (ResolveContext ec)
9431 Arguments args = new Arguments (2);
9432 args.Add (new Argument (mg.CreateExpressionTree (ec)));
9434 ArrayList expr_initializers = new ArrayList (arguments.Count);
9435 foreach (Argument a in arguments)
9436 expr_initializers.Add (a.CreateExpressionTree (ec));
9438 args.Add (new Argument (new ArrayCreation (
9439 CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
9440 return CreateExpressionFactoryCall (ec, "ElementInit", args);
9443 protected override void CloneTo (CloneContext clonectx, Expression t)
9445 CollectionElementInitializer target = (CollectionElementInitializer) t;
9446 if (arguments != null)
9447 target.arguments = arguments.Clone (clonectx);
9450 protected override Expression DoResolve (ResolveContext ec)
9452 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
9454 return base.DoResolve (ec);
9459 // A block of object or collection initializers
9461 public class CollectionOrObjectInitializers : ExpressionStatement
9463 ArrayList initializers;
9464 bool is_collection_initialization;
9466 public static readonly CollectionOrObjectInitializers Empty =
9467 new CollectionOrObjectInitializers (new ArrayList (0), Location.Null);
9469 public CollectionOrObjectInitializers (ArrayList initializers, Location loc)
9471 this.initializers = initializers;
9475 public bool IsEmpty {
9477 return initializers.Count == 0;
9481 public bool IsCollectionInitializer {
9483 return is_collection_initialization;
9487 protected override void CloneTo (CloneContext clonectx, Expression target)
9489 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
9491 t.initializers = new ArrayList (initializers.Count);
9492 foreach (Expression e in initializers)
9493 t.initializers.Add (e.Clone (clonectx));
9496 public override Expression CreateExpressionTree (ResolveContext ec)
9498 ArrayList expr_initializers = new ArrayList (initializers.Count);
9499 foreach (Expression e in initializers) {
9500 Expression expr = e.CreateExpressionTree (ec);
9502 expr_initializers.Add (expr);
9505 return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
9508 protected override Expression DoResolve (ResolveContext ec)
9510 ArrayList element_names = null;
9511 for (int i = 0; i < initializers.Count; ++i) {
9512 Expression initializer = (Expression) initializers [i];
9513 ElementInitializer element_initializer = initializer as ElementInitializer;
9516 if (element_initializer != null) {
9517 element_names = new ArrayList (initializers.Count);
9518 element_names.Add (element_initializer.Name);
9519 } else if (initializer is CompletingExpression){
9520 initializer.Resolve (ec);
9521 throw new InternalErrorException ("This line should never be reached");
9523 if (!TypeManager.ImplementsInterface (ec.CurrentInitializerVariable.Type, TypeManager.ienumerable_type)) {
9524 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
9525 "object initializer because type `{1}' does not implement `{2}' interface",
9526 ec.CurrentInitializerVariable.GetSignatureForError (),
9527 TypeManager.CSharpName (ec.CurrentInitializerVariable.Type),
9528 TypeManager.CSharpName (TypeManager.ienumerable_type));
9531 is_collection_initialization = true;
9534 if (is_collection_initialization != (element_initializer == null)) {
9535 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
9536 is_collection_initialization ? "collection initializer" : "object initializer");
9540 if (!is_collection_initialization) {
9541 if (element_names.Contains (element_initializer.Name)) {
9542 ec.Report.Error (1912, element_initializer.Location,
9543 "An object initializer includes more than one member `{0}' initialization",
9544 element_initializer.Name);
9546 element_names.Add (element_initializer.Name);
9551 Expression e = initializer.Resolve (ec);
9552 if (e == EmptyExpressionStatement.Instance)
9553 initializers.RemoveAt (i--);
9555 initializers [i] = e;
9558 type = ec.CurrentInitializerVariable.Type;
9559 if (is_collection_initialization) {
9560 if (TypeManager.HasElementType (type)) {
9561 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
9562 TypeManager.CSharpName (type));
9566 eclass = ExprClass.Variable;
9570 public override void Emit (EmitContext ec)
9575 public override void EmitStatement (EmitContext ec)
9577 foreach (ExpressionStatement e in initializers)
9578 e.EmitStatement (ec);
9581 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9583 foreach (Expression e in initializers)
9584 e.MutateHoistedGenericType (storey);
9589 // New expression with element/object initializers
9591 public class NewInitialize : New
9594 // This class serves as a proxy for variable initializer target instances.
9595 // A real variable is assigned later when we resolve left side of an
9598 sealed class InitializerTargetExpression : Expression, IMemoryLocation
9600 NewInitialize new_instance;
9602 public InitializerTargetExpression (NewInitialize newInstance)
9604 this.type = newInstance.type;
9605 this.loc = newInstance.loc;
9606 this.eclass = newInstance.eclass;
9607 this.new_instance = newInstance;
9610 public override Expression CreateExpressionTree (ResolveContext ec)
9612 // Should not be reached
9613 throw new NotSupportedException ("ET");
9616 protected override Expression DoResolve (ResolveContext ec)
9621 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
9626 public override void Emit (EmitContext ec)
9628 Expression e = (Expression) new_instance.instance;
9632 #region IMemoryLocation Members
9634 public void AddressOf (EmitContext ec, AddressOp mode)
9636 new_instance.instance.AddressOf (ec, mode);
9642 CollectionOrObjectInitializers initializers;
9643 IMemoryLocation instance;
9645 public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
9646 : base (requested_type, arguments, l)
9648 this.initializers = initializers;
9651 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
9653 instance = base.EmitAddressOf (ec, Mode);
9655 if (!initializers.IsEmpty)
9656 initializers.Emit (ec);
9661 protected override void CloneTo (CloneContext clonectx, Expression t)
9663 base.CloneTo (clonectx, t);
9665 NewInitialize target = (NewInitialize) t;
9666 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
9669 public override Expression CreateExpressionTree (ResolveContext ec)
9671 Arguments args = new Arguments (2);
9672 args.Add (new Argument (base.CreateExpressionTree (ec)));
9673 if (!initializers.IsEmpty)
9674 args.Add (new Argument (initializers.CreateExpressionTree (ec)));
9676 return CreateExpressionFactoryCall (ec,
9677 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
9681 protected override Expression DoResolve (ResolveContext ec)
9683 Expression e = base.DoResolve (ec);
9687 Expression previous = ec.CurrentInitializerVariable;
9688 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
9689 initializers.Resolve (ec);
9690 ec.CurrentInitializerVariable = previous;
9694 public override bool Emit (EmitContext ec, IMemoryLocation target)
9696 bool left_on_stack = base.Emit (ec, target);
9698 if (initializers.IsEmpty)
9699 return left_on_stack;
9701 LocalTemporary temp = target as LocalTemporary;
9703 if (!left_on_stack) {
9704 VariableReference vr = target as VariableReference;
9706 // FIXME: This still does not work correctly for pre-set variables
9707 if (vr != null && vr.IsRef)
9708 target.AddressOf (ec, AddressOp.Load);
9710 ((Expression) target).Emit (ec);
9711 left_on_stack = true;
9714 temp = new LocalTemporary (type);
9721 initializers.Emit (ec);
9723 if (left_on_stack) {
9728 return left_on_stack;
9731 public override bool HasInitializer {
9733 return !initializers.IsEmpty;
9737 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
9739 base.MutateHoistedGenericType (storey);
9740 initializers.MutateHoistedGenericType (storey);
9744 public class NewAnonymousType : New
9746 static readonly ArrayList EmptyParameters = new ArrayList (0);
9748 ArrayList parameters;
9749 readonly TypeContainer parent;
9750 AnonymousTypeClass anonymous_type;
9752 public NewAnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
9753 : base (null, null, loc)
9755 this.parameters = parameters;
9756 this.parent = parent;
9759 protected override void CloneTo (CloneContext clonectx, Expression target)
9761 if (parameters == null)
9764 NewAnonymousType t = (NewAnonymousType) target;
9765 t.parameters = new ArrayList (parameters.Count);
9766 foreach (AnonymousTypeParameter atp in parameters)
9767 t.parameters.Add (atp.Clone (clonectx));
9770 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, ArrayList parameters)
9772 AnonymousTypeClass type = parent.Module.Compiled.GetAnonymousType (parameters);
9776 type = AnonymousTypeClass.Create (ec.Compiler, parent, parameters, loc);
9783 if (ec.Report.Errors == 0)
9786 parent.Module.Compiled.AddAnonymousType (type);
9790 public override Expression CreateExpressionTree (ResolveContext ec)
9792 if (parameters == null)
9793 return base.CreateExpressionTree (ec);
9795 ArrayList init = new ArrayList (parameters.Count);
9796 foreach (Property p in anonymous_type.Properties)
9797 init.Add (new TypeOfMethod (TypeBuilder.GetMethod (type, p.GetBuilder), loc));
9799 ArrayList ctor_args = new ArrayList (Arguments.Count);
9800 foreach (Argument a in Arguments)
9801 ctor_args.Add (a.CreateExpressionTree (ec));
9803 Arguments args = new Arguments (3);
9804 args.Add (new Argument (method.CreateExpressionTree (ec)));
9805 args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, "[]", ctor_args, loc)));
9806 args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", init, loc)));
9808 return CreateExpressionFactoryCall (ec, "New", args);
9811 protected override Expression DoResolve (ResolveContext ec)
9813 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
9814 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
9818 if (parameters == null) {
9819 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
9820 RequestedType = new TypeExpression (anonymous_type.TypeBuilder, loc);
9821 return base.DoResolve (ec);
9825 Arguments = new Arguments (parameters.Count);
9826 TypeExpression [] t_args = new TypeExpression [parameters.Count];
9827 for (int i = 0; i < parameters.Count; ++i) {
9828 Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
9834 Arguments.Add (new Argument (e));
9835 t_args [i] = new TypeExpression (e.Type, e.Location);
9841 anonymous_type = CreateAnonymousType (ec, parameters);
9842 if (anonymous_type == null)
9845 RequestedType = new GenericTypeExpr (anonymous_type.TypeBuilder, new TypeArguments (t_args), loc);
9846 return base.DoResolve (ec);
9850 public class AnonymousTypeParameter : ShimExpression
9852 public readonly string Name;
9854 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
9855 : base (initializer)
9861 public AnonymousTypeParameter (Parameter parameter)
9862 : base (new SimpleName (parameter.Name, parameter.Location))
9864 this.Name = parameter.Name;
9865 this.loc = parameter.Location;
9868 public override bool Equals (object o)
9870 AnonymousTypeParameter other = o as AnonymousTypeParameter;
9871 return other != null && Name == other.Name;
9874 public override int GetHashCode ()
9876 return Name.GetHashCode ();
9879 protected override Expression DoResolve (ResolveContext ec)
9881 Expression e = expr.Resolve (ec);
9885 if (e.eclass == ExprClass.MethodGroup) {
9886 Error_InvalidInitializer (ec, e.ExprClassName);
9891 if (type == TypeManager.void_type || type == TypeManager.null_type ||
9892 type == InternalType.AnonymousMethod || type.IsPointer) {
9893 Error_InvalidInitializer (ec, e.GetSignatureForError ());
9900 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
9902 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",