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.
10 // Copyright 2011 Xamarin Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using MetaType = IKVM.Reflection.Type;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using MetaType = System.Type;
25 using System.Reflection;
26 using System.Reflection.Emit;
32 // This is an user operator expression, automatically created during
35 public class UserOperatorCall : Expression {
36 protected readonly Arguments arguments;
37 protected readonly MethodSpec oper;
38 readonly Func<ResolveContext, Expression, Expression> expr_tree;
40 public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
43 this.arguments = args;
44 this.expr_tree = expr_tree;
46 type = oper.ReturnType;
47 eclass = ExprClass.Value;
51 public override bool ContainsEmitWithAwait ()
53 return arguments.ContainsEmitWithAwait ();
56 public override Expression CreateExpressionTree (ResolveContext ec)
58 if (expr_tree != null)
59 return expr_tree (ec, new TypeOfMethod (oper, loc));
61 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
62 new NullLiteral (loc),
63 new TypeOfMethod (oper, loc));
65 return CreateExpressionFactoryCall (ec, "Call", args);
68 protected override void CloneTo (CloneContext context, Expression target)
73 protected override Expression DoResolve (ResolveContext ec)
76 // We are born fully resolved
81 public override void Emit (EmitContext ec)
83 var call = new CallEmitter ();
84 call.Emit (ec, oper, arguments, loc);
87 public override void FlowAnalysis (FlowAnalysisContext fc)
89 arguments.FlowAnalysis (fc);
92 public override SLE.Expression MakeExpression (BuilderContext ctx)
95 return base.MakeExpression (ctx);
97 return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
102 public class ParenthesizedExpression : ShimExpression
104 public ParenthesizedExpression (Expression expr, Location loc)
110 protected override Expression DoResolve (ResolveContext ec)
112 var res = expr.Resolve (ec);
113 var constant = res as Constant;
114 if (constant != null && constant.IsLiteral)
115 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
120 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
122 return expr.DoResolveLValue (ec, right_side);
125 public override object Accept (StructuralVisitor visitor)
127 return visitor.Visit (this);
132 // Unary implements unary expressions.
134 public class Unary : Expression
136 public enum Operator : byte {
137 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
141 public readonly Operator Oper;
142 public Expression Expr;
143 ConvCast.Mode enum_conversion;
145 public Unary (Operator op, Expression expr, Location loc)
153 // This routine will attempt to simplify the unary expression when the
154 // argument is a constant.
156 Constant TryReduceConstant (ResolveContext ec, Constant constant)
160 while (e is EmptyConstantCast)
161 e = ((EmptyConstantCast) e).child;
163 if (e is SideEffectConstant) {
164 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
165 return r == null ? null : new SideEffectConstant (r, e, r.Location);
168 TypeSpec expr_type = e.Type;
171 case Operator.UnaryPlus:
172 // Unary numeric promotions
173 switch (expr_type.BuiltinType) {
174 case BuiltinTypeSpec.Type.Byte:
175 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
176 case BuiltinTypeSpec.Type.SByte:
177 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
178 case BuiltinTypeSpec.Type.Short:
179 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
180 case BuiltinTypeSpec.Type.UShort:
181 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
182 case BuiltinTypeSpec.Type.Char:
183 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
185 // Predefined operators
186 case BuiltinTypeSpec.Type.Int:
187 case BuiltinTypeSpec.Type.UInt:
188 case BuiltinTypeSpec.Type.Long:
189 case BuiltinTypeSpec.Type.ULong:
190 case BuiltinTypeSpec.Type.Float:
191 case BuiltinTypeSpec.Type.Double:
192 case BuiltinTypeSpec.Type.Decimal:
198 case Operator.UnaryNegation:
199 // Unary numeric promotions
200 switch (expr_type.BuiltinType) {
201 case BuiltinTypeSpec.Type.Byte:
202 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
203 case BuiltinTypeSpec.Type.SByte:
204 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
205 case BuiltinTypeSpec.Type.Short:
206 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
207 case BuiltinTypeSpec.Type.UShort:
208 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
209 case BuiltinTypeSpec.Type.Char:
210 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
212 // Predefined operators
213 case BuiltinTypeSpec.Type.Int:
214 int ivalue = ((IntConstant) e).Value;
215 if (ivalue == int.MinValue) {
216 if (ec.ConstantCheckState) {
217 ConstantFold.Error_CompileTimeOverflow (ec, loc);
222 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
224 case BuiltinTypeSpec.Type.Long:
225 long lvalue = ((LongConstant) e).Value;
226 if (lvalue == long.MinValue) {
227 if (ec.ConstantCheckState) {
228 ConstantFold.Error_CompileTimeOverflow (ec, loc);
233 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
235 case BuiltinTypeSpec.Type.UInt:
236 UIntLiteral uil = constant as UIntLiteral;
238 if (uil.Value == int.MaxValue + (uint) 1)
239 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
240 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
242 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
245 case BuiltinTypeSpec.Type.ULong:
246 ULongLiteral ull = constant as ULongLiteral;
247 if (ull != null && ull.Value == 9223372036854775808)
248 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
251 case BuiltinTypeSpec.Type.Float:
252 FloatLiteral fl = constant as FloatLiteral;
253 // For better error reporting
255 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
257 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
259 case BuiltinTypeSpec.Type.Double:
260 DoubleLiteral dl = constant as DoubleLiteral;
261 // For better error reporting
263 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
265 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
267 case BuiltinTypeSpec.Type.Decimal:
268 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
273 case Operator.LogicalNot:
274 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
277 bool b = (bool)e.GetValue ();
278 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
280 case Operator.OnesComplement:
281 // Unary numeric promotions
282 switch (expr_type.BuiltinType) {
283 case BuiltinTypeSpec.Type.Byte:
284 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
285 case BuiltinTypeSpec.Type.SByte:
286 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
287 case BuiltinTypeSpec.Type.Short:
288 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
289 case BuiltinTypeSpec.Type.UShort:
290 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
291 case BuiltinTypeSpec.Type.Char:
292 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
294 // Predefined operators
295 case BuiltinTypeSpec.Type.Int:
296 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
297 case BuiltinTypeSpec.Type.UInt:
298 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
299 case BuiltinTypeSpec.Type.Long:
300 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
301 case BuiltinTypeSpec.Type.ULong:
302 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
304 if (e is EnumConstant) {
305 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
308 // Numeric promotion upgraded types to int but for enum constant
309 // original underlying constant type is needed
311 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
312 int v = ((IntConstant) res).Value;
313 switch (((EnumConstant) e).Child.Type.BuiltinType) {
314 case BuiltinTypeSpec.Type.UShort:
315 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
317 case BuiltinTypeSpec.Type.Short:
318 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
320 case BuiltinTypeSpec.Type.Byte:
321 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
323 case BuiltinTypeSpec.Type.SByte:
324 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
329 res = new EnumConstant (res, expr_type);
335 throw new Exception ("Can not constant fold: " + Oper.ToString());
338 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
340 eclass = ExprClass.Value;
342 TypeSpec expr_type = expr.Type;
343 Expression best_expr;
345 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
348 // Primitive types first
350 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
351 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
352 if (best_expr == null)
355 type = best_expr.Type;
361 // E operator ~(E x);
363 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
364 return ResolveEnumOperator (ec, expr, predefined);
366 return ResolveUserType (ec, expr, predefined);
369 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
371 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
372 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
373 if (best_expr == null)
377 enum_conversion = Binary.GetEnumResultCast (underlying_type);
379 return EmptyCast.Create (this, type);
382 public override bool ContainsEmitWithAwait ()
384 return Expr.ContainsEmitWithAwait ();
387 public override Expression CreateExpressionTree (ResolveContext ec)
389 return CreateExpressionTree (ec, null);
392 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
396 case Operator.AddressOf:
397 Error_PointerInsideExpressionTree (ec);
399 case Operator.UnaryNegation:
400 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
401 method_name = "NegateChecked";
403 method_name = "Negate";
405 case Operator.OnesComplement:
406 case Operator.LogicalNot:
409 case Operator.UnaryPlus:
410 method_name = "UnaryPlus";
413 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
416 Arguments args = new Arguments (2);
417 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
419 args.Add (new Argument (user_op));
421 return CreateExpressionFactoryCall (ec, method_name, args);
424 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
426 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
429 // 7.6.1 Unary plus operator
431 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
432 types.Int, types.UInt,
433 types.Long, types.ULong,
434 types.Float, types.Double,
439 // 7.6.2 Unary minus operator
441 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
442 types.Int, types.Long,
443 types.Float, types.Double,
448 // 7.6.3 Logical negation operator
450 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
455 // 7.6.4 Bitwise complement operator
457 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
458 types.Int, types.UInt,
459 types.Long, types.ULong
462 return predefined_operators;
466 // Unary numeric promotions
468 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
470 TypeSpec expr_type = expr.Type;
471 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
472 switch (expr_type.BuiltinType) {
473 case BuiltinTypeSpec.Type.Byte:
474 case BuiltinTypeSpec.Type.SByte:
475 case BuiltinTypeSpec.Type.Short:
476 case BuiltinTypeSpec.Type.UShort:
477 case BuiltinTypeSpec.Type.Char:
478 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
482 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
483 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
488 protected override Expression DoResolve (ResolveContext ec)
490 if (Oper == Operator.AddressOf) {
491 return ResolveAddressOf (ec);
494 Expr = Expr.Resolve (ec);
498 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
499 Arguments args = new Arguments (1);
500 args.Add (new Argument (Expr));
501 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
504 if (Expr.Type.IsNullableType)
505 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
508 // Attempt to use a constant folding operation.
510 Constant cexpr = Expr as Constant;
512 cexpr = TryReduceConstant (ec, cexpr);
517 Expression expr = ResolveOperator (ec, Expr);
519 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
522 // Reduce unary operator on predefined types
524 if (expr == this && Oper == Operator.UnaryPlus)
530 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
535 public override void Emit (EmitContext ec)
537 EmitOperator (ec, type);
540 protected void EmitOperator (EmitContext ec, TypeSpec type)
543 case Operator.UnaryPlus:
547 case Operator.UnaryNegation:
548 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
549 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
550 Expr = Expr.EmitToField (ec);
553 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
554 ec.Emit (OpCodes.Conv_U8);
556 ec.Emit (OpCodes.Sub_Ovf);
559 ec.Emit (OpCodes.Neg);
564 case Operator.LogicalNot:
567 ec.Emit (OpCodes.Ceq);
570 case Operator.OnesComplement:
572 ec.Emit (OpCodes.Not);
575 case Operator.AddressOf:
576 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
580 throw new Exception ("This should not happen: Operator = "
585 // Same trick as in Binary expression
587 if (enum_conversion != 0) {
588 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
589 ConvCast.Emit (ec, enum_conversion);
594 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
596 if (Oper == Operator.LogicalNot)
597 Expr.EmitBranchable (ec, target, !on_true);
599 base.EmitBranchable (ec, target, on_true);
602 public override void EmitSideEffect (EmitContext ec)
604 Expr.EmitSideEffect (ec);
607 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
609 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
610 oper, type.GetSignatureForError ());
613 public override void FlowAnalysis (FlowAnalysisContext fc)
615 FlowAnalysis (fc, false);
618 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
620 FlowAnalysis (fc, true);
623 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
625 if (Oper == Operator.AddressOf) {
626 var vr = Expr as VariableReference;
627 if (vr != null && vr.VariableInfo != null)
628 fc.SetVariableAssigned (vr.VariableInfo);
633 if (Oper == Operator.LogicalNot && conditional) {
634 Expr.FlowAnalysisConditional (fc);
636 var temp = fc.DefiniteAssignmentOnTrue;
637 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
638 fc.DefiniteAssignmentOnFalse = temp;
640 Expr.FlowAnalysis (fc);
645 // Converts operator to System.Linq.Expressions.ExpressionType enum name
647 string GetOperatorExpressionTypeName ()
650 case Operator.OnesComplement:
651 return "OnesComplement";
652 case Operator.LogicalNot:
654 case Operator.UnaryNegation:
656 case Operator.UnaryPlus:
659 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
663 static bool IsFloat (TypeSpec t)
665 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
669 // Returns a stringified representation of the Operator
671 public static string OperName (Operator oper)
674 case Operator.UnaryPlus:
676 case Operator.UnaryNegation:
678 case Operator.LogicalNot:
680 case Operator.OnesComplement:
682 case Operator.AddressOf:
686 throw new NotImplementedException (oper.ToString ());
689 public override SLE.Expression MakeExpression (BuilderContext ctx)
691 var expr = Expr.MakeExpression (ctx);
692 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
695 case Operator.UnaryNegation:
696 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
697 case Operator.LogicalNot:
698 return SLE.Expression.Not (expr);
699 #if NET_4_0 || MOBILE_DYNAMIC
700 case Operator.OnesComplement:
701 return SLE.Expression.OnesComplement (expr);
704 throw new NotImplementedException (Oper.ToString ());
708 Expression ResolveAddressOf (ResolveContext ec)
711 UnsafeError (ec, loc);
713 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
714 if (Expr == null || Expr.eclass != ExprClass.Variable) {
715 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
719 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
723 IVariableReference vr = Expr as IVariableReference;
726 is_fixed = vr.IsFixed;
727 vr.SetHasAddressTaken ();
730 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
733 IFixedExpression fe = Expr as IFixedExpression;
734 is_fixed = fe != null && fe.IsFixed;
737 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
738 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
741 type = PointerContainer.MakeType (ec.Module, Expr.Type);
742 eclass = ExprClass.Value;
746 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
748 expr = DoNumericPromotion (rc, Oper, expr);
749 TypeSpec expr_type = expr.Type;
750 foreach (TypeSpec t in predefined) {
758 // Perform user-operator overload resolution
760 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
762 CSharp.Operator.OpType op_type;
764 case Operator.LogicalNot:
765 op_type = CSharp.Operator.OpType.LogicalNot; break;
766 case Operator.OnesComplement:
767 op_type = CSharp.Operator.OpType.OnesComplement; break;
768 case Operator.UnaryNegation:
769 op_type = CSharp.Operator.OpType.UnaryNegation; break;
770 case Operator.UnaryPlus:
771 op_type = CSharp.Operator.OpType.UnaryPlus; break;
773 throw new InternalErrorException (Oper.ToString ());
776 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
780 Arguments args = new Arguments (1);
781 args.Add (new Argument (expr));
783 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
784 var oper = res.ResolveOperator (ec, ref args);
789 Expr = args [0].Expr;
790 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
794 // Unary user type overload resolution
796 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
798 Expression best_expr = ResolveUserOperator (ec, expr);
799 if (best_expr != null)
802 foreach (TypeSpec t in predefined) {
803 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
804 if (oper_expr == null)
807 if (oper_expr == ErrorExpression.Instance)
811 // decimal type is predefined but has user-operators
813 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
814 oper_expr = ResolveUserType (ec, oper_expr, predefined);
816 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
818 if (oper_expr == null)
821 if (best_expr == null) {
822 best_expr = oper_expr;
826 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
828 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
829 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
831 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
838 best_expr = oper_expr;
841 if (best_expr == null)
845 // HACK: Decimal user-operator is included in standard operators
847 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
851 type = best_expr.Type;
855 protected override void CloneTo (CloneContext clonectx, Expression t)
857 Unary target = (Unary) t;
859 target.Expr = Expr.Clone (clonectx);
862 public override object Accept (StructuralVisitor visitor)
864 return visitor.Visit (this);
870 // Unary operators are turned into Indirection expressions
871 // after semantic analysis (this is so we can take the address
872 // of an indirection).
874 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
876 LocalTemporary temporary;
879 public Indirection (Expression expr, Location l)
885 public Expression Expr {
891 public bool IsFixed {
895 public override Location StartLocation {
897 return expr.StartLocation;
901 protected override void CloneTo (CloneContext clonectx, Expression t)
903 Indirection target = (Indirection) t;
904 target.expr = expr.Clone (clonectx);
907 public override bool ContainsEmitWithAwait ()
909 throw new NotImplementedException ();
912 public override Expression CreateExpressionTree (ResolveContext ec)
914 Error_PointerInsideExpressionTree (ec);
918 public override void Emit (EmitContext ec)
923 ec.EmitLoadFromPtr (Type);
926 public void Emit (EmitContext ec, bool leave_copy)
930 ec.Emit (OpCodes.Dup);
931 temporary = new LocalTemporary (expr.Type);
932 temporary.Store (ec);
936 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
938 prepared = isCompound;
943 ec.Emit (OpCodes.Dup);
947 ec.Emit (OpCodes.Dup);
948 temporary = new LocalTemporary (source.Type);
949 temporary.Store (ec);
952 ec.EmitStoreFromPtr (type);
954 if (temporary != null) {
956 temporary.Release (ec);
960 public void AddressOf (EmitContext ec, AddressOp Mode)
965 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
967 return DoResolve (ec);
970 protected override Expression DoResolve (ResolveContext ec)
972 expr = expr.Resolve (ec);
977 UnsafeError (ec, loc);
979 var pc = expr.Type as PointerContainer;
982 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
988 if (type.Kind == MemberKind.Void) {
989 Error_VoidPointerOperation (ec);
993 eclass = ExprClass.Variable;
997 public override object Accept (StructuralVisitor visitor)
999 return visitor.Visit (this);
1004 /// Unary Mutator expressions (pre and post ++ and --)
1008 /// UnaryMutator implements ++ and -- expressions. It derives from
1009 /// ExpressionStatement becuase the pre/post increment/decrement
1010 /// operators can be used in a statement context.
1012 /// FIXME: Idea, we could split this up in two classes, one simpler
1013 /// for the common case, and one with the extra fields for more complex
1014 /// classes (indexers require temporary access; overloaded require method)
1017 public class UnaryMutator : ExpressionStatement
1019 class DynamicPostMutator : Expression, IAssignMethod
1021 LocalTemporary temp;
1024 public DynamicPostMutator (Expression expr)
1027 this.type = expr.Type;
1028 this.loc = expr.Location;
1031 public override Expression CreateExpressionTree (ResolveContext ec)
1033 throw new NotImplementedException ("ET");
1036 protected override Expression DoResolve (ResolveContext rc)
1038 eclass = expr.eclass;
1042 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1044 expr.DoResolveLValue (ec, right_side);
1045 return DoResolve (ec);
1048 public override void Emit (EmitContext ec)
1053 public void Emit (EmitContext ec, bool leave_copy)
1055 throw new NotImplementedException ();
1059 // Emits target assignment using unmodified source value
1061 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1064 // Allocate temporary variable to keep original value before it's modified
1066 temp = new LocalTemporary (type);
1070 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1081 public enum Mode : byte {
1088 PreDecrement = IsDecrement,
1089 PostIncrement = IsPost,
1090 PostDecrement = IsPost | IsDecrement
1094 bool is_expr, recurse;
1096 protected Expression expr;
1098 // Holds the real operation
1099 Expression operation;
1101 public UnaryMutator (Mode m, Expression e, Location loc)
1108 public Mode UnaryMutatorMode {
1114 public Expression Expr {
1120 public override Location StartLocation {
1122 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1126 public override bool ContainsEmitWithAwait ()
1128 return expr.ContainsEmitWithAwait ();
1131 public override Expression CreateExpressionTree (ResolveContext ec)
1133 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1136 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1139 // Predefined ++ and -- operators exist for the following types:
1140 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1142 return new TypeSpec[] {
1158 protected override Expression DoResolve (ResolveContext ec)
1160 expr = expr.Resolve (ec);
1162 if (expr == null || expr.Type == InternalType.ErrorType)
1165 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1167 // Handle postfix unary operators using local
1168 // temporary variable
1170 if ((mode & Mode.IsPost) != 0)
1171 expr = new DynamicPostMutator (expr);
1173 Arguments args = new Arguments (1);
1174 args.Add (new Argument (expr));
1175 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1178 if (expr.Type.IsNullableType)
1179 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1181 return DoResolveOperation (ec);
1184 protected Expression DoResolveOperation (ResolveContext ec)
1186 eclass = ExprClass.Value;
1189 if (expr is RuntimeValueExpression) {
1192 // Use itself at the top of the stack
1193 operation = new EmptyExpression (type);
1197 // The operand of the prefix/postfix increment decrement operators
1198 // should be an expression that is classified as a variable,
1199 // a property access or an indexer access
1201 // TODO: Move to parser, expr is ATypeNameExpression
1202 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1203 expr = expr.ResolveLValue (ec, expr);
1205 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1209 // Step 1: Try to find a user operator, it has priority over predefined ones
1211 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1212 var methods = MemberCache.GetUserOperator (type, user_op, false);
1214 if (methods != null) {
1215 Arguments args = new Arguments (1);
1216 args.Add (new Argument (expr));
1218 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1219 var method = res.ResolveOperator (ec, ref args);
1223 args[0].Expr = operation;
1224 operation = new UserOperatorCall (method, args, null, loc);
1225 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1230 // Step 2: Try predefined types
1233 Expression source = null;
1234 bool primitive_type;
1237 // Predefined without user conversion first for speed-up
1239 // Predefined ++ and -- operators exist for the following types:
1240 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1242 switch (type.BuiltinType) {
1243 case BuiltinTypeSpec.Type.Byte:
1244 case BuiltinTypeSpec.Type.SByte:
1245 case BuiltinTypeSpec.Type.Short:
1246 case BuiltinTypeSpec.Type.UShort:
1247 case BuiltinTypeSpec.Type.Int:
1248 case BuiltinTypeSpec.Type.UInt:
1249 case BuiltinTypeSpec.Type.Long:
1250 case BuiltinTypeSpec.Type.ULong:
1251 case BuiltinTypeSpec.Type.Char:
1252 case BuiltinTypeSpec.Type.Float:
1253 case BuiltinTypeSpec.Type.Double:
1254 case BuiltinTypeSpec.Type.Decimal:
1256 primitive_type = true;
1259 primitive_type = false;
1261 // ++/-- on pointer variables of all types except void*
1262 if (type.IsPointer) {
1263 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1264 Error_VoidPointerOperation (ec);
1270 Expression best_source = null;
1271 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1272 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1274 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1278 if (best_source == null) {
1279 best_source = source;
1283 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1288 best_source = source;
1292 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1296 source = best_source;
1299 // ++/-- on enum types
1300 if (source == null && type.IsEnum)
1303 if (source == null) {
1304 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1311 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1312 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1313 operation = new Binary (op, source, one);
1314 operation = operation.Resolve (ec);
1315 if (operation == null)
1316 throw new NotImplementedException ("should not be reached");
1318 if (operation.Type != type) {
1320 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1322 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1328 void EmitCode (EmitContext ec, bool is_expr)
1331 this.is_expr = is_expr;
1332 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1335 public override void Emit (EmitContext ec)
1338 // We use recurse to allow ourselfs to be the source
1339 // of an assignment. This little hack prevents us from
1340 // having to allocate another expression
1343 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1351 EmitCode (ec, true);
1354 protected virtual void EmitOperation (EmitContext ec)
1356 operation.Emit (ec);
1359 public override void EmitStatement (EmitContext ec)
1361 EmitCode (ec, false);
1364 public override void FlowAnalysis (FlowAnalysisContext fc)
1366 expr.FlowAnalysis (fc);
1370 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1372 string GetOperatorExpressionTypeName ()
1374 return IsDecrement ? "Decrement" : "Increment";
1378 get { return (mode & Mode.IsDecrement) != 0; }
1382 #if NET_4_0 || MOBILE_DYNAMIC
1383 public override SLE.Expression MakeExpression (BuilderContext ctx)
1385 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1386 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1387 return SLE.Expression.Assign (target, source);
1391 public static string OperName (Mode oper)
1393 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1396 protected override void CloneTo (CloneContext clonectx, Expression t)
1398 UnaryMutator target = (UnaryMutator) t;
1400 target.expr = expr.Clone (clonectx);
1403 public override object Accept (StructuralVisitor visitor)
1405 return visitor.Visit (this);
1411 // Base class for the `is' and `as' operators
1413 public abstract class Probe : Expression
1415 public Expression ProbeType;
1416 protected Expression expr;
1417 protected TypeSpec probe_type_expr;
1419 protected Probe (Expression expr, Expression probe_type, Location l)
1421 ProbeType = probe_type;
1426 public Expression Expr {
1432 public override bool ContainsEmitWithAwait ()
1434 return expr.ContainsEmitWithAwait ();
1437 protected Expression ResolveCommon (ResolveContext rc)
1439 expr = expr.Resolve (rc);
1443 ResolveProbeType (rc);
1444 if (probe_type_expr == null)
1447 if (probe_type_expr.IsStatic) {
1448 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1449 probe_type_expr.GetSignatureForError ());
1453 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1454 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1459 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1460 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1468 protected virtual void ResolveProbeType (ResolveContext rc)
1470 probe_type_expr = ProbeType.ResolveAsType (rc);
1473 public override void EmitSideEffect (EmitContext ec)
1475 expr.EmitSideEffect (ec);
1478 public override void FlowAnalysis (FlowAnalysisContext fc)
1480 expr.FlowAnalysis (fc);
1483 protected abstract string OperatorName { get; }
1485 protected override void CloneTo (CloneContext clonectx, Expression t)
1487 Probe target = (Probe) t;
1489 target.expr = expr.Clone (clonectx);
1490 target.ProbeType = ProbeType.Clone (clonectx);
1496 /// Implementation of the `is' operator.
1498 public class Is : Probe
1500 Nullable.Unwrap expr_unwrap;
1501 MethodSpec number_mg;
1502 Arguments number_args;
1504 public Is (Expression expr, Expression probe_type, Location l)
1505 : base (expr, probe_type, l)
1509 protected override string OperatorName {
1510 get { return "is"; }
1513 public LocalVariable Variable { get; set; }
1515 public override Expression CreateExpressionTree (ResolveContext ec)
1517 if (Variable != null)
1518 throw new NotSupportedException ();
1520 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1521 expr.CreateExpressionTree (ec),
1522 new TypeOf (probe_type_expr, loc));
1524 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1527 Expression CreateConstantResult (ResolveContext rc, bool result)
1530 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1531 probe_type_expr.GetSignatureForError ());
1533 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1534 probe_type_expr.GetSignatureForError ());
1536 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1537 return expr.IsSideEffectFree ?
1538 ReducedExpression.Create (c, this) :
1539 new SideEffectConstant (c, this, loc);
1542 public override void Emit (EmitContext ec)
1544 if (probe_type_expr == null) {
1545 if (ProbeType is WildcardPattern) {
1546 expr.EmitSideEffect (ec);
1547 ProbeType.Emit (ec);
1549 EmitPatternMatch (ec);
1556 if (expr_unwrap == null) {
1558 ec.Emit (OpCodes.Cgt_Un);
1562 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1564 if (probe_type_expr == null) {
1565 EmitPatternMatch (ec);
1570 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1573 void EmitPatternMatch (EmitContext ec)
1575 var no_match = ec.DefineLabel ();
1576 var end = ec.DefineLabel ();
1578 if (expr_unwrap != null) {
1579 expr_unwrap.EmitCheck (ec);
1581 if (ProbeType.IsNull) {
1583 ec.Emit (OpCodes.Ceq);
1587 ec.Emit (OpCodes.Brfalse_S, no_match);
1588 expr_unwrap.Emit (ec);
1589 ProbeType.Emit (ec);
1590 ec.Emit (OpCodes.Ceq);
1591 ec.Emit (OpCodes.Br_S, end);
1592 ec.MarkLabel (no_match);
1598 if (number_args != null && number_args.Count == 3) {
1599 var ce = new CallEmitter ();
1600 ce.Emit (ec, number_mg, number_args, loc);
1604 var probe_type = ProbeType.Type;
1607 ec.Emit (OpCodes.Isinst, probe_type);
1608 ec.Emit (OpCodes.Dup);
1609 ec.Emit (OpCodes.Brfalse, no_match);
1611 bool complex_pattern = ProbeType is ComplexPatternExpression;
1612 Label prev = ec.RecursivePatternLabel;
1613 if (complex_pattern)
1614 ec.RecursivePatternLabel = ec.DefineLabel ();
1616 if (number_mg != null) {
1617 var ce = new CallEmitter ();
1618 ce.Emit (ec, number_mg, number_args, loc);
1620 if (TypeSpec.IsValueType (probe_type))
1621 ec.Emit (OpCodes.Unbox_Any, probe_type);
1623 ProbeType.Emit (ec);
1624 if (complex_pattern) {
1627 ec.Emit (OpCodes.Ceq);
1630 ec.Emit (OpCodes.Br_S, end);
1631 ec.MarkLabel (no_match);
1633 ec.Emit (OpCodes.Pop);
1635 if (complex_pattern)
1636 ec.MarkLabel (ec.RecursivePatternLabel);
1638 ec.RecursivePatternLabel = prev;
1644 void EmitLoad (EmitContext ec)
1646 Label no_value_label = new Label ();
1648 if (expr_unwrap != null) {
1649 expr_unwrap.EmitCheck (ec);
1651 if (Variable == null)
1654 ec.Emit (OpCodes.Dup);
1655 no_value_label = ec.DefineLabel ();
1656 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1657 expr_unwrap.Emit (ec);
1661 // Only to make verifier happy
1662 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1663 ec.Emit (OpCodes.Box, expr.Type);
1665 ec.Emit (OpCodes.Isinst, probe_type_expr);
1668 if (Variable != null) {
1669 bool value_on_stack;
1670 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1671 ec.Emit (OpCodes.Dup);
1672 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1673 value_on_stack = true;
1675 value_on_stack = false;
1678 Variable.CreateBuilder (ec);
1679 Variable.EmitAssign (ec);
1681 if (expr_unwrap != null) {
1682 ec.MarkLabel (no_value_label);
1683 } else if (!value_on_stack) {
1689 protected override Expression DoResolve (ResolveContext rc)
1691 if (ResolveCommon (rc) == null)
1694 type = rc.BuiltinTypes.Bool;
1695 eclass = ExprClass.Value;
1697 if (probe_type_expr == null)
1698 return ResolveMatchingExpression (rc);
1700 var res = ResolveResultExpression (rc);
1701 if (Variable != null) {
1702 if (res is Constant)
1703 throw new NotImplementedException ("constant in type pattern matching");
1705 Variable.Type = probe_type_expr;
1706 var bc = rc as BlockContext;
1708 Variable.PrepareAssignmentAnalysis (bc);
1714 public override void FlowAnalysis (FlowAnalysisContext fc)
1716 base.FlowAnalysis (fc);
1718 if (Variable != null)
1719 fc.SetVariableAssigned (Variable.VariableInfo, true);
1722 protected override void ResolveProbeType (ResolveContext rc)
1724 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1725 if (ProbeType is PatternExpression) {
1726 ProbeType.Resolve (rc);
1731 // Have to use session recording because we don't have reliable type probing
1732 // mechanism (similar issue as in attributes resolving)
1734 // TODO: This is still wrong because ResolveAsType can be destructive
1736 var type_printer = new SessionReportPrinter ();
1737 var prev_recorder = rc.Report.SetPrinter (type_printer);
1739 probe_type_expr = ProbeType.ResolveAsType (rc);
1740 type_printer.EndSession ();
1742 if (probe_type_expr != null) {
1743 type_printer.Merge (rc.Report.Printer);
1744 rc.Report.SetPrinter (prev_recorder);
1748 var vexpr = ProbeType as VarExpr;
1749 if (vexpr != null && vexpr.InferType (rc, expr)) {
1750 probe_type_expr = vexpr.Type;
1751 rc.Report.SetPrinter (prev_recorder);
1755 var expr_printer = new SessionReportPrinter ();
1756 rc.Report.SetPrinter (expr_printer);
1757 ProbeType = ProbeType.Resolve (rc);
1758 expr_printer.EndSession ();
1760 if (ProbeType != null) {
1761 expr_printer.Merge (rc.Report.Printer);
1763 type_printer.Merge (rc.Report.Printer);
1766 rc.Report.SetPrinter (prev_recorder);
1770 base.ResolveProbeType (rc);
1773 Expression ResolveMatchingExpression (ResolveContext rc)
1775 var mc = ProbeType as Constant;
1777 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1778 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1783 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1785 var c = Expr as Constant;
1787 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1792 if (Expr.Type.IsNullableType) {
1793 expr_unwrap = new Nullable.Unwrap (Expr);
1794 expr_unwrap.Resolve (rc);
1795 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1796 } else if (ProbeType.Type == Expr.Type) {
1797 // TODO: Better error handling
1798 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1799 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1800 var helper = rc.Module.CreatePatterMatchingHelper ();
1801 number_mg = helper.NumberMatcher.Spec;
1804 // There are actually 3 arguments but the first one is already on the stack
1806 number_args = new Arguments (3);
1807 if (!ProbeType.Type.IsEnum)
1808 number_args.Add (new Argument (Expr));
1810 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1811 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1817 if (ProbeType is PatternExpression) {
1818 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1819 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1825 // TODO: Better error message
1826 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1830 Expression ResolveResultExpression (ResolveContext ec)
1832 TypeSpec d = expr.Type;
1833 bool d_is_nullable = false;
1836 // If E is a method group or the null literal, or if the type of E is a reference
1837 // type or a nullable type and the value of E is null, the result is false
1839 if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
1840 return CreateConstantResult (ec, false);
1842 if (d.IsNullableType) {
1843 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1844 if (!ut.IsGenericParameter) {
1846 d_is_nullable = true;
1850 TypeSpec t = probe_type_expr;
1851 bool t_is_nullable = false;
1852 if (t.IsNullableType) {
1853 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1854 if (!ut.IsGenericParameter) {
1856 t_is_nullable = true;
1863 // D and T are the same value types but D can be null
1865 if (d_is_nullable && !t_is_nullable) {
1866 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1871 // The result is true if D and T are the same value types
1873 return CreateConstantResult (ec, true);
1876 var tp = d as TypeParameterSpec;
1878 return ResolveGenericParameter (ec, t, tp);
1881 // An unboxing conversion exists
1883 if (Convert.ExplicitReferenceConversionExists (d, t))
1887 // open generic type
1889 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1892 var tps = t as TypeParameterSpec;
1894 return ResolveGenericParameter (ec, d, tps);
1896 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1897 ec.Report.Warning (1981, 3, loc,
1898 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1899 OperatorName, t.GetSignatureForError ());
1902 if (TypeManager.IsGenericParameter (d))
1903 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1905 if (TypeSpec.IsValueType (d)) {
1906 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1907 if (d_is_nullable && !t_is_nullable) {
1908 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1912 return CreateConstantResult (ec, true);
1915 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1916 var c = expr as Constant;
1918 return CreateConstantResult (ec, !c.IsNull);
1921 // Do not optimize for imported type or dynamic type
1923 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1924 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
1928 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
1932 // Turn is check into simple null check for implicitly convertible reference types
1934 return ReducedExpression.Create (
1935 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
1939 if (Convert.ExplicitReferenceConversionExists (d, t))
1943 // open generic type
1945 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
1950 return CreateConstantResult (ec, false);
1953 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
1955 if (t.IsReferenceType) {
1957 return CreateConstantResult (ec, false);
1960 if (expr.Type.IsGenericParameter) {
1961 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
1962 return CreateConstantResult (ec, true);
1964 expr = new BoxedCast (expr, d);
1970 public override object Accept (StructuralVisitor visitor)
1972 return visitor.Visit (this);
1976 class WildcardPattern : PatternExpression
1978 public WildcardPattern (Location loc)
1983 protected override Expression DoResolve (ResolveContext rc)
1985 eclass = ExprClass.Value;
1986 type = rc.BuiltinTypes.Object;
1990 public override void Emit (EmitContext ec)
1996 class RecursivePattern : ComplexPatternExpression
1998 MethodGroupExpr operator_mg;
1999 Arguments operator_args;
2001 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2002 : base (typeExpresion, loc)
2004 Arguments = arguments;
2007 public Arguments Arguments { get; private set; }
2009 protected override Expression DoResolve (ResolveContext rc)
2011 type = TypeExpression.ResolveAsType (rc);
2015 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2016 if (operators == null) {
2017 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2021 var ops = FindMatchingOverloads (operators);
2023 // TODO: better error message
2024 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2029 Arguments.Resolve (rc, out dynamic_args);
2031 throw new NotImplementedException ("dynamic argument");
2033 var op = FindBestOverload (rc, ops);
2035 // TODO: better error message
2036 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2040 var op_types = op.Parameters.Types;
2041 operator_args = new Arguments (op_types.Length);
2042 operator_args.Add (new Argument (new EmptyExpression (type)));
2044 for (int i = 0; i < Arguments.Count; ++i) {
2045 // TODO: Needs releasing optimization
2046 var lt = new LocalTemporary (op_types [i + 1]);
2047 operator_args.Add (new Argument (lt, Argument.AType.Out));
2049 if (comparisons == null)
2050 comparisons = new Expression[Arguments.Count];
2055 var arg = Arguments [i];
2056 var named = arg as NamedArgument;
2057 if (named != null) {
2058 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2059 expr = Arguments [arg_comp_index].Expr;
2065 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2068 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2070 eclass = ExprClass.Value;
2074 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2076 int arg_count = Arguments.Count + 1;
2077 List<MethodSpec> best = null;
2078 foreach (MethodSpec method in members) {
2079 var pm = method.Parameters;
2080 if (pm.Count != arg_count)
2083 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2085 for (int ii = 1; ii < pm.Count; ++ii) {
2086 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2096 best = new List<MethodSpec> ();
2104 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2106 for (int ii = 0; ii < Arguments.Count; ++ii) {
2107 var arg = Arguments [ii];
2108 var expr = arg.Expr;
2109 if (expr is WildcardPattern)
2112 var na = arg as NamedArgument;
2113 for (int i = 0; i < methods.Count; ++i) {
2114 var pd = methods [i].Parameters;
2118 index = pd.GetParameterIndexByName (na.Name);
2120 methods.RemoveAt (i--);
2127 var m = pd.Types [index];
2128 if (!Convert.ImplicitConversionExists (rc, expr, m))
2129 methods.RemoveAt (i--);
2133 if (methods.Count != 1)
2139 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2141 operator_mg.EmitCall (ec, operator_args, false);
2142 ec.Emit (OpCodes.Brfalse, target);
2144 base.EmitBranchable (ec, target, on_true);
2147 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2149 if (expr is WildcardPattern)
2150 return new EmptyExpression (expr.Type);
2152 var recursive = expr as RecursivePattern;
2153 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2157 if (recursive != null) {
2158 recursive.SetParentInstance (lt);
2162 // TODO: Better error handling
2163 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2166 public void SetParentInstance (Expression instance)
2168 operator_args [0] = new Argument (instance);
2172 class PropertyPattern : ComplexPatternExpression
2174 LocalTemporary instance;
2176 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2177 : base (typeExpresion, loc)
2182 public List<PropertyPatternMember> Members { get; private set; }
2184 protected override Expression DoResolve (ResolveContext rc)
2186 type = TypeExpression.ResolveAsType (rc);
2190 comparisons = new Expression[Members.Count];
2192 // TODO: optimize when source is VariableReference, it'd save dup+pop
2193 instance = new LocalTemporary (type);
2195 for (int i = 0; i < Members.Count; i++) {
2196 var lookup = Members [i];
2198 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2199 if (member == null) {
2200 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2201 if (member != null) {
2202 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2207 if (member == null) {
2208 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2212 var pe = member as PropertyExpr;
2213 if (pe == null || member is FieldExpr) {
2214 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2218 // TODO: Obsolete checks
2219 // TODO: check accessibility
2220 if (pe != null && !pe.PropertyInfo.HasGet) {
2221 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2225 var expr = lookup.Expr.Resolve (rc);
2229 var me = (MemberExpr)member;
2230 me.InstanceExpression = instance;
2232 comparisons [i] = ResolveComparison (rc, expr, me);
2235 eclass = ExprClass.Value;
2239 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2241 if (expr is WildcardPattern)
2242 return new EmptyExpression (expr.Type);
2244 return new Is (instance, expr, expr.Location).Resolve (rc);
2247 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2249 instance.Store (ec);
2251 base.EmitBranchable (ec, target, on_true);
2255 class PropertyPatternMember
2257 public PropertyPatternMember (string name, Expression expr, Location loc)
2264 public string Name { get; private set; }
2265 public Expression Expr { get; private set; }
2266 public Location Location { get; private set; }
2269 abstract class PatternExpression : Expression
2271 protected PatternExpression (Location loc)
2276 public override Expression CreateExpressionTree (ResolveContext ec)
2278 throw new NotImplementedException ();
2282 abstract class ComplexPatternExpression : PatternExpression
2284 protected Expression[] comparisons;
2286 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2289 TypeExpression = typeExpresion;
2292 public ATypeNameExpression TypeExpression { get; private set; }
2294 public override void Emit (EmitContext ec)
2296 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2299 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2301 if (comparisons != null) {
2302 foreach (var comp in comparisons) {
2303 comp.EmitBranchable (ec, target, false);
2310 /// Implementation of the `as' operator.
2312 public class As : Probe {
2314 public As (Expression expr, Expression probe_type, Location l)
2315 : base (expr, probe_type, l)
2319 protected override string OperatorName {
2320 get { return "as"; }
2323 public override Expression CreateExpressionTree (ResolveContext ec)
2325 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2326 expr.CreateExpressionTree (ec),
2327 new TypeOf (probe_type_expr, loc));
2329 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2332 public override void Emit (EmitContext ec)
2336 ec.Emit (OpCodes.Isinst, type);
2338 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2339 ec.Emit (OpCodes.Unbox_Any, type);
2342 protected override Expression DoResolve (ResolveContext ec)
2344 if (ResolveCommon (ec) == null)
2347 type = probe_type_expr;
2348 eclass = ExprClass.Value;
2349 TypeSpec etype = expr.Type;
2351 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2352 if (TypeManager.IsGenericParameter (type)) {
2353 ec.Report.Error (413, loc,
2354 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2355 probe_type_expr.GetSignatureForError ());
2357 ec.Report.Error (77, loc,
2358 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2359 type.GetSignatureForError ());
2364 if (expr.IsNull && type.IsNullableType) {
2365 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2368 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2369 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2373 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2375 e = EmptyCast.Create (e, type);
2376 return ReducedExpression.Create (e, this).Resolve (ec);
2379 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2380 if (TypeManager.IsGenericParameter (etype))
2381 expr = new BoxedCast (expr, etype);
2386 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2387 expr = new BoxedCast (expr, etype);
2391 if (etype != InternalType.ErrorType) {
2392 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2393 etype.GetSignatureForError (), type.GetSignatureForError ());
2399 public override object Accept (StructuralVisitor visitor)
2401 return visitor.Visit (this);
2406 // This represents a typecast in the source language.
2408 public class Cast : ShimExpression {
2409 Expression target_type;
2411 public Cast (Expression cast_type, Expression expr, Location loc)
2414 this.target_type = cast_type;
2418 public Expression TargetType {
2419 get { return target_type; }
2422 protected override Expression DoResolve (ResolveContext ec)
2424 expr = expr.Resolve (ec);
2428 type = target_type.ResolveAsType (ec);
2432 if (type.IsStatic) {
2433 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2437 if (type.IsPointer && !ec.IsUnsafe) {
2438 UnsafeError (ec, loc);
2441 eclass = ExprClass.Value;
2443 Constant c = expr as Constant;
2445 c = c.Reduce (ec, type);
2450 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2452 return EmptyCast.Create (res, type);
2457 protected override void CloneTo (CloneContext clonectx, Expression t)
2459 Cast target = (Cast) t;
2461 target.target_type = target_type.Clone (clonectx);
2462 target.expr = expr.Clone (clonectx);
2465 public override object Accept (StructuralVisitor visitor)
2467 return visitor.Visit (this);
2471 public class ImplicitCast : ShimExpression
2475 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2478 this.loc = expr.Location;
2480 this.arrayAccess = arrayAccess;
2483 protected override Expression DoResolve (ResolveContext ec)
2485 expr = expr.Resolve (ec);
2490 expr = ConvertExpressionToArrayIndex (ec, expr);
2492 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2498 public class DeclarationExpression : Expression, IMemoryLocation
2500 LocalVariableReference lvr;
2502 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2504 VariableType = variableType;
2505 Variable = variable;
2506 this.loc = variable.Location;
2509 public LocalVariable Variable { get; set; }
2510 public Expression Initializer { get; set; }
2511 public FullNamedExpression VariableType { get; set; }
2513 public void AddressOf (EmitContext ec, AddressOp mode)
2515 Variable.CreateBuilder (ec);
2517 if (Initializer != null) {
2518 lvr.EmitAssign (ec, Initializer, false, false);
2521 lvr.AddressOf (ec, mode);
2524 protected override void CloneTo (CloneContext clonectx, Expression t)
2526 var target = (DeclarationExpression) t;
2528 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2530 if (Initializer != null)
2531 target.Initializer = Initializer.Clone (clonectx);
2534 public override Expression CreateExpressionTree (ResolveContext rc)
2536 rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
2540 bool DoResolveCommon (ResolveContext rc)
2542 var var_expr = VariableType as VarExpr;
2543 if (var_expr != null) {
2544 type = InternalType.VarOutType;
2546 type = VariableType.ResolveAsType (rc);
2551 if (Initializer != null) {
2552 Initializer = Initializer.Resolve (rc);
2554 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2555 type = var_expr.Type;
2559 Variable.Type = type;
2560 lvr = new LocalVariableReference (Variable, loc);
2562 eclass = ExprClass.Variable;
2566 protected override Expression DoResolve (ResolveContext rc)
2568 if (DoResolveCommon (rc))
2574 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2576 if (lvr == null && DoResolveCommon (rc))
2577 lvr.ResolveLValue (rc, right_side);
2582 public override void Emit (EmitContext ec)
2584 throw new NotImplementedException ();
2589 // C# 2.0 Default value expression
2591 public class DefaultValueExpression : Expression
2595 public DefaultValueExpression (Expression expr, Location loc)
2601 public Expression Expr {
2607 public override bool IsSideEffectFree {
2613 public override bool ContainsEmitWithAwait ()
2618 public override Expression CreateExpressionTree (ResolveContext ec)
2620 Arguments args = new Arguments (2);
2621 args.Add (new Argument (this));
2622 args.Add (new Argument (new TypeOf (type, loc)));
2623 return CreateExpressionFactoryCall (ec, "Constant", args);
2626 protected override Expression DoResolve (ResolveContext ec)
2628 type = expr.ResolveAsType (ec);
2632 if (type.IsStatic) {
2633 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2637 return new NullLiteral (Location).ConvertImplicitly (type);
2639 if (TypeSpec.IsReferenceType (type))
2640 return new NullConstant (type, loc);
2642 Constant c = New.Constantify (type, expr.Location);
2646 eclass = ExprClass.Variable;
2650 public override void Emit (EmitContext ec)
2652 LocalTemporary temp_storage = new LocalTemporary(type);
2654 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2655 ec.Emit(OpCodes.Initobj, type);
2656 temp_storage.Emit(ec);
2657 temp_storage.Release (ec);
2660 #if (NET_4_0 || MOBILE_DYNAMIC) && !STATIC
2661 public override SLE.Expression MakeExpression (BuilderContext ctx)
2663 return SLE.Expression.Default (type.GetMetaInfo ());
2667 protected override void CloneTo (CloneContext clonectx, Expression t)
2669 DefaultValueExpression target = (DefaultValueExpression) t;
2671 target.expr = expr.Clone (clonectx);
2674 public override object Accept (StructuralVisitor visitor)
2676 return visitor.Visit (this);
2681 /// Binary operators
2683 public class Binary : Expression, IDynamicBinder
2685 public class PredefinedOperator
2687 protected readonly TypeSpec left;
2688 protected readonly TypeSpec right;
2689 protected readonly TypeSpec left_unwrap;
2690 protected readonly TypeSpec right_unwrap;
2691 public readonly Operator OperatorsMask;
2692 public TypeSpec ReturnType;
2694 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2695 : this (ltype, rtype, op_mask, ltype)
2699 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2700 : this (type, type, op_mask, return_type)
2704 public PredefinedOperator (TypeSpec type, Operator op_mask)
2705 : this (type, type, op_mask, type)
2709 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2711 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2712 throw new InternalErrorException ("Only masked values can be used");
2714 if ((op_mask & Operator.NullableMask) != 0) {
2715 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2716 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2718 left_unwrap = ltype;
2719 right_unwrap = rtype;
2724 this.OperatorsMask = op_mask;
2725 this.ReturnType = return_type;
2728 public bool IsLifted {
2730 return (OperatorsMask & Operator.NullableMask) != 0;
2734 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2738 var left_expr = b.left;
2739 var right_expr = b.right;
2741 b.type = ReturnType;
2744 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2745 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2746 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2749 if (right_expr.IsNull) {
2750 if ((b.oper & Operator.EqualityMask) != 0) {
2751 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2752 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2753 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2754 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2755 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2757 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2758 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2760 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2761 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2763 return b.CreateLiftedValueTypeResult (rc, left);
2765 } else if (left_expr.IsNull) {
2766 if ((b.oper & Operator.EqualityMask) != 0) {
2767 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2768 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2769 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2770 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2771 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2773 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2774 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2776 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2777 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2779 return b.CreateLiftedValueTypeResult (rc, right);
2785 // A user operators does not support multiple user conversions, but decimal type
2786 // is considered to be predefined type therefore we apply predefined operators rules
2787 // and then look for decimal user-operator implementation
2789 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2790 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2791 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2793 return b.ResolveUserOperator (rc, b.left, b.right);
2796 c = right_expr as Constant;
2798 if (c.IsDefaultValue) {
2802 // (expr + 0) to expr
2803 // (expr - 0) to expr
2804 // (bool? | false) to bool?
2806 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2807 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2808 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2809 return ReducedExpression.Create (b.left, b).Resolve (rc);
2813 // Optimizes (value &/&& 0) to 0
2815 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2816 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2817 return ReducedExpression.Create (side_effect, b);
2821 // Optimizes (bool? & true) to bool?
2823 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2824 return ReducedExpression.Create (b.left, b).Resolve (rc);
2828 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2829 return ReducedExpression.Create (b.left, b).Resolve (rc);
2831 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2832 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2836 c = b.left as Constant;
2838 if (c.IsDefaultValue) {
2842 // (0 + expr) to expr
2843 // (false | bool?) to bool?
2845 if (b.oper == Operator.Addition ||
2846 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2847 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2848 return ReducedExpression.Create (b.right, b).Resolve (rc);
2852 // Optimizes (false && expr) to false
2854 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2855 // No rhs side-effects
2856 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2857 return ReducedExpression.Create (c, b);
2861 // Optimizes (0 & value) to 0
2863 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2864 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2865 return ReducedExpression.Create (side_effect, b);
2869 // Optimizes (true & bool?) to bool?
2871 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2872 return ReducedExpression.Create (b.right, b).Resolve (rc);
2876 // Optimizes (true || expr) to true
2878 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2879 // No rhs side-effects
2880 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2881 return ReducedExpression.Create (c, b);
2885 if (b.oper == Operator.Multiply && c.IsOneInteger)
2886 return ReducedExpression.Create (b.right, b).Resolve (rc);
2890 var lifted = new Nullable.LiftedBinaryOperator (b);
2892 TypeSpec ltype, rtype;
2893 if (b.left.Type.IsNullableType) {
2894 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2895 ltype = left_unwrap;
2900 if (b.right.Type.IsNullableType) {
2901 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2902 rtype = right_unwrap;
2907 lifted.Left = b.left.IsNull ?
2909 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
2911 lifted.Right = b.right.IsNull ?
2913 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
2915 return lifted.Resolve (rc);
2918 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2919 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2924 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
2927 // We are dealing with primitive types only
2929 return left == ltype && ltype == rtype;
2932 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
2935 if (left == lexpr.Type && right == rexpr.Type)
2938 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
2939 Convert.ImplicitConversionExists (ec, rexpr, right);
2942 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
2944 if ((OperatorsMask & Operator.DecomposedMask) != 0)
2945 return best_operator;
2947 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
2951 if (left != null && best_operator.left != null) {
2952 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
2956 // When second argument is same as the first one, the result is same
2958 if (right != null && (left != right || best_operator.left != best_operator.right)) {
2959 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
2962 if (result == 0 || result > 2)
2965 return result == 1 ? best_operator : this;
2969 sealed class PredefinedStringOperator : PredefinedOperator
2971 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
2972 : base (type, type, op_mask, retType)
2976 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
2977 : base (ltype, rtype, op_mask, retType)
2981 public override Expression ConvertResult (ResolveContext ec, Binary b)
2984 // Use original expression for nullable arguments
2986 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
2988 b.left = unwrap.Original;
2990 unwrap = b.right as Nullable.Unwrap;
2992 b.right = unwrap.Original;
2994 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
2995 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
2998 // Start a new concat expression using converted expression
3000 return StringConcat.Create (ec, b.left, b.right, b.loc);
3004 sealed class PredefinedEqualityOperator : PredefinedOperator
3006 MethodSpec equal_method, inequal_method;
3008 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3009 : base (arg, arg, Operator.EqualityMask, retType)
3013 public override Expression ConvertResult (ResolveContext ec, Binary b)
3015 b.type = ReturnType;
3017 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3018 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3020 Arguments args = new Arguments (2);
3021 args.Add (new Argument (b.left));
3022 args.Add (new Argument (b.right));
3025 if (b.oper == Operator.Equality) {
3026 if (equal_method == null) {
3027 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3028 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3029 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3030 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3032 throw new NotImplementedException (left.GetSignatureForError ());
3035 method = equal_method;
3037 if (inequal_method == null) {
3038 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3039 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3040 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3041 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3043 throw new NotImplementedException (left.GetSignatureForError ());
3046 method = inequal_method;
3049 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3053 class PredefinedPointerOperator : PredefinedOperator
3055 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3056 : base (ltype, rtype, op_mask)
3060 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3061 : base (ltype, rtype, op_mask, retType)
3065 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3066 : base (type, op_mask, return_type)
3070 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3073 if (!lexpr.Type.IsPointer)
3076 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3080 if (right == null) {
3081 if (!rexpr.Type.IsPointer)
3084 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3091 public override Expression ConvertResult (ResolveContext ec, Binary b)
3094 b.left = EmptyCast.Create (b.left, left);
3095 } else if (right != null) {
3096 b.right = EmptyCast.Create (b.right, right);
3099 TypeSpec r_type = ReturnType;
3100 Expression left_arg, right_arg;
3101 if (r_type == null) {
3104 right_arg = b.right;
3105 r_type = b.left.Type;
3109 r_type = b.right.Type;
3113 right_arg = b.right;
3116 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3121 public enum Operator {
3122 Multiply = 0 | ArithmeticMask,
3123 Division = 1 | ArithmeticMask,
3124 Modulus = 2 | ArithmeticMask,
3125 Addition = 3 | ArithmeticMask | AdditionMask,
3126 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3128 LeftShift = 5 | ShiftMask,
3129 RightShift = 6 | ShiftMask,
3131 LessThan = 7 | ComparisonMask | RelationalMask,
3132 GreaterThan = 8 | ComparisonMask | RelationalMask,
3133 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3134 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3135 Equality = 11 | ComparisonMask | EqualityMask,
3136 Inequality = 12 | ComparisonMask | EqualityMask,
3138 BitwiseAnd = 13 | BitwiseMask,
3139 ExclusiveOr = 14 | BitwiseMask,
3140 BitwiseOr = 15 | BitwiseMask,
3142 LogicalAnd = 16 | LogicalMask,
3143 LogicalOr = 17 | LogicalMask,
3148 ValuesOnlyMask = ArithmeticMask - 1,
3149 ArithmeticMask = 1 << 5,
3151 ComparisonMask = 1 << 7,
3152 EqualityMask = 1 << 8,
3153 BitwiseMask = 1 << 9,
3154 LogicalMask = 1 << 10,
3155 AdditionMask = 1 << 11,
3156 SubtractionMask = 1 << 12,
3157 RelationalMask = 1 << 13,
3159 DecomposedMask = 1 << 19,
3160 NullableMask = 1 << 20,
3170 readonly Operator oper;
3171 Expression left, right;
3173 ConvCast.Mode enum_conversion;
3175 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3176 : this (oper, left, right)
3179 state |= State.Compound;
3182 public Binary (Operator oper, Expression left, Expression right)
3183 : this (oper, left, right, left.Location)
3187 public Binary (Operator oper, Expression left, Expression right, Location loc)
3197 public bool IsCompound {
3199 return (state & State.Compound) != 0;
3203 public Operator Oper {
3209 public Expression Left {
3215 public Expression Right {
3221 public override Location StartLocation {
3223 return left.StartLocation;
3230 /// Returns a stringified representation of the Operator
3232 string OperName (Operator oper)
3236 case Operator.Multiply:
3239 case Operator.Division:
3242 case Operator.Modulus:
3245 case Operator.Addition:
3248 case Operator.Subtraction:
3251 case Operator.LeftShift:
3254 case Operator.RightShift:
3257 case Operator.LessThan:
3260 case Operator.GreaterThan:
3263 case Operator.LessThanOrEqual:
3266 case Operator.GreaterThanOrEqual:
3269 case Operator.Equality:
3272 case Operator.Inequality:
3275 case Operator.BitwiseAnd:
3278 case Operator.BitwiseOr:
3281 case Operator.ExclusiveOr:
3284 case Operator.LogicalOr:
3287 case Operator.LogicalAnd:
3291 s = oper.ToString ();
3301 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3303 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3306 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3308 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3312 l = left.Type.GetSignatureForError ();
3313 r = right.Type.GetSignatureForError ();
3315 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3319 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3321 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3324 public override void FlowAnalysis (FlowAnalysisContext fc)
3327 // Optimized version when on-true/on-false data are not needed
3329 if ((oper & Operator.LogicalMask) == 0) {
3330 left.FlowAnalysis (fc);
3331 right.FlowAnalysis (fc);
3335 left.FlowAnalysisConditional (fc);
3336 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3337 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3339 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3340 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3341 right.FlowAnalysisConditional (fc);
3343 if (oper == Operator.LogicalOr)
3344 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3346 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3349 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3351 if ((oper & Operator.LogicalMask) == 0) {
3352 base.FlowAnalysisConditional (fc);
3356 left.FlowAnalysisConditional (fc);
3357 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3358 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3360 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3361 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3362 right.FlowAnalysisConditional (fc);
3364 var lc = left as Constant;
3365 if (oper == Operator.LogicalOr) {
3366 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3367 if (lc != null && lc.IsDefaultValue)
3368 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3370 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3372 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3373 if (lc != null && !lc.IsDefaultValue)
3374 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3376 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3381 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3383 string GetOperatorExpressionTypeName ()
3386 case Operator.Addition:
3387 return IsCompound ? "AddAssign" : "Add";
3388 case Operator.BitwiseAnd:
3389 return IsCompound ? "AndAssign" : "And";
3390 case Operator.BitwiseOr:
3391 return IsCompound ? "OrAssign" : "Or";
3392 case Operator.Division:
3393 return IsCompound ? "DivideAssign" : "Divide";
3394 case Operator.ExclusiveOr:
3395 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3396 case Operator.Equality:
3398 case Operator.GreaterThan:
3399 return "GreaterThan";
3400 case Operator.GreaterThanOrEqual:
3401 return "GreaterThanOrEqual";
3402 case Operator.Inequality:
3404 case Operator.LeftShift:
3405 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3406 case Operator.LessThan:
3408 case Operator.LessThanOrEqual:
3409 return "LessThanOrEqual";
3410 case Operator.LogicalAnd:
3412 case Operator.LogicalOr:
3414 case Operator.Modulus:
3415 return IsCompound ? "ModuloAssign" : "Modulo";
3416 case Operator.Multiply:
3417 return IsCompound ? "MultiplyAssign" : "Multiply";
3418 case Operator.RightShift:
3419 return IsCompound ? "RightShiftAssign" : "RightShift";
3420 case Operator.Subtraction:
3421 return IsCompound ? "SubtractAssign" : "Subtract";
3423 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3427 static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3430 case Operator.Addition:
3431 return CSharp.Operator.OpType.Addition;
3432 case Operator.BitwiseAnd:
3433 case Operator.LogicalAnd:
3434 return CSharp.Operator.OpType.BitwiseAnd;
3435 case Operator.BitwiseOr:
3436 case Operator.LogicalOr:
3437 return CSharp.Operator.OpType.BitwiseOr;
3438 case Operator.Division:
3439 return CSharp.Operator.OpType.Division;
3440 case Operator.Equality:
3441 return CSharp.Operator.OpType.Equality;
3442 case Operator.ExclusiveOr:
3443 return CSharp.Operator.OpType.ExclusiveOr;
3444 case Operator.GreaterThan:
3445 return CSharp.Operator.OpType.GreaterThan;
3446 case Operator.GreaterThanOrEqual:
3447 return CSharp.Operator.OpType.GreaterThanOrEqual;
3448 case Operator.Inequality:
3449 return CSharp.Operator.OpType.Inequality;
3450 case Operator.LeftShift:
3451 return CSharp.Operator.OpType.LeftShift;
3452 case Operator.LessThan:
3453 return CSharp.Operator.OpType.LessThan;
3454 case Operator.LessThanOrEqual:
3455 return CSharp.Operator.OpType.LessThanOrEqual;
3456 case Operator.Modulus:
3457 return CSharp.Operator.OpType.Modulus;
3458 case Operator.Multiply:
3459 return CSharp.Operator.OpType.Multiply;
3460 case Operator.RightShift:
3461 return CSharp.Operator.OpType.RightShift;
3462 case Operator.Subtraction:
3463 return CSharp.Operator.OpType.Subtraction;
3465 throw new InternalErrorException (op.ToString ());
3469 public override bool ContainsEmitWithAwait ()
3471 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3474 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3479 case Operator.Multiply:
3480 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3481 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3482 opcode = OpCodes.Mul_Ovf;
3483 else if (!IsFloat (l))
3484 opcode = OpCodes.Mul_Ovf_Un;
3486 opcode = OpCodes.Mul;
3488 opcode = OpCodes.Mul;
3492 case Operator.Division:
3494 opcode = OpCodes.Div_Un;
3496 opcode = OpCodes.Div;
3499 case Operator.Modulus:
3501 opcode = OpCodes.Rem_Un;
3503 opcode = OpCodes.Rem;
3506 case Operator.Addition:
3507 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3508 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3509 opcode = OpCodes.Add_Ovf;
3510 else if (!IsFloat (l))
3511 opcode = OpCodes.Add_Ovf_Un;
3513 opcode = OpCodes.Add;
3515 opcode = OpCodes.Add;
3518 case Operator.Subtraction:
3519 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3520 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3521 opcode = OpCodes.Sub_Ovf;
3522 else if (!IsFloat (l))
3523 opcode = OpCodes.Sub_Ovf_Un;
3525 opcode = OpCodes.Sub;
3527 opcode = OpCodes.Sub;
3530 case Operator.RightShift:
3531 if (!(right is IntConstant)) {
3532 ec.EmitInt (GetShiftMask (l));
3533 ec.Emit (OpCodes.And);
3537 opcode = OpCodes.Shr_Un;
3539 opcode = OpCodes.Shr;
3542 case Operator.LeftShift:
3543 if (!(right is IntConstant)) {
3544 ec.EmitInt (GetShiftMask (l));
3545 ec.Emit (OpCodes.And);
3548 opcode = OpCodes.Shl;
3551 case Operator.Equality:
3552 opcode = OpCodes.Ceq;
3555 case Operator.Inequality:
3556 ec.Emit (OpCodes.Ceq);
3559 opcode = OpCodes.Ceq;
3562 case Operator.LessThan:
3564 opcode = OpCodes.Clt_Un;
3566 opcode = OpCodes.Clt;
3569 case Operator.GreaterThan:
3571 opcode = OpCodes.Cgt_Un;
3573 opcode = OpCodes.Cgt;
3576 case Operator.LessThanOrEqual:
3577 if (IsUnsigned (l) || IsFloat (l))
3578 ec.Emit (OpCodes.Cgt_Un);
3580 ec.Emit (OpCodes.Cgt);
3583 opcode = OpCodes.Ceq;
3586 case Operator.GreaterThanOrEqual:
3587 if (IsUnsigned (l) || IsFloat (l))
3588 ec.Emit (OpCodes.Clt_Un);
3590 ec.Emit (OpCodes.Clt);
3594 opcode = OpCodes.Ceq;
3597 case Operator.BitwiseOr:
3598 opcode = OpCodes.Or;
3601 case Operator.BitwiseAnd:
3602 opcode = OpCodes.And;
3605 case Operator.ExclusiveOr:
3606 opcode = OpCodes.Xor;
3610 throw new InternalErrorException (oper.ToString ());
3616 static int GetShiftMask (TypeSpec type)
3618 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3621 static bool IsUnsigned (TypeSpec t)
3623 switch (t.BuiltinType) {
3624 case BuiltinTypeSpec.Type.Char:
3625 case BuiltinTypeSpec.Type.UInt:
3626 case BuiltinTypeSpec.Type.ULong:
3627 case BuiltinTypeSpec.Type.UShort:
3628 case BuiltinTypeSpec.Type.Byte:
3635 static bool IsFloat (TypeSpec t)
3637 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3640 public Expression ResolveOperator (ResolveContext rc)
3642 eclass = ExprClass.Value;
3644 TypeSpec l = left.Type;
3645 TypeSpec r = right.Type;
3647 bool primitives_only = false;
3650 // Handles predefined primitive types
3652 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3653 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3654 if ((oper & Operator.ShiftMask) == 0) {
3655 if (!DoBinaryOperatorPromotion (rc))
3658 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3662 if (l.IsPointer || r.IsPointer)
3663 return ResolveOperatorPointer (rc, l, r);
3666 expr = ResolveUserOperator (rc, left, right);
3671 bool lenum = l.IsEnum;
3672 bool renum = r.IsEnum;
3673 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3677 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3678 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3683 if ((oper & Operator.BitwiseMask) != 0) {
3684 expr = EmptyCast.Create (expr, type);
3685 enum_conversion = GetEnumResultCast (type);
3687 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3688 expr = OptimizeAndOperation (expr);
3692 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3693 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3696 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3697 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3701 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3704 // We cannot break here there is also Enum + String possible match
3705 // which is not ambiguous with predefined enum operators
3708 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3709 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3713 } else if (l.IsDelegate || r.IsDelegate) {
3717 expr = ResolveOperatorDelegate (rc, l, r);
3719 // TODO: Can this be ambiguous
3727 // Equality operators are more complicated
3729 if ((oper & Operator.EqualityMask) != 0) {
3730 return ResolveEquality (rc, l, r, primitives_only);
3733 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3737 if (primitives_only)
3741 // Lifted operators have lower priority
3743 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3746 static bool IsEnumOrNullableEnum (TypeSpec type)
3748 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3752 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3753 // if 'left' is not an enumeration constant, create one from the type of 'right'
3754 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3757 case Operator.BitwiseOr:
3758 case Operator.BitwiseAnd:
3759 case Operator.ExclusiveOr:
3760 case Operator.Equality:
3761 case Operator.Inequality:
3762 case Operator.LessThan:
3763 case Operator.LessThanOrEqual:
3764 case Operator.GreaterThan:
3765 case Operator.GreaterThanOrEqual:
3766 if (left.Type.IsEnum)
3769 if (left.IsZeroInteger)
3770 return left.Reduce (ec, right.Type);
3774 case Operator.Addition:
3775 case Operator.Subtraction:
3778 case Operator.Multiply:
3779 case Operator.Division:
3780 case Operator.Modulus:
3781 case Operator.LeftShift:
3782 case Operator.RightShift:
3783 if (right.Type.IsEnum || left.Type.IsEnum)
3792 // The `|' operator used on types which were extended is dangerous
3794 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3796 OpcodeCast lcast = left as OpcodeCast;
3797 if (lcast != null) {
3798 if (IsUnsigned (lcast.UnderlyingType))
3802 OpcodeCast rcast = right as OpcodeCast;
3803 if (rcast != null) {
3804 if (IsUnsigned (rcast.UnderlyingType))
3808 if (lcast == null && rcast == null)
3811 // FIXME: consider constants
3813 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3814 ec.Report.Warning (675, 3, loc,
3815 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3816 ltype.GetSignatureForError ());
3819 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3821 return new PredefinedOperator[] {
3823 // Pointer arithmetic:
3825 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3826 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3827 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3828 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3830 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3831 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3832 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3833 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3836 // T* operator + (int y, T* x);
3837 // T* operator + (uint y, T *x);
3838 // T* operator + (long y, T *x);
3839 // T* operator + (ulong y, T *x);
3841 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3842 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3843 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3844 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3847 // long operator - (T* x, T *y)
3849 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3853 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3855 TypeSpec bool_type = types.Bool;
3858 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3859 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3860 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3861 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3862 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3863 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3864 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3866 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3867 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3868 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3869 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3870 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3871 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3872 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3874 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3875 // Remaining string operators are in lifted tables
3877 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3879 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3880 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3881 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3885 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3887 var types = module.Compiler.BuiltinTypes;
3890 // Not strictly lifted but need to be in second group otherwise expressions like
3891 // int + null would resolve to +(object, string) instead of +(int?, int?)
3893 var string_operators = new [] {
3894 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3895 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3898 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3899 if (nullable == null)
3900 return string_operators;
3902 var bool_type = types.Bool;
3904 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
3905 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3906 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3907 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3908 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3909 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3910 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3911 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3914 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3915 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3916 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3917 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
3918 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
3919 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
3920 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
3922 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3923 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3924 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3925 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3926 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3927 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3928 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
3930 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
3932 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3933 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3934 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
3936 string_operators [0],
3937 string_operators [1]
3941 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
3943 TypeSpec bool_type = types.Bool;
3946 new PredefinedEqualityOperator (types.String, bool_type),
3947 new PredefinedEqualityOperator (types.Delegate, bool_type),
3948 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
3949 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
3950 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
3951 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
3952 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
3953 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
3954 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
3955 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
3959 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
3961 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3963 if (nullable == null)
3964 return new PredefinedOperator [0];
3966 var types = module.Compiler.BuiltinTypes;
3967 var bool_type = types.Bool;
3968 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
3969 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
3970 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
3971 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
3972 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
3973 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
3974 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
3975 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
3978 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
3979 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
3980 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
3981 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
3982 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
3983 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
3984 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
3985 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
3990 // 7.2.6.2 Binary numeric promotions
3992 bool DoBinaryOperatorPromotion (ResolveContext rc)
3994 TypeSpec ltype = left.Type;
3995 if (ltype.IsNullableType) {
3996 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4000 // This is numeric promotion code only
4002 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4005 TypeSpec rtype = right.Type;
4006 if (rtype.IsNullableType) {
4007 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4010 var lb = ltype.BuiltinType;
4011 var rb = rtype.BuiltinType;
4015 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4016 type = rc.BuiltinTypes.Decimal;
4017 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4018 type = rc.BuiltinTypes.Double;
4019 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4020 type = rc.BuiltinTypes.Float;
4021 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4022 type = rc.BuiltinTypes.ULong;
4024 if (IsSignedType (lb)) {
4025 expr = ConvertSignedConstant (left, type);
4029 } else if (IsSignedType (rb)) {
4030 expr = ConvertSignedConstant (right, type);
4036 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4037 type = rc.BuiltinTypes.Long;
4038 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4039 type = rc.BuiltinTypes.UInt;
4041 if (IsSignedType (lb)) {
4042 expr = ConvertSignedConstant (left, type);
4044 type = rc.BuiltinTypes.Long;
4045 } else if (IsSignedType (rb)) {
4046 expr = ConvertSignedConstant (right, type);
4048 type = rc.BuiltinTypes.Long;
4051 type = rc.BuiltinTypes.Int;
4054 if (ltype != type) {
4055 expr = PromoteExpression (rc, left, type);
4062 if (rtype != type) {
4063 expr = PromoteExpression (rc, right, type);
4073 static bool IsSignedType (BuiltinTypeSpec.Type type)
4076 case BuiltinTypeSpec.Type.Int:
4077 case BuiltinTypeSpec.Type.Short:
4078 case BuiltinTypeSpec.Type.SByte:
4079 case BuiltinTypeSpec.Type.Long:
4086 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4088 var c = expr as Constant;
4092 return c.ConvertImplicitly (type);
4095 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4097 if (expr.Type.IsNullableType) {
4098 return Convert.ImplicitConversionStandard (rc, expr,
4099 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4102 var c = expr as Constant;
4104 return c.ConvertImplicitly (type);
4106 return Convert.ImplicitNumericConversion (expr, type);
4109 protected override Expression DoResolve (ResolveContext ec)
4114 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4115 left = ((ParenthesizedExpression) left).Expr;
4116 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4120 if (left.eclass == ExprClass.Type) {
4121 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4125 left = left.Resolve (ec);
4130 right = right.Resolve (ec);
4134 Constant lc = left as Constant;
4135 Constant rc = right as Constant;
4137 // The conversion rules are ignored in enum context but why
4138 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4139 lc = EnumLiftUp (ec, lc, rc);
4141 rc = EnumLiftUp (ec, rc, lc);
4144 if (rc != null && lc != null) {
4145 int prev_e = ec.Report.Errors;
4146 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4147 if (e != null || ec.Report.Errors != prev_e)
4151 // Comparison warnings
4152 if ((oper & Operator.ComparisonMask) != 0) {
4153 if (left.Equals (right)) {
4154 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4156 CheckOutOfRangeComparison (ec, lc, right.Type);
4157 CheckOutOfRangeComparison (ec, rc, left.Type);
4160 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4161 return DoResolveDynamic (ec);
4163 return DoResolveCore (ec, left, right);
4166 Expression DoResolveDynamic (ResolveContext rc)
4169 var rt = right.Type;
4170 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4171 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4172 Error_OperatorCannotBeApplied (rc, left, right);
4179 // Special handling for logical boolean operators which require rhs not to be
4180 // evaluated based on lhs value
4182 if ((oper & Operator.LogicalMask) != 0) {
4183 Expression cond_left, cond_right, expr;
4185 args = new Arguments (2);
4187 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4188 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4190 var cond_args = new Arguments (1);
4191 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4194 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4195 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4197 left = temp.CreateReferenceExpression (rc, loc);
4198 if (oper == Operator.LogicalAnd) {
4199 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4202 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4206 args.Add (new Argument (left));
4207 args.Add (new Argument (right));
4208 cond_right = new DynamicExpressionStatement (this, args, loc);
4210 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4212 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4213 rc.Report.Error (7083, left.Location,
4214 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4215 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4219 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4220 args.Add (new Argument (right));
4221 right = new DynamicExpressionStatement (this, args, loc);
4224 // bool && dynamic => (temp = left) ? temp && right : temp;
4225 // bool || dynamic => (temp = left) ? temp : temp || right;
4227 if (oper == Operator.LogicalAnd) {
4229 cond_right = temp.CreateReferenceExpression (rc, loc);
4231 cond_left = temp.CreateReferenceExpression (rc, loc);
4235 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4238 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4241 args = new Arguments (2);
4242 args.Add (new Argument (left));
4243 args.Add (new Argument (right));
4244 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4247 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4249 Expression expr = ResolveOperator (ec);
4251 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4253 if (left == null || right == null)
4254 throw new InternalErrorException ("Invalid conversion");
4256 if (oper == Operator.BitwiseOr)
4257 CheckBitwiseOrOnSignExtended (ec);
4262 public override SLE.Expression MakeExpression (BuilderContext ctx)
4264 return MakeExpression (ctx, left, right);
4267 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4269 var le = left.MakeExpression (ctx);
4270 var re = right.MakeExpression (ctx);
4271 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4274 case Operator.Addition:
4275 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4276 case Operator.BitwiseAnd:
4277 return SLE.Expression.And (le, re);
4278 case Operator.BitwiseOr:
4279 return SLE.Expression.Or (le, re);
4280 case Operator.Division:
4281 return SLE.Expression.Divide (le, re);
4282 case Operator.Equality:
4283 return SLE.Expression.Equal (le, re);
4284 case Operator.ExclusiveOr:
4285 return SLE.Expression.ExclusiveOr (le, re);
4286 case Operator.GreaterThan:
4287 return SLE.Expression.GreaterThan (le, re);
4288 case Operator.GreaterThanOrEqual:
4289 return SLE.Expression.GreaterThanOrEqual (le, re);
4290 case Operator.Inequality:
4291 return SLE.Expression.NotEqual (le, re);
4292 case Operator.LeftShift:
4293 return SLE.Expression.LeftShift (le, re);
4294 case Operator.LessThan:
4295 return SLE.Expression.LessThan (le, re);
4296 case Operator.LessThanOrEqual:
4297 return SLE.Expression.LessThanOrEqual (le, re);
4298 case Operator.LogicalAnd:
4299 return SLE.Expression.AndAlso (le, re);
4300 case Operator.LogicalOr:
4301 return SLE.Expression.OrElse (le, re);
4302 case Operator.Modulus:
4303 return SLE.Expression.Modulo (le, re);
4304 case Operator.Multiply:
4305 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4306 case Operator.RightShift:
4307 return SLE.Expression.RightShift (le, re);
4308 case Operator.Subtraction:
4309 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4311 throw new NotImplementedException (oper.ToString ());
4316 // D operator + (D x, D y)
4317 // D operator - (D x, D y)
4319 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4321 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4323 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4324 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4329 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4330 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4340 MethodSpec method = null;
4341 Arguments args = new Arguments (2);
4342 args.Add (new Argument (left));
4343 args.Add (new Argument (right));
4345 if (oper == Operator.Addition) {
4346 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4347 } else if (oper == Operator.Subtraction) {
4348 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4352 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4354 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4355 return new ClassCast (expr, l);
4359 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4361 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4364 // bool operator == (E x, E y);
4365 // bool operator != (E x, E y);
4366 // bool operator < (E x, E y);
4367 // bool operator > (E x, E y);
4368 // bool operator <= (E x, E y);
4369 // bool operator >= (E x, E y);
4371 // E operator & (E x, E y);
4372 // E operator | (E x, E y);
4373 // E operator ^ (E x, E y);
4376 if ((oper & Operator.ComparisonMask) != 0) {
4377 type = rc.BuiltinTypes.Bool;
4383 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4389 if (ltype == rtype) {
4393 var lifted = new Nullable.LiftedBinaryOperator (this);
4395 lifted.Right = right;
4396 return lifted.Resolve (rc);
4399 if (renum && !ltype.IsNullableType) {
4400 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4405 } else if (lenum && !rtype.IsNullableType) {
4406 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4414 // Now try lifted version of predefined operator
4416 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4417 if (nullable_type != null) {
4418 if (renum && !ltype.IsNullableType) {
4419 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4421 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4424 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4427 if ((oper & Operator.BitwiseMask) != 0)
4431 if ((oper & Operator.BitwiseMask) != 0)
4432 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4434 return CreateLiftedValueTypeResult (rc, rtype);
4438 var lifted = new Nullable.LiftedBinaryOperator (this);
4440 lifted.Right = right;
4441 return lifted.Resolve (rc);
4443 } else if (lenum && !rtype.IsNullableType) {
4444 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4446 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4449 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4452 if ((oper & Operator.BitwiseMask) != 0)
4456 if ((oper & Operator.BitwiseMask) != 0)
4457 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4459 return CreateLiftedValueTypeResult (rc, ltype);
4463 var lifted = new Nullable.LiftedBinaryOperator (this);
4465 lifted.Right = expr;
4466 return lifted.Resolve (rc);
4468 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4469 Nullable.Unwrap unwrap = null;
4470 if (left.IsNull || right.IsNull) {
4471 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4472 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4474 if ((oper & Operator.RelationalMask) != 0)
4475 return CreateLiftedValueTypeResult (rc, rtype);
4477 if ((oper & Operator.BitwiseMask) != 0)
4478 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4481 return CreateLiftedValueTypeResult (rc, left.Type);
4483 // Equality operators are valid between E? and null
4485 unwrap = new Nullable.Unwrap (right);
4487 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4493 var lifted = new Nullable.LiftedBinaryOperator (this);
4495 lifted.Right = right;
4496 lifted.UnwrapRight = unwrap;
4497 return lifted.Resolve (rc);
4499 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4500 Nullable.Unwrap unwrap = null;
4501 if (right.IsNull || left.IsNull) {
4502 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4503 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4505 if ((oper & Operator.RelationalMask) != 0)
4506 return CreateLiftedValueTypeResult (rc, ltype);
4508 if ((oper & Operator.BitwiseMask) != 0)
4509 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4512 return CreateLiftedValueTypeResult (rc, right.Type);
4514 // Equality operators are valid between E? and null
4516 unwrap = new Nullable.Unwrap (left);
4518 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4524 var lifted = new Nullable.LiftedBinaryOperator (this);
4526 lifted.UnwrapLeft = unwrap;
4527 lifted.Right = expr;
4528 return lifted.Resolve (rc);
4536 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4538 TypeSpec underlying_type;
4539 if (expr.Type.IsNullableType) {
4540 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4542 underlying_type = EnumSpec.GetUnderlyingType (nt);
4544 underlying_type = nt;
4545 } else if (expr.Type.IsEnum) {
4546 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4548 underlying_type = expr.Type;
4551 switch (underlying_type.BuiltinType) {
4552 case BuiltinTypeSpec.Type.SByte:
4553 case BuiltinTypeSpec.Type.Byte:
4554 case BuiltinTypeSpec.Type.Short:
4555 case BuiltinTypeSpec.Type.UShort:
4556 underlying_type = rc.BuiltinTypes.Int;
4560 if (expr.Type.IsNullableType || liftType)
4561 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4563 if (expr.Type == underlying_type)
4566 return EmptyCast.Create (expr, underlying_type);
4569 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4572 // U operator - (E e, E f)
4573 // E operator - (E e, U x) // Internal decomposition operator
4574 // E operator - (U x, E e) // Internal decomposition operator
4576 // E operator + (E e, U x)
4577 // E operator + (U x, E e)
4586 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4592 if (!enum_type.IsNullableType) {
4593 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4595 if (oper == Operator.Subtraction)
4596 expr = ConvertEnumSubtractionResult (rc, expr);
4598 expr = ConvertEnumAdditionalResult (expr, enum_type);
4600 enum_conversion = GetEnumResultCast (expr.Type);
4605 var nullable = rc.Module.PredefinedTypes.Nullable;
4608 // Don't try nullable version when nullable type is undefined
4610 if (!nullable.IsDefined)
4613 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4616 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4618 if (oper == Operator.Subtraction)
4619 expr = ConvertEnumSubtractionResult (rc, expr);
4621 expr = ConvertEnumAdditionalResult (expr, enum_type);
4623 enum_conversion = GetEnumResultCast (expr.Type);
4629 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4631 return EmptyCast.Create (expr, enumType);
4634 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4637 // Enumeration subtraction has different result type based on
4640 TypeSpec result_type;
4641 if (left.Type == right.Type) {
4642 var c = right as EnumConstant;
4643 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4645 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4646 // E which is not what expressions E - 1 or 0 - E return
4648 result_type = left.Type;
4650 result_type = left.Type.IsNullableType ?
4651 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4652 EnumSpec.GetUnderlyingType (left.Type);
4655 if (IsEnumOrNullableEnum (left.Type)) {
4656 result_type = left.Type;
4658 result_type = right.Type;
4661 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4662 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4665 return EmptyCast.Create (expr, result_type);
4668 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4670 if (type.IsNullableType)
4671 type = Nullable.NullableInfo.GetUnderlyingType (type);
4674 type = EnumSpec.GetUnderlyingType (type);
4676 switch (type.BuiltinType) {
4677 case BuiltinTypeSpec.Type.SByte:
4678 return ConvCast.Mode.I4_I1;
4679 case BuiltinTypeSpec.Type.Byte:
4680 return ConvCast.Mode.I4_U1;
4681 case BuiltinTypeSpec.Type.Short:
4682 return ConvCast.Mode.I4_I2;
4683 case BuiltinTypeSpec.Type.UShort:
4684 return ConvCast.Mode.I4_U2;
4691 // Equality operators rules
4693 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4696 type = ec.BuiltinTypes.Bool;
4697 bool no_arg_conv = false;
4699 if (!primitives_only) {
4702 // a, Both operands are reference-type values or the value null
4703 // b, One operand is a value of type T where T is a type-parameter and
4704 // the other operand is the value null. Furthermore T does not have the
4705 // value type constraint
4707 // LAMESPEC: Very confusing details in the specification, basically any
4708 // reference like type-parameter is allowed
4710 var tparam_l = l as TypeParameterSpec;
4711 var tparam_r = r as TypeParameterSpec;
4712 if (tparam_l != null) {
4713 if (right is NullLiteral) {
4714 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4717 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4721 if (!tparam_l.IsReferenceType)
4724 l = tparam_l.GetEffectiveBase ();
4725 left = new BoxedCast (left, l);
4726 } else if (left is NullLiteral && tparam_r == null) {
4727 if (TypeSpec.IsReferenceType (r))
4730 if (r.Kind == MemberKind.InternalCompilerType)
4734 if (tparam_r != null) {
4735 if (left is NullLiteral) {
4736 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4739 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4743 if (!tparam_r.IsReferenceType)
4746 r = tparam_r.GetEffectiveBase ();
4747 right = new BoxedCast (right, r);
4748 } else if (right is NullLiteral) {
4749 if (TypeSpec.IsReferenceType (l))
4752 if (l.Kind == MemberKind.InternalCompilerType)
4757 // LAMESPEC: method groups can be compared when they convert to other side delegate
4760 if (right.eclass == ExprClass.MethodGroup) {
4761 result = Convert.ImplicitConversion (ec, right, l, loc);
4767 } else if (r.IsDelegate && l != r) {
4770 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4771 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4778 no_arg_conv = l == r && !l.IsStruct;
4783 // bool operator != (string a, string b)
4784 // bool operator == (string a, string b)
4786 // bool operator != (Delegate a, Delegate b)
4787 // bool operator == (Delegate a, Delegate b)
4789 // bool operator != (bool a, bool b)
4790 // bool operator == (bool a, bool b)
4792 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4793 // they implement an implicit conversion to any of types above. This does
4794 // not apply when both operands are of same reference type
4796 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4797 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4802 // Now try lifted version of predefined operators
4804 if (no_arg_conv && !l.IsNullableType) {
4806 // Optimizes cases which won't match
4809 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4815 // The == and != operators permit one operand to be a value of a nullable
4816 // type and the other to be the null literal, even if no predefined or user-defined
4817 // operator (in unlifted or lifted form) exists for the operation.
4819 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4820 var lifted = new Nullable.LiftedBinaryOperator (this);
4822 lifted.Right = right;
4823 return lifted.Resolve (ec);
4828 // bool operator != (object a, object b)
4829 // bool operator == (object a, object b)
4831 // An explicit reference conversion exists from the
4832 // type of either operand to the type of the other operand.
4835 // Optimize common path
4837 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4840 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4841 !Convert.ExplicitReferenceConversionExists (r, l))
4844 // Reject allowed explicit conversions like int->object
4845 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4848 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4849 ec.Report.Warning (253, 2, loc,
4850 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4851 l.GetSignatureForError ());
4853 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4854 ec.Report.Warning (252, 2, loc,
4855 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4856 r.GetSignatureForError ());
4862 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4865 // bool operator == (void* x, void* y);
4866 // bool operator != (void* x, void* y);
4867 // bool operator < (void* x, void* y);
4868 // bool operator > (void* x, void* y);
4869 // bool operator <= (void* x, void* y);
4870 // bool operator >= (void* x, void* y);
4872 if ((oper & Operator.ComparisonMask) != 0) {
4875 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4882 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4888 type = ec.BuiltinTypes.Bool;
4892 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4896 // Build-in operators method overloading
4898 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
4900 PredefinedOperator best_operator = null;
4901 TypeSpec l = left.Type;
4902 TypeSpec r = right.Type;
4903 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
4905 foreach (PredefinedOperator po in operators) {
4906 if ((po.OperatorsMask & oper_mask) == 0)
4909 if (primitives_only) {
4910 if (!po.IsPrimitiveApplicable (l, r))
4913 if (!po.IsApplicable (ec, left, right))
4917 if (best_operator == null) {
4919 if (primitives_only)
4925 best_operator = po.ResolveBetterOperator (ec, best_operator);
4927 if (best_operator == null) {
4928 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
4929 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
4936 if (best_operator == null)
4939 return best_operator.ConvertResult (ec, this);
4943 // Optimize & constant expressions with 0 value
4945 Expression OptimizeAndOperation (Expression expr)
4947 Constant rc = right as Constant;
4948 Constant lc = left as Constant;
4949 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
4951 // The result is a constant with side-effect
4953 Constant side_effect = rc == null ?
4954 new SideEffectConstant (lc, right, loc) :
4955 new SideEffectConstant (rc, left, loc);
4957 return ReducedExpression.Create (side_effect, expr);
4964 // Value types can be compared with the null literal because of the lifting
4965 // language rules. However the result is always true or false.
4967 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
4969 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
4970 type = rc.BuiltinTypes.Bool;
4974 // FIXME: Handle side effect constants
4975 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
4977 if ((Oper & Operator.EqualityMask) != 0) {
4978 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
4979 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4981 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
4982 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
4989 // Performs user-operator overloading
4991 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
4993 Expression oper_expr;
4995 var op = ConvertBinaryToUserOperator (oper);
4997 if (l.IsNullableType)
4998 l = Nullable.NullableInfo.GetUnderlyingType (l);
5000 if (r.IsNullableType)
5001 r = Nullable.NullableInfo.GetUnderlyingType (r);
5003 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5004 IList<MemberSpec> right_operators = null;
5007 right_operators = MemberCache.GetUserOperator (r, op, false);
5008 if (right_operators == null && left_operators == null)
5010 } else if (left_operators == null) {
5014 Arguments args = new Arguments (2);
5015 Argument larg = new Argument (left);
5017 Argument rarg = new Argument (right);
5021 // User-defined operator implementations always take precedence
5022 // over predefined operator implementations
5024 if (left_operators != null && right_operators != null) {
5025 left_operators = CombineUserOperators (left_operators, right_operators);
5026 } else if (right_operators != null) {
5027 left_operators = right_operators;
5030 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5031 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5033 var res = new OverloadResolver (left_operators, restr, loc);
5035 var oper_method = res.ResolveOperator (rc, ref args);
5036 if (oper_method == null) {
5038 // Logical && and || cannot be lifted
5040 if ((oper & Operator.LogicalMask) != 0)
5044 // Apply lifted user operators only for liftable types. Implicit conversion
5045 // to nullable types is not allowed
5047 if (!IsLiftedOperatorApplicable ())
5050 // TODO: Cache the result in module container
5051 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5052 if (lifted_methods == null)
5055 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5057 oper_method = res.ResolveOperator (rc, ref args);
5058 if (oper_method == null)
5061 MethodSpec best_original = null;
5062 foreach (MethodSpec ms in left_operators) {
5063 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5069 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5071 // Expression trees use lifted notation in this case
5073 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5074 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5077 var ptypes = best_original.Parameters.Types;
5079 if (left.IsNull || right.IsNull) {
5081 // The lifted operator produces a null value if one or both operands are null
5083 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5084 type = oper_method.ReturnType;
5085 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5089 // The lifted operator produces the value false if one or both operands are null for
5090 // relational operators.
5092 if ((oper & Operator.RelationalMask) != 0) {
5094 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5095 // because return type is actually bool
5097 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5100 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5101 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5105 type = oper_method.ReturnType;
5106 var lifted = new Nullable.LiftedBinaryOperator (this);
5107 lifted.UserOperator = best_original;
5109 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5110 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5113 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5114 lifted.UnwrapRight = new Nullable.Unwrap (right);
5117 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5118 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5120 return lifted.Resolve (rc);
5123 if ((oper & Operator.LogicalMask) != 0) {
5124 // TODO: CreateExpressionTree is allocated every time
5125 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5126 oper == Operator.LogicalAnd, loc).Resolve (rc);
5128 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5131 this.left = larg.Expr;
5132 this.right = rarg.Expr;
5137 bool IsLiftedOperatorApplicable ()
5139 if (left.Type.IsNullableType) {
5140 if ((oper & Operator.EqualityMask) != 0)
5141 return !right.IsNull;
5146 if (right.Type.IsNullableType) {
5147 if ((oper & Operator.EqualityMask) != 0)
5148 return !left.IsNull;
5153 if (TypeSpec.IsValueType (left.Type))
5154 return right.IsNull;
5156 if (TypeSpec.IsValueType (right.Type))
5162 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5164 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5165 if (nullable_type == null)
5169 // Lifted operators permit predefined and user-defined operators that operate
5170 // on non-nullable value types to also be used with nullable forms of those types.
5171 // Lifted operators are constructed from predefined and user-defined operators
5172 // that meet certain requirements
5174 List<MemberSpec> lifted = null;
5175 foreach (MethodSpec oper in operators) {
5177 if ((Oper & Operator.ComparisonMask) != 0) {
5179 // Result type must be of type bool for lifted comparison operators
5181 rt = oper.ReturnType;
5182 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5185 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5191 var ptypes = oper.Parameters.Types;
5192 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5196 // LAMESPEC: I am not sure why but for equality operators to be lifted
5197 // both types have to match
5199 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5203 lifted = new List<MemberSpec> ();
5206 // The lifted form is constructed by adding a single ? modifier to each operand and
5207 // result type except for comparison operators where return type is bool
5210 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5212 var parameters = ParametersCompiled.CreateFullyResolved (
5213 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5214 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5216 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5217 rt, parameters, oper.Modifiers);
5219 lifted.Add (lifted_op);
5226 // Merge two sets of user operators into one, they are mostly distinguish
5227 // except when they share base type and it contains an operator
5229 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5231 var combined = new List<MemberSpec> (left.Count + right.Count);
5232 combined.AddRange (left);
5233 foreach (var r in right) {
5235 foreach (var l in left) {
5236 if (l.DeclaringType == r.DeclaringType) {
5249 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5251 if (c is IntegralConstant || c is CharConstant) {
5253 c.ConvertExplicitly (true, type);
5254 } catch (OverflowException) {
5255 ec.Report.Warning (652, 2, loc,
5256 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5257 type.GetSignatureForError ());
5263 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5264 /// context of a conditional bool expression. This function will return
5265 /// false if it is was possible to use EmitBranchable, or true if it was.
5267 /// The expression's code is generated, and we will generate a branch to `target'
5268 /// if the resulting expression value is equal to isTrue
5270 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5272 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5273 left = left.EmitToField (ec);
5275 if ((oper & Operator.LogicalMask) == 0) {
5276 right = right.EmitToField (ec);
5281 // This is more complicated than it looks, but its just to avoid
5282 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5283 // but on top of that we want for == and != to use a special path
5284 // if we are comparing against null
5286 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5287 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5290 // put the constant on the rhs, for simplicity
5292 if (left is Constant) {
5293 Expression swap = right;
5299 // brtrue/brfalse works with native int only
5301 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5302 left.EmitBranchable (ec, target, my_on_true);
5305 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5306 // right is a boolean, and it's not 'false' => it is 'true'
5307 left.EmitBranchable (ec, target, !my_on_true);
5311 } else if (oper == Operator.LogicalAnd) {
5314 Label tests_end = ec.DefineLabel ();
5316 left.EmitBranchable (ec, tests_end, false);
5317 right.EmitBranchable (ec, target, true);
5318 ec.MarkLabel (tests_end);
5321 // This optimizes code like this
5322 // if (true && i > 4)
5324 if (!(left is Constant))
5325 left.EmitBranchable (ec, target, false);
5327 if (!(right is Constant))
5328 right.EmitBranchable (ec, target, false);
5333 } else if (oper == Operator.LogicalOr){
5335 left.EmitBranchable (ec, target, true);
5336 right.EmitBranchable (ec, target, true);
5339 Label tests_end = ec.DefineLabel ();
5340 left.EmitBranchable (ec, tests_end, true);
5341 right.EmitBranchable (ec, target, false);
5342 ec.MarkLabel (tests_end);
5347 } else if ((oper & Operator.ComparisonMask) == 0) {
5348 base.EmitBranchable (ec, target, on_true);
5355 TypeSpec t = left.Type;
5356 bool is_float = IsFloat (t);
5357 bool is_unsigned = is_float || IsUnsigned (t);
5360 case Operator.Equality:
5362 ec.Emit (OpCodes.Beq, target);
5364 ec.Emit (OpCodes.Bne_Un, target);
5367 case Operator.Inequality:
5369 ec.Emit (OpCodes.Bne_Un, target);
5371 ec.Emit (OpCodes.Beq, target);
5374 case Operator.LessThan:
5376 if (is_unsigned && !is_float)
5377 ec.Emit (OpCodes.Blt_Un, target);
5379 ec.Emit (OpCodes.Blt, target);
5382 ec.Emit (OpCodes.Bge_Un, target);
5384 ec.Emit (OpCodes.Bge, target);
5387 case Operator.GreaterThan:
5389 if (is_unsigned && !is_float)
5390 ec.Emit (OpCodes.Bgt_Un, target);
5392 ec.Emit (OpCodes.Bgt, target);
5395 ec.Emit (OpCodes.Ble_Un, target);
5397 ec.Emit (OpCodes.Ble, target);
5400 case Operator.LessThanOrEqual:
5402 if (is_unsigned && !is_float)
5403 ec.Emit (OpCodes.Ble_Un, target);
5405 ec.Emit (OpCodes.Ble, target);
5408 ec.Emit (OpCodes.Bgt_Un, target);
5410 ec.Emit (OpCodes.Bgt, target);
5414 case Operator.GreaterThanOrEqual:
5416 if (is_unsigned && !is_float)
5417 ec.Emit (OpCodes.Bge_Un, target);
5419 ec.Emit (OpCodes.Bge, target);
5422 ec.Emit (OpCodes.Blt_Un, target);
5424 ec.Emit (OpCodes.Blt, target);
5427 throw new InternalErrorException (oper.ToString ());
5431 public override void Emit (EmitContext ec)
5433 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5434 left = left.EmitToField (ec);
5436 if ((oper & Operator.LogicalMask) == 0) {
5437 right = right.EmitToField (ec);
5442 // Handle short-circuit operators differently
5445 if ((oper & Operator.LogicalMask) != 0) {
5446 Label load_result = ec.DefineLabel ();
5447 Label end = ec.DefineLabel ();
5449 bool is_or = oper == Operator.LogicalOr;
5450 left.EmitBranchable (ec, load_result, is_or);
5452 ec.Emit (OpCodes.Br_S, end);
5454 ec.MarkLabel (load_result);
5455 ec.EmitInt (is_or ? 1 : 0);
5461 // Optimize zero-based operations which cannot be optimized at expression level
5463 if (oper == Operator.Subtraction) {
5464 var lc = left as IntegralConstant;
5465 if (lc != null && lc.IsDefaultValue) {
5467 ec.Emit (OpCodes.Neg);
5472 EmitOperator (ec, left, right);
5475 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5480 EmitOperatorOpcode (ec, oper, left.Type, right);
5483 // Emit result enumerable conversion this way because it's quite complicated get it
5484 // to resolved tree because expression tree cannot see it.
5486 if (enum_conversion != 0)
5487 ConvCast.Emit (ec, enum_conversion);
5490 public override void EmitSideEffect (EmitContext ec)
5492 if ((oper & Operator.LogicalMask) != 0 ||
5493 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5494 base.EmitSideEffect (ec);
5496 left.EmitSideEffect (ec);
5497 right.EmitSideEffect (ec);
5501 public override Expression EmitToField (EmitContext ec)
5503 if ((oper & Operator.LogicalMask) == 0) {
5504 var await_expr = left as Await;
5505 if (await_expr != null && right.IsSideEffectFree) {
5506 await_expr.Statement.EmitPrologue (ec);
5507 left = await_expr.Statement.GetResultExpression (ec);
5511 await_expr = right as Await;
5512 if (await_expr != null && left.IsSideEffectFree) {
5513 await_expr.Statement.EmitPrologue (ec);
5514 right = await_expr.Statement.GetResultExpression (ec);
5519 return base.EmitToField (ec);
5522 protected override void CloneTo (CloneContext clonectx, Expression t)
5524 Binary target = (Binary) t;
5526 target.left = left.Clone (clonectx);
5527 target.right = right.Clone (clonectx);
5530 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5532 Arguments binder_args = new Arguments (4);
5534 MemberAccess sle = new MemberAccess (new MemberAccess (
5535 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5537 CSharpBinderFlags flags = 0;
5538 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5539 flags = CSharpBinderFlags.CheckedContext;
5541 if ((oper & Operator.LogicalMask) != 0)
5542 flags |= CSharpBinderFlags.BinaryOperationLogical;
5544 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5545 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5546 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5547 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5549 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5552 public override Expression CreateExpressionTree (ResolveContext ec)
5554 return CreateExpressionTree (ec, null);
5557 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5560 bool lift_arg = false;
5563 case Operator.Addition:
5564 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5565 method_name = "AddChecked";
5567 method_name = "Add";
5569 case Operator.BitwiseAnd:
5570 method_name = "And";
5572 case Operator.BitwiseOr:
5575 case Operator.Division:
5576 method_name = "Divide";
5578 case Operator.Equality:
5579 method_name = "Equal";
5582 case Operator.ExclusiveOr:
5583 method_name = "ExclusiveOr";
5585 case Operator.GreaterThan:
5586 method_name = "GreaterThan";
5589 case Operator.GreaterThanOrEqual:
5590 method_name = "GreaterThanOrEqual";
5593 case Operator.Inequality:
5594 method_name = "NotEqual";
5597 case Operator.LeftShift:
5598 method_name = "LeftShift";
5600 case Operator.LessThan:
5601 method_name = "LessThan";
5604 case Operator.LessThanOrEqual:
5605 method_name = "LessThanOrEqual";
5608 case Operator.LogicalAnd:
5609 method_name = "AndAlso";
5611 case Operator.LogicalOr:
5612 method_name = "OrElse";
5614 case Operator.Modulus:
5615 method_name = "Modulo";
5617 case Operator.Multiply:
5618 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5619 method_name = "MultiplyChecked";
5621 method_name = "Multiply";
5623 case Operator.RightShift:
5624 method_name = "RightShift";
5626 case Operator.Subtraction:
5627 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5628 method_name = "SubtractChecked";
5630 method_name = "Subtract";
5634 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5637 Arguments args = new Arguments (2);
5638 args.Add (new Argument (left.CreateExpressionTree (ec)));
5639 args.Add (new Argument (right.CreateExpressionTree (ec)));
5640 if (method != null) {
5642 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5644 args.Add (new Argument (method));
5647 return CreateExpressionFactoryCall (ec, method_name, args);
5650 public override object Accept (StructuralVisitor visitor)
5652 return visitor.Visit (this);
5658 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5659 // b, c, d... may be strings or objects.
5661 public class StringConcat : Expression
5663 Arguments arguments;
5665 StringConcat (Location loc)
5668 arguments = new Arguments (2);
5671 public override bool ContainsEmitWithAwait ()
5673 return arguments.ContainsEmitWithAwait ();
5676 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5678 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5679 throw new ArgumentException ();
5681 var s = new StringConcat (loc);
5682 s.type = rc.BuiltinTypes.String;
5683 s.eclass = ExprClass.Value;
5685 s.Append (rc, left);
5686 s.Append (rc, right);
5690 public override Expression CreateExpressionTree (ResolveContext ec)
5692 Argument arg = arguments [0];
5693 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5697 // Creates nested calls tree from an array of arguments used for IL emit
5699 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5701 Arguments concat_args = new Arguments (2);
5702 Arguments add_args = new Arguments (3);
5704 concat_args.Add (left);
5705 add_args.Add (new Argument (left_etree));
5707 concat_args.Add (arguments [pos]);
5708 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5710 var methods = GetConcatMethodCandidates ();
5711 if (methods == null)
5714 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5715 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5719 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5721 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5722 if (++pos == arguments.Count)
5725 left = new Argument (new EmptyExpression (method.ReturnType));
5726 return CreateExpressionAddCall (ec, left, expr, pos);
5729 protected override Expression DoResolve (ResolveContext ec)
5734 void Append (ResolveContext rc, Expression operand)
5739 StringConstant sc = operand as StringConstant;
5741 if (arguments.Count != 0) {
5742 Argument last_argument = arguments [arguments.Count - 1];
5743 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5744 if (last_expr_constant != null) {
5745 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5751 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5753 StringConcat concat_oper = operand as StringConcat;
5754 if (concat_oper != null) {
5755 arguments.AddRange (concat_oper.arguments);
5760 arguments.Add (new Argument (operand));
5763 IList<MemberSpec> GetConcatMethodCandidates ()
5765 return MemberCache.FindMembers (type, "Concat", true);
5768 public override void Emit (EmitContext ec)
5770 // Optimize by removing any extra null arguments, they are no-op
5771 for (int i = 0; i < arguments.Count; ++i) {
5772 if (arguments[i].Expr is NullConstant)
5773 arguments.RemoveAt (i--);
5776 var members = GetConcatMethodCandidates ();
5777 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5778 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5779 if (method != null) {
5780 var call = new CallEmitter ();
5781 call.EmitPredefined (ec, method, arguments, false);
5785 public override void FlowAnalysis (FlowAnalysisContext fc)
5787 arguments.FlowAnalysis (fc);
5790 public override SLE.Expression MakeExpression (BuilderContext ctx)
5792 if (arguments.Count != 2)
5793 throw new NotImplementedException ("arguments.Count != 2");
5795 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5796 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5801 // User-defined conditional logical operator
5803 public class ConditionalLogicalOperator : UserOperatorCall
5805 readonly bool is_and;
5806 Expression oper_expr;
5808 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5809 : base (oper, arguments, expr_tree, loc)
5811 this.is_and = is_and;
5812 eclass = ExprClass.Unresolved;
5815 protected override Expression DoResolve (ResolveContext ec)
5817 AParametersCollection pd = oper.Parameters;
5818 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5819 ec.Report.Error (217, loc,
5820 "A user-defined operator `{0}' must have each parameter type and return type of the same type in order to be applicable as a short circuit operator",
5821 oper.GetSignatureForError ());
5825 Expression left_dup = new EmptyExpression (type);
5826 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5827 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5828 if (op_true == null || op_false == null) {
5829 ec.Report.Error (218, loc,
5830 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5831 type.GetSignatureForError (), oper.GetSignatureForError ());
5835 oper_expr = is_and ? op_false : op_true;
5836 eclass = ExprClass.Value;
5840 public override void Emit (EmitContext ec)
5842 Label end_target = ec.DefineLabel ();
5845 // Emit and duplicate left argument
5847 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5848 if (right_contains_await) {
5849 arguments[0] = arguments[0].EmitToField (ec, false);
5850 arguments[0].Expr.Emit (ec);
5852 arguments[0].Expr.Emit (ec);
5853 ec.Emit (OpCodes.Dup);
5854 arguments.RemoveAt (0);
5857 oper_expr.EmitBranchable (ec, end_target, true);
5861 if (right_contains_await) {
5863 // Special handling when right expression contains await and left argument
5864 // could not be left on stack before logical branch
5866 Label skip_left_load = ec.DefineLabel ();
5867 ec.Emit (OpCodes.Br_S, skip_left_load);
5868 ec.MarkLabel (end_target);
5869 arguments[0].Expr.Emit (ec);
5870 ec.MarkLabel (skip_left_load);
5872 ec.MarkLabel (end_target);
5877 public class PointerArithmetic : Expression {
5878 Expression left, right;
5879 readonly Binary.Operator op;
5882 // We assume that `l' is always a pointer
5884 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5893 public override bool ContainsEmitWithAwait ()
5895 throw new NotImplementedException ();
5898 public override Expression CreateExpressionTree (ResolveContext ec)
5900 Error_PointerInsideExpressionTree (ec);
5904 protected override Expression DoResolve (ResolveContext ec)
5906 eclass = ExprClass.Variable;
5908 var pc = left.Type as PointerContainer;
5909 if (pc != null && pc.Element.Kind == MemberKind.Void) {
5910 Error_VoidPointerOperation (ec);
5917 public override void Emit (EmitContext ec)
5919 TypeSpec op_type = left.Type;
5921 // It must be either array or fixed buffer
5923 if (TypeManager.HasElementType (op_type)) {
5924 element = TypeManager.GetElementType (op_type);
5926 FieldExpr fe = left as FieldExpr;
5928 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
5933 int size = BuiltinTypeSpec.GetSize(element);
5934 TypeSpec rtype = right.Type;
5936 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
5938 // handle (pointer - pointer)
5942 ec.Emit (OpCodes.Sub);
5946 ec.Emit (OpCodes.Sizeof, element);
5949 ec.Emit (OpCodes.Div);
5951 ec.Emit (OpCodes.Conv_I8);
5954 // handle + and - on (pointer op int)
5956 Constant left_const = left as Constant;
5957 if (left_const != null) {
5959 // Optimize ((T*)null) pointer operations
5961 if (left_const.IsDefaultValue) {
5962 left = EmptyExpression.Null;
5970 var right_const = right as Constant;
5971 if (right_const != null) {
5973 // Optimize 0-based arithmetic
5975 if (right_const.IsDefaultValue)
5979 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
5981 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
5983 // TODO: Should be the checks resolve context sensitive?
5984 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
5985 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
5991 switch (rtype.BuiltinType) {
5992 case BuiltinTypeSpec.Type.SByte:
5993 case BuiltinTypeSpec.Type.Byte:
5994 case BuiltinTypeSpec.Type.Short:
5995 case BuiltinTypeSpec.Type.UShort:
5996 ec.Emit (OpCodes.Conv_I);
5998 case BuiltinTypeSpec.Type.UInt:
5999 ec.Emit (OpCodes.Conv_U);
6003 if (right_const == null && size != 1){
6005 ec.Emit (OpCodes.Sizeof, element);
6008 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6009 ec.Emit (OpCodes.Conv_I8);
6011 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6014 if (left_const == null) {
6015 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6016 ec.Emit (OpCodes.Conv_I);
6017 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6018 ec.Emit (OpCodes.Conv_U);
6020 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6027 // A boolean-expression is an expression that yields a result
6030 public class BooleanExpression : ShimExpression
6032 public BooleanExpression (Expression expr)
6035 this.loc = expr.Location;
6038 public override Expression CreateExpressionTree (ResolveContext ec)
6040 // TODO: We should emit IsTrue (v4) instead of direct user operator
6041 // call but that would break csc compatibility
6042 return base.CreateExpressionTree (ec);
6045 protected override Expression DoResolve (ResolveContext ec)
6047 // A boolean-expression is required to be of a type
6048 // that can be implicitly converted to bool or of
6049 // a type that implements operator true
6051 expr = expr.Resolve (ec);
6055 Assign ass = expr as Assign;
6056 if (ass != null && ass.Source is Constant) {
6057 ec.Report.Warning (665, 3, loc,
6058 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6061 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6064 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6065 Arguments args = new Arguments (1);
6066 args.Add (new Argument (expr));
6067 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6070 type = ec.BuiltinTypes.Bool;
6071 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6072 if (converted != null)
6076 // If no implicit conversion to bool exists, try using `operator true'
6078 converted = GetOperatorTrue (ec, expr, loc);
6079 if (converted == null) {
6080 expr.Error_ValueCannotBeConverted (ec, type, false);
6087 public override object Accept (StructuralVisitor visitor)
6089 return visitor.Visit (this);
6093 public class BooleanExpressionFalse : Unary
6095 public BooleanExpressionFalse (Expression expr)
6096 : base (Operator.LogicalNot, expr, expr.Location)
6100 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6102 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6107 /// Implements the ternary conditional operator (?:)
6109 public class Conditional : Expression {
6110 Expression expr, true_expr, false_expr;
6112 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6115 this.true_expr = true_expr;
6116 this.false_expr = false_expr;
6122 public Expression Expr {
6128 public Expression TrueExpr {
6134 public Expression FalseExpr {
6142 public override bool ContainsEmitWithAwait ()
6144 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6147 public override Expression CreateExpressionTree (ResolveContext ec)
6149 Arguments args = new Arguments (3);
6150 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6151 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6152 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6153 return CreateExpressionFactoryCall (ec, "Condition", args);
6156 protected override Expression DoResolve (ResolveContext ec)
6158 expr = expr.Resolve (ec);
6159 true_expr = true_expr.Resolve (ec);
6160 false_expr = false_expr.Resolve (ec);
6162 if (true_expr == null || false_expr == null || expr == null)
6165 eclass = ExprClass.Value;
6166 TypeSpec true_type = true_expr.Type;
6167 TypeSpec false_type = false_expr.Type;
6171 // First, if an implicit conversion exists from true_expr
6172 // to false_expr, then the result type is of type false_expr.Type
6174 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6175 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6176 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6178 // Check if both can convert implicitly to each other's type
6182 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6183 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6185 // LAMESPEC: There seems to be hardcoded promotition to int type when
6186 // both sides are numeric constants and one side is int constant and
6187 // other side is numeric constant convertible to int.
6189 // var res = condition ? (short)1 : 1;
6191 // Type of res is int even if according to the spec the conversion is
6192 // ambiguous because 1 literal can be converted to short.
6194 if (conv_false_expr != null) {
6195 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6197 conv_false_expr = null;
6198 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6199 conv_false_expr = null;
6203 if (conv_false_expr != null) {
6204 ec.Report.Error (172, true_expr.Location,
6205 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6206 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6211 if (true_expr.Type != type)
6212 true_expr = EmptyCast.Create (true_expr, type);
6213 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6216 if (false_type != InternalType.ErrorType) {
6217 ec.Report.Error (173, true_expr.Location,
6218 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6219 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6225 Constant c = expr as Constant;
6227 bool is_false = c.IsDefaultValue;
6230 // Don't issue the warning for constant expressions
6232 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6233 // CSC: Missing warning
6234 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6237 return ReducedExpression.Create (
6238 is_false ? false_expr : true_expr, this,
6239 false_expr is Constant && true_expr is Constant).Resolve (ec);
6245 public override void Emit (EmitContext ec)
6247 Label false_target = ec.DefineLabel ();
6248 Label end_target = ec.DefineLabel ();
6250 expr.EmitBranchable (ec, false_target, false);
6251 true_expr.Emit (ec);
6254 // Verifier doesn't support interface merging. When there are two types on
6255 // the stack without common type hint and the common type is an interface.
6256 // Use temporary local to give verifier hint on what type to unify the stack
6258 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6259 var temp = ec.GetTemporaryLocal (type);
6260 ec.Emit (OpCodes.Stloc, temp);
6261 ec.Emit (OpCodes.Ldloc, temp);
6262 ec.FreeTemporaryLocal (temp, type);
6265 ec.Emit (OpCodes.Br, end_target);
6266 ec.MarkLabel (false_target);
6267 false_expr.Emit (ec);
6268 ec.MarkLabel (end_target);
6271 public override void FlowAnalysis (FlowAnalysisContext fc)
6273 expr.FlowAnalysisConditional (fc);
6274 var expr_true = fc.DefiniteAssignmentOnTrue;
6275 var expr_false = fc.DefiniteAssignmentOnFalse;
6277 fc.BranchDefiniteAssignment (expr_true);
6278 true_expr.FlowAnalysis (fc);
6279 var true_fc = fc.DefiniteAssignment;
6281 fc.BranchDefiniteAssignment (expr_false);
6282 false_expr.FlowAnalysis (fc);
6284 fc.DefiniteAssignment &= true_fc;
6287 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6289 expr.FlowAnalysisConditional (fc);
6290 var expr_true = fc.DefiniteAssignmentOnTrue;
6291 var expr_false = fc.DefiniteAssignmentOnFalse;
6293 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6294 true_expr.FlowAnalysisConditional (fc);
6295 var true_fc = fc.DefiniteAssignment;
6296 var true_da_true = fc.DefiniteAssignmentOnTrue;
6297 var true_da_false = fc.DefiniteAssignmentOnFalse;
6299 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6300 false_expr.FlowAnalysisConditional (fc);
6302 fc.DefiniteAssignment &= true_fc;
6303 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6304 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6307 protected override void CloneTo (CloneContext clonectx, Expression t)
6309 Conditional target = (Conditional) t;
6311 target.expr = expr.Clone (clonectx);
6312 target.true_expr = true_expr.Clone (clonectx);
6313 target.false_expr = false_expr.Clone (clonectx);
6317 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6319 LocalTemporary temp;
6322 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6323 public abstract void SetHasAddressTaken ();
6325 public abstract bool IsLockedByStatement { get; set; }
6327 public abstract bool IsFixed { get; }
6328 public abstract bool IsRef { get; }
6329 public abstract string Name { get; }
6332 // Variable IL data, it has to be protected to encapsulate hoisted variables
6334 protected abstract ILocalVariable Variable { get; }
6337 // Variable flow-analysis data
6339 public abstract VariableInfo VariableInfo { get; }
6342 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6344 HoistedVariable hv = GetHoistedVariable (ec);
6346 hv.AddressOf (ec, mode);
6350 Variable.EmitAddressOf (ec);
6353 public override bool ContainsEmitWithAwait ()
6358 public override Expression CreateExpressionTree (ResolveContext ec)
6360 HoistedVariable hv = GetHoistedVariable (ec);
6362 return hv.CreateExpressionTree ();
6364 Arguments arg = new Arguments (1);
6365 arg.Add (new Argument (this));
6366 return CreateExpressionFactoryCall (ec, "Constant", arg);
6369 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6371 if (IsLockedByStatement) {
6372 rc.Report.Warning (728, 2, loc,
6373 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6380 public override void Emit (EmitContext ec)
6385 public override void EmitSideEffect (EmitContext ec)
6391 // This method is used by parameters that are references, that are
6392 // being passed as references: we only want to pass the pointer (that
6393 // is already stored in the parameter, not the address of the pointer,
6394 // and not the value of the variable).
6396 public void EmitLoad (EmitContext ec)
6401 public void Emit (EmitContext ec, bool leave_copy)
6403 HoistedVariable hv = GetHoistedVariable (ec);
6405 hv.Emit (ec, leave_copy);
6413 // If we are a reference, we loaded on the stack a pointer
6414 // Now lets load the real value
6416 ec.EmitLoadFromPtr (type);
6420 ec.Emit (OpCodes.Dup);
6423 temp = new LocalTemporary (Type);
6429 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6430 bool prepare_for_load)
6432 HoistedVariable hv = GetHoistedVariable (ec);
6434 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6438 New n_source = source as New;
6439 if (n_source != null) {
6440 if (!n_source.Emit (ec, this)) {
6444 ec.EmitLoadFromPtr (type);
6456 ec.Emit (OpCodes.Dup);
6458 temp = new LocalTemporary (Type);
6464 ec.EmitStoreFromPtr (type);
6466 Variable.EmitAssign (ec);
6474 public override Expression EmitToField (EmitContext ec)
6476 HoistedVariable hv = GetHoistedVariable (ec);
6478 return hv.EmitToField (ec);
6481 return base.EmitToField (ec);
6484 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6486 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6489 public HoistedVariable GetHoistedVariable (EmitContext ec)
6491 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6494 public override string GetSignatureForError ()
6499 public bool IsHoisted {
6500 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6505 // Resolved reference to a local variable
6507 public class LocalVariableReference : VariableReference
6509 public LocalVariable local_info;
6511 public LocalVariableReference (LocalVariable li, Location l)
6513 this.local_info = li;
6517 public override VariableInfo VariableInfo {
6518 get { return local_info.VariableInfo; }
6521 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6523 return local_info.HoistedVariant;
6529 // A local variable is always fixed
6531 public override bool IsFixed {
6537 public override bool IsLockedByStatement {
6539 return local_info.IsLocked;
6542 local_info.IsLocked = value;
6546 public override bool IsRef {
6547 get { return false; }
6550 public override string Name {
6551 get { return local_info.Name; }
6556 public override void FlowAnalysis (FlowAnalysisContext fc)
6558 VariableInfo variable_info = VariableInfo;
6559 if (variable_info == null)
6562 if (fc.IsDefinitelyAssigned (variable_info))
6565 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6566 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6569 public override void SetHasAddressTaken ()
6571 local_info.SetHasAddressTaken ();
6574 void DoResolveBase (ResolveContext ec)
6576 eclass = ExprClass.Variable;
6577 type = local_info.Type;
6580 // If we are referencing a variable from the external block
6581 // flag it for capturing
6583 if (ec.MustCaptureVariable (local_info)) {
6584 if (local_info.AddressTaken) {
6585 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6586 } else if (local_info.IsFixed) {
6587 ec.Report.Error (1764, loc,
6588 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6589 GetSignatureForError ());
6592 if (ec.IsVariableCapturingRequired) {
6593 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6594 storey.CaptureLocalVariable (ec, local_info);
6599 protected override Expression DoResolve (ResolveContext ec)
6601 local_info.SetIsUsed ();
6605 if (local_info.Type == InternalType.VarOutType) {
6606 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6607 GetSignatureForError ());
6609 type = InternalType.ErrorType;
6615 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6618 // Don't be too pedantic when variable is used as out param or for some broken code
6619 // which uses property/indexer access to run some initialization
6621 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6622 local_info.SetIsUsed ();
6624 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6625 if (rhs == EmptyExpression.LValueMemberAccess) {
6626 // CS1654 already reported
6630 if (rhs == EmptyExpression.OutAccess) {
6631 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6632 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6633 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6634 } else if (rhs == EmptyExpression.UnaryAddress) {
6635 code = 459; msg = "Cannot take the address of {1} `{0}'";
6637 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6639 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6643 if (eclass == ExprClass.Unresolved)
6646 return base.DoResolveLValue (ec, rhs);
6649 public override int GetHashCode ()
6651 return local_info.GetHashCode ();
6654 public override bool Equals (object obj)
6656 LocalVariableReference lvr = obj as LocalVariableReference;
6660 return local_info == lvr.local_info;
6663 protected override ILocalVariable Variable {
6664 get { return local_info; }
6667 public override string ToString ()
6669 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6672 protected override void CloneTo (CloneContext clonectx, Expression t)
6679 /// This represents a reference to a parameter in the intermediate
6682 public class ParameterReference : VariableReference
6684 protected ParametersBlock.ParameterInfo pi;
6686 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6694 public override bool IsLockedByStatement {
6699 pi.IsLocked = value;
6703 public override bool IsRef {
6704 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6707 bool HasOutModifier {
6708 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6711 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6713 return pi.Parameter.HoistedVariant;
6717 // A ref or out parameter is classified as a moveable variable, even
6718 // if the argument given for the parameter is a fixed variable
6720 public override bool IsFixed {
6721 get { return !IsRef; }
6724 public override string Name {
6725 get { return Parameter.Name; }
6728 public Parameter Parameter {
6729 get { return pi.Parameter; }
6732 public override VariableInfo VariableInfo {
6733 get { return pi.VariableInfo; }
6736 protected override ILocalVariable Variable {
6737 get { return Parameter; }
6742 public override void AddressOf (EmitContext ec, AddressOp mode)
6745 // ParameterReferences might already be a reference
6752 base.AddressOf (ec, mode);
6755 public override void SetHasAddressTaken ()
6757 Parameter.HasAddressTaken = true;
6760 bool DoResolveBase (ResolveContext ec)
6762 if (eclass != ExprClass.Unresolved)
6765 type = pi.ParameterType;
6766 eclass = ExprClass.Variable;
6769 // If we are referencing a parameter from the external block
6770 // flag it for capturing
6772 if (ec.MustCaptureVariable (pi)) {
6773 if (Parameter.HasAddressTaken)
6774 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6777 ec.Report.Error (1628, loc,
6778 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6779 Name, ec.CurrentAnonymousMethod.ContainerType);
6782 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6783 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6784 storey.CaptureParameter (ec, pi, this);
6791 public override int GetHashCode ()
6793 return Name.GetHashCode ();
6796 public override bool Equals (object obj)
6798 ParameterReference pr = obj as ParameterReference;
6802 return Name == pr.Name;
6805 protected override void CloneTo (CloneContext clonectx, Expression target)
6811 public override Expression CreateExpressionTree (ResolveContext ec)
6813 HoistedVariable hv = GetHoistedVariable (ec);
6815 return hv.CreateExpressionTree ();
6817 return Parameter.ExpressionTreeVariableReference ();
6820 protected override Expression DoResolve (ResolveContext ec)
6822 if (!DoResolveBase (ec))
6828 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6830 if (!DoResolveBase (ec))
6833 if (Parameter.HoistedVariant != null)
6834 Parameter.HoistedVariant.IsAssigned = true;
6836 return base.DoResolveLValue (ec, right_side);
6839 public override void FlowAnalysis (FlowAnalysisContext fc)
6841 VariableInfo variable_info = VariableInfo;
6842 if (variable_info == null)
6845 if (fc.IsDefinitelyAssigned (variable_info))
6848 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6849 fc.SetVariableAssigned (variable_info);
6854 /// Invocation of methods or delegates.
6856 public class Invocation : ExpressionStatement
6858 public class Predefined : Invocation
6860 public Predefined (MethodGroupExpr expr, Arguments arguments)
6861 : base (expr, arguments)
6866 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6868 if (!rc.IsObsolete) {
6869 var member = mg.BestCandidate;
6870 ObsoleteAttribute oa = member.GetAttributeObsolete ();
6872 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
6879 protected Arguments arguments;
6880 protected Expression expr;
6881 protected MethodGroupExpr mg;
6882 bool conditional_access_receiver;
6884 public Invocation (Expression expr, Arguments arguments)
6887 this.arguments = arguments;
6889 loc = expr.Location;
6894 public Arguments Arguments {
6900 public Expression Exp {
6906 public MethodGroupExpr MethodGroup {
6912 public override Location StartLocation {
6914 return expr.StartLocation;
6920 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6922 if (MethodGroup == null)
6925 var candidate = MethodGroup.BestCandidate;
6926 if (candidate == null || !(candidate.IsStatic || Exp is This))
6929 var args_count = arguments == null ? 0 : arguments.Count;
6930 if (args_count != body.Parameters.Count)
6933 var lambda_parameters = body.Block.Parameters.FixedParameters;
6934 for (int i = 0; i < args_count; ++i) {
6935 var pr = arguments[i].Expr as ParameterReference;
6939 if (lambda_parameters[i] != pr.Parameter)
6942 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
6946 var emg = MethodGroup as ExtensionMethodGroupExpr;
6948 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
6949 if (candidate.IsGeneric) {
6950 var targs = new TypeExpression [candidate.Arity];
6951 for (int i = 0; i < targs.Length; ++i) {
6952 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
6955 mg.SetTypeArguments (null, new TypeArguments (targs));
6964 protected override void CloneTo (CloneContext clonectx, Expression t)
6966 Invocation target = (Invocation) t;
6968 if (arguments != null)
6969 target.arguments = arguments.Clone (clonectx);
6971 target.expr = expr.Clone (clonectx);
6974 public override bool ContainsEmitWithAwait ()
6976 if (arguments != null && arguments.ContainsEmitWithAwait ())
6979 return mg.ContainsEmitWithAwait ();
6982 public override Expression CreateExpressionTree (ResolveContext ec)
6984 Expression instance = mg.IsInstance ?
6985 mg.InstanceExpression.CreateExpressionTree (ec) :
6986 new NullLiteral (loc);
6988 var args = Arguments.CreateForExpressionTree (ec, arguments,
6990 mg.CreateExpressionTree (ec));
6992 return CreateExpressionFactoryCall (ec, "Call", args);
6995 protected override Expression DoResolve (ResolveContext rc)
6997 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
6998 if (expr.HasConditionalAccess ()) {
6999 conditional_access_receiver = true;
7000 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
7001 return DoResolveInvocation (rc);
7006 return DoResolveInvocation (rc);
7009 Expression DoResolveInvocation (ResolveContext ec)
7011 Expression member_expr;
7012 var atn = expr as ATypeNameExpression;
7014 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7015 if (member_expr != null) {
7016 var name_of = member_expr as NameOf;
7017 if (name_of != null) {
7018 return name_of.ResolveOverload (ec, arguments);
7021 member_expr = member_expr.Resolve (ec);
7024 member_expr = expr.Resolve (ec);
7027 if (member_expr == null)
7031 // Next, evaluate all the expressions in the argument list
7033 bool dynamic_arg = false;
7034 if (arguments != null)
7035 arguments.Resolve (ec, out dynamic_arg);
7037 TypeSpec expr_type = member_expr.Type;
7038 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7039 return DoResolveDynamic (ec, member_expr);
7041 mg = member_expr as MethodGroupExpr;
7042 Expression invoke = null;
7045 if (expr_type != null && expr_type.IsDelegate) {
7046 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7047 invoke = invoke.Resolve (ec);
7048 if (invoke == null || !dynamic_arg)
7051 if (member_expr is RuntimeValueExpression) {
7052 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7053 member_expr.Type.GetSignatureForError ());
7057 MemberExpr me = member_expr as MemberExpr;
7059 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7063 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7064 member_expr.GetSignatureForError ());
7069 if (invoke == null) {
7070 mg = DoResolveOverload (ec);
7076 return DoResolveDynamic (ec, member_expr);
7078 var method = mg.BestCandidate;
7079 type = mg.BestCandidateReturnType;
7080 if (conditional_access_receiver)
7081 type = LiftMemberType (ec, type);
7083 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7085 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7087 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7091 IsSpecialMethodInvocation (ec, method, loc);
7093 eclass = ExprClass.Value;
7097 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7100 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7102 args = dmb.Arguments;
7103 if (arguments != null)
7104 args.AddRange (arguments);
7105 } else if (mg == null) {
7106 if (arguments == null)
7107 args = new Arguments (1);
7111 args.Insert (0, new Argument (memberExpr));
7115 ec.Report.Error (1971, loc,
7116 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7121 if (arguments == null)
7122 args = new Arguments (1);
7126 MemberAccess ma = expr as MemberAccess;
7128 var inst = mg.InstanceExpression;
7129 var left_type = inst as TypeExpr;
7130 if (left_type != null) {
7131 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7132 } else if (inst != null) {
7134 // Any value type has to be pass as by-ref to get back the same
7135 // instance on which the member was called
7137 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7138 Argument.AType.Ref : Argument.AType.None;
7139 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7141 } else { // is SimpleName
7143 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7145 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7150 return new DynamicInvocation (expr as ATypeNameExpression, args, loc).Resolve (ec);
7153 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7155 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7158 public override void FlowAnalysis (FlowAnalysisContext fc)
7160 if (mg.IsConditionallyExcluded)
7163 mg.FlowAnalysis (fc);
7165 if (arguments != null)
7166 arguments.FlowAnalysis (fc);
7168 if (conditional_access_receiver)
7169 fc.ConditionalAccessEnd ();
7172 public override string GetSignatureForError ()
7174 return mg.GetSignatureForError ();
7177 public override bool HasConditionalAccess ()
7179 return expr.HasConditionalAccess ();
7183 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7184 // or the type dynamic, then the member is invocable
7186 public static bool IsMemberInvocable (MemberSpec member)
7188 switch (member.Kind) {
7189 case MemberKind.Event:
7191 case MemberKind.Field:
7192 case MemberKind.Property:
7193 var m = member as IInterfaceMemberSpec;
7194 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7200 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7202 if (!method.IsReservedMethod)
7205 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7208 ec.Report.SymbolRelatedToPreviousError (method);
7209 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7210 method.GetSignatureForError ());
7215 public override void Emit (EmitContext ec)
7217 if (mg.IsConditionallyExcluded)
7220 if (conditional_access_receiver)
7221 mg.EmitCall (ec, arguments, type, false);
7223 mg.EmitCall (ec, arguments, false);
7226 public override void EmitStatement (EmitContext ec)
7228 if (mg.IsConditionallyExcluded)
7231 if (conditional_access_receiver)
7232 mg.EmitCall (ec, arguments, type, true);
7234 mg.EmitCall (ec, arguments, true);
7237 public override SLE.Expression MakeExpression (BuilderContext ctx)
7239 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7242 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7245 throw new NotSupportedException ();
7247 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7248 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7252 public override object Accept (StructuralVisitor visitor)
7254 return visitor.Visit (this);
7259 // Implements simple new expression
7261 public class New : ExpressionStatement, IMemoryLocation
7263 protected Arguments arguments;
7266 // During bootstrap, it contains the RequestedType,
7267 // but if `type' is not null, it *might* contain a NewDelegate
7268 // (because of field multi-initialization)
7270 protected Expression RequestedType;
7272 protected MethodSpec method;
7274 public New (Expression requested_type, Arguments arguments, Location l)
7276 RequestedType = requested_type;
7277 this.arguments = arguments;
7282 public Arguments Arguments {
7289 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7291 public bool IsGeneratedStructConstructor {
7293 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7297 public Expression TypeExpression {
7299 return RequestedType;
7306 /// Converts complex core type syntax like 'new int ()' to simple constant
7308 public static Constant Constantify (TypeSpec t, Location loc)
7310 switch (t.BuiltinType) {
7311 case BuiltinTypeSpec.Type.Int:
7312 return new IntConstant (t, 0, loc);
7313 case BuiltinTypeSpec.Type.UInt:
7314 return new UIntConstant (t, 0, loc);
7315 case BuiltinTypeSpec.Type.Long:
7316 return new LongConstant (t, 0, loc);
7317 case BuiltinTypeSpec.Type.ULong:
7318 return new ULongConstant (t, 0, loc);
7319 case BuiltinTypeSpec.Type.Float:
7320 return new FloatConstant (t, 0, loc);
7321 case BuiltinTypeSpec.Type.Double:
7322 return new DoubleConstant (t, 0, loc);
7323 case BuiltinTypeSpec.Type.Short:
7324 return new ShortConstant (t, 0, loc);
7325 case BuiltinTypeSpec.Type.UShort:
7326 return new UShortConstant (t, 0, loc);
7327 case BuiltinTypeSpec.Type.SByte:
7328 return new SByteConstant (t, 0, loc);
7329 case BuiltinTypeSpec.Type.Byte:
7330 return new ByteConstant (t, 0, loc);
7331 case BuiltinTypeSpec.Type.Char:
7332 return new CharConstant (t, '\0', loc);
7333 case BuiltinTypeSpec.Type.Bool:
7334 return new BoolConstant (t, false, loc);
7335 case BuiltinTypeSpec.Type.Decimal:
7336 return new DecimalConstant (t, 0, loc);
7340 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7342 if (t.IsNullableType)
7343 return Nullable.LiftedNull.Create (t, loc);
7348 public override bool ContainsEmitWithAwait ()
7350 return arguments != null && arguments.ContainsEmitWithAwait ();
7354 // Checks whether the type is an interface that has the
7355 // [ComImport, CoClass] attributes and must be treated
7358 public Expression CheckComImport (ResolveContext ec)
7360 if (!type.IsInterface)
7364 // Turn the call into:
7365 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7367 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7368 if (real_class == null)
7371 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7372 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7373 return cast.Resolve (ec);
7376 public override Expression CreateExpressionTree (ResolveContext ec)
7379 if (method == null) {
7380 args = new Arguments (1);
7381 args.Add (new Argument (new TypeOf (type, loc)));
7383 args = Arguments.CreateForExpressionTree (ec,
7384 arguments, new TypeOfMethod (method, loc));
7387 return CreateExpressionFactoryCall (ec, "New", args);
7390 protected override Expression DoResolve (ResolveContext ec)
7392 type = RequestedType.ResolveAsType (ec);
7396 eclass = ExprClass.Value;
7398 if (type.IsPointer) {
7399 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7400 type.GetSignatureForError ());
7404 if (arguments == null) {
7405 Constant c = Constantify (type, RequestedType.Location);
7407 return ReducedExpression.Create (c, this);
7410 if (type.IsDelegate) {
7411 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7414 var tparam = type as TypeParameterSpec;
7415 if (tparam != null) {
7417 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7418 // where type parameter constraint is inflated to struct
7420 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7421 ec.Report.Error (304, loc,
7422 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7423 type.GetSignatureForError ());
7426 if ((arguments != null) && (arguments.Count != 0)) {
7427 ec.Report.Error (417, loc,
7428 "`{0}': cannot provide arguments when creating an instance of a variable type",
7429 type.GetSignatureForError ());
7435 if (type.IsStatic) {
7436 ec.Report.SymbolRelatedToPreviousError (type);
7437 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7441 if (type.IsInterface || type.IsAbstract){
7442 if (!TypeManager.IsGenericType (type)) {
7443 RequestedType = CheckComImport (ec);
7444 if (RequestedType != null)
7445 return RequestedType;
7448 ec.Report.SymbolRelatedToPreviousError (type);
7449 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7454 if (arguments != null) {
7455 arguments.Resolve (ec, out dynamic);
7460 method = ConstructorLookup (ec, type, ref arguments, loc);
7463 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7464 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7470 void DoEmitTypeParameter (EmitContext ec)
7472 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7476 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7477 ec.Emit (OpCodes.Call, ctor_factory);
7481 // This Emit can be invoked in two contexts:
7482 // * As a mechanism that will leave a value on the stack (new object)
7483 // * As one that wont (init struct)
7485 // If we are dealing with a ValueType, we have a few
7486 // situations to deal with:
7488 // * The target is a ValueType, and we have been provided
7489 // the instance (this is easy, we are being assigned).
7491 // * The target of New is being passed as an argument,
7492 // to a boxing operation or a function that takes a
7495 // In this case, we need to create a temporary variable
7496 // that is the argument of New.
7498 // Returns whether a value is left on the stack
7500 // *** Implementation note ***
7502 // To benefit from this optimization, each assignable expression
7503 // has to manually cast to New and call this Emit.
7505 // TODO: It's worth to implement it for arrays and fields
7507 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7509 bool is_value_type = type.IsStructOrEnum;
7510 VariableReference vr = target as VariableReference;
7512 if (target != null && is_value_type && (vr != null || method == null)) {
7513 target.AddressOf (ec, AddressOp.Store);
7514 } else if (vr != null && vr.IsRef) {
7518 if (arguments != null) {
7519 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
7520 arguments = arguments.Emit (ec, false, true);
7522 arguments.Emit (ec);
7525 if (is_value_type) {
7526 if (method == null) {
7527 ec.Emit (OpCodes.Initobj, type);
7532 ec.MarkCallEntry (loc);
7533 ec.Emit (OpCodes.Call, method);
7538 if (type is TypeParameterSpec) {
7539 DoEmitTypeParameter (ec);
7543 ec.MarkCallEntry (loc);
7544 ec.Emit (OpCodes.Newobj, method);
7548 public override void Emit (EmitContext ec)
7550 LocalTemporary v = null;
7551 if (method == null && type.IsStructOrEnum) {
7552 // TODO: Use temporary variable from pool
7553 v = new LocalTemporary (type);
7560 public override void EmitStatement (EmitContext ec)
7562 LocalTemporary v = null;
7563 if (method == null && TypeSpec.IsValueType (type)) {
7564 // TODO: Use temporary variable from pool
7565 v = new LocalTemporary (type);
7569 ec.Emit (OpCodes.Pop);
7572 public override void FlowAnalysis (FlowAnalysisContext fc)
7574 if (arguments != null)
7575 arguments.FlowAnalysis (fc);
7578 public void AddressOf (EmitContext ec, AddressOp mode)
7580 EmitAddressOf (ec, mode);
7583 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7585 LocalTemporary value_target = new LocalTemporary (type);
7587 if (type is TypeParameterSpec) {
7588 DoEmitTypeParameter (ec);
7589 value_target.Store (ec);
7590 value_target.AddressOf (ec, mode);
7591 return value_target;
7594 value_target.AddressOf (ec, AddressOp.Store);
7596 if (method == null) {
7597 ec.Emit (OpCodes.Initobj, type);
7599 if (arguments != null)
7600 arguments.Emit (ec);
7602 ec.Emit (OpCodes.Call, method);
7605 value_target.AddressOf (ec, mode);
7606 return value_target;
7609 protected override void CloneTo (CloneContext clonectx, Expression t)
7611 New target = (New) t;
7613 target.RequestedType = RequestedType.Clone (clonectx);
7614 if (arguments != null){
7615 target.arguments = arguments.Clone (clonectx);
7619 public override SLE.Expression MakeExpression (BuilderContext ctx)
7622 return base.MakeExpression (ctx);
7624 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7628 public override object Accept (StructuralVisitor visitor)
7630 return visitor.Visit (this);
7635 // Array initializer expression, the expression is allowed in
7636 // variable or field initialization only which makes it tricky as
7637 // the type has to be infered based on the context either from field
7638 // type or variable type (think of multiple declarators)
7640 public class ArrayInitializer : Expression
7642 List<Expression> elements;
7643 BlockVariable variable;
7645 public ArrayInitializer (List<Expression> init, Location loc)
7651 public ArrayInitializer (int count, Location loc)
7652 : this (new List<Expression> (count), loc)
7656 public ArrayInitializer (Location loc)
7664 get { return elements.Count; }
7667 public List<Expression> Elements {
7673 public Expression this [int index] {
7675 return elements [index];
7679 public BlockVariable VariableDeclaration {
7690 public void Add (Expression expr)
7692 elements.Add (expr);
7695 public override bool ContainsEmitWithAwait ()
7697 throw new NotSupportedException ();
7700 public override Expression CreateExpressionTree (ResolveContext ec)
7702 throw new NotSupportedException ("ET");
7705 protected override void CloneTo (CloneContext clonectx, Expression t)
7707 var target = (ArrayInitializer) t;
7709 target.elements = new List<Expression> (elements.Count);
7710 foreach (var element in elements)
7711 target.elements.Add (element.Clone (clonectx));
7714 protected override Expression DoResolve (ResolveContext rc)
7716 var current_field = rc.CurrentMemberDefinition as FieldBase;
7717 TypeExpression type;
7718 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7719 type = new TypeExpression (current_field.MemberType, current_field.Location);
7720 } else if (variable != null) {
7721 if (variable.TypeExpression is VarExpr) {
7722 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7723 return EmptyExpression.Null;
7726 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7728 throw new NotImplementedException ("Unexpected array initializer context");
7731 return new ArrayCreation (type, this).Resolve (rc);
7734 public override void Emit (EmitContext ec)
7736 throw new InternalErrorException ("Missing Resolve call");
7739 public override void FlowAnalysis (FlowAnalysisContext fc)
7741 throw new InternalErrorException ("Missing Resolve call");
7744 public override object Accept (StructuralVisitor visitor)
7746 return visitor.Visit (this);
7751 /// 14.5.10.2: Represents an array creation expression.
7755 /// There are two possible scenarios here: one is an array creation
7756 /// expression that specifies the dimensions and optionally the
7757 /// initialization data and the other which does not need dimensions
7758 /// specified but where initialization data is mandatory.
7760 public class ArrayCreation : Expression
7762 FullNamedExpression requested_base_type;
7763 ArrayInitializer initializers;
7766 // The list of Argument types.
7767 // This is used to construct the `newarray' or constructor signature
7769 protected List<Expression> arguments;
7771 protected TypeSpec array_element_type;
7773 protected int dimensions;
7774 protected readonly ComposedTypeSpecifier rank;
7775 Expression first_emit;
7776 LocalTemporary first_emit_temp;
7778 protected List<Expression> array_data;
7780 Dictionary<int, int> bounds;
7783 // The number of constants in array initializers
7784 int const_initializers_count;
7785 bool only_constant_initializers;
7787 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7788 : this (requested_base_type, rank, initializers, l)
7790 arguments = new List<Expression> (exprs);
7791 num_arguments = arguments.Count;
7795 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7797 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7799 this.requested_base_type = requested_base_type;
7801 this.initializers = initializers;
7805 num_arguments = rank.Dimension;
7809 // For compiler generated single dimensional arrays only
7811 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7812 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7817 // For expressions like int[] foo = { 1, 2, 3 };
7819 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7820 : this (requested_base_type, null, initializers, initializers.Location)
7824 public ComposedTypeSpecifier Rank {
7830 public FullNamedExpression TypeExpression {
7832 return this.requested_base_type;
7836 public ArrayInitializer Initializers {
7838 return this.initializers;
7842 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
7844 if (initializers != null && bounds == null) {
7846 // We use this to store all the data values in the order in which we
7847 // will need to store them in the byte blob later
7849 array_data = new List<Expression> (probe.Count);
7850 bounds = new Dictionary<int, int> ();
7853 if (specified_dims) {
7854 Expression a = arguments [idx];
7859 a = ConvertExpressionToArrayIndex (ec, a);
7865 if (initializers != null) {
7866 Constant c = a as Constant;
7867 if (c == null && a is ArrayIndexCast)
7868 c = ((ArrayIndexCast) a).Child as Constant;
7871 ec.Report.Error (150, a.Location, "A constant value is expected");
7877 value = System.Convert.ToInt32 (c.GetValue ());
7879 ec.Report.Error (150, a.Location, "A constant value is expected");
7883 // TODO: probe.Count does not fit ulong in
7884 if (value != probe.Count) {
7885 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
7889 bounds[idx] = value;
7893 if (initializers == null)
7896 for (int i = 0; i < probe.Count; ++i) {
7898 if (o is ArrayInitializer) {
7899 var sub_probe = o as ArrayInitializer;
7900 if (idx + 1 >= dimensions){
7901 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
7905 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
7906 if (!bounds.ContainsKey(idx + 1))
7907 bounds[idx + 1] = sub_probe.Count;
7909 if (bounds[idx + 1] != sub_probe.Count) {
7910 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
7914 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
7917 } else if (child_bounds > 1) {
7918 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
7920 Expression element = ResolveArrayElement (ec, o);
7921 if (element == null)
7924 // Initializers with the default values can be ignored
7925 Constant c = element as Constant;
7927 if (!c.IsDefaultInitializer (array_element_type)) {
7928 ++const_initializers_count;
7931 only_constant_initializers = false;
7934 array_data.Add (element);
7941 public override bool ContainsEmitWithAwait ()
7943 foreach (var arg in arguments) {
7944 if (arg.ContainsEmitWithAwait ())
7948 return InitializersContainAwait ();
7951 public override Expression CreateExpressionTree (ResolveContext ec)
7955 if (array_data == null) {
7956 args = new Arguments (arguments.Count + 1);
7957 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7958 foreach (Expression a in arguments)
7959 args.Add (new Argument (a.CreateExpressionTree (ec)));
7961 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
7964 if (dimensions > 1) {
7965 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
7969 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
7970 args.Add (new Argument (new TypeOf (array_element_type, loc)));
7971 if (array_data != null) {
7972 for (int i = 0; i < array_data.Count; ++i) {
7973 Expression e = array_data [i];
7974 args.Add (new Argument (e.CreateExpressionTree (ec)));
7978 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
7981 void UpdateIndices (ResolveContext rc)
7984 for (var probe = initializers; probe != null;) {
7985 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
7987 bounds[i++] = probe.Count;
7989 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
7990 probe = (ArrayInitializer) probe[0];
7991 } else if (dimensions > i) {
7999 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8001 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8004 public override void FlowAnalysis (FlowAnalysisContext fc)
8006 foreach (var arg in arguments)
8007 arg.FlowAnalysis (fc);
8009 if (array_data != null) {
8010 foreach (var ad in array_data)
8011 ad.FlowAnalysis (fc);
8015 bool InitializersContainAwait ()
8017 if (array_data == null)
8020 foreach (var expr in array_data) {
8021 if (expr.ContainsEmitWithAwait ())
8028 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8030 element = element.Resolve (ec);
8031 if (element == null)
8034 if (element is CompoundAssign.TargetExpression) {
8035 if (first_emit != null)
8036 throw new InternalErrorException ("Can only handle one mutator at a time");
8037 first_emit = element;
8038 element = first_emit_temp = new LocalTemporary (element.Type);
8041 return Convert.ImplicitConversionRequired (
8042 ec, element, array_element_type, loc);
8045 protected bool ResolveInitializers (ResolveContext ec)
8048 only_constant_initializers = true;
8051 if (arguments != null) {
8053 for (int i = 0; i < arguments.Count; ++i) {
8054 res &= CheckIndices (ec, initializers, i, true, dimensions);
8055 if (initializers != null)
8062 arguments = new List<Expression> ();
8064 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8073 // Resolved the type of the array
8075 bool ResolveArrayType (ResolveContext ec)
8080 FullNamedExpression array_type_expr;
8081 if (num_arguments > 0) {
8082 array_type_expr = new ComposedCast (requested_base_type, rank);
8084 array_type_expr = requested_base_type;
8087 type = array_type_expr.ResolveAsType (ec);
8088 if (array_type_expr == null)
8091 var ac = type as ArrayContainer;
8093 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8097 array_element_type = ac.Element;
8098 dimensions = ac.Rank;
8103 protected override Expression DoResolve (ResolveContext ec)
8108 if (!ResolveArrayType (ec))
8112 // validate the initializers and fill in any missing bits
8114 if (!ResolveInitializers (ec))
8117 eclass = ExprClass.Value;
8121 byte [] MakeByteBlob ()
8126 int count = array_data.Count;
8128 TypeSpec element_type = array_element_type;
8129 if (element_type.IsEnum)
8130 element_type = EnumSpec.GetUnderlyingType (element_type);
8132 factor = BuiltinTypeSpec.GetSize (element_type);
8134 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8136 data = new byte [(count * factor + 3) & ~3];
8139 for (int i = 0; i < count; ++i) {
8140 var c = array_data[i] as Constant;
8146 object v = c.GetValue ();
8148 switch (element_type.BuiltinType) {
8149 case BuiltinTypeSpec.Type.Long:
8150 long lval = (long) v;
8152 for (int j = 0; j < factor; ++j) {
8153 data[idx + j] = (byte) (lval & 0xFF);
8157 case BuiltinTypeSpec.Type.ULong:
8158 ulong ulval = (ulong) v;
8160 for (int j = 0; j < factor; ++j) {
8161 data[idx + j] = (byte) (ulval & 0xFF);
8162 ulval = (ulval >> 8);
8165 case BuiltinTypeSpec.Type.Float:
8166 var fval = SingleConverter.SingleToInt32Bits((float) v);
8168 data[idx] = (byte) (fval & 0xff);
8169 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8170 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8171 data[idx + 3] = (byte) (fval >> 24);
8173 case BuiltinTypeSpec.Type.Double:
8174 element = BitConverter.GetBytes ((double) v);
8176 for (int j = 0; j < factor; ++j)
8177 data[idx + j] = element[j];
8179 // FIXME: Handle the ARM float format.
8180 if (!BitConverter.IsLittleEndian)
8181 System.Array.Reverse (data, idx, 8);
8183 case BuiltinTypeSpec.Type.Char:
8184 int chval = (int) ((char) v);
8186 data[idx] = (byte) (chval & 0xff);
8187 data[idx + 1] = (byte) (chval >> 8);
8189 case BuiltinTypeSpec.Type.Short:
8190 int sval = (int) ((short) v);
8192 data[idx] = (byte) (sval & 0xff);
8193 data[idx + 1] = (byte) (sval >> 8);
8195 case BuiltinTypeSpec.Type.UShort:
8196 int usval = (int) ((ushort) v);
8198 data[idx] = (byte) (usval & 0xff);
8199 data[idx + 1] = (byte) (usval >> 8);
8201 case BuiltinTypeSpec.Type.Int:
8204 data[idx] = (byte) (val & 0xff);
8205 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8206 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8207 data[idx + 3] = (byte) (val >> 24);
8209 case BuiltinTypeSpec.Type.UInt:
8210 uint uval = (uint) v;
8212 data[idx] = (byte) (uval & 0xff);
8213 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8214 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8215 data[idx + 3] = (byte) (uval >> 24);
8217 case BuiltinTypeSpec.Type.SByte:
8218 data[idx] = (byte) (sbyte) v;
8220 case BuiltinTypeSpec.Type.Byte:
8221 data[idx] = (byte) v;
8223 case BuiltinTypeSpec.Type.Bool:
8224 data[idx] = (byte) ((bool) v ? 1 : 0);
8226 case BuiltinTypeSpec.Type.Decimal:
8227 int[] bits = Decimal.GetBits ((decimal) v);
8230 // FIXME: For some reason, this doesn't work on the MS runtime.
8231 int[] nbits = new int[4];
8237 for (int j = 0; j < 4; j++) {
8238 data[p++] = (byte) (nbits[j] & 0xff);
8239 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8240 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8241 data[p++] = (byte) (nbits[j] >> 24);
8245 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8254 #if NET_4_0 || MOBILE_DYNAMIC
8255 public override SLE.Expression MakeExpression (BuilderContext ctx)
8258 return base.MakeExpression (ctx);
8260 var initializers = new SLE.Expression [array_data.Count];
8261 for (var i = 0; i < initializers.Length; i++) {
8262 if (array_data [i] == null)
8263 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8265 initializers [i] = array_data [i].MakeExpression (ctx);
8268 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8274 // Emits the initializers for the array
8276 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8278 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8283 // First, the static data
8285 byte [] data = MakeByteBlob ();
8286 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8288 if (stackArray == null) {
8289 ec.Emit (OpCodes.Dup);
8291 stackArray.Emit (ec);
8294 ec.Emit (OpCodes.Ldtoken, fb);
8295 ec.Emit (OpCodes.Call, m);
8300 // Emits pieces of the array that can not be computed at compile
8301 // time (variables and string locations).
8303 // This always expect the top value on the stack to be the array
8305 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8307 int dims = bounds.Count;
8308 var current_pos = new int [dims];
8310 for (int i = 0; i < array_data.Count; i++){
8312 Expression e = array_data [i];
8313 var c = e as Constant;
8315 // Constant can be initialized via StaticInitializer
8316 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8320 if (stackArray != null) {
8321 if (e.ContainsEmitWithAwait ()) {
8322 e = e.EmitToField (ec);
8325 stackArray.EmitLoad (ec);
8327 ec.Emit (OpCodes.Dup);
8330 for (int idx = 0; idx < dims; idx++)
8331 ec.EmitInt (current_pos [idx]);
8334 // If we are dealing with a struct, get the
8335 // address of it, so we can store it.
8337 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8338 ec.Emit (OpCodes.Ldelema, etype);
8342 ec.EmitArrayStore ((ArrayContainer) type);
8348 for (int j = dims - 1; j >= 0; j--){
8350 if (current_pos [j] < bounds [j])
8352 current_pos [j] = 0;
8356 if (stackArray != null)
8357 stackArray.PrepareCleanup (ec);
8360 public override void Emit (EmitContext ec)
8362 var await_field = EmitToFieldSource (ec);
8363 if (await_field != null)
8364 await_field.Emit (ec);
8367 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8369 if (first_emit != null) {
8370 first_emit.Emit (ec);
8371 first_emit_temp.Store (ec);
8374 StackFieldExpr await_stack_field;
8375 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8376 await_stack_field = ec.GetTemporaryField (type);
8379 await_stack_field = null;
8382 EmitExpressionsList (ec, arguments);
8384 ec.EmitArrayNew ((ArrayContainer) type);
8386 if (initializers == null)
8387 return await_stack_field;
8389 if (await_stack_field != null)
8390 await_stack_field.EmitAssignFromStack (ec);
8394 // Emit static initializer for arrays which contain more than 2 items and
8395 // the static initializer will initialize at least 25% of array values or there
8396 // is more than 10 items to be initialized
8398 // NOTE: const_initializers_count does not contain default constant values.
8400 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8401 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8402 EmitStaticInitializers (ec, await_stack_field);
8404 if (!only_constant_initializers)
8405 EmitDynamicInitializers (ec, false, await_stack_field);
8409 EmitDynamicInitializers (ec, true, await_stack_field);
8412 if (first_emit_temp != null)
8413 first_emit_temp.Release (ec);
8415 return await_stack_field;
8418 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8420 // no multi dimensional or jagged arrays
8421 if (arguments.Count != 1 || array_element_type.IsArray) {
8422 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8426 // No array covariance, except for array -> object
8427 if (type != targetType) {
8428 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8429 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8433 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8434 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8439 // Single dimensional array of 0 size
8440 if (array_data == null) {
8441 IntConstant ic = arguments[0] as IntConstant;
8442 if (ic == null || !ic.IsDefaultValue) {
8443 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8451 enc.Encode (array_data.Count);
8452 foreach (var element in array_data) {
8453 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8457 protected override void CloneTo (CloneContext clonectx, Expression t)
8459 ArrayCreation target = (ArrayCreation) t;
8461 if (requested_base_type != null)
8462 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8464 if (arguments != null){
8465 target.arguments = new List<Expression> (arguments.Count);
8466 foreach (Expression e in arguments)
8467 target.arguments.Add (e.Clone (clonectx));
8470 if (initializers != null)
8471 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8474 public override object Accept (StructuralVisitor visitor)
8476 return visitor.Visit (this);
8481 // Represents an implicitly typed array epxression
8483 class ImplicitlyTypedArrayCreation : ArrayCreation
8485 TypeInferenceContext best_type_inference;
8487 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8488 : base (null, rank, initializers, loc)
8492 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8493 : base (null, initializers, loc)
8497 protected override Expression DoResolve (ResolveContext ec)
8502 dimensions = rank.Dimension;
8504 best_type_inference = new TypeInferenceContext ();
8506 if (!ResolveInitializers (ec))
8509 best_type_inference.FixAllTypes (ec);
8510 array_element_type = best_type_inference.InferredTypeArguments[0];
8511 best_type_inference = null;
8513 if (array_element_type == null ||
8514 array_element_type == InternalType.NullLiteral || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
8515 arguments.Count != rank.Dimension) {
8516 ec.Report.Error (826, loc,
8517 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8522 // At this point we found common base type for all initializer elements
8523 // but we have to be sure that all static initializer elements are of
8526 UnifyInitializerElement (ec);
8528 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8529 eclass = ExprClass.Value;
8534 // Converts static initializer only
8536 void UnifyInitializerElement (ResolveContext ec)
8538 for (int i = 0; i < array_data.Count; ++i) {
8539 Expression e = array_data[i];
8541 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8545 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8547 element = element.Resolve (ec);
8548 if (element != null)
8549 best_type_inference.AddCommonTypeBound (element.Type);
8555 sealed class CompilerGeneratedThis : This
8557 public CompilerGeneratedThis (TypeSpec type, Location loc)
8563 protected override Expression DoResolve (ResolveContext rc)
8565 eclass = ExprClass.Variable;
8567 var block = rc.CurrentBlock;
8568 if (block != null) {
8569 var top = block.ParametersBlock.TopBlock;
8570 if (top.ThisVariable != null)
8571 variable_info = top.ThisVariable.VariableInfo;
8578 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8580 return DoResolve (rc);
8583 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8590 /// Represents the `this' construct
8593 public class This : VariableReference
8595 sealed class ThisVariable : ILocalVariable
8597 public static readonly ILocalVariable Instance = new ThisVariable ();
8599 public void Emit (EmitContext ec)
8604 public void EmitAssign (EmitContext ec)
8606 throw new InvalidOperationException ();
8609 public void EmitAddressOf (EmitContext ec)
8615 protected VariableInfo variable_info;
8617 public This (Location loc)
8624 public override string Name {
8625 get { return "this"; }
8628 public override bool IsLockedByStatement {
8636 public override bool IsRef {
8637 get { return type.IsStruct; }
8640 public override bool IsSideEffectFree {
8646 protected override ILocalVariable Variable {
8647 get { return ThisVariable.Instance; }
8650 public override VariableInfo VariableInfo {
8651 get { return variable_info; }
8654 public override bool IsFixed {
8655 get { return false; }
8660 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8663 // It's null for all cases when we don't need to check `this'
8664 // definitive assignment
8666 if (variable_info == null)
8669 if (fc.IsDefinitelyAssigned (variable_info))
8672 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8675 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8677 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8678 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8679 } else if (ec.CurrentAnonymousMethod != null) {
8680 ec.Report.Error (1673, loc,
8681 "Anonymous methods inside structs cannot access instance members of `this'. " +
8682 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8684 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8688 public override void FlowAnalysis (FlowAnalysisContext fc)
8690 CheckStructThisDefiniteAssignment (fc);
8693 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8698 AnonymousMethodStorey storey = ae.Storey;
8699 return storey != null ? storey.HoistedThis : null;
8702 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8704 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8707 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8710 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8716 public virtual void ResolveBase (ResolveContext ec)
8718 eclass = ExprClass.Variable;
8719 type = ec.CurrentType;
8721 if (!IsThisAvailable (ec, false)) {
8722 Error_ThisNotAvailable (ec);
8726 var block = ec.CurrentBlock;
8727 if (block != null) {
8728 var top = block.ParametersBlock.TopBlock;
8729 if (top.ThisVariable != null)
8730 variable_info = top.ThisVariable.VariableInfo;
8732 AnonymousExpression am = ec.CurrentAnonymousMethod;
8733 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8735 // Hoisted this is almost like hoisted variable but not exactly. When
8736 // there is no variable hoisted we can simply emit an instance method
8737 // without lifting this into a storey. Unfotunatelly this complicates
8738 // things in other cases because we don't know where this will be hoisted
8739 // until top-level block is fully resolved
8741 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8742 am.SetHasThisAccess ();
8747 protected override Expression DoResolve (ResolveContext ec)
8753 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8755 if (eclass == ExprClass.Unresolved)
8759 if (right_side == EmptyExpression.UnaryAddress)
8760 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8761 else if (right_side == EmptyExpression.OutAccess)
8762 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8764 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8770 public override int GetHashCode()
8772 throw new NotImplementedException ();
8775 public override bool Equals (object obj)
8777 This t = obj as This;
8784 protected override void CloneTo (CloneContext clonectx, Expression t)
8789 public override void SetHasAddressTaken ()
8794 public override object Accept (StructuralVisitor visitor)
8796 return visitor.Visit (this);
8801 /// Represents the `__arglist' construct
8803 public class ArglistAccess : Expression
8805 public ArglistAccess (Location loc)
8810 protected override void CloneTo (CloneContext clonectx, Expression target)
8815 public override bool ContainsEmitWithAwait ()
8820 public override Expression CreateExpressionTree (ResolveContext ec)
8822 throw new NotSupportedException ("ET");
8825 protected override Expression DoResolve (ResolveContext ec)
8827 eclass = ExprClass.Variable;
8828 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
8830 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
8831 ec.Report.Error (190, loc,
8832 "The __arglist construct is valid only within a variable argument method");
8838 public override void Emit (EmitContext ec)
8840 ec.Emit (OpCodes.Arglist);
8843 public override object Accept (StructuralVisitor visitor)
8845 return visitor.Visit (this);
8850 /// Represents the `__arglist (....)' construct
8852 public class Arglist : Expression
8854 Arguments arguments;
8856 public Arglist (Location loc)
8861 public Arglist (Arguments args, Location l)
8867 public Arguments Arguments {
8873 public MetaType[] ArgumentTypes {
8875 if (arguments == null)
8876 return MetaType.EmptyTypes;
8878 var retval = new MetaType[arguments.Count];
8879 for (int i = 0; i < retval.Length; i++)
8880 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
8886 public override bool ContainsEmitWithAwait ()
8888 throw new NotImplementedException ();
8891 public override Expression CreateExpressionTree (ResolveContext ec)
8893 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
8897 protected override Expression DoResolve (ResolveContext ec)
8899 eclass = ExprClass.Variable;
8900 type = InternalType.Arglist;
8901 if (arguments != null) {
8902 bool dynamic; // Can be ignored as there is always only 1 overload
8903 arguments.Resolve (ec, out dynamic);
8909 public override void Emit (EmitContext ec)
8911 if (arguments != null)
8912 arguments.Emit (ec);
8915 protected override void CloneTo (CloneContext clonectx, Expression t)
8917 Arglist target = (Arglist) t;
8919 if (arguments != null)
8920 target.arguments = arguments.Clone (clonectx);
8923 public override object Accept (StructuralVisitor visitor)
8925 return visitor.Visit (this);
8929 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
8931 FullNamedExpression texpr;
8933 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
8940 public FullNamedExpression TypeExpression {
8946 public override bool ContainsEmitWithAwait ()
8951 public void AddressOf (EmitContext ec, AddressOp mode)
8954 ec.Emit (OpCodes.Refanyval, type);
8957 protected override Expression DoResolve (ResolveContext rc)
8959 expr = expr.Resolve (rc);
8960 type = texpr.ResolveAsType (rc);
8961 if (expr == null || type == null)
8964 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
8965 eclass = ExprClass.Variable;
8969 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8971 return DoResolve (rc);
8974 public override void Emit (EmitContext ec)
8977 ec.Emit (OpCodes.Refanyval, type);
8978 ec.EmitLoadFromPtr (type);
8981 public void Emit (EmitContext ec, bool leave_copy)
8983 throw new NotImplementedException ();
8986 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
8989 ec.Emit (OpCodes.Refanyval, type);
8992 LocalTemporary temporary = null;
8994 ec.Emit (OpCodes.Dup);
8995 temporary = new LocalTemporary (source.Type);
8996 temporary.Store (ec);
8999 ec.EmitStoreFromPtr (type);
9001 if (temporary != null) {
9002 temporary.Emit (ec);
9003 temporary.Release (ec);
9007 public override object Accept (StructuralVisitor visitor)
9009 return visitor.Visit (this);
9013 public class RefTypeExpr : ShimExpression
9015 public RefTypeExpr (Expression expr, Location loc)
9021 protected override Expression DoResolve (ResolveContext rc)
9023 expr = expr.Resolve (rc);
9027 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9031 type = rc.BuiltinTypes.Type;
9032 eclass = ExprClass.Value;
9036 public override void Emit (EmitContext ec)
9039 ec.Emit (OpCodes.Refanytype);
9040 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9042 ec.Emit (OpCodes.Call, m);
9045 public override object Accept (StructuralVisitor visitor)
9047 return visitor.Visit (this);
9051 public class MakeRefExpr : ShimExpression
9053 public MakeRefExpr (Expression expr, Location loc)
9059 public override bool ContainsEmitWithAwait ()
9061 throw new NotImplementedException ();
9064 protected override Expression DoResolve (ResolveContext rc)
9066 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9067 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9068 eclass = ExprClass.Value;
9072 public override void Emit (EmitContext ec)
9074 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9075 ec.Emit (OpCodes.Mkrefany, expr.Type);
9078 public override object Accept (StructuralVisitor visitor)
9080 return visitor.Visit (this);
9085 /// Implements the typeof operator
9087 public class TypeOf : Expression {
9088 FullNamedExpression QueriedType;
9091 public TypeOf (FullNamedExpression queried_type, Location l)
9093 QueriedType = queried_type;
9098 // Use this constructor for any compiler generated typeof expression
9100 public TypeOf (TypeSpec type, Location loc)
9102 this.typearg = type;
9108 public override bool IsSideEffectFree {
9114 public TypeSpec TypeArgument {
9120 public FullNamedExpression TypeExpression {
9129 protected override void CloneTo (CloneContext clonectx, Expression t)
9131 TypeOf target = (TypeOf) t;
9132 if (QueriedType != null)
9133 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9136 public override bool ContainsEmitWithAwait ()
9141 public override Expression CreateExpressionTree (ResolveContext ec)
9143 Arguments args = new Arguments (2);
9144 args.Add (new Argument (this));
9145 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9146 return CreateExpressionFactoryCall (ec, "Constant", args);
9149 protected override Expression DoResolve (ResolveContext ec)
9151 if (eclass != ExprClass.Unresolved)
9154 if (typearg == null) {
9156 // Pointer types are allowed without explicit unsafe, they are just tokens
9158 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9159 typearg = QueriedType.ResolveAsType (ec, true);
9162 if (typearg == null)
9165 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9166 ec.Report.Error (1962, QueriedType.Location,
9167 "The typeof operator cannot be used on the dynamic type");
9171 type = ec.BuiltinTypes.Type;
9173 // Even though what is returned is a type object, it's treated as a value by the compiler.
9174 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9175 eclass = ExprClass.Value;
9179 static bool ContainsDynamicType (TypeSpec type)
9181 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9184 var element_container = type as ElementTypeSpec;
9185 if (element_container != null)
9186 return ContainsDynamicType (element_container.Element);
9188 foreach (var t in type.TypeArguments) {
9189 if (ContainsDynamicType (t)) {
9197 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9199 // Target type is not System.Type therefore must be object
9200 // and we need to use different encoding sequence
9201 if (targetType != type)
9204 if (typearg is InflatedTypeSpec) {
9207 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9208 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9209 typearg.GetSignatureForError ());
9213 gt = gt.DeclaringType;
9214 } while (gt != null);
9217 if (ContainsDynamicType (typearg)) {
9218 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9222 enc.EncodeTypeName (typearg);
9225 public override void Emit (EmitContext ec)
9227 ec.Emit (OpCodes.Ldtoken, typearg);
9228 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9230 ec.Emit (OpCodes.Call, m);
9233 public override object Accept (StructuralVisitor visitor)
9235 return visitor.Visit (this);
9239 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9241 public TypeOfMethod (MethodSpec method, Location loc)
9242 : base (method, loc)
9246 protected override Expression DoResolve (ResolveContext ec)
9248 if (member.IsConstructor) {
9249 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9251 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9257 return base.DoResolve (ec);
9260 public override void Emit (EmitContext ec)
9262 ec.Emit (OpCodes.Ldtoken, member);
9265 ec.Emit (OpCodes.Castclass, type);
9268 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9270 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9273 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9275 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9279 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9281 protected readonly T member;
9283 protected TypeOfMember (T member, Location loc)
9285 this.member = member;
9289 public override bool IsSideEffectFree {
9295 public override bool ContainsEmitWithAwait ()
9300 public override Expression CreateExpressionTree (ResolveContext ec)
9302 Arguments args = new Arguments (2);
9303 args.Add (new Argument (this));
9304 args.Add (new Argument (new TypeOf (type, loc)));
9305 return CreateExpressionFactoryCall (ec, "Constant", args);
9308 protected override Expression DoResolve (ResolveContext ec)
9310 eclass = ExprClass.Value;
9314 public override void Emit (EmitContext ec)
9316 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9317 PredefinedMember<MethodSpec> p;
9319 p = GetTypeFromHandleGeneric (ec);
9320 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9322 p = GetTypeFromHandle (ec);
9325 var mi = p.Resolve (loc);
9327 ec.Emit (OpCodes.Call, mi);
9330 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9331 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9334 sealed class TypeOfField : TypeOfMember<FieldSpec>
9336 public TypeOfField (FieldSpec field, Location loc)
9341 protected override Expression DoResolve (ResolveContext ec)
9343 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9347 return base.DoResolve (ec);
9350 public override void Emit (EmitContext ec)
9352 ec.Emit (OpCodes.Ldtoken, member);
9356 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9358 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9361 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9363 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9368 /// Implements the sizeof expression
9370 public class SizeOf : Expression {
9371 readonly Expression texpr;
9372 TypeSpec type_queried;
9374 public SizeOf (Expression queried_type, Location l)
9376 this.texpr = queried_type;
9380 public override bool IsSideEffectFree {
9386 public Expression TypeExpression {
9392 public override bool ContainsEmitWithAwait ()
9397 public override Expression CreateExpressionTree (ResolveContext ec)
9399 Error_PointerInsideExpressionTree (ec);
9403 protected override Expression DoResolve (ResolveContext ec)
9405 type_queried = texpr.ResolveAsType (ec);
9406 if (type_queried == null)
9409 if (type_queried.IsEnum)
9410 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9412 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9414 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9417 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9422 ec.Report.Error (233, loc,
9423 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9424 type_queried.GetSignatureForError ());
9427 type = ec.BuiltinTypes.Int;
9428 eclass = ExprClass.Value;
9432 public override void Emit (EmitContext ec)
9434 ec.Emit (OpCodes.Sizeof, type_queried);
9437 protected override void CloneTo (CloneContext clonectx, Expression t)
9441 public override object Accept (StructuralVisitor visitor)
9443 return visitor.Visit (this);
9448 /// Implements the qualified-alias-member (::) expression.
9450 public class QualifiedAliasMember : MemberAccess
9452 readonly string alias;
9453 public static readonly string GlobalAlias = "global";
9455 public QualifiedAliasMember (string alias, string identifier, Location l)
9456 : base (null, identifier, l)
9461 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9462 : base (null, identifier, targs, l)
9467 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9468 : base (null, identifier, arity, l)
9473 public string Alias {
9479 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9481 if (alias == GlobalAlias)
9482 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9484 int errors = mc.Module.Compiler.Report.Errors;
9485 var expr = mc.LookupNamespaceAlias (alias);
9487 if (errors == mc.Module.Compiler.Report.Errors)
9488 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9496 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9498 expr = CreateExpressionFromAlias (mc);
9502 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9505 protected override Expression DoResolve (ResolveContext rc)
9507 return ResolveAsTypeOrNamespace (rc, false);
9510 public override string GetSignatureForError ()
9513 if (targs != null) {
9514 name = Name + "<" + targs.GetSignatureForError () + ">";
9517 return alias + "::" + name;
9520 public override bool HasConditionalAccess ()
9525 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9527 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9528 rc.Module.Compiler.Report.Error (687, loc,
9529 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9530 GetSignatureForError ());
9535 return DoResolve (rc);
9538 protected override void CloneTo (CloneContext clonectx, Expression t)
9543 public override object Accept (StructuralVisitor visitor)
9545 return visitor.Visit (this);
9550 /// Implements the member access expression
9552 public class MemberAccess : ATypeNameExpression
9554 protected Expression expr;
9556 public MemberAccess (Expression expr, string id)
9557 : base (id, expr.Location)
9562 public MemberAccess (Expression expr, string identifier, Location loc)
9563 : base (identifier, loc)
9568 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9569 : base (identifier, args, loc)
9574 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9575 : base (identifier, arity, loc)
9580 public Expression LeftExpression {
9586 public override Location StartLocation {
9588 return expr == null ? loc : expr.StartLocation;
9592 protected override Expression DoResolve (ResolveContext rc)
9594 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess);
9596 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9601 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9603 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9605 if (e is TypeExpr) {
9606 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9611 e = e.ResolveLValue (rc, rhs);
9616 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9618 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9619 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9621 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9624 public override bool HasConditionalAccess ()
9626 return LeftExpression.HasConditionalAccess ();
9629 public static bool IsValidDotExpression (TypeSpec type)
9631 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9632 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9634 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9637 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9639 var sn = expr as SimpleName;
9640 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9643 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9646 // Resolve expression which does have type set as we need expression type
9647 // with disable flow analysis as we don't know whether left side expression
9648 // is used as variable or type
9650 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9651 expr = expr.Resolve (rc);
9652 } else if (expr is TypeParameterExpr) {
9653 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9657 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
9658 expr = expr.Resolve (rc, flags);
9665 var ns = expr as NamespaceExpression;
9667 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9669 if (retval == null) {
9670 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9675 if (HasTypeArguments)
9676 return new GenericTypeExpr (retval.Type, targs, loc);
9678 targs.Resolve (rc, false);
9685 TypeSpec expr_type = expr.Type;
9686 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9687 me = expr as MemberExpr;
9689 me.ResolveInstanceExpression (rc, null);
9691 Arguments args = new Arguments (1);
9692 args.Add (new Argument (expr));
9693 return new DynamicMemberBinder (Name, args, loc);
9696 var cma = this as ConditionalMemberAccess;
9698 if (!IsNullPropagatingValid (expr.Type)) {
9699 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9703 if (expr_type.IsNullableType) {
9704 expr = Nullable.Unwrap.Create (expr, true).Resolve (rc);
9705 expr_type = expr.Type;
9709 if (!IsValidDotExpression (expr_type)) {
9710 Error_OperatorCannotBeApplied (rc, expr_type);
9714 var lookup_arity = Arity;
9715 bool errorMode = false;
9716 Expression member_lookup;
9718 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9719 if (member_lookup == null) {
9721 // Try to look for extension method when member lookup failed
9723 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9724 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9725 if (methods != null) {
9726 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9727 if (HasTypeArguments) {
9728 if (!targs.Resolve (rc, false))
9731 emg.SetTypeArguments (rc, targs);
9735 emg.ConditionalAccess = true;
9737 // TODO: it should really skip the checks bellow
9738 return emg.Resolve (rc);
9744 if (member_lookup == null) {
9745 var dep = expr_type.GetMissingDependencies ();
9747 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9748 } else if (expr is TypeExpr) {
9749 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9751 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9757 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9758 // Leave it to overload resolution to report correct error
9759 } else if (!(member_lookup is TypeExpr)) {
9760 // TODO: rc.SymbolRelatedToPreviousError
9761 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9766 if (member_lookup != null)
9770 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9774 TypeExpr texpr = member_lookup as TypeExpr;
9775 if (texpr != null) {
9776 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9777 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9778 Name, texpr.GetSignatureForError ());
9781 if (!texpr.Type.IsAccessible (rc)) {
9782 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9783 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9787 if (HasTypeArguments) {
9788 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9791 return member_lookup;
9794 me = member_lookup as MemberExpr;
9796 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
9801 me.ConditionalAccess = true;
9804 me = me.ResolveMemberAccess (rc, expr, sn);
9807 if (!targs.Resolve (rc, false))
9810 me.SetTypeArguments (rc, targs);
9816 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
9818 FullNamedExpression fexpr = expr as FullNamedExpression;
9819 if (fexpr == null) {
9820 expr.ResolveAsType (rc);
9824 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
9826 if (expr_resolved == null)
9829 var ns = expr_resolved as NamespaceExpression;
9831 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9833 if (retval == null) {
9834 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9835 } else if (Arity > 0) {
9836 if (HasTypeArguments) {
9837 retval = new GenericTypeExpr (retval.Type, targs, loc);
9838 if (retval.ResolveAsType (rc) == null)
9841 targs.Resolve (rc, allowUnboundTypeArguments);
9843 retval = new GenericOpenTypeExpr (retval.Type, loc);
9850 var tnew_expr = expr_resolved.ResolveAsType (rc);
9851 if (tnew_expr == null)
9854 TypeSpec expr_type = tnew_expr;
9855 if (TypeManager.IsGenericParameter (expr_type)) {
9856 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
9857 tnew_expr.GetSignatureForError ());
9861 var qam = this as QualifiedAliasMember;
9863 rc.Module.Compiler.Report.Error (431, loc,
9864 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
9869 TypeSpec nested = null;
9870 while (expr_type != null) {
9871 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9872 if (nested == null) {
9873 if (expr_type == tnew_expr) {
9874 Error_IdentifierNotFound (rc, expr_type);
9878 expr_type = tnew_expr;
9879 nested = MemberCache.FindNestedType (expr_type, Name, Arity);
9880 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
9884 if (nested.IsAccessible (rc))
9888 // Keep looking after inaccessible candidate but only if
9889 // we are not in same context as the definition itself
9891 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
9894 expr_type = expr_type.BaseType;
9899 if (HasTypeArguments) {
9900 texpr = new GenericTypeExpr (nested, targs, loc);
9902 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
9904 texpr = new GenericOpenTypeExpr (nested, loc);
9906 } else if (expr_resolved is GenericOpenTypeExpr) {
9907 texpr = new GenericOpenTypeExpr (nested, loc);
9909 texpr = new TypeExpression (nested, loc);
9912 if (texpr.ResolveAsType (rc) == null)
9918 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
9920 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
9922 if (nested != null) {
9923 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
9927 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
9928 if (any_other_member != null) {
9929 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
9933 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
9934 Name, expr_type.GetSignatureForError ());
9937 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
9939 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
9942 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
9944 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9945 ec.Report.SymbolRelatedToPreviousError (type);
9947 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
9949 // a using directive or an assembly reference
9951 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
9953 missing = "an assembly reference";
9956 ec.Report.Error (1061, loc,
9957 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
9958 type.GetSignatureForError (), name, missing);
9962 base.Error_TypeDoesNotContainDefinition (ec, type, name);
9965 public override string GetSignatureForError ()
9967 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
9970 protected override void CloneTo (CloneContext clonectx, Expression t)
9972 MemberAccess target = (MemberAccess) t;
9974 target.expr = expr.Clone (clonectx);
9977 public override object Accept (StructuralVisitor visitor)
9979 return visitor.Visit (this);
9983 public class ConditionalMemberAccess : MemberAccess
9985 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9986 : base (expr, identifier, args, loc)
9990 public override bool HasConditionalAccess ()
9997 /// Implements checked expressions
9999 public class CheckedExpr : Expression {
10001 public Expression Expr;
10003 public CheckedExpr (Expression e, Location l)
10009 public override bool ContainsEmitWithAwait ()
10011 return Expr.ContainsEmitWithAwait ();
10014 public override Expression CreateExpressionTree (ResolveContext ec)
10016 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10017 return Expr.CreateExpressionTree (ec);
10020 protected override Expression DoResolve (ResolveContext ec)
10022 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10023 Expr = Expr.Resolve (ec);
10028 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10031 eclass = Expr.eclass;
10036 public override void Emit (EmitContext ec)
10038 using (ec.With (EmitContext.Options.CheckedScope, true))
10042 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10044 using (ec.With (EmitContext.Options.CheckedScope, true))
10045 Expr.EmitBranchable (ec, target, on_true);
10048 public override void FlowAnalysis (FlowAnalysisContext fc)
10050 Expr.FlowAnalysis (fc);
10053 public override SLE.Expression MakeExpression (BuilderContext ctx)
10055 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10056 return Expr.MakeExpression (ctx);
10060 protected override void CloneTo (CloneContext clonectx, Expression t)
10062 CheckedExpr target = (CheckedExpr) t;
10064 target.Expr = Expr.Clone (clonectx);
10067 public override object Accept (StructuralVisitor visitor)
10069 return visitor.Visit (this);
10074 /// Implements the unchecked expression
10076 public class UnCheckedExpr : Expression {
10078 public Expression Expr;
10080 public UnCheckedExpr (Expression e, Location l)
10086 public override bool ContainsEmitWithAwait ()
10088 return Expr.ContainsEmitWithAwait ();
10091 public override Expression CreateExpressionTree (ResolveContext ec)
10093 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10094 return Expr.CreateExpressionTree (ec);
10097 protected override Expression DoResolve (ResolveContext ec)
10099 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10100 Expr = Expr.Resolve (ec);
10105 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10108 eclass = Expr.eclass;
10113 public override void Emit (EmitContext ec)
10115 using (ec.With (EmitContext.Options.CheckedScope, false))
10119 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10121 using (ec.With (EmitContext.Options.CheckedScope, false))
10122 Expr.EmitBranchable (ec, target, on_true);
10125 public override void FlowAnalysis (FlowAnalysisContext fc)
10127 Expr.FlowAnalysis (fc);
10130 protected override void CloneTo (CloneContext clonectx, Expression t)
10132 UnCheckedExpr target = (UnCheckedExpr) t;
10134 target.Expr = Expr.Clone (clonectx);
10137 public override object Accept (StructuralVisitor visitor)
10139 return visitor.Visit (this);
10144 /// An Element Access expression.
10146 /// During semantic analysis these are transformed into
10147 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10149 public class ElementAccess : Expression
10151 public Arguments Arguments;
10152 public Expression Expr;
10154 public ElementAccess (Expression e, Arguments args, Location loc)
10158 this.Arguments = args;
10161 public bool ConditionalAccess { get; set; }
10163 public override Location StartLocation {
10165 return Expr.StartLocation;
10169 public override bool ContainsEmitWithAwait ()
10171 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10175 // We perform some simple tests, and then to "split" the emit and store
10176 // code we create an instance of a different class, and return that.
10178 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10180 Expr = Expr.Resolve (ec);
10186 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10187 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10192 return new ArrayAccess (this, loc) {
10193 ConditionalAccess = ConditionalAccess,
10194 ConditionalAccessReceiver = conditionalAccessReceiver
10197 if (type.IsPointer)
10198 return MakePointerAccess (ec, type);
10200 FieldExpr fe = Expr as FieldExpr;
10202 var ff = fe.Spec as FixedFieldSpec;
10204 return MakePointerAccess (ec, ff.ElementType);
10208 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10209 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10210 var indexer = new IndexerExpr (indexers, type, this) {
10211 ConditionalAccess = ConditionalAccess
10214 if (conditionalAccessReceiver)
10215 indexer.SetConditionalAccessReceiver ();
10220 Error_CannotApplyIndexing (ec, type, loc);
10225 public override Expression CreateExpressionTree (ResolveContext ec)
10227 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10228 Expr.CreateExpressionTree (ec));
10230 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10233 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10235 if (type != InternalType.ErrorType) {
10236 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10237 type.GetSignatureForError ());
10241 public override bool HasConditionalAccess ()
10243 return ConditionalAccess || Expr.HasConditionalAccess ();
10246 Expression MakePointerAccess (ResolveContext rc, TypeSpec type)
10248 if (Arguments.Count != 1){
10249 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
10253 var arg = Arguments[0];
10254 if (arg is NamedArgument)
10255 Error_NamedArgument ((NamedArgument) arg, rc.Report);
10257 var index = arg.Expr.Resolve (rc);
10261 index = ConvertExpressionToArrayIndex (rc, index, true);
10263 Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, index, type, loc);
10264 return new Indirection (p, loc);
10267 protected override Expression DoResolve (ResolveContext rc)
10270 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
10271 if (HasConditionalAccess ()) {
10272 using (rc.Set (ResolveContext.Options.ConditionalAccessReceiver)) {
10273 expr = CreateAccessExpression (rc, true);
10277 return expr.Resolve (rc);
10282 expr = CreateAccessExpression (rc, false);
10286 return expr.Resolve (rc);
10289 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10291 var res = CreateAccessExpression (ec, false);
10295 return res.ResolveLValue (ec, rhs);
10298 public override void Emit (EmitContext ec)
10300 throw new Exception ("Should never be reached");
10303 public static void Error_NamedArgument (NamedArgument na, Report Report)
10305 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
10308 public override void FlowAnalysis (FlowAnalysisContext fc)
10310 Expr.FlowAnalysis (fc);
10312 if (ConditionalAccess)
10313 fc.BranchConditionalAccessDefiniteAssignment ();
10315 Arguments.FlowAnalysis (fc);
10318 public override string GetSignatureForError ()
10320 return Expr.GetSignatureForError ();
10323 protected override void CloneTo (CloneContext clonectx, Expression t)
10325 ElementAccess target = (ElementAccess) t;
10327 target.Expr = Expr.Clone (clonectx);
10328 if (Arguments != null)
10329 target.Arguments = Arguments.Clone (clonectx);
10332 public override object Accept (StructuralVisitor visitor)
10334 return visitor.Visit (this);
10339 /// Implements array access
10341 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10343 // Points to our "data" repository
10347 LocalTemporary temp;
10349 bool? has_await_args;
10351 public ArrayAccess (ElementAccess ea_data, Location l)
10357 public bool ConditionalAccess { get; set; }
10359 public bool ConditionalAccessReceiver { get; set; }
10361 public void AddressOf (EmitContext ec, AddressOp mode)
10363 var ac = (ArrayContainer) ea.Expr.Type;
10365 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10366 LoadInstanceAndArguments (ec, false, true);
10369 LoadInstanceAndArguments (ec, false, false);
10371 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10372 ec.Emit (OpCodes.Readonly);
10374 ec.EmitArrayAddress (ac);
10377 public override Expression CreateExpressionTree (ResolveContext ec)
10379 if (ConditionalAccess)
10380 Error_NullShortCircuitInsideExpressionTree (ec);
10382 return ea.CreateExpressionTree (ec);
10385 public override bool ContainsEmitWithAwait ()
10387 return ea.ContainsEmitWithAwait ();
10390 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10392 if (ConditionalAccess)
10393 throw new NotSupportedException ("null propagating operator assignment");
10395 return DoResolve (ec);
10398 protected override Expression DoResolve (ResolveContext ec)
10400 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10402 ea.Arguments.Resolve (ec, out dynamic);
10404 var ac = ea.Expr.Type as ArrayContainer;
10405 int rank = ea.Arguments.Count;
10406 if (ac.Rank != rank) {
10407 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10408 rank.ToString (), ac.Rank.ToString ());
10413 if (type.IsPointer && !ec.IsUnsafe) {
10414 UnsafeError (ec, ea.Location);
10417 if (ConditionalAccessReceiver)
10418 type = LiftMemberType (ec, type);
10420 foreach (Argument a in ea.Arguments) {
10421 var na = a as NamedArgument;
10423 ElementAccess.Error_NamedArgument (na, ec.Report);
10425 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10428 eclass = ExprClass.Variable;
10433 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10435 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10438 public override void FlowAnalysis (FlowAnalysisContext fc)
10440 ea.FlowAnalysis (fc);
10443 public override bool HasConditionalAccess ()
10445 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10449 // Load the array arguments into the stack.
10451 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10453 if (prepareAwait) {
10454 ea.Expr = ea.Expr.EmitToField (ec);
10456 var ie = new InstanceEmitter (ea.Expr, false);
10457 ie.Emit (ec, ConditionalAccess);
10459 if (duplicateArguments) {
10460 ec.Emit (OpCodes.Dup);
10462 var copy = new LocalTemporary (ea.Expr.Type);
10468 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10469 if (dup_args != null)
10470 ea.Arguments = dup_args;
10473 public void Emit (EmitContext ec, bool leave_copy)
10476 ec.EmitLoadFromPtr (type);
10478 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10479 LoadInstanceAndArguments (ec, false, true);
10482 if (ConditionalAccessReceiver)
10483 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10485 var ac = (ArrayContainer) ea.Expr.Type;
10486 LoadInstanceAndArguments (ec, false, false);
10487 ec.EmitArrayLoad (ac);
10489 if (ConditionalAccessReceiver)
10490 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10494 ec.Emit (OpCodes.Dup);
10495 temp = new LocalTemporary (this.type);
10500 public override void Emit (EmitContext ec)
10505 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10507 var ac = (ArrayContainer) ea.Expr.Type;
10508 TypeSpec t = source.Type;
10510 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10513 // When we are dealing with a struct, get the address of it to avoid value copy
10514 // Same cannot be done for reference type because array covariance and the
10515 // check in ldelema requires to specify the type of array element stored at the index
10517 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10518 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10520 if (has_await_args.Value) {
10521 if (source.ContainsEmitWithAwait ()) {
10522 source = source.EmitToField (ec);
10523 isCompound = false;
10527 LoadInstanceAndArguments (ec, isCompound, false);
10532 ec.EmitArrayAddress (ac);
10535 ec.Emit (OpCodes.Dup);
10539 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10541 if (has_await_args.Value) {
10542 if (source.ContainsEmitWithAwait ())
10543 source = source.EmitToField (ec);
10545 LoadInstanceAndArguments (ec, false, false);
10552 var lt = ea.Expr as LocalTemporary;
10558 ec.Emit (OpCodes.Dup);
10559 temp = new LocalTemporary (this.type);
10564 ec.EmitStoreFromPtr (t);
10566 ec.EmitArrayStore (ac);
10569 if (temp != null) {
10575 public override Expression EmitToField (EmitContext ec)
10578 // Have to be specialized for arrays to get access to
10579 // underlying element. Instead of another result copy we
10580 // need direct access to element
10584 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10586 ea.Expr = ea.Expr.EmitToField (ec);
10587 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10591 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10593 #if NET_4_0 || MOBILE_DYNAMIC
10594 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10596 throw new NotImplementedException ();
10600 public override SLE.Expression MakeExpression (BuilderContext ctx)
10602 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10605 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10607 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10608 return Arguments.MakeExpression (ea.Arguments, ctx);
10614 // Indexer access expression
10616 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10618 IList<MemberSpec> indexers;
10619 Arguments arguments;
10620 TypeSpec queried_type;
10622 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10623 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10627 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10630 this.indexers = indexers;
10631 this.queried_type = queriedType;
10632 this.InstanceExpression = instance;
10633 this.arguments = args;
10638 protected override Arguments Arguments {
10647 protected override TypeSpec DeclaringType {
10649 return best_candidate.DeclaringType;
10653 public override bool IsInstance {
10659 public override bool IsStatic {
10665 public override string KindName {
10666 get { return "indexer"; }
10669 public override string Name {
10677 public override bool ContainsEmitWithAwait ()
10679 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10682 public override Expression CreateExpressionTree (ResolveContext ec)
10684 if (ConditionalAccess) {
10685 Error_NullShortCircuitInsideExpressionTree (ec);
10688 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10689 InstanceExpression.CreateExpressionTree (ec),
10690 new TypeOfMethod (Getter, loc));
10692 return CreateExpressionFactoryCall (ec, "Call", args);
10695 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10697 LocalTemporary await_source_arg = null;
10700 emitting_compound_assignment = true;
10701 if (source is DynamicExpressionStatement) {
10706 emitting_compound_assignment = false;
10708 if (has_await_arguments) {
10709 await_source_arg = new LocalTemporary (Type);
10710 await_source_arg.Store (ec);
10712 arguments.Add (new Argument (await_source_arg));
10715 temp = await_source_arg;
10718 has_await_arguments = false;
10723 ec.Emit (OpCodes.Dup);
10724 temp = new LocalTemporary (Type);
10730 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10731 source = source.EmitToField (ec);
10733 temp = new LocalTemporary (Type);
10740 arguments.Add (new Argument (source));
10743 var call = new CallEmitter ();
10744 call.InstanceExpression = InstanceExpression;
10745 if (arguments == null)
10746 call.InstanceExpressionOnStack = true;
10748 call.Emit (ec, Setter, arguments, loc);
10750 if (temp != null) {
10753 } else if (leave_copy) {
10757 if (await_source_arg != null) {
10758 await_source_arg.Release (ec);
10762 public override void FlowAnalysis (FlowAnalysisContext fc)
10764 base.FlowAnalysis (fc);
10765 arguments.FlowAnalysis (fc);
10767 if (conditional_access_receiver)
10768 fc.ConditionalAccessEnd ();
10771 public override string GetSignatureForError ()
10773 return best_candidate.GetSignatureForError ();
10776 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10779 throw new NotSupportedException ();
10781 var value = new[] { source.MakeExpression (ctx) };
10782 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10783 #if NET_4_0 || MOBILE_DYNAMIC
10784 return SLE.Expression.Block (
10785 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10788 return args.First ();
10793 public override SLE.Expression MakeExpression (BuilderContext ctx)
10796 return base.MakeExpression (ctx);
10798 var args = Arguments.MakeExpression (arguments, ctx);
10799 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10803 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10805 if (best_candidate != null)
10808 eclass = ExprClass.IndexerAccess;
10811 arguments.Resolve (rc, out dynamic);
10813 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10816 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
10817 res.BaseMembersProvider = this;
10818 res.InstanceQualifier = this;
10820 // TODO: Do I need 2 argument sets?
10821 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
10822 if (best_candidate != null)
10823 type = res.BestCandidateReturnType;
10824 else if (!res.BestCandidateIsDynamic)
10829 // It has dynamic arguments
10832 Arguments args = new Arguments (arguments.Count + 1);
10834 rc.Report.Error (1972, loc,
10835 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
10837 args.Add (new Argument (InstanceExpression));
10839 args.AddRange (arguments);
10841 best_candidate = null;
10842 return new DynamicIndexBinder (args, loc);
10846 // Try to avoid resolving left expression again
10848 if (right_side != null)
10849 ResolveInstanceExpression (rc, right_side);
10854 protected override void CloneTo (CloneContext clonectx, Expression t)
10856 IndexerExpr target = (IndexerExpr) t;
10858 if (arguments != null)
10859 target.arguments = arguments.Clone (clonectx);
10862 public void SetConditionalAccessReceiver ()
10864 conditional_access_receiver = true;
10867 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
10869 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
10872 #region IBaseMembersProvider Members
10874 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
10876 return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
10879 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
10881 if (queried_type == member.DeclaringType)
10884 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
10885 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
10888 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
10897 // A base access expression
10899 public class BaseThis : This
10901 public BaseThis (Location loc)
10906 public BaseThis (TypeSpec type, Location loc)
10910 eclass = ExprClass.Variable;
10915 public override string Name {
10923 public override Expression CreateExpressionTree (ResolveContext ec)
10925 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
10926 return base.CreateExpressionTree (ec);
10929 public override void Emit (EmitContext ec)
10933 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
10934 var context_type = ec.CurrentType;
10935 ec.Emit (OpCodes.Ldobj, context_type);
10936 ec.Emit (OpCodes.Box, context_type);
10940 protected override void Error_ThisNotAvailable (ResolveContext ec)
10943 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
10945 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
10949 public override void ResolveBase (ResolveContext ec)
10951 base.ResolveBase (ec);
10952 type = ec.CurrentType.BaseType;
10955 public override object Accept (StructuralVisitor visitor)
10957 return visitor.Visit (this);
10962 /// This class exists solely to pass the Type around and to be a dummy
10963 /// that can be passed to the conversion functions (this is used by
10964 /// foreach implementation to typecast the object return value from
10965 /// get_Current into the proper type. All code has been generated and
10966 /// we only care about the side effect conversions to be performed
10968 /// This is also now used as a placeholder where a no-action expression
10969 /// is needed (the `New' class).
10971 public class EmptyExpression : Expression
10973 sealed class OutAccessExpression : EmptyExpression
10975 public OutAccessExpression (TypeSpec t)
10980 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
10982 rc.Report.Error (206, right_side.Location,
10983 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
10989 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
10990 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
10991 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
10992 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
10993 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
10994 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
10995 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
10996 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
10998 public EmptyExpression (TypeSpec t)
11001 eclass = ExprClass.Value;
11002 loc = Location.Null;
11005 protected override void CloneTo (CloneContext clonectx, Expression target)
11009 public override bool ContainsEmitWithAwait ()
11014 public override Expression CreateExpressionTree (ResolveContext ec)
11016 throw new NotSupportedException ("ET");
11019 protected override Expression DoResolve (ResolveContext ec)
11024 public override void Emit (EmitContext ec)
11026 // nothing, as we only exist to not do anything.
11029 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11033 public override void EmitSideEffect (EmitContext ec)
11037 public override object Accept (StructuralVisitor visitor)
11039 return visitor.Visit (this);
11043 sealed class EmptyAwaitExpression : EmptyExpression
11045 public EmptyAwaitExpression (TypeSpec type)
11050 public override bool ContainsEmitWithAwait ()
11057 // Empty statement expression
11059 public sealed class EmptyExpressionStatement : ExpressionStatement
11061 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11063 private EmptyExpressionStatement ()
11065 loc = Location.Null;
11068 public override bool ContainsEmitWithAwait ()
11073 public override Expression CreateExpressionTree (ResolveContext ec)
11078 public override void EmitStatement (EmitContext ec)
11083 protected override Expression DoResolve (ResolveContext ec)
11085 eclass = ExprClass.Value;
11086 type = ec.BuiltinTypes.Object;
11090 public override void Emit (EmitContext ec)
11095 public override object Accept (StructuralVisitor visitor)
11097 return visitor.Visit (this);
11101 public class ErrorExpression : EmptyExpression
11103 public static readonly ErrorExpression Instance = new ErrorExpression ();
11105 private ErrorExpression ()
11106 : base (InternalType.ErrorType)
11110 public override Expression CreateExpressionTree (ResolveContext ec)
11115 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11120 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11124 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11128 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11132 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11136 public override object Accept (StructuralVisitor visitor)
11138 return visitor.Visit (this);
11142 public class UserCast : Expression {
11146 public UserCast (MethodSpec method, Expression source, Location l)
11148 if (source == null)
11149 throw new ArgumentNullException ("source");
11151 this.method = method;
11152 this.source = source;
11153 type = method.ReturnType;
11157 public Expression Source {
11166 public override bool ContainsEmitWithAwait ()
11168 return source.ContainsEmitWithAwait ();
11171 public override Expression CreateExpressionTree (ResolveContext ec)
11173 Arguments args = new Arguments (3);
11174 args.Add (new Argument (source.CreateExpressionTree (ec)));
11175 args.Add (new Argument (new TypeOf (type, loc)));
11176 args.Add (new Argument (new TypeOfMethod (method, loc)));
11177 return CreateExpressionFactoryCall (ec, "Convert", args);
11180 protected override Expression DoResolve (ResolveContext ec)
11182 ObsoleteAttribute oa = method.GetAttributeObsolete ();
11184 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
11186 eclass = ExprClass.Value;
11190 public override void Emit (EmitContext ec)
11193 ec.MarkCallEntry (loc);
11194 ec.Emit (OpCodes.Call, method);
11197 public override void FlowAnalysis (FlowAnalysisContext fc)
11199 source.FlowAnalysis (fc);
11202 public override string GetSignatureForError ()
11204 return TypeManager.CSharpSignature (method);
11207 public override SLE.Expression MakeExpression (BuilderContext ctx)
11210 return base.MakeExpression (ctx);
11212 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11218 // Holds additional type specifiers like ?, *, []
11220 public class ComposedTypeSpecifier
11222 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11224 public readonly int Dimension;
11225 public readonly Location Location;
11227 public ComposedTypeSpecifier (int specifier, Location loc)
11229 this.Dimension = specifier;
11230 this.Location = loc;
11234 public bool IsNullable {
11236 return Dimension == -1;
11240 public bool IsPointer {
11242 return Dimension == -2;
11246 public ComposedTypeSpecifier Next { get; set; }
11250 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11252 return new ComposedTypeSpecifier (dimension, loc);
11255 public static ComposedTypeSpecifier CreateNullable (Location loc)
11257 return new ComposedTypeSpecifier (-1, loc);
11260 public static ComposedTypeSpecifier CreatePointer (Location loc)
11262 return new ComposedTypeSpecifier (-2, loc);
11265 public string GetSignatureForError ()
11270 ArrayContainer.GetPostfixSignature (Dimension);
11272 return Next != null ? s + Next.GetSignatureForError () : s;
11277 // This class is used to "construct" the type during a typecast
11278 // operation. Since the Type.GetType class in .NET can parse
11279 // the type specification, we just use this to construct the type
11280 // one bit at a time.
11282 public class ComposedCast : TypeExpr {
11283 FullNamedExpression left;
11284 ComposedTypeSpecifier spec;
11286 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11289 throw new ArgumentNullException ("spec");
11293 this.loc = left.Location;
11296 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11298 type = left.ResolveAsType (ec);
11302 eclass = ExprClass.Type;
11304 var single_spec = spec;
11306 if (single_spec.IsNullable) {
11307 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11311 single_spec = single_spec.Next;
11312 } else if (single_spec.IsPointer) {
11313 if (!TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11316 if (!ec.IsUnsafe) {
11317 UnsafeError (ec.Module.Compiler.Report, loc);
11321 type = PointerContainer.MakeType (ec.Module, type);
11322 single_spec = single_spec.Next;
11323 } while (single_spec != null && single_spec.IsPointer);
11326 if (single_spec != null && single_spec.Dimension > 0) {
11327 if (type.IsSpecialRuntimeType) {
11328 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11329 } else if (type.IsStatic) {
11330 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11331 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11332 type.GetSignatureForError ());
11334 MakeArray (ec.Module, single_spec);
11341 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11343 if (spec.Next != null)
11344 MakeArray (module, spec.Next);
11346 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11349 public override string GetSignatureForError ()
11351 return left.GetSignatureForError () + spec.GetSignatureForError ();
11354 public override object Accept (StructuralVisitor visitor)
11356 return visitor.Visit (this);
11360 class FixedBufferPtr : Expression
11362 readonly Expression array;
11364 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11366 this.type = array_type;
11367 this.array = array;
11371 public override bool ContainsEmitWithAwait ()
11373 throw new NotImplementedException ();
11376 public override Expression CreateExpressionTree (ResolveContext ec)
11378 Error_PointerInsideExpressionTree (ec);
11382 public override void Emit(EmitContext ec)
11387 protected override Expression DoResolve (ResolveContext ec)
11389 type = PointerContainer.MakeType (ec.Module, type);
11390 eclass = ExprClass.Value;
11397 // This class is used to represent the address of an array, used
11398 // only by the Fixed statement, this generates "&a [0]" construct
11399 // for fixed (char *pa = a)
11401 class ArrayPtr : FixedBufferPtr
11403 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11404 base (array, array_type, l)
11408 public override void Emit (EmitContext ec)
11413 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11418 // Encapsulates a conversion rules required for array indexes
11420 public class ArrayIndexCast : TypeCast
11422 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11423 : base (expr, returnType)
11425 if (expr.Type == returnType) // int -> int
11426 throw new ArgumentException ("unnecessary array index conversion");
11429 public override Expression CreateExpressionTree (ResolveContext ec)
11431 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11432 return base.CreateExpressionTree (ec);
11436 public override void Emit (EmitContext ec)
11440 switch (child.Type.BuiltinType) {
11441 case BuiltinTypeSpec.Type.UInt:
11442 ec.Emit (OpCodes.Conv_U);
11444 case BuiltinTypeSpec.Type.Long:
11445 ec.Emit (OpCodes.Conv_Ovf_I);
11447 case BuiltinTypeSpec.Type.ULong:
11448 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11451 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11457 // Implements the `stackalloc' keyword
11459 public class StackAlloc : Expression {
11464 public StackAlloc (Expression type, Expression count, Location l)
11467 this.count = count;
11471 public Expression TypeExpression {
11477 public Expression CountExpression {
11483 public override bool ContainsEmitWithAwait ()
11488 public override Expression CreateExpressionTree (ResolveContext ec)
11490 throw new NotSupportedException ("ET");
11493 protected override Expression DoResolve (ResolveContext ec)
11495 count = count.Resolve (ec);
11499 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11500 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11505 Constant c = count as Constant;
11506 if (c != null && c.IsNegative) {
11507 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11510 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11511 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11514 otype = t.ResolveAsType (ec);
11518 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11521 type = PointerContainer.MakeType (ec.Module, otype);
11522 eclass = ExprClass.Value;
11527 public override void Emit (EmitContext ec)
11529 int size = BuiltinTypeSpec.GetSize (otype);
11534 ec.Emit (OpCodes.Sizeof, otype);
11538 ec.Emit (OpCodes.Mul_Ovf_Un);
11539 ec.Emit (OpCodes.Localloc);
11542 protected override void CloneTo (CloneContext clonectx, Expression t)
11544 StackAlloc target = (StackAlloc) t;
11545 target.count = count.Clone (clonectx);
11546 target.t = t.Clone (clonectx);
11549 public override object Accept (StructuralVisitor visitor)
11551 return visitor.Visit (this);
11556 // An object initializer expression
11558 public class ElementInitializer : Assign
11560 public readonly string Name;
11562 public ElementInitializer (string name, Expression initializer, Location loc)
11563 : base (null, initializer, loc)
11568 public bool IsDictionaryInitializer {
11570 return Name == null;
11574 protected override void CloneTo (CloneContext clonectx, Expression t)
11576 ElementInitializer target = (ElementInitializer) t;
11577 target.source = source.Clone (clonectx);
11580 public override Expression CreateExpressionTree (ResolveContext ec)
11582 Arguments args = new Arguments (2);
11583 FieldExpr fe = target as FieldExpr;
11585 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11587 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11590 Expression arg_expr;
11591 var cinit = source as CollectionOrObjectInitializers;
11592 if (cinit == null) {
11594 arg_expr = source.CreateExpressionTree (ec);
11596 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11597 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11600 args.Add (new Argument (arg_expr));
11601 return CreateExpressionFactoryCall (ec, mname, args);
11604 protected override Expression DoResolve (ResolveContext ec)
11606 if (source == null)
11607 return EmptyExpressionStatement.Instance;
11609 if (!ResolveElement (ec))
11612 if (source is CollectionOrObjectInitializers) {
11613 Expression previous = ec.CurrentInitializerVariable;
11614 ec.CurrentInitializerVariable = target;
11615 source = source.Resolve (ec);
11616 ec.CurrentInitializerVariable = previous;
11617 if (source == null)
11620 eclass = source.eclass;
11621 type = source.Type;
11625 return base.DoResolve (ec);
11628 public override void EmitStatement (EmitContext ec)
11630 if (source is CollectionOrObjectInitializers)
11633 base.EmitStatement (ec);
11636 protected virtual bool ResolveElement (ResolveContext rc)
11638 var t = rc.CurrentInitializerVariable.Type;
11639 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11640 Arguments args = new Arguments (1);
11641 args.Add (new Argument (rc.CurrentInitializerVariable));
11642 target = new DynamicMemberBinder (Name, args, loc);
11645 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11646 if (member == null) {
11647 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11649 if (member != null) {
11650 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11651 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11656 if (member == null) {
11657 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11661 var me = member as MemberExpr;
11662 if (me is EventExpr) {
11663 me = me.ResolveMemberAccess (rc, null, null);
11664 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11665 rc.Report.Error (1913, loc,
11666 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11667 member.GetSignatureForError ());
11673 rc.Report.Error (1914, loc,
11674 "Static field or property `{0}' cannot be assigned in an object initializer",
11675 me.GetSignatureForError ());
11679 me.InstanceExpression = rc.CurrentInitializerVariable;
11687 // A collection initializer expression
11689 class CollectionElementInitializer : Invocation
11691 public class ElementInitializerArgument : Argument
11693 public ElementInitializerArgument (Expression e)
11699 sealed class AddMemberAccess : MemberAccess
11701 public AddMemberAccess (Expression expr, Location loc)
11702 : base (expr, "Add", loc)
11706 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11708 if (TypeManager.HasElementType (type))
11711 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11715 public CollectionElementInitializer (Expression argument)
11716 : base (null, new Arguments (1))
11718 base.arguments.Add (new ElementInitializerArgument (argument));
11719 this.loc = argument.Location;
11722 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11723 : base (null, new Arguments (arguments.Count))
11725 foreach (Expression e in arguments)
11726 base.arguments.Add (new ElementInitializerArgument (e));
11731 public CollectionElementInitializer (Location loc)
11732 : base (null, null)
11737 public override Expression CreateExpressionTree (ResolveContext ec)
11739 Arguments args = new Arguments (2);
11740 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11742 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11743 foreach (Argument a in arguments)
11744 expr_initializers.Add (a.CreateExpressionTree (ec));
11746 args.Add (new Argument (new ArrayCreation (
11747 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11748 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11751 protected override void CloneTo (CloneContext clonectx, Expression t)
11753 CollectionElementInitializer target = (CollectionElementInitializer) t;
11754 if (arguments != null)
11755 target.arguments = arguments.Clone (clonectx);
11758 protected override Expression DoResolve (ResolveContext ec)
11760 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11762 return base.DoResolve (ec);
11766 class DictionaryElementInitializer : ElementInitializer
11768 readonly Arguments args;
11770 public DictionaryElementInitializer (List<Expression> arguments, Expression initializer, Location loc)
11771 : base (null, initializer, loc)
11773 this.args = new Arguments (arguments.Count);
11774 foreach (var arg in arguments)
11775 this.args.Add (new Argument (arg));
11778 public override Expression CreateExpressionTree (ResolveContext ec)
11780 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11784 protected override bool ResolveElement (ResolveContext rc)
11786 var init = rc.CurrentInitializerVariable;
11787 var type = init.Type;
11789 if (type.IsArray) {
11790 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
11794 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
11795 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11796 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
11800 target = new IndexerExpr (indexers, type, init, args, loc).Resolve (rc);
11806 // A block of object or collection initializers
11808 public class CollectionOrObjectInitializers : ExpressionStatement
11810 IList<Expression> initializers;
11811 bool is_collection_initialization;
11813 public CollectionOrObjectInitializers (Location loc)
11814 : this (new Expression[0], loc)
11818 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
11820 this.initializers = initializers;
11824 public IList<Expression> Initializers {
11826 return initializers;
11830 public bool IsEmpty {
11832 return initializers.Count == 0;
11836 public bool IsCollectionInitializer {
11838 return is_collection_initialization;
11842 protected override void CloneTo (CloneContext clonectx, Expression target)
11844 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
11846 t.initializers = new List<Expression> (initializers.Count);
11847 foreach (var e in initializers)
11848 t.initializers.Add (e.Clone (clonectx));
11851 public override bool ContainsEmitWithAwait ()
11853 foreach (var e in initializers) {
11854 if (e.ContainsEmitWithAwait ())
11861 public override Expression CreateExpressionTree (ResolveContext ec)
11863 return CreateExpressionTree (ec, false);
11866 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
11868 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
11869 foreach (Expression e in initializers) {
11870 Expression expr = e.CreateExpressionTree (ec);
11872 expr_initializers.Add (expr);
11876 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
11878 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
11881 protected override Expression DoResolve (ResolveContext ec)
11883 List<string> element_names = null;
11884 for (int i = 0; i < initializers.Count; ++i) {
11885 Expression initializer = initializers [i];
11886 ElementInitializer element_initializer = initializer as ElementInitializer;
11889 if (element_initializer != null) {
11890 element_names = new List<string> (initializers.Count);
11891 if (!element_initializer.IsDictionaryInitializer)
11892 element_names.Add (element_initializer.Name);
11893 } else if (initializer is CompletingExpression) {
11894 initializer.Resolve (ec);
11895 throw new InternalErrorException ("This line should never be reached");
11897 var t = ec.CurrentInitializerVariable.Type;
11898 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
11899 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
11900 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
11901 "object initializer because type `{1}' does not implement `{2}' interface",
11902 ec.CurrentInitializerVariable.GetSignatureForError (),
11903 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
11904 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
11907 is_collection_initialization = true;
11910 if (is_collection_initialization != (element_initializer == null)) {
11911 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
11912 is_collection_initialization ? "collection initializer" : "object initializer");
11916 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
11917 if (element_names.Contains (element_initializer.Name)) {
11918 ec.Report.Error (1912, element_initializer.Location,
11919 "An object initializer includes more than one member `{0}' initialization",
11920 element_initializer.Name);
11922 element_names.Add (element_initializer.Name);
11927 Expression e = initializer.Resolve (ec);
11928 if (e == EmptyExpressionStatement.Instance)
11929 initializers.RemoveAt (i--);
11931 initializers [i] = e;
11934 type = ec.CurrentInitializerVariable.Type;
11935 if (is_collection_initialization) {
11936 if (TypeManager.HasElementType (type)) {
11937 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
11938 type.GetSignatureForError ());
11942 eclass = ExprClass.Variable;
11946 public override void Emit (EmitContext ec)
11948 EmitStatement (ec);
11951 public override void EmitStatement (EmitContext ec)
11953 foreach (ExpressionStatement e in initializers) {
11954 // TODO: need location region
11955 ec.Mark (e.Location);
11956 e.EmitStatement (ec);
11960 public override void FlowAnalysis (FlowAnalysisContext fc)
11962 foreach (var initializer in initializers) {
11963 if (initializer != null)
11964 initializer.FlowAnalysis (fc);
11970 // New expression with element/object initializers
11972 public class NewInitialize : New
11975 // This class serves as a proxy for variable initializer target instances.
11976 // A real variable is assigned later when we resolve left side of an
11979 sealed class InitializerTargetExpression : Expression, IMemoryLocation
11981 NewInitialize new_instance;
11983 public InitializerTargetExpression (NewInitialize newInstance)
11985 this.type = newInstance.type;
11986 this.loc = newInstance.loc;
11987 this.eclass = newInstance.eclass;
11988 this.new_instance = newInstance;
11991 public override bool ContainsEmitWithAwait ()
11996 public override Expression CreateExpressionTree (ResolveContext ec)
11998 // Should not be reached
11999 throw new NotSupportedException ("ET");
12002 protected override Expression DoResolve (ResolveContext ec)
12007 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12012 public override void Emit (EmitContext ec)
12014 Expression e = (Expression) new_instance.instance;
12018 public override Expression EmitToField (EmitContext ec)
12020 return (Expression) new_instance.instance;
12023 #region IMemoryLocation Members
12025 public void AddressOf (EmitContext ec, AddressOp mode)
12027 new_instance.instance.AddressOf (ec, mode);
12033 CollectionOrObjectInitializers initializers;
12034 IMemoryLocation instance;
12035 DynamicExpressionStatement dynamic;
12037 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12038 : base (requested_type, arguments, l)
12040 this.initializers = initializers;
12043 public CollectionOrObjectInitializers Initializers {
12045 return initializers;
12049 protected override void CloneTo (CloneContext clonectx, Expression t)
12051 base.CloneTo (clonectx, t);
12053 NewInitialize target = (NewInitialize) t;
12054 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12057 public override bool ContainsEmitWithAwait ()
12059 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12062 public override Expression CreateExpressionTree (ResolveContext ec)
12064 Arguments args = new Arguments (2);
12065 args.Add (new Argument (base.CreateExpressionTree (ec)));
12066 if (!initializers.IsEmpty)
12067 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12069 return CreateExpressionFactoryCall (ec,
12070 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12074 protected override Expression DoResolve (ResolveContext ec)
12076 Expression e = base.DoResolve (ec);
12080 if (type.IsDelegate) {
12081 ec.Report.Error (1958, Initializers.Location,
12082 "Object and collection initializers cannot be used to instantiate a delegate");
12085 Expression previous = ec.CurrentInitializerVariable;
12086 ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
12087 initializers.Resolve (ec);
12088 ec.CurrentInitializerVariable = previous;
12090 dynamic = e as DynamicExpressionStatement;
12091 if (dynamic != null)
12097 public override void Emit (EmitContext ec)
12099 if (method == null && TypeSpec.IsValueType (type) && initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12100 var fe = ec.GetTemporaryField (type);
12102 if (!Emit (ec, fe))
12111 public override bool Emit (EmitContext ec, IMemoryLocation target)
12113 bool left_on_stack;
12114 if (dynamic != null) {
12116 left_on_stack = true;
12118 left_on_stack = base.Emit (ec, target);
12121 if (initializers.IsEmpty)
12122 return left_on_stack;
12124 LocalTemporary temp = null;
12126 instance = target as LocalTemporary;
12127 if (instance == null)
12128 instance = target as StackFieldExpr;
12130 if (instance == null) {
12131 if (!left_on_stack) {
12132 VariableReference vr = target as VariableReference;
12134 // FIXME: This still does not work correctly for pre-set variables
12135 if (vr != null && vr.IsRef)
12136 target.AddressOf (ec, AddressOp.Load);
12138 ((Expression) target).Emit (ec);
12139 left_on_stack = true;
12142 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12143 instance = new EmptyAwaitExpression (Type).EmitToField (ec) as IMemoryLocation;
12145 temp = new LocalTemporary (type);
12150 if (left_on_stack && temp != null)
12153 initializers.Emit (ec);
12155 if (left_on_stack) {
12156 if (temp != null) {
12160 ((Expression) instance).Emit (ec);
12164 return left_on_stack;
12167 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12169 instance = base.EmitAddressOf (ec, Mode);
12171 if (!initializers.IsEmpty)
12172 initializers.Emit (ec);
12177 public override void FlowAnalysis (FlowAnalysisContext fc)
12179 base.FlowAnalysis (fc);
12180 initializers.FlowAnalysis (fc);
12183 public override object Accept (StructuralVisitor visitor)
12185 return visitor.Visit (this);
12189 public class NewAnonymousType : New
12191 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12193 List<AnonymousTypeParameter> parameters;
12194 readonly TypeContainer parent;
12195 AnonymousTypeClass anonymous_type;
12197 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12198 : base (null, null, loc)
12200 this.parameters = parameters;
12201 this.parent = parent;
12204 public List<AnonymousTypeParameter> Parameters {
12206 return this.parameters;
12210 protected override void CloneTo (CloneContext clonectx, Expression target)
12212 if (parameters == null)
12215 NewAnonymousType t = (NewAnonymousType) target;
12216 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12217 foreach (AnonymousTypeParameter atp in parameters)
12218 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12221 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12223 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12227 type = AnonymousTypeClass.Create (parent, parameters, loc);
12231 int errors = ec.Report.Errors;
12232 type.CreateContainer ();
12233 type.DefineContainer ();
12235 if ((ec.Report.Errors - errors) == 0) {
12236 parent.Module.AddAnonymousType (type);
12237 type.PrepareEmit ();
12243 public override Expression CreateExpressionTree (ResolveContext ec)
12245 if (parameters == null)
12246 return base.CreateExpressionTree (ec);
12248 var init = new ArrayInitializer (parameters.Count, loc);
12249 foreach (var m in anonymous_type.Members) {
12250 var p = m as Property;
12252 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12255 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12256 foreach (Argument a in arguments)
12257 ctor_args.Add (a.CreateExpressionTree (ec));
12259 Arguments args = new Arguments (3);
12260 args.Add (new Argument (new TypeOfMethod (method, loc)));
12261 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12262 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12264 return CreateExpressionFactoryCall (ec, "New", args);
12267 protected override Expression DoResolve (ResolveContext ec)
12269 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12270 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12274 if (parameters == null) {
12275 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12276 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12277 return base.DoResolve (ec);
12280 bool error = false;
12281 arguments = new Arguments (parameters.Count);
12282 var t_args = new TypeSpec [parameters.Count];
12283 for (int i = 0; i < parameters.Count; ++i) {
12284 Expression e = parameters [i].Resolve (ec);
12290 arguments.Add (new Argument (e));
12291 t_args [i] = e.Type;
12297 anonymous_type = CreateAnonymousType (ec, parameters);
12298 if (anonymous_type == null)
12301 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12302 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12303 eclass = ExprClass.Value;
12307 public override object Accept (StructuralVisitor visitor)
12309 return visitor.Visit (this);
12313 public class AnonymousTypeParameter : ShimExpression
12315 public readonly string Name;
12317 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12318 : base (initializer)
12324 public AnonymousTypeParameter (Parameter parameter)
12325 : base (new SimpleName (parameter.Name, parameter.Location))
12327 this.Name = parameter.Name;
12328 this.loc = parameter.Location;
12331 public override bool Equals (object o)
12333 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12334 return other != null && Name == other.Name;
12337 public override int GetHashCode ()
12339 return Name.GetHashCode ();
12342 protected override Expression DoResolve (ResolveContext ec)
12344 Expression e = expr.Resolve (ec);
12348 if (e.eclass == ExprClass.MethodGroup) {
12349 Error_InvalidInitializer (ec, e.ExprClassName);
12354 if (type.Kind == MemberKind.Void || type == InternalType.NullLiteral || type == InternalType.AnonymousMethod || type.IsPointer) {
12355 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12362 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12364 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12365 Name, initializer);
12369 public class CatchFilterExpression : BooleanExpression
12371 public CatchFilterExpression (Expression expr, Location loc)
12378 public class InterpolatedString : Expression
12380 readonly StringLiteral start, end;
12381 readonly List<Expression> interpolations;
12382 Arguments arguments;
12384 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12386 this.start = start;
12388 this.interpolations = interpolations;
12389 loc = start.Location;
12392 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12394 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12395 if (factory == null)
12398 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12399 var res = new Invocation (ma, arguments).Resolve (rc);
12400 if (res != null && res.Type != type)
12401 res = Convert.ExplicitConversion (rc, res, type, loc);
12406 public override bool ContainsEmitWithAwait ()
12408 if (interpolations == null)
12411 foreach (var expr in interpolations) {
12412 if (expr.ContainsEmitWithAwait ())
12419 public override Expression CreateExpressionTree (ResolveContext rc)
12421 var best = ResolveBestFormatOverload (rc);
12425 Expression instance = new NullLiteral (loc);
12426 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12427 return CreateExpressionFactoryCall (rc, "Call", args);
12430 protected override Expression DoResolve (ResolveContext rc)
12434 if (interpolations == null) {
12436 arguments = new Arguments (1);
12438 for (int i = 0; i < interpolations.Count; i += 2) {
12439 var ipi = (InterpolatedStringInsert)interpolations [i];
12443 arguments = new Arguments (interpolations.Count);
12445 var sb = new StringBuilder (start.Value);
12446 for (int i = 0; i < interpolations.Count; ++i) {
12448 sb.Append ('{').Append (i / 2);
12449 var isi = (InterpolatedStringInsert)interpolations [i];
12450 if (isi.Alignment != null) {
12452 var value = isi.ResolveAligment (rc);
12454 sb.Append (value.Value);
12457 if (isi.Format != null) {
12459 sb.Append (isi.Format);
12463 arguments.Add (new Argument (interpolations [i]));
12465 sb.Append (((StringLiteral)interpolations [i]).Value);
12469 sb.Append (end.Value);
12470 str = sb.ToString ();
12473 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12475 eclass = ExprClass.Value;
12476 type = rc.BuiltinTypes.String;
12480 public override void Emit (EmitContext ec)
12482 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12483 if (interpolations == null) {
12484 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12485 if (str != start.Value)
12486 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12493 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12497 var ca = new CallEmitter ();
12498 ca.Emit (ec, best, arguments, loc);
12501 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12503 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12504 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12505 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12509 public class InterpolatedStringInsert : CompositeExpression
12511 public InterpolatedStringInsert (Expression expr)
12516 public Expression Alignment { get; set; }
12517 public string Format { get; set; }
12519 protected override Expression DoResolve (ResolveContext rc)
12521 var expr = base.DoResolve (rc);
12526 // For better error reporting, assumes the built-in implementation uses object
12529 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12532 public int? ResolveAligment (ResolveContext rc)
12534 var c = Alignment.ResolveLabelConstant (rc);
12538 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12542 var value = (int) c.GetValueAsLong ();
12543 if (value > 32767 || value < -32767) {
12544 rc.Report.Warning (8094, 1, Alignment.Location,
12545 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");