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 rc)
112 Expression res = null;
113 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
114 res = expr.Resolve (rc);
117 var constant = res as Constant;
118 if (constant != null && constant.IsLiteral) {
119 if (res is NullLiteral)
122 return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
128 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130 return expr.DoResolveLValue (ec, right_side);
133 public override object Accept (StructuralVisitor visitor)
135 return visitor.Visit (this);
138 public override bool HasConditionalAccess ()
145 // Unary implements unary expressions.
147 public class Unary : Expression
149 public enum Operator : byte {
150 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
154 public readonly Operator Oper;
155 public Expression Expr;
156 ConvCast.Mode enum_conversion;
158 public Unary (Operator op, Expression expr, Location loc)
166 // This routine will attempt to simplify the unary expression when the
167 // argument is a constant.
169 Constant TryReduceConstant (ResolveContext ec, Constant constant)
173 while (e is EmptyConstantCast)
174 e = ((EmptyConstantCast) e).child;
176 if (e is SideEffectConstant) {
177 Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
178 return r == null ? null : new SideEffectConstant (r, e, r.Location);
181 TypeSpec expr_type = e.Type;
184 case Operator.UnaryPlus:
185 // Unary numeric promotions
186 switch (expr_type.BuiltinType) {
187 case BuiltinTypeSpec.Type.Byte:
188 return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
189 case BuiltinTypeSpec.Type.SByte:
190 return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
191 case BuiltinTypeSpec.Type.Short:
192 return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
193 case BuiltinTypeSpec.Type.UShort:
194 return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
195 case BuiltinTypeSpec.Type.Char:
196 return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
198 // Predefined operators
199 case BuiltinTypeSpec.Type.Int:
200 case BuiltinTypeSpec.Type.UInt:
201 case BuiltinTypeSpec.Type.Long:
202 case BuiltinTypeSpec.Type.ULong:
203 case BuiltinTypeSpec.Type.Float:
204 case BuiltinTypeSpec.Type.Double:
205 case BuiltinTypeSpec.Type.Decimal:
211 case Operator.UnaryNegation:
212 // Unary numeric promotions
213 switch (expr_type.BuiltinType) {
214 case BuiltinTypeSpec.Type.Byte:
215 return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
216 case BuiltinTypeSpec.Type.SByte:
217 return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
218 case BuiltinTypeSpec.Type.Short:
219 return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
220 case BuiltinTypeSpec.Type.UShort:
221 return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
222 case BuiltinTypeSpec.Type.Char:
223 return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
225 // Predefined operators
226 case BuiltinTypeSpec.Type.Int:
227 int ivalue = ((IntConstant) e).Value;
228 if (ivalue == int.MinValue) {
229 if (ec.ConstantCheckState) {
230 ConstantFold.Error_CompileTimeOverflow (ec, loc);
235 return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
237 case BuiltinTypeSpec.Type.Long:
238 long lvalue = ((LongConstant) e).Value;
239 if (lvalue == long.MinValue) {
240 if (ec.ConstantCheckState) {
241 ConstantFold.Error_CompileTimeOverflow (ec, loc);
246 return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
248 case BuiltinTypeSpec.Type.UInt:
249 UIntLiteral uil = constant as UIntLiteral;
251 if (uil.Value == int.MaxValue + (uint) 1)
252 return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
253 return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
255 return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
258 case BuiltinTypeSpec.Type.ULong:
259 ULongLiteral ull = constant as ULongLiteral;
260 if (ull != null && ull.Value == 9223372036854775808)
261 return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
264 case BuiltinTypeSpec.Type.Float:
265 FloatLiteral fl = constant as FloatLiteral;
266 // For better error reporting
268 return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
270 return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
272 case BuiltinTypeSpec.Type.Double:
273 DoubleLiteral dl = constant as DoubleLiteral;
274 // For better error reporting
276 return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
278 return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
280 case BuiltinTypeSpec.Type.Decimal:
281 return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
286 case Operator.LogicalNot:
287 if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
290 bool b = (bool)e.GetValue ();
291 return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
293 case Operator.OnesComplement:
294 // Unary numeric promotions
295 switch (expr_type.BuiltinType) {
296 case BuiltinTypeSpec.Type.Byte:
297 return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
298 case BuiltinTypeSpec.Type.SByte:
299 return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
300 case BuiltinTypeSpec.Type.Short:
301 return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
302 case BuiltinTypeSpec.Type.UShort:
303 return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
304 case BuiltinTypeSpec.Type.Char:
305 return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
307 // Predefined operators
308 case BuiltinTypeSpec.Type.Int:
309 return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
310 case BuiltinTypeSpec.Type.UInt:
311 return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
312 case BuiltinTypeSpec.Type.Long:
313 return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
314 case BuiltinTypeSpec.Type.ULong:
315 return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
317 if (e is EnumConstant) {
318 var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
321 // Numeric promotion upgraded types to int but for enum constant
322 // original underlying constant type is needed
324 if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
325 int v = ((IntConstant) res).Value;
326 switch (((EnumConstant) e).Child.Type.BuiltinType) {
327 case BuiltinTypeSpec.Type.UShort:
328 res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
330 case BuiltinTypeSpec.Type.Short:
331 res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
333 case BuiltinTypeSpec.Type.Byte:
334 res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
336 case BuiltinTypeSpec.Type.SByte:
337 res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
342 res = new EnumConstant (res, expr_type);
348 throw new Exception ("Can not constant fold: " + Oper.ToString());
351 protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
353 eclass = ExprClass.Value;
355 TypeSpec expr_type = expr.Type;
356 Expression best_expr;
358 TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
361 // Primitive types first
363 if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
364 best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
365 if (best_expr == null)
368 type = best_expr.Type;
374 // E operator ~(E x);
376 if (Oper == Operator.OnesComplement && expr_type.IsEnum)
377 return ResolveEnumOperator (ec, expr, predefined);
379 return ResolveUserType (ec, expr, predefined);
382 protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
384 TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
385 Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
386 if (best_expr == null)
390 enum_conversion = Binary.GetEnumResultCast (underlying_type);
392 return EmptyCast.Create (this, type);
395 public override bool ContainsEmitWithAwait ()
397 return Expr.ContainsEmitWithAwait ();
400 public override Expression CreateExpressionTree (ResolveContext ec)
402 return CreateExpressionTree (ec, null);
405 Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
409 case Operator.AddressOf:
410 Error_PointerInsideExpressionTree (ec);
412 case Operator.UnaryNegation:
413 if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
414 method_name = "NegateChecked";
416 method_name = "Negate";
418 case Operator.OnesComplement:
419 case Operator.LogicalNot:
422 case Operator.UnaryPlus:
423 method_name = "UnaryPlus";
426 throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
429 Arguments args = new Arguments (2);
430 args.Add (new Argument (Expr.CreateExpressionTree (ec)));
432 args.Add (new Argument (user_op));
434 return CreateExpressionFactoryCall (ec, method_name, args);
437 public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
439 var predefined_operators = new TypeSpec[(int) Operator.TOP][];
442 // 7.6.1 Unary plus operator
444 predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
445 types.Int, types.UInt,
446 types.Long, types.ULong,
447 types.Float, types.Double,
452 // 7.6.2 Unary minus operator
454 predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
455 types.Int, types.Long,
456 types.Float, types.Double,
461 // 7.6.3 Logical negation operator
463 predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
468 // 7.6.4 Bitwise complement operator
470 predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
471 types.Int, types.UInt,
472 types.Long, types.ULong
475 return predefined_operators;
479 // Unary numeric promotions
481 static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
483 TypeSpec expr_type = expr.Type;
484 if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
485 switch (expr_type.BuiltinType) {
486 case BuiltinTypeSpec.Type.Byte:
487 case BuiltinTypeSpec.Type.SByte:
488 case BuiltinTypeSpec.Type.Short:
489 case BuiltinTypeSpec.Type.UShort:
490 case BuiltinTypeSpec.Type.Char:
491 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
495 if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
496 return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
501 protected override Expression DoResolve (ResolveContext ec)
503 if (Oper == Operator.AddressOf) {
504 return ResolveAddressOf (ec);
507 Expr = Expr.Resolve (ec);
511 if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
512 Arguments args = new Arguments (1);
513 args.Add (new Argument (Expr));
514 return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
517 if (Expr.Type.IsNullableType)
518 return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
521 // Attempt to use a constant folding operation.
523 Constant cexpr = Expr as Constant;
525 cexpr = TryReduceConstant (ec, cexpr);
530 Expression expr = ResolveOperator (ec, Expr);
532 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
535 // Reduce unary operator on predefined types
537 if (expr == this && Oper == Operator.UnaryPlus)
543 public override Expression DoResolveLValue (ResolveContext ec, Expression right)
548 public override void Emit (EmitContext ec)
550 EmitOperator (ec, type);
553 protected void EmitOperator (EmitContext ec, TypeSpec type)
556 case Operator.UnaryPlus:
560 case Operator.UnaryNegation:
561 if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
562 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
563 Expr = Expr.EmitToField (ec);
566 if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
567 ec.Emit (OpCodes.Conv_U8);
569 ec.Emit (OpCodes.Sub_Ovf);
572 ec.Emit (OpCodes.Neg);
577 case Operator.LogicalNot:
580 ec.Emit (OpCodes.Ceq);
583 case Operator.OnesComplement:
585 ec.Emit (OpCodes.Not);
588 case Operator.AddressOf:
589 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
593 throw new Exception ("This should not happen: Operator = "
598 // Same trick as in Binary expression
600 if (enum_conversion != 0) {
601 using (ec.With (BuilderContext.Options.CheckedScope, false)) {
602 ConvCast.Emit (ec, enum_conversion);
607 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
609 if (Oper == Operator.LogicalNot)
610 Expr.EmitBranchable (ec, target, !on_true);
612 base.EmitBranchable (ec, target, on_true);
615 public override void EmitSideEffect (EmitContext ec)
617 Expr.EmitSideEffect (ec);
620 public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
622 rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
623 oper, type.GetSignatureForError ());
626 public override void FlowAnalysis (FlowAnalysisContext fc)
628 FlowAnalysis (fc, false);
631 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
633 FlowAnalysis (fc, true);
636 void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
638 if (Oper == Operator.AddressOf) {
639 var vr = Expr as VariableReference;
640 if (vr != null && vr.VariableInfo != null)
641 fc.SetVariableAssigned (vr.VariableInfo);
646 if (Oper == Operator.LogicalNot && conditional) {
647 Expr.FlowAnalysisConditional (fc);
649 var temp = fc.DefiniteAssignmentOnTrue;
650 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
651 fc.DefiniteAssignmentOnFalse = temp;
653 Expr.FlowAnalysis (fc);
658 // Converts operator to System.Linq.Expressions.ExpressionType enum name
660 string GetOperatorExpressionTypeName ()
663 case Operator.OnesComplement:
664 return "OnesComplement";
665 case Operator.LogicalNot:
667 case Operator.UnaryNegation:
669 case Operator.UnaryPlus:
672 throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
676 static bool IsFloat (TypeSpec t)
678 return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
682 // Returns a stringified representation of the Operator
684 public static string OperName (Operator oper)
687 case Operator.UnaryPlus:
689 case Operator.UnaryNegation:
691 case Operator.LogicalNot:
693 case Operator.OnesComplement:
695 case Operator.AddressOf:
699 throw new NotImplementedException (oper.ToString ());
702 public override SLE.Expression MakeExpression (BuilderContext ctx)
704 var expr = Expr.MakeExpression (ctx);
705 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
708 case Operator.UnaryNegation:
709 return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
710 case Operator.LogicalNot:
711 return SLE.Expression.Not (expr);
712 case Operator.OnesComplement:
713 return SLE.Expression.OnesComplement (expr);
715 throw new NotImplementedException (Oper.ToString ());
719 Expression ResolveAddressOf (ResolveContext ec)
721 if (ec.CurrentIterator != null) {
722 UnsafeInsideIteratorError (ec, loc);
723 } else if (!ec.IsUnsafe) {
724 UnsafeError (ec, loc);
727 Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
728 if (Expr == null || Expr.eclass != ExprClass.Variable) {
729 ec.Report.Error (211, loc, "Cannot take the address of the given expression");
733 if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
737 IVariableReference vr = Expr as IVariableReference;
740 is_fixed = vr.IsFixed;
741 vr.SetHasAddressTaken ();
743 if (vr.IsHoisted && ec.CurrentIterator == null) {
744 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
747 IFixedExpression fe = Expr as IFixedExpression;
748 is_fixed = fe != null && fe.IsFixed;
751 if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
752 ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
755 type = PointerContainer.MakeType (ec.Module, Expr.Type);
756 eclass = ExprClass.Value;
760 Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
762 expr = DoNumericPromotion (rc, Oper, expr);
763 TypeSpec expr_type = expr.Type;
764 foreach (TypeSpec t in predefined) {
772 // Perform user-operator overload resolution
774 protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
776 CSharp.Operator.OpType op_type;
778 case Operator.LogicalNot:
779 op_type = CSharp.Operator.OpType.LogicalNot; break;
780 case Operator.OnesComplement:
781 op_type = CSharp.Operator.OpType.OnesComplement; break;
782 case Operator.UnaryNegation:
783 op_type = CSharp.Operator.OpType.UnaryNegation; break;
784 case Operator.UnaryPlus:
785 op_type = CSharp.Operator.OpType.UnaryPlus; break;
787 throw new InternalErrorException (Oper.ToString ());
790 var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
794 Arguments args = new Arguments (1);
795 args.Add (new Argument (expr));
797 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
798 var oper = res.ResolveOperator (ec, ref args);
803 Expr = args [0].Expr;
804 return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
808 // Unary user type overload resolution
810 Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
812 Expression best_expr = ResolveUserOperator (ec, expr);
813 if (best_expr != null)
816 foreach (TypeSpec t in predefined) {
817 Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
818 if (oper_expr == null)
821 if (oper_expr == ErrorExpression.Instance)
825 // decimal type is predefined but has user-operators
827 if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
828 oper_expr = ResolveUserType (ec, oper_expr, predefined);
830 oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
832 if (oper_expr == null)
835 if (best_expr == null) {
836 best_expr = oper_expr;
840 int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
842 if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
843 Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
845 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
852 best_expr = oper_expr;
855 if (best_expr == null)
859 // HACK: Decimal user-operator is included in standard operators
861 if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
865 type = best_expr.Type;
869 protected override void CloneTo (CloneContext clonectx, Expression t)
871 Unary target = (Unary) t;
873 target.Expr = Expr.Clone (clonectx);
876 public override object Accept (StructuralVisitor visitor)
878 return visitor.Visit (this);
884 // Unary operators are turned into Indirection expressions
885 // after semantic analysis (this is so we can take the address
886 // of an indirection).
888 public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
890 LocalTemporary temporary;
893 public Indirection (Expression expr, Location l)
899 public Expression Expr {
905 public bool IsFixed {
909 public override Location StartLocation {
911 return expr.StartLocation;
915 protected override void CloneTo (CloneContext clonectx, Expression t)
917 Indirection target = (Indirection) t;
918 target.expr = expr.Clone (clonectx);
921 public override bool ContainsEmitWithAwait ()
923 throw new NotImplementedException ();
926 public override Expression CreateExpressionTree (ResolveContext ec)
928 Error_PointerInsideExpressionTree (ec);
932 public override void Emit (EmitContext ec)
937 ec.EmitLoadFromPtr (Type);
940 public void Emit (EmitContext ec, bool leave_copy)
944 ec.Emit (OpCodes.Dup);
945 temporary = new LocalTemporary (expr.Type);
946 temporary.Store (ec);
950 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
952 prepared = isCompound;
957 ec.Emit (OpCodes.Dup);
961 ec.Emit (OpCodes.Dup);
962 temporary = new LocalTemporary (source.Type);
963 temporary.Store (ec);
966 ec.EmitStoreFromPtr (type);
968 if (temporary != null) {
970 temporary.Release (ec);
974 public void AddressOf (EmitContext ec, AddressOp Mode)
979 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
981 return DoResolve (ec);
984 protected override Expression DoResolve (ResolveContext ec)
986 expr = expr.Resolve (ec);
990 if (ec.CurrentIterator != null) {
991 UnsafeInsideIteratorError (ec, loc);
992 } else if (!ec.IsUnsafe) {
993 UnsafeError (ec, loc);
996 var pc = expr.Type as PointerContainer;
999 ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
1005 if (type.Kind == MemberKind.Void) {
1006 Error_VoidPointerOperation (ec);
1010 eclass = ExprClass.Variable;
1014 public override object Accept (StructuralVisitor visitor)
1016 return visitor.Visit (this);
1021 /// Unary Mutator expressions (pre and post ++ and --)
1025 /// UnaryMutator implements ++ and -- expressions. It derives from
1026 /// ExpressionStatement becuase the pre/post increment/decrement
1027 /// operators can be used in a statement context.
1029 /// FIXME: Idea, we could split this up in two classes, one simpler
1030 /// for the common case, and one with the extra fields for more complex
1031 /// classes (indexers require temporary access; overloaded require method)
1034 public class UnaryMutator : ExpressionStatement
1036 class DynamicPostMutator : Expression, IAssignMethod
1038 LocalTemporary temp;
1041 public DynamicPostMutator (Expression expr)
1044 this.type = expr.Type;
1045 this.loc = expr.Location;
1048 public override Expression CreateExpressionTree (ResolveContext ec)
1050 throw new NotImplementedException ("ET");
1053 protected override Expression DoResolve (ResolveContext rc)
1055 eclass = expr.eclass;
1059 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1061 expr.DoResolveLValue (ec, right_side);
1062 return DoResolve (ec);
1065 public override void Emit (EmitContext ec)
1070 public void Emit (EmitContext ec, bool leave_copy)
1072 throw new NotImplementedException ();
1076 // Emits target assignment using unmodified source value
1078 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
1081 // Allocate temporary variable to keep original value before it's modified
1083 temp = new LocalTemporary (type);
1087 ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
1098 public enum Mode : byte {
1105 PreDecrement = IsDecrement,
1106 PostIncrement = IsPost,
1107 PostDecrement = IsPost | IsDecrement
1111 bool is_expr, recurse;
1113 protected Expression expr;
1115 // Holds the real operation
1116 Expression operation;
1118 public UnaryMutator (Mode m, Expression e, Location loc)
1125 public Mode UnaryMutatorMode {
1131 public Expression Expr {
1137 public override Location StartLocation {
1139 return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
1143 public override bool ContainsEmitWithAwait ()
1145 return expr.ContainsEmitWithAwait ();
1148 public override Expression CreateExpressionTree (ResolveContext ec)
1150 return new SimpleAssign (this, this).CreateExpressionTree (ec);
1153 public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
1156 // Predefined ++ and -- operators exist for the following types:
1157 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1159 return new TypeSpec[] {
1175 protected override Expression DoResolve (ResolveContext ec)
1177 expr = expr.Resolve (ec);
1179 if (expr == null || expr.Type == InternalType.ErrorType)
1182 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 // Handle postfix unary operators using local
1185 // temporary variable
1187 if ((mode & Mode.IsPost) != 0)
1188 expr = new DynamicPostMutator (expr);
1190 Arguments args = new Arguments (1);
1191 args.Add (new Argument (expr));
1192 return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
1195 if (expr.Type.IsNullableType)
1196 return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
1198 return DoResolveOperation (ec);
1201 protected Expression DoResolveOperation (ResolveContext ec)
1203 eclass = ExprClass.Value;
1206 if (expr is RuntimeValueExpression) {
1209 // Use itself at the top of the stack
1210 operation = new EmptyExpression (type);
1214 // The operand of the prefix/postfix increment decrement operators
1215 // should be an expression that is classified as a variable,
1216 // a property access or an indexer access
1218 // TODO: Move to parser, expr is ATypeNameExpression
1219 if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
1220 expr = expr.ResolveLValue (ec, expr);
1222 ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
1226 // Step 1: Try to find a user operator, it has priority over predefined ones
1228 var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
1229 var methods = MemberCache.GetUserOperator (type, user_op, false);
1231 if (methods != null) {
1232 Arguments args = new Arguments (1);
1233 args.Add (new Argument (expr));
1235 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1236 var method = res.ResolveOperator (ec, ref args);
1240 args[0].Expr = operation;
1241 operation = new UserOperatorCall (method, args, null, loc);
1242 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1247 // Step 2: Try predefined types
1250 Expression source = null;
1251 bool primitive_type;
1254 // Predefined without user conversion first for speed-up
1256 // Predefined ++ and -- operators exist for the following types:
1257 // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
1259 switch (type.BuiltinType) {
1260 case BuiltinTypeSpec.Type.Byte:
1261 case BuiltinTypeSpec.Type.SByte:
1262 case BuiltinTypeSpec.Type.Short:
1263 case BuiltinTypeSpec.Type.UShort:
1264 case BuiltinTypeSpec.Type.Int:
1265 case BuiltinTypeSpec.Type.UInt:
1266 case BuiltinTypeSpec.Type.Long:
1267 case BuiltinTypeSpec.Type.ULong:
1268 case BuiltinTypeSpec.Type.Char:
1269 case BuiltinTypeSpec.Type.Float:
1270 case BuiltinTypeSpec.Type.Double:
1271 case BuiltinTypeSpec.Type.Decimal:
1273 primitive_type = true;
1276 primitive_type = false;
1278 // ++/-- on pointer variables of all types except void*
1279 if (type.IsPointer) {
1280 if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
1281 Error_VoidPointerOperation (ec);
1287 Expression best_source = null;
1288 foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
1289 source = Convert.ImplicitUserConversion (ec, operation, t, loc);
1291 // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
1295 if (best_source == null) {
1296 best_source = source;
1300 var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
1305 best_source = source;
1309 Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
1313 source = best_source;
1316 // ++/-- on enum types
1317 if (source == null && type.IsEnum)
1320 if (source == null) {
1321 expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
1328 var one = new IntConstant (ec.BuiltinTypes, 1, loc);
1329 var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
1330 operation = new Binary (op, source, one);
1331 operation = operation.Resolve (ec);
1332 if (operation == null)
1333 throw new NotImplementedException ("should not be reached");
1335 if (operation.Type != type) {
1337 operation = Convert.ExplicitNumericConversion (ec, operation, type);
1339 operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
1345 void EmitCode (EmitContext ec, bool is_expr)
1348 this.is_expr = is_expr;
1349 ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
1352 public override void Emit (EmitContext ec)
1355 // We use recurse to allow ourselfs to be the source
1356 // of an assignment. This little hack prevents us from
1357 // having to allocate another expression
1360 ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
1368 EmitCode (ec, true);
1371 protected virtual void EmitOperation (EmitContext ec)
1373 operation.Emit (ec);
1376 public override void EmitStatement (EmitContext ec)
1378 EmitCode (ec, false);
1381 public override void FlowAnalysis (FlowAnalysisContext fc)
1383 expr.FlowAnalysis (fc);
1387 // Converts operator to System.Linq.Expressions.ExpressionType enum name
1389 string GetOperatorExpressionTypeName ()
1391 return IsDecrement ? "Decrement" : "Increment";
1395 get { return (mode & Mode.IsDecrement) != 0; }
1399 public override SLE.Expression MakeExpression (BuilderContext ctx)
1401 var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
1402 var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
1403 return SLE.Expression.Assign (target, source);
1406 public static string OperName (Mode oper)
1408 return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
1411 protected override void CloneTo (CloneContext clonectx, Expression t)
1413 UnaryMutator target = (UnaryMutator) t;
1415 target.expr = expr.Clone (clonectx);
1418 public override object Accept (StructuralVisitor visitor)
1420 return visitor.Visit (this);
1426 // Base class for the `is' and `as' operators
1428 public abstract class Probe : Expression
1430 public Expression ProbeType;
1431 protected Expression expr;
1432 protected TypeSpec probe_type_expr;
1434 protected Probe (Expression expr, Expression probe_type, Location l)
1436 ProbeType = probe_type;
1441 public Expression Expr {
1447 public override bool ContainsEmitWithAwait ()
1449 return expr.ContainsEmitWithAwait ();
1452 protected Expression ResolveCommon (ResolveContext rc)
1454 expr = expr.Resolve (rc);
1458 ResolveProbeType (rc);
1459 if (probe_type_expr == null)
1462 if (probe_type_expr.IsStatic) {
1463 rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
1464 probe_type_expr.GetSignatureForError ());
1468 if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
1469 rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
1474 if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
1475 rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
1483 protected virtual void ResolveProbeType (ResolveContext rc)
1485 probe_type_expr = ProbeType.ResolveAsType (rc);
1488 public override void EmitSideEffect (EmitContext ec)
1490 expr.EmitSideEffect (ec);
1493 public override void EmitPrepare (EmitContext ec)
1495 expr.EmitPrepare (ec);
1498 public override void FlowAnalysis (FlowAnalysisContext fc)
1500 expr.FlowAnalysis (fc);
1503 public override bool HasConditionalAccess ()
1505 return expr.HasConditionalAccess ();
1508 protected abstract string OperatorName { get; }
1510 protected override void CloneTo (CloneContext clonectx, Expression t)
1512 Probe target = (Probe) t;
1514 target.expr = expr.Clone (clonectx);
1515 target.ProbeType = ProbeType.Clone (clonectx);
1521 /// Implementation of the `is' operator.
1523 public class Is : Probe
1525 Nullable.Unwrap expr_unwrap;
1526 MethodSpec number_mg;
1527 Arguments number_args;
1529 public Is (Expression expr, Expression probe_type, Location l)
1530 : base (expr, probe_type, l)
1534 protected override string OperatorName {
1535 get { return "is"; }
1538 public LocalVariable Variable { get; set; }
1540 public override Expression CreateExpressionTree (ResolveContext ec)
1542 if (Variable != null)
1543 ec.Report.Error (8122, loc, "An expression tree cannot contain a pattern matching operator");
1545 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1546 expr.CreateExpressionTree (ec),
1547 new TypeOf (probe_type_expr, loc));
1549 return CreateExpressionFactoryCall (ec, "TypeIs", args);
1552 Expression CreateConstantResult (ResolveContext rc, bool result)
1555 rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
1556 probe_type_expr.GetSignatureForError ());
1558 rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
1559 probe_type_expr.GetSignatureForError ());
1561 var c = new BoolConstant (rc.BuiltinTypes, result, loc);
1562 return expr.IsSideEffectFree ?
1563 ReducedExpression.Create (c, this) :
1564 new SideEffectConstant (c, this, loc);
1567 public override void Emit (EmitContext ec)
1569 if (probe_type_expr == null) {
1570 if (ProbeType is WildcardPattern) {
1571 expr.EmitSideEffect (ec);
1572 ProbeType.Emit (ec);
1574 EmitPatternMatch (ec);
1581 if (expr_unwrap == null) {
1583 ec.Emit (OpCodes.Cgt_Un);
1587 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1589 if (probe_type_expr == null) {
1590 EmitPatternMatch (ec);
1595 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
1598 public override void EmitPrepare (EmitContext ec)
1600 base.EmitPrepare (ec);
1602 if (Variable != null)
1603 Variable.CreateBuilder (ec);
1606 void EmitPatternMatch (EmitContext ec)
1608 var no_match = ec.DefineLabel ();
1609 var end = ec.DefineLabel ();
1611 if (expr_unwrap != null) {
1612 expr_unwrap.EmitCheck (ec);
1614 if (ProbeType.IsNull) {
1616 ec.Emit (OpCodes.Ceq);
1620 ec.Emit (OpCodes.Brfalse_S, no_match);
1621 expr_unwrap.Emit (ec);
1622 ProbeType.Emit (ec);
1623 ec.Emit (OpCodes.Ceq);
1624 ec.Emit (OpCodes.Br_S, end);
1625 ec.MarkLabel (no_match);
1631 if (number_args != null && number_args.Count == 3) {
1632 var ce = new CallEmitter ();
1633 ce.Emit (ec, number_mg, number_args, loc);
1637 var probe_type = ProbeType.Type;
1640 ec.Emit (OpCodes.Isinst, probe_type);
1641 ec.Emit (OpCodes.Dup);
1642 ec.Emit (OpCodes.Brfalse, no_match);
1644 bool complex_pattern = ProbeType is ComplexPatternExpression;
1645 Label prev = ec.RecursivePatternLabel;
1646 if (complex_pattern)
1647 ec.RecursivePatternLabel = ec.DefineLabel ();
1649 if (number_mg != null) {
1650 var ce = new CallEmitter ();
1651 ce.Emit (ec, number_mg, number_args, loc);
1653 if (TypeSpec.IsValueType (probe_type))
1654 ec.Emit (OpCodes.Unbox_Any, probe_type);
1656 ProbeType.Emit (ec);
1657 if (complex_pattern) {
1660 ec.Emit (OpCodes.Ceq);
1663 ec.Emit (OpCodes.Br_S, end);
1664 ec.MarkLabel (no_match);
1666 ec.Emit (OpCodes.Pop);
1668 if (complex_pattern)
1669 ec.MarkLabel (ec.RecursivePatternLabel);
1671 ec.RecursivePatternLabel = prev;
1677 void EmitLoad (EmitContext ec)
1679 Label no_value_label = new Label ();
1681 if (expr_unwrap != null) {
1682 expr_unwrap.EmitCheck (ec);
1684 if (Variable == null)
1687 ec.Emit (OpCodes.Dup);
1688 no_value_label = ec.DefineLabel ();
1689 ec.Emit (OpCodes.Brfalse_S, no_value_label);
1690 expr_unwrap.Emit (ec);
1694 // Only to make verifier happy
1695 if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
1696 ec.Emit (OpCodes.Box, expr.Type);
1698 ec.Emit (OpCodes.Isinst, probe_type_expr);
1701 if (Variable != null) {
1702 bool value_on_stack;
1703 if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
1704 ec.Emit (OpCodes.Dup);
1705 ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
1706 value_on_stack = true;
1708 value_on_stack = false;
1712 // It's ok to have variable builder created out of order. It simplifies emit
1713 // of statements like while (condition) { }
1715 if (!Variable.Created)
1716 Variable.CreateBuilder (ec);
1718 Variable.EmitAssign (ec);
1720 if (expr_unwrap != null) {
1721 ec.MarkLabel (no_value_label);
1722 } else if (!value_on_stack) {
1728 protected override Expression DoResolve (ResolveContext rc)
1730 if (ResolveCommon (rc) == null)
1733 type = rc.BuiltinTypes.Bool;
1734 eclass = ExprClass.Value;
1736 if (probe_type_expr == null)
1737 return ResolveMatchingExpression (rc);
1739 var res = ResolveResultExpression (rc);
1740 if (Variable != null) {
1741 if (res is Constant)
1742 throw new NotImplementedException ("constant in type pattern matching");
1744 Variable.Type = probe_type_expr;
1745 var bc = rc as BlockContext;
1747 Variable.PrepareAssignmentAnalysis (bc);
1753 public override void FlowAnalysis (FlowAnalysisContext fc)
1755 base.FlowAnalysis (fc);
1757 if (Variable != null)
1758 fc.SetVariableAssigned (Variable.VariableInfo, true);
1761 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
1763 if (Variable == null) {
1764 base.FlowAnalysisConditional (fc);
1768 expr.FlowAnalysis (fc);
1770 fc.DefiniteAssignmentOnTrue = fc.BranchDefiniteAssignment ();
1771 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1773 fc.SetVariableAssigned (Variable.VariableInfo, fc.DefiniteAssignmentOnTrue);
1776 protected override void ResolveProbeType (ResolveContext rc)
1778 if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
1779 if (ProbeType is PatternExpression) {
1780 ProbeType.Resolve (rc);
1785 // Have to use session recording because we don't have reliable type probing
1786 // mechanism (similar issue as in attributes resolving)
1788 // TODO: This is still wrong because ResolveAsType can be destructive
1790 var type_printer = new SessionReportPrinter ();
1791 var prev_recorder = rc.Report.SetPrinter (type_printer);
1793 probe_type_expr = ProbeType.ResolveAsType (rc);
1794 type_printer.EndSession ();
1796 if (probe_type_expr != null) {
1797 type_printer.Merge (rc.Report.Printer);
1798 rc.Report.SetPrinter (prev_recorder);
1802 var vexpr = ProbeType as VarExpr;
1803 if (vexpr != null && vexpr.InferType (rc, expr)) {
1804 probe_type_expr = vexpr.Type;
1805 rc.Report.SetPrinter (prev_recorder);
1809 var expr_printer = new SessionReportPrinter ();
1810 rc.Report.SetPrinter (expr_printer);
1811 ProbeType = ProbeType.Resolve (rc);
1812 expr_printer.EndSession ();
1814 if (ProbeType != null) {
1815 expr_printer.Merge (rc.Report.Printer);
1817 type_printer.Merge (rc.Report.Printer);
1820 rc.Report.SetPrinter (prev_recorder);
1824 base.ResolveProbeType (rc);
1827 Expression ResolveMatchingExpression (ResolveContext rc)
1829 var mc = ProbeType as Constant;
1831 if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1832 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1837 return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
1839 var c = Expr as Constant;
1841 c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
1846 if (Expr.Type.IsNullableType) {
1847 expr_unwrap = new Nullable.Unwrap (Expr);
1848 expr_unwrap.Resolve (rc);
1849 ProbeType = Convert.ImplicitConversion (rc, ProbeType, expr_unwrap.Type, loc);
1850 } else if (ProbeType.Type == Expr.Type) {
1851 // TODO: Better error handling
1852 return new Binary (Binary.Operator.Equality, Expr, mc, loc).Resolve (rc);
1853 } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
1854 var helper = rc.Module.CreatePatterMatchingHelper ();
1855 number_mg = helper.NumberMatcher.Spec;
1858 // There are actually 3 arguments but the first one is already on the stack
1860 number_args = new Arguments (3);
1861 if (!ProbeType.Type.IsEnum)
1862 number_args.Add (new Argument (Expr));
1864 number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
1865 number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
1871 if (ProbeType is PatternExpression) {
1872 if (!(ProbeType is WildcardPattern) && !Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
1873 ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
1879 // TODO: Better error message
1880 rc.Report.Error (150, ProbeType.Location, "A constant value is expected");
1884 Expression ResolveResultExpression (ResolveContext ec)
1886 if (Variable != null) {
1887 if (expr is NullLiteral) {
1888 ec.Report.Error (8117, loc, "Cannot use null as pattern matching operand");
1892 CheckExpressionVariable (ec);
1895 TypeSpec d = expr.Type;
1896 bool d_is_nullable = false;
1899 // If E is a method group or the null literal, or if the type of E is a reference
1900 // type or a nullable type and the value of E is null, the result is false
1903 return CreateConstantResult (ec, false);
1905 if (d.IsNullableType) {
1906 var ut = Nullable.NullableInfo.GetUnderlyingType (d);
1907 if (!ut.IsGenericParameter) {
1909 d_is_nullable = true;
1913 TypeSpec t = probe_type_expr;
1914 bool t_is_nullable = false;
1915 if (t.IsNullableType) {
1916 if (Variable != null) {
1917 ec.Report.Error (8116, loc, "The nullable type `{0}' pattern matching is not allowed. Consider using underlying type `{1}'",
1918 t.GetSignatureForError (), Nullable.NullableInfo.GetUnderlyingType (t).GetSignatureForError ());
1921 var ut = Nullable.NullableInfo.GetUnderlyingType (t);
1922 if (!ut.IsGenericParameter) {
1924 t_is_nullable = true;
1931 // D and T are the same value types but D can be null
1933 if (d_is_nullable && !t_is_nullable) {
1934 expr_unwrap = Nullable.Unwrap.Create (expr, true);
1939 // The result is true if D and T are the same value types
1941 return CreateConstantResult (ec, true);
1944 var tp = d as TypeParameterSpec;
1946 return ResolveGenericParameter (ec, t, tp);
1949 // An unboxing conversion exists
1951 if (Convert.ExplicitReferenceConversionExists (d, t))
1955 // open generic type
1957 if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
1960 var tps = t as TypeParameterSpec;
1962 return ResolveGenericParameter (ec, d, tps);
1964 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1965 if (Variable != null) {
1966 ec.Report.Error (8208, loc, "The type `{0}' pattern matching is not allowed", t.GetSignatureForError ());
1968 ec.Report.Warning (1981, 3, loc,
1969 "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
1970 OperatorName, t.GetSignatureForError ());
1974 if (TypeManager.IsGenericParameter (d))
1975 return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
1977 if (TypeSpec.IsValueType (d)) {
1978 if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
1979 if (d_is_nullable && !t_is_nullable) {
1980 expr_unwrap = Nullable.Unwrap.Create (expr, false);
1984 return CreateConstantResult (ec, true);
1987 if (Convert.ImplicitReferenceConversionExists (d, t)) {
1988 var c = expr as Constant;
1990 return CreateConstantResult (ec, !c.IsNull);
1993 // Do not optimize for imported type or dynamic type
1995 if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
1996 d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
2000 if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
2004 // Turn is check into simple null check for implicitly convertible reference types
2006 return ReducedExpression.Create (
2007 new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc), Binary.State.UserOperatorsExcluded).Resolve (ec),
2011 if (Convert.ExplicitReferenceConversionExists (d, t))
2015 // open generic type
2017 if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
2022 return CreateConstantResult (ec, false);
2025 Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
2027 if (t.IsReferenceType) {
2029 return CreateConstantResult (ec, false);
2032 if (expr.Type.IsGenericParameter) {
2033 if (expr.Type == d && TypeSpec.IsValueType (t) && TypeSpec.IsValueType (d))
2034 return CreateConstantResult (ec, true);
2036 expr = new BoxedCast (expr, d);
2042 public override object Accept (StructuralVisitor visitor)
2044 return visitor.Visit (this);
2048 class WildcardPattern : PatternExpression
2050 public WildcardPattern (Location loc)
2055 protected override Expression DoResolve (ResolveContext rc)
2057 eclass = ExprClass.Value;
2058 type = rc.BuiltinTypes.Object;
2062 public override void Emit (EmitContext ec)
2068 class RecursivePattern : ComplexPatternExpression
2070 MethodGroupExpr operator_mg;
2071 Arguments operator_args;
2073 public RecursivePattern (ATypeNameExpression typeExpresion, Arguments arguments, Location loc)
2074 : base (typeExpresion, loc)
2076 Arguments = arguments;
2079 public Arguments Arguments { get; private set; }
2081 protected override Expression DoResolve (ResolveContext rc)
2083 type = TypeExpression.ResolveAsType (rc);
2087 var operators = MemberCache.GetUserOperator (type, Operator.OpType.Is, true);
2088 if (operators == null) {
2089 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2093 var ops = FindMatchingOverloads (operators);
2095 // TODO: better error message
2096 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2101 Arguments.Resolve (rc, out dynamic_args);
2103 throw new NotImplementedException ("dynamic argument");
2105 var op = FindBestOverload (rc, ops);
2107 // TODO: better error message
2108 Error_TypeDoesNotContainDefinition (rc, type, Operator.GetName (Operator.OpType.Is) + " operator");
2112 var op_types = op.Parameters.Types;
2113 operator_args = new Arguments (op_types.Length);
2114 operator_args.Add (new Argument (new EmptyExpression (type)));
2116 for (int i = 0; i < Arguments.Count; ++i) {
2117 // TODO: Needs releasing optimization
2118 var lt = new LocalTemporary (op_types [i + 1]);
2119 operator_args.Add (new Argument (lt, Argument.AType.Out));
2121 if (comparisons == null)
2122 comparisons = new Expression[Arguments.Count];
2127 var arg = Arguments [i];
2128 var named = arg as NamedArgument;
2129 if (named != null) {
2130 arg_comp_index = op.Parameters.GetParameterIndexByName (named.Name) - 1;
2131 expr = Arguments [arg_comp_index].Expr;
2137 comparisons [arg_comp_index] = ResolveComparison (rc, expr, lt);
2140 operator_mg = MethodGroupExpr.CreatePredefined (op, type, loc);
2142 eclass = ExprClass.Value;
2146 List<MethodSpec> FindMatchingOverloads (IList<MemberSpec> members)
2148 int arg_count = Arguments.Count + 1;
2149 List<MethodSpec> best = null;
2150 foreach (MethodSpec method in members) {
2151 var pm = method.Parameters;
2152 if (pm.Count != arg_count)
2155 // TODO: Needs more thorough operator checks elsewhere to avoid doing this every time
2157 for (int ii = 1; ii < pm.Count; ++ii) {
2158 if ((pm.FixedParameters [ii].ModFlags & Parameter.Modifier.OUT) == 0) {
2168 best = new List<MethodSpec> ();
2176 MethodSpec FindBestOverload (ResolveContext rc, List<MethodSpec> methods)
2178 for (int ii = 0; ii < Arguments.Count; ++ii) {
2179 var arg = Arguments [ii];
2180 var expr = arg.Expr;
2181 if (expr is WildcardPattern)
2184 var na = arg as NamedArgument;
2185 for (int i = 0; i < methods.Count; ++i) {
2186 var pd = methods [i].Parameters;
2190 index = pd.GetParameterIndexByName (na.Name);
2192 methods.RemoveAt (i--);
2199 var m = pd.Types [index];
2200 if (!Convert.ImplicitConversionExists (rc, expr, m))
2201 methods.RemoveAt (i--);
2205 if (methods.Count != 1)
2211 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2213 operator_mg.EmitCall (ec, operator_args, false);
2214 ec.Emit (OpCodes.Brfalse, target);
2216 base.EmitBranchable (ec, target, on_true);
2219 static Expression ResolveComparison (ResolveContext rc, Expression expr, LocalTemporary lt)
2221 if (expr is WildcardPattern)
2222 return new EmptyExpression (expr.Type);
2224 var recursive = expr as RecursivePattern;
2225 expr = Convert.ImplicitConversionRequired (rc, expr, lt.Type, expr.Location);
2229 if (recursive != null) {
2230 recursive.SetParentInstance (lt);
2234 // TODO: Better error handling
2235 return new Binary (Binary.Operator.Equality, lt, expr, expr.Location).Resolve (rc);
2238 public void SetParentInstance (Expression instance)
2240 operator_args [0] = new Argument (instance);
2244 class PropertyPattern : ComplexPatternExpression
2246 LocalTemporary instance;
2248 public PropertyPattern (ATypeNameExpression typeExpresion, List<PropertyPatternMember> members, Location loc)
2249 : base (typeExpresion, loc)
2254 public List<PropertyPatternMember> Members { get; private set; }
2256 protected override Expression DoResolve (ResolveContext rc)
2258 type = TypeExpression.ResolveAsType (rc);
2262 comparisons = new Expression[Members.Count];
2264 // TODO: optimize when source is VariableReference, it'd save dup+pop
2265 instance = new LocalTemporary (type);
2267 for (int i = 0; i < Members.Count; i++) {
2268 var lookup = Members [i];
2270 var member = MemberLookup (rc, false, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2271 if (member == null) {
2272 member = MemberLookup (rc, true, type, lookup.Name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
2273 if (member != null) {
2274 Expression.ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
2279 if (member == null) {
2280 Expression.Error_TypeDoesNotContainDefinition (rc, Location, Type, lookup.Name);
2284 var pe = member as PropertyExpr;
2285 if (pe == null || member is FieldExpr) {
2286 rc.Report.Error (-2001, lookup.Location, "`{0}' is not a valid pattern member", lookup.Name);
2290 // TODO: Obsolete checks
2291 // TODO: check accessibility
2292 if (pe != null && !pe.PropertyInfo.HasGet) {
2293 rc.Report.Error (-2002, lookup.Location, "Property `{0}.get' accessor is required", pe.GetSignatureForError ());
2297 var expr = lookup.Expr.Resolve (rc);
2301 var me = (MemberExpr)member;
2302 me.InstanceExpression = instance;
2304 comparisons [i] = ResolveComparison (rc, expr, me);
2307 eclass = ExprClass.Value;
2311 static Expression ResolveComparison (ResolveContext rc, Expression expr, Expression instance)
2313 if (expr is WildcardPattern)
2314 return new EmptyExpression (expr.Type);
2316 return new Is (instance, expr, expr.Location).Resolve (rc);
2319 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2321 instance.Store (ec);
2323 base.EmitBranchable (ec, target, on_true);
2327 class PropertyPatternMember
2329 public PropertyPatternMember (string name, Expression expr, Location loc)
2336 public string Name { get; private set; }
2337 public Expression Expr { get; private set; }
2338 public Location Location { get; private set; }
2341 abstract class PatternExpression : Expression
2343 protected PatternExpression (Location loc)
2348 public override Expression CreateExpressionTree (ResolveContext ec)
2350 throw new NotImplementedException ();
2354 abstract class ComplexPatternExpression : PatternExpression
2356 protected Expression[] comparisons;
2358 protected ComplexPatternExpression (ATypeNameExpression typeExpresion, Location loc)
2361 TypeExpression = typeExpresion;
2364 public ATypeNameExpression TypeExpression { get; private set; }
2366 public override void Emit (EmitContext ec)
2368 EmitBranchable (ec, ec.RecursivePatternLabel, false);
2371 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2373 if (comparisons != null) {
2374 foreach (var comp in comparisons) {
2375 comp.EmitBranchable (ec, target, false);
2382 /// Implementation of the `as' operator.
2384 public class As : Probe {
2386 public As (Expression expr, Expression probe_type, Location l)
2387 : base (expr, probe_type, l)
2391 protected override string OperatorName {
2392 get { return "as"; }
2395 public override Expression CreateExpressionTree (ResolveContext ec)
2397 Arguments args = Arguments.CreateForExpressionTree (ec, null,
2398 expr.CreateExpressionTree (ec),
2399 new TypeOf (probe_type_expr, loc));
2401 return CreateExpressionFactoryCall (ec, "TypeAs", args);
2404 public override void Emit (EmitContext ec)
2408 ec.Emit (OpCodes.Isinst, type);
2410 if (TypeManager.IsGenericParameter (type) || type.IsNullableType)
2411 ec.Emit (OpCodes.Unbox_Any, type);
2414 protected override Expression DoResolve (ResolveContext ec)
2416 if (ResolveCommon (ec) == null)
2419 type = probe_type_expr;
2420 eclass = ExprClass.Value;
2421 TypeSpec etype = expr.Type;
2423 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (etype)) {
2424 ec.Report.Error (8307, expr.Location, "The first operand of an `as' operator may not be a tuple literal without a natural type");
2425 type = InternalType.ErrorType;
2430 type = InternalType.ErrorType;
2434 if (!TypeSpec.IsReferenceType (type) && !type.IsNullableType) {
2435 if (TypeManager.IsGenericParameter (type)) {
2436 ec.Report.Error (413, loc,
2437 "The `as' operator cannot be used with a non-reference type parameter `{0}'. Consider adding `class' or a reference type constraint",
2438 probe_type_expr.GetSignatureForError ());
2440 ec.Report.Error (77, loc,
2441 "The `as' operator cannot be used with a non-nullable value type `{0}'",
2442 type.GetSignatureForError ());
2447 if (expr.IsNull && type.IsNullableType) {
2448 return Nullable.LiftedNull.CreateFromExpression (ec, this);
2451 // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
2452 if (etype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
2456 Expression e = Convert.ImplicitConversionStandard (ec, expr, type, loc);
2458 e = EmptyCast.Create (e, type);
2459 return ReducedExpression.Create (e, this).Resolve (ec);
2462 if (Convert.ExplicitReferenceConversionExists (etype, type)){
2463 if (TypeManager.IsGenericParameter (etype))
2464 expr = new BoxedCast (expr, etype);
2469 if (InflatedTypeSpec.ContainsTypeParameter (etype) || InflatedTypeSpec.ContainsTypeParameter (type)) {
2470 expr = new BoxedCast (expr, etype);
2474 if (etype != InternalType.ErrorType) {
2475 ec.Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
2476 etype.GetSignatureForError (), type.GetSignatureForError ());
2482 public override object Accept (StructuralVisitor visitor)
2484 return visitor.Visit (this);
2489 // This represents a typecast in the source language.
2491 public class Cast : ShimExpression {
2492 Expression target_type;
2494 public Cast (Expression cast_type, Expression expr, Location loc)
2497 this.target_type = cast_type;
2501 public Expression TargetType {
2502 get { return target_type; }
2505 protected override Expression DoResolve (ResolveContext ec)
2507 expr = expr.Resolve (ec);
2511 type = target_type.ResolveAsType (ec);
2515 if (type.IsStatic) {
2516 ec.Report.Error (716, loc, "Cannot convert to static type `{0}'", type.GetSignatureForError ());
2520 if (type.IsPointer) {
2521 if (ec.CurrentIterator != null) {
2522 UnsafeInsideIteratorError (ec, loc);
2523 } else if (!ec.IsUnsafe) {
2524 UnsafeError (ec, loc);
2528 eclass = ExprClass.Value;
2530 Constant c = expr as Constant;
2532 c = c.Reduce (ec, type);
2537 var res = Convert.ExplicitConversion (ec, expr, type, loc);
2539 return EmptyCast.Create (res, type);
2544 protected override void CloneTo (CloneContext clonectx, Expression t)
2546 Cast target = (Cast) t;
2548 target.target_type = target_type.Clone (clonectx);
2549 target.expr = expr.Clone (clonectx);
2552 public override object Accept (StructuralVisitor visitor)
2554 return visitor.Visit (this);
2558 public class ImplicitCast : ShimExpression
2562 public ImplicitCast (Expression expr, TypeSpec target, bool arrayAccess)
2565 this.loc = expr.Location;
2567 this.arrayAccess = arrayAccess;
2570 protected override Expression DoResolve (ResolveContext ec)
2572 expr = expr.Resolve (ec);
2577 expr = ConvertExpressionToArrayIndex (ec, expr);
2579 expr = Convert.ImplicitConversionRequired (ec, expr, type, loc);
2585 public class DeclarationExpression : Expression, IMemoryLocation
2587 LocalVariableReference lvr;
2589 public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
2591 VariableType = variableType;
2592 Variable = variable;
2593 this.loc = variable.Location;
2596 public LocalVariable Variable { get; set; }
2597 public Expression Initializer { get; set; }
2598 public FullNamedExpression VariableType { get; set; }
2600 public void AddressOf (EmitContext ec, AddressOp mode)
2602 Variable.CreateBuilder (ec);
2604 if (Initializer != null) {
2605 lvr.EmitAssign (ec, Initializer, false, false);
2608 lvr.AddressOf (ec, mode);
2611 protected override void CloneTo (CloneContext clonectx, Expression t)
2613 var target = (DeclarationExpression) t;
2615 target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
2617 if (Initializer != null)
2618 target.Initializer = Initializer.Clone (clonectx);
2621 public override Expression CreateExpressionTree (ResolveContext rc)
2623 rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration");
2627 bool DoResolveCommon (ResolveContext rc)
2629 CheckExpressionVariable (rc);
2631 var var_expr = VariableType as VarExpr;
2632 if (var_expr != null) {
2633 type = InternalType.VarOutType;
2635 type = VariableType.ResolveAsType (rc);
2640 if (Initializer != null) {
2641 Initializer = Initializer.Resolve (rc);
2643 if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
2644 type = var_expr.Type;
2648 Variable.Type = type;
2649 lvr = new LocalVariableReference (Variable, loc);
2651 eclass = ExprClass.Variable;
2655 protected override Expression DoResolve (ResolveContext rc)
2657 if (DoResolveCommon (rc))
2663 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
2665 if (lvr == null && DoResolveCommon (rc))
2666 lvr.ResolveLValue (rc, right_side);
2671 public override void Emit (EmitContext ec)
2673 throw new NotImplementedException ();
2678 // C# 2.0 Default value expression
2680 public class DefaultValueExpression : Expression
2684 public DefaultValueExpression (Expression expr, Location loc)
2690 public Expression Expr {
2696 public override bool IsSideEffectFree {
2702 public override bool ContainsEmitWithAwait ()
2707 public override Expression CreateExpressionTree (ResolveContext ec)
2709 Arguments args = new Arguments (2);
2710 args.Add (new Argument (this));
2711 args.Add (new Argument (new TypeOf (type, loc)));
2712 return CreateExpressionFactoryCall (ec, "Constant", args);
2715 protected override Expression DoResolve (ResolveContext ec)
2717 type = expr.ResolveAsType (ec);
2721 if (type.IsStatic) {
2722 ec.Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
2726 return new NullLiteral (Location).ConvertImplicitly (type);
2728 if (TypeSpec.IsReferenceType (type))
2729 return new NullConstant (type, loc);
2731 Constant c = New.Constantify (type, expr.Location);
2735 eclass = ExprClass.Variable;
2739 public override void Emit (EmitContext ec)
2741 LocalTemporary temp_storage = new LocalTemporary(type);
2743 temp_storage.AddressOf(ec, AddressOp.LoadStore);
2744 ec.Emit(OpCodes.Initobj, type);
2745 temp_storage.Emit(ec);
2746 temp_storage.Release (ec);
2750 public override SLE.Expression MakeExpression (BuilderContext ctx)
2752 return SLE.Expression.Default (type.GetMetaInfo ());
2756 protected override void CloneTo (CloneContext clonectx, Expression t)
2758 DefaultValueExpression target = (DefaultValueExpression) t;
2760 target.expr = expr.Clone (clonectx);
2763 public override object Accept (StructuralVisitor visitor)
2765 return visitor.Visit (this);
2770 /// Binary operators
2772 public class Binary : Expression, IDynamicBinder
2774 public class PredefinedOperator
2776 protected readonly TypeSpec left;
2777 protected readonly TypeSpec right;
2778 protected readonly TypeSpec left_unwrap;
2779 protected readonly TypeSpec right_unwrap;
2780 public readonly Operator OperatorsMask;
2781 public TypeSpec ReturnType;
2783 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
2784 : this (ltype, rtype, op_mask, ltype)
2788 public PredefinedOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
2789 : this (type, type, op_mask, return_type)
2793 public PredefinedOperator (TypeSpec type, Operator op_mask)
2794 : this (type, type, op_mask, type)
2798 public PredefinedOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec return_type)
2800 if ((op_mask & Operator.ValuesOnlyMask) != 0)
2801 throw new InternalErrorException ("Only masked values can be used");
2803 if ((op_mask & Operator.NullableMask) != 0) {
2804 left_unwrap = Nullable.NullableInfo.GetUnderlyingType (ltype);
2805 right_unwrap = Nullable.NullableInfo.GetUnderlyingType (rtype);
2807 left_unwrap = ltype;
2808 right_unwrap = rtype;
2813 this.OperatorsMask = op_mask;
2814 this.ReturnType = return_type;
2817 public bool IsLifted {
2819 return (OperatorsMask & Operator.NullableMask) != 0;
2823 public virtual Expression ConvertResult (ResolveContext rc, Binary b)
2827 var left_expr = b.left;
2828 var right_expr = b.right;
2830 b.type = ReturnType;
2833 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
2834 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2835 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2838 if (right_expr.IsNull) {
2839 if ((b.oper & Operator.EqualityMask) != 0) {
2840 if (!left_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (left_expr.Type))
2841 return b.CreateLiftedValueTypeResult (rc, left_expr.Type);
2842 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2843 if (left_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2844 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2846 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2847 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2849 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2850 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2852 return b.CreateLiftedValueTypeResult (rc, left);
2854 } else if (left_expr.IsNull) {
2855 if ((b.oper & Operator.EqualityMask) != 0) {
2856 if (!right_expr.Type.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (right_expr.Type))
2857 return b.CreateLiftedValueTypeResult (rc, right_expr.Type);
2858 } else if ((b.oper & Operator.BitwiseMask) != 0) {
2859 if (right_unwrap.BuiltinType != BuiltinTypeSpec.Type.Bool)
2860 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2862 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2863 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2865 if ((b.Oper & (Operator.ArithmeticMask | Operator.ShiftMask)) != 0)
2866 return Nullable.LiftedNull.CreateFromExpression (rc, b);
2868 return b.CreateLiftedValueTypeResult (rc, right);
2874 // A user operators does not support multiple user conversions, but decimal type
2875 // is considered to be predefined type therefore we apply predefined operators rules
2876 // and then look for decimal user-operator implementation
2878 if (left.BuiltinType == BuiltinTypeSpec.Type.Decimal) {
2879 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2880 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2882 return b.ResolveUserOperator (rc, b.left, b.right);
2885 c = right_expr as Constant;
2887 if (c.IsDefaultValue) {
2891 // (expr + 0) to expr
2892 // (expr - 0) to expr
2893 // (bool? | false) to bool?
2895 if (b.oper == Operator.Addition || b.oper == Operator.Subtraction ||
2896 (b.oper == Operator.BitwiseOr && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2897 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
2898 return ReducedExpression.Create (b.left, b).Resolve (rc);
2902 // Optimizes (value &/&& 0) to 0
2904 if ((b.oper == Operator.BitwiseAnd || b.oper == Operator.LogicalAnd) && !IsLifted) {
2905 Constant side_effect = new SideEffectConstant (c, b.left, c.Location);
2906 return ReducedExpression.Create (side_effect, b);
2910 // Optimizes (bool? & true) to bool?
2912 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2913 return ReducedExpression.Create (b.left, b).Resolve (rc);
2917 if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
2918 return ReducedExpression.Create (b.left, b).Resolve (rc);
2920 if ((b.oper & Operator.ShiftMask) != 0 && c is IntConstant) {
2921 b.right = new IntConstant (rc.BuiltinTypes, ((IntConstant) c).Value & GetShiftMask (left_unwrap), b.right.Location);
2925 c = b.left as Constant;
2927 if (c.IsDefaultValue) {
2931 // (0 + expr) to expr
2932 // (false | bool?) to bool?
2934 if (b.oper == Operator.Addition ||
2935 (b.oper == Operator.BitwiseOr && right_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && c is BoolConstant)) {
2936 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
2937 return ReducedExpression.Create (b.right, b).Resolve (rc);
2941 // Optimizes (false && expr) to false
2943 if (b.oper == Operator.LogicalAnd && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2944 // No rhs side-effects
2945 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2946 return ReducedExpression.Create (c, b);
2950 // Optimizes (0 & value) to 0
2952 if (b.oper == Operator.BitwiseAnd && !IsLifted) {
2953 Constant side_effect = new SideEffectConstant (c, b.right, c.Location);
2954 return ReducedExpression.Create (side_effect, b);
2958 // Optimizes (true & bool?) to bool?
2960 if (IsLifted && left_unwrap.BuiltinType == BuiltinTypeSpec.Type.Bool && b.oper == Operator.BitwiseAnd) {
2961 return ReducedExpression.Create (b.right, b).Resolve (rc);
2965 // Optimizes (true || expr) to true
2967 if (b.oper == Operator.LogicalOr && c.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
2968 // No rhs side-effects
2969 Expression.Warning_UnreachableExpression (rc, b.right.StartLocation);
2970 return ReducedExpression.Create (c, b);
2974 if (b.oper == Operator.Multiply && c.IsOneInteger)
2975 return ReducedExpression.Create (b.right, b).Resolve (rc);
2979 var lifted = new Nullable.LiftedBinaryOperator (b);
2981 TypeSpec ltype, rtype;
2982 if (b.left.Type.IsNullableType) {
2983 lifted.UnwrapLeft = new Nullable.Unwrap (b.left);
2984 ltype = left_unwrap;
2989 if (b.right.Type.IsNullableType) {
2990 lifted.UnwrapRight = new Nullable.Unwrap (b.right);
2991 rtype = right_unwrap;
2996 lifted.Left = b.left.IsNull ?
2997 Nullable.LiftedNull.Create (ltype, b.left.Location) :
2998 Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? b.left, ltype, b.left.Location);
3000 lifted.Right = b.right.IsNull ?
3001 Nullable.LiftedNull.Create (rtype, b.right.Location) :
3002 Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? b.right, rtype, b.right.Location);
3004 return lifted.Resolve (rc);
3007 b.left = Convert.ImplicitConversion (rc, b.left, left, b.left.Location);
3008 b.right = Convert.ImplicitConversion (rc, b.right, right, b.right.Location);
3013 public bool IsPrimitiveApplicable (TypeSpec ltype, TypeSpec rtype)
3016 // We are dealing with primitive types only
3018 return left == ltype && ltype == rtype;
3021 public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3024 if (left == lexpr.Type && right == rexpr.Type)
3027 return Convert.ImplicitConversionExists (ec, lexpr, left) &&
3028 Convert.ImplicitConversionExists (ec, rexpr, right);
3031 public PredefinedOperator ResolveBetterOperator (ResolveContext ec, PredefinedOperator best_operator)
3033 if ((OperatorsMask & Operator.DecomposedMask) != 0)
3034 return best_operator;
3036 if ((best_operator.OperatorsMask & Operator.DecomposedMask) != 0)
3040 if (left != null && best_operator.left != null) {
3041 result = OverloadResolver.BetterTypeConversion (ec, best_operator.left_unwrap, left_unwrap);
3045 // When second argument is same as the first one, the result is same
3047 if (right != null && (left != right || best_operator.left != best_operator.right)) {
3048 result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right_unwrap, right_unwrap);
3051 if (result == 0 || result > 2)
3054 return result == 1 ? best_operator : this;
3058 sealed class PredefinedStringOperator : PredefinedOperator
3060 public PredefinedStringOperator (TypeSpec type, Operator op_mask, TypeSpec retType)
3061 : base (type, type, op_mask, retType)
3065 public PredefinedStringOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3066 : base (ltype, rtype, op_mask, retType)
3070 public override Expression ConvertResult (ResolveContext ec, Binary b)
3073 // Use original expression for nullable arguments
3075 Nullable.Unwrap unwrap = b.left as Nullable.Unwrap;
3077 b.left = unwrap.Original;
3079 unwrap = b.right as Nullable.Unwrap;
3081 b.right = unwrap.Original;
3083 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3084 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3087 // Start a new concat expression using converted expression
3089 return StringConcat.Create (ec, b.left, b.right, b.loc);
3093 sealed class PredefinedEqualityOperator : PredefinedOperator
3095 MethodSpec equal_method, inequal_method;
3097 public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
3098 : base (arg, arg, Operator.EqualityMask, retType)
3102 public override Expression ConvertResult (ResolveContext ec, Binary b)
3104 b.type = ReturnType;
3106 b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
3107 b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
3109 Arguments args = new Arguments (2);
3110 args.Add (new Argument (b.left));
3111 args.Add (new Argument (b.right));
3114 if (b.oper == Operator.Equality) {
3115 if (equal_method == null) {
3116 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3117 equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (b.loc);
3118 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3119 equal_method = ec.Module.PredefinedMembers.DelegateEqual.Resolve (b.loc);
3121 throw new NotImplementedException (left.GetSignatureForError ());
3124 method = equal_method;
3126 if (inequal_method == null) {
3127 if (left.BuiltinType == BuiltinTypeSpec.Type.String)
3128 inequal_method = ec.Module.PredefinedMembers.StringInequal.Resolve (b.loc);
3129 else if (left.BuiltinType == BuiltinTypeSpec.Type.Delegate)
3130 inequal_method = ec.Module.PredefinedMembers.DelegateInequal.Resolve (b.loc);
3132 throw new NotImplementedException (left.GetSignatureForError ());
3135 method = inequal_method;
3138 return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
3142 class PredefinedPointerOperator : PredefinedOperator
3144 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
3145 : base (ltype, rtype, op_mask)
3149 public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask, TypeSpec retType)
3150 : base (ltype, rtype, op_mask, retType)
3154 public PredefinedPointerOperator (TypeSpec type, Operator op_mask, TypeSpec return_type)
3155 : base (type, op_mask, return_type)
3159 public override bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
3162 if (!lexpr.Type.IsPointer)
3165 if (!Convert.ImplicitConversionExists (ec, lexpr, left))
3169 if (right == null) {
3170 if (!rexpr.Type.IsPointer)
3173 if (!Convert.ImplicitConversionExists (ec, rexpr, right))
3180 public override Expression ConvertResult (ResolveContext ec, Binary b)
3183 b.left = Convert.UserDefinedConversion (ec, b.left, left, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.left, left);
3184 } else if (right != null) {
3185 b.right = Convert.UserDefinedConversion (ec, b.right, right, Convert.UserConversionRestriction.ImplicitOnly, b.loc) ?? EmptyCast.Create (b.right, right);
3188 TypeSpec r_type = ReturnType;
3189 Expression left_arg, right_arg;
3190 if (r_type == null) {
3193 right_arg = b.right;
3194 r_type = b.left.Type;
3198 r_type = b.right.Type;
3202 right_arg = b.right;
3205 return new PointerArithmetic (b.oper, left_arg, right_arg, r_type, b.loc).Resolve (ec);
3210 public enum Operator {
3211 Multiply = 0 | ArithmeticMask,
3212 Division = 1 | ArithmeticMask,
3213 Modulus = 2 | ArithmeticMask,
3214 Addition = 3 | ArithmeticMask | AdditionMask,
3215 Subtraction = 4 | ArithmeticMask | SubtractionMask,
3217 LeftShift = 5 | ShiftMask,
3218 RightShift = 6 | ShiftMask,
3220 LessThan = 7 | ComparisonMask | RelationalMask,
3221 GreaterThan = 8 | ComparisonMask | RelationalMask,
3222 LessThanOrEqual = 9 | ComparisonMask | RelationalMask,
3223 GreaterThanOrEqual = 10 | ComparisonMask | RelationalMask,
3224 Equality = 11 | ComparisonMask | EqualityMask,
3225 Inequality = 12 | ComparisonMask | EqualityMask,
3227 BitwiseAnd = 13 | BitwiseMask,
3228 ExclusiveOr = 14 | BitwiseMask,
3229 BitwiseOr = 15 | BitwiseMask,
3231 LogicalAnd = 16 | LogicalMask,
3232 LogicalOr = 17 | LogicalMask,
3237 ValuesOnlyMask = ArithmeticMask - 1,
3238 ArithmeticMask = 1 << 5,
3240 ComparisonMask = 1 << 7,
3241 EqualityMask = 1 << 8,
3242 BitwiseMask = 1 << 9,
3243 LogicalMask = 1 << 10,
3244 AdditionMask = 1 << 11,
3245 SubtractionMask = 1 << 12,
3246 RelationalMask = 1 << 13,
3248 DecomposedMask = 1 << 19,
3249 NullableMask = 1 << 20
3253 public enum State : byte
3257 UserOperatorsExcluded = 1 << 2
3260 readonly Operator oper;
3261 Expression left, right;
3263 ConvCast.Mode enum_conversion;
3265 public Binary (Operator oper, Expression left, Expression right, bool isCompound)
3266 : this (oper, left, right, State.Compound)
3270 public Binary (Operator oper, Expression left, Expression right, State state)
3271 : this (oper, left, right)
3276 public Binary (Operator oper, Expression left, Expression right)
3277 : this (oper, left, right, left.Location)
3281 public Binary (Operator oper, Expression left, Expression right, Location loc)
3291 public bool IsCompound {
3293 return (state & State.Compound) != 0;
3297 public Operator Oper {
3303 public Expression Left {
3309 public Expression Right {
3315 public override Location StartLocation {
3317 return left.StartLocation;
3324 /// Returns a stringified representation of the Operator
3326 string OperName (Operator oper)
3330 case Operator.Multiply:
3333 case Operator.Division:
3336 case Operator.Modulus:
3339 case Operator.Addition:
3342 case Operator.Subtraction:
3345 case Operator.LeftShift:
3348 case Operator.RightShift:
3351 case Operator.LessThan:
3354 case Operator.GreaterThan:
3357 case Operator.LessThanOrEqual:
3360 case Operator.GreaterThanOrEqual:
3363 case Operator.Equality:
3366 case Operator.Inequality:
3369 case Operator.BitwiseAnd:
3372 case Operator.BitwiseOr:
3375 case Operator.ExclusiveOr:
3378 case Operator.LogicalOr:
3381 case Operator.LogicalAnd:
3385 s = oper.ToString ();
3395 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, Operator oper, Location loc)
3397 new Binary (oper, left, right).Error_OperatorCannotBeApplied (ec, left, right);
3400 public static void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right, string oper, Location loc)
3402 if (left.Type == InternalType.ErrorType || right.Type == InternalType.ErrorType)
3406 l = left.Type.GetSignatureForError ();
3407 r = right.Type.GetSignatureForError ();
3409 ec.Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
3413 void Error_OperatorCannotBeApplied (ResolveContext ec, Expression left, Expression right)
3415 Error_OperatorCannotBeApplied (ec, left, right, OperName (oper), loc);
3418 public override void FlowAnalysis (FlowAnalysisContext fc)
3421 // Optimized version when on-true/on-false data are not needed
3423 if ((oper & Operator.LogicalMask) == 0) {
3424 left.FlowAnalysis (fc);
3425 right.FlowAnalysis (fc);
3429 left.FlowAnalysisConditional (fc);
3430 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3431 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3433 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3434 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3435 right.FlowAnalysisConditional (fc);
3437 if (oper == Operator.LogicalOr)
3438 fc.DefiniteAssignment = (left_fc_onfalse | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_ontrue;
3440 fc.DefiniteAssignment = (left_fc_ontrue | (fc.DefiniteAssignmentOnFalse & fc.DefiniteAssignmentOnTrue)) & left_fc_onfalse;
3443 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
3445 if ((oper & Operator.LogicalMask) == 0) {
3446 base.FlowAnalysisConditional (fc);
3450 left.FlowAnalysisConditional (fc);
3451 var left_fc_ontrue = fc.DefiniteAssignmentOnTrue;
3452 var left_fc_onfalse = fc.DefiniteAssignmentOnFalse;
3454 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (
3455 oper == Operator.LogicalOr ? left_fc_onfalse : left_fc_ontrue);
3456 right.FlowAnalysisConditional (fc);
3458 var lc = left as Constant;
3459 if (oper == Operator.LogicalOr) {
3460 fc.DefiniteAssignmentOnFalse = left_fc_onfalse | fc.DefiniteAssignmentOnFalse;
3461 if (lc != null && lc.IsDefaultValue)
3462 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
3464 fc.DefiniteAssignmentOnTrue = new DefiniteAssignmentBitSet (left_fc_ontrue & (left_fc_onfalse | fc.DefiniteAssignmentOnTrue));
3466 fc.DefiniteAssignmentOnTrue = left_fc_ontrue | fc.DefiniteAssignmentOnTrue;
3467 if (lc != null && !lc.IsDefaultValue)
3468 fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignmentOnTrue;
3470 fc.DefiniteAssignmentOnFalse = new DefiniteAssignmentBitSet ((left_fc_ontrue | fc.DefiniteAssignmentOnFalse) & left_fc_onfalse);
3475 // Converts operator to System.Linq.Expressions.ExpressionType enum name
3477 string GetOperatorExpressionTypeName ()
3480 case Operator.Addition:
3481 return IsCompound ? "AddAssign" : "Add";
3482 case Operator.BitwiseAnd:
3483 return IsCompound ? "AndAssign" : "And";
3484 case Operator.BitwiseOr:
3485 return IsCompound ? "OrAssign" : "Or";
3486 case Operator.Division:
3487 return IsCompound ? "DivideAssign" : "Divide";
3488 case Operator.ExclusiveOr:
3489 return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
3490 case Operator.Equality:
3492 case Operator.GreaterThan:
3493 return "GreaterThan";
3494 case Operator.GreaterThanOrEqual:
3495 return "GreaterThanOrEqual";
3496 case Operator.Inequality:
3498 case Operator.LeftShift:
3499 return IsCompound ? "LeftShiftAssign" : "LeftShift";
3500 case Operator.LessThan:
3502 case Operator.LessThanOrEqual:
3503 return "LessThanOrEqual";
3504 case Operator.LogicalAnd:
3506 case Operator.LogicalOr:
3508 case Operator.Modulus:
3509 return IsCompound ? "ModuloAssign" : "Modulo";
3510 case Operator.Multiply:
3511 return IsCompound ? "MultiplyAssign" : "Multiply";
3512 case Operator.RightShift:
3513 return IsCompound ? "RightShiftAssign" : "RightShift";
3514 case Operator.Subtraction:
3515 return IsCompound ? "SubtractAssign" : "Subtract";
3517 throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
3521 public static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
3524 case Operator.Addition:
3525 return CSharp.Operator.OpType.Addition;
3526 case Operator.BitwiseAnd:
3527 case Operator.LogicalAnd:
3528 return CSharp.Operator.OpType.BitwiseAnd;
3529 case Operator.BitwiseOr:
3530 case Operator.LogicalOr:
3531 return CSharp.Operator.OpType.BitwiseOr;
3532 case Operator.Division:
3533 return CSharp.Operator.OpType.Division;
3534 case Operator.Equality:
3535 return CSharp.Operator.OpType.Equality;
3536 case Operator.ExclusiveOr:
3537 return CSharp.Operator.OpType.ExclusiveOr;
3538 case Operator.GreaterThan:
3539 return CSharp.Operator.OpType.GreaterThan;
3540 case Operator.GreaterThanOrEqual:
3541 return CSharp.Operator.OpType.GreaterThanOrEqual;
3542 case Operator.Inequality:
3543 return CSharp.Operator.OpType.Inequality;
3544 case Operator.LeftShift:
3545 return CSharp.Operator.OpType.LeftShift;
3546 case Operator.LessThan:
3547 return CSharp.Operator.OpType.LessThan;
3548 case Operator.LessThanOrEqual:
3549 return CSharp.Operator.OpType.LessThanOrEqual;
3550 case Operator.Modulus:
3551 return CSharp.Operator.OpType.Modulus;
3552 case Operator.Multiply:
3553 return CSharp.Operator.OpType.Multiply;
3554 case Operator.RightShift:
3555 return CSharp.Operator.OpType.RightShift;
3556 case Operator.Subtraction:
3557 return CSharp.Operator.OpType.Subtraction;
3559 throw new InternalErrorException (op.ToString ());
3563 public override bool ContainsEmitWithAwait ()
3565 return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
3568 public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l, Expression right)
3573 case Operator.Multiply:
3574 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3575 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3576 opcode = OpCodes.Mul_Ovf;
3577 else if (!IsFloat (l))
3578 opcode = OpCodes.Mul_Ovf_Un;
3580 opcode = OpCodes.Mul;
3582 opcode = OpCodes.Mul;
3586 case Operator.Division:
3588 opcode = OpCodes.Div_Un;
3590 opcode = OpCodes.Div;
3593 case Operator.Modulus:
3595 opcode = OpCodes.Rem_Un;
3597 opcode = OpCodes.Rem;
3600 case Operator.Addition:
3601 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3602 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3603 opcode = OpCodes.Add_Ovf;
3604 else if (!IsFloat (l))
3605 opcode = OpCodes.Add_Ovf_Un;
3607 opcode = OpCodes.Add;
3609 opcode = OpCodes.Add;
3612 case Operator.Subtraction:
3613 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
3614 if (l.BuiltinType == BuiltinTypeSpec.Type.Int || l.BuiltinType == BuiltinTypeSpec.Type.Long)
3615 opcode = OpCodes.Sub_Ovf;
3616 else if (!IsFloat (l))
3617 opcode = OpCodes.Sub_Ovf_Un;
3619 opcode = OpCodes.Sub;
3621 opcode = OpCodes.Sub;
3624 case Operator.RightShift:
3625 if (!(right is IntConstant)) {
3626 ec.EmitInt (GetShiftMask (l));
3627 ec.Emit (OpCodes.And);
3631 opcode = OpCodes.Shr_Un;
3633 opcode = OpCodes.Shr;
3636 case Operator.LeftShift:
3637 if (!(right is IntConstant)) {
3638 ec.EmitInt (GetShiftMask (l));
3639 ec.Emit (OpCodes.And);
3642 opcode = OpCodes.Shl;
3645 case Operator.Equality:
3646 opcode = OpCodes.Ceq;
3649 case Operator.Inequality:
3650 ec.Emit (OpCodes.Ceq);
3653 opcode = OpCodes.Ceq;
3656 case Operator.LessThan:
3658 opcode = OpCodes.Clt_Un;
3660 opcode = OpCodes.Clt;
3663 case Operator.GreaterThan:
3665 opcode = OpCodes.Cgt_Un;
3667 opcode = OpCodes.Cgt;
3670 case Operator.LessThanOrEqual:
3671 if (IsUnsigned (l) || IsFloat (l))
3672 ec.Emit (OpCodes.Cgt_Un);
3674 ec.Emit (OpCodes.Cgt);
3677 opcode = OpCodes.Ceq;
3680 case Operator.GreaterThanOrEqual:
3681 if (IsUnsigned (l) || IsFloat (l))
3682 ec.Emit (OpCodes.Clt_Un);
3684 ec.Emit (OpCodes.Clt);
3688 opcode = OpCodes.Ceq;
3691 case Operator.BitwiseOr:
3692 opcode = OpCodes.Or;
3695 case Operator.BitwiseAnd:
3696 opcode = OpCodes.And;
3699 case Operator.ExclusiveOr:
3700 opcode = OpCodes.Xor;
3704 throw new InternalErrorException (oper.ToString ());
3710 static int GetShiftMask (TypeSpec type)
3712 return type.BuiltinType == BuiltinTypeSpec.Type.Int || type.BuiltinType == BuiltinTypeSpec.Type.UInt ? 0x1f : 0x3f;
3715 static bool IsUnsigned (TypeSpec t)
3717 switch (t.BuiltinType) {
3718 case BuiltinTypeSpec.Type.Char:
3719 case BuiltinTypeSpec.Type.UInt:
3720 case BuiltinTypeSpec.Type.ULong:
3721 case BuiltinTypeSpec.Type.UShort:
3722 case BuiltinTypeSpec.Type.Byte:
3729 static bool IsFloat (TypeSpec t)
3731 return t.BuiltinType == BuiltinTypeSpec.Type.Float || t.BuiltinType == BuiltinTypeSpec.Type.Double;
3734 public Expression ResolveOperator (ResolveContext rc)
3736 eclass = ExprClass.Value;
3738 TypeSpec l = left.Type;
3739 TypeSpec r = right.Type;
3741 bool primitives_only = false;
3744 // Handles predefined primitive types
3746 if ((BuiltinTypeSpec.IsPrimitiveType (l) || (l.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (l)))) &&
3747 (BuiltinTypeSpec.IsPrimitiveType (r) || (r.IsNullableType && BuiltinTypeSpec.IsPrimitiveType (Nullable.NullableInfo.GetUnderlyingType (r))))) {
3748 if ((oper & Operator.ShiftMask) == 0) {
3749 if (!DoBinaryOperatorPromotion (rc))
3752 primitives_only = BuiltinTypeSpec.IsPrimitiveType (l) && BuiltinTypeSpec.IsPrimitiveType (r);
3756 if (l.IsPointer || r.IsPointer)
3757 return ResolveOperatorPointer (rc, l, r);
3760 if ((state & State.UserOperatorsExcluded) == 0) {
3761 expr = ResolveUserOperator (rc, left, right);
3766 bool lenum = l.IsEnum;
3767 bool renum = r.IsEnum;
3768 if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
3772 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3773 expr = ResolveSingleEnumOperators (rc, lenum, renum, l, r);
3778 if ((oper & Operator.BitwiseMask) != 0) {
3779 expr = EmptyCast.Create (expr, type);
3780 enum_conversion = GetEnumResultCast (type);
3782 if (oper == Operator.BitwiseAnd && left.Type.IsEnum && right.Type.IsEnum) {
3783 expr = OptimizeAndOperation (expr);
3787 left = ConvertEnumOperandToUnderlyingType (rc, left, r.IsNullableType);
3788 right = ConvertEnumOperandToUnderlyingType (rc, right, l.IsNullableType);
3791 } else if ((oper == Operator.Addition || oper == Operator.Subtraction)) {
3792 if (IsEnumOrNullableEnum (l) || IsEnumOrNullableEnum (r)) {
3796 expr = ResolveEnumOperators (rc, lenum, renum, l, r);
3799 // We cannot break here there is also Enum + String possible match
3800 // which is not ambiguous with predefined enum operators
3803 left = ConvertEnumOperandToUnderlyingType (rc, left, false);
3804 right = ConvertEnumOperandToUnderlyingType (rc, right, false);
3808 } else if (l.IsDelegate || r.IsDelegate) {
3812 expr = ResolveOperatorDelegate (rc, l, r);
3814 // TODO: Can this be ambiguous
3822 // Equality operators are more complicated
3824 if ((oper & Operator.EqualityMask) != 0) {
3825 return ResolveEquality (rc, l, r, primitives_only);
3828 expr = ResolveOperatorPredefined (rc, rc.BuiltinTypes.OperatorsBinaryStandard, primitives_only);
3832 if (primitives_only)
3836 // Lifted operators have lower priority
3838 return ResolveOperatorPredefined (rc, rc.Module.OperatorsBinaryLifted, false);
3841 static bool IsEnumOrNullableEnum (TypeSpec type)
3843 return type.IsEnum || (type.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (type).IsEnum);
3847 // at least one of 'left' or 'right' is an enumeration constant (EnumConstant or SideEffectConstant or ...)
3848 // if 'left' is not an enumeration constant, create one from the type of 'right'
3849 Constant EnumLiftUp (ResolveContext ec, Constant left, Constant right)
3852 case Operator.BitwiseOr:
3853 case Operator.BitwiseAnd:
3854 case Operator.ExclusiveOr:
3855 case Operator.Equality:
3856 case Operator.Inequality:
3857 case Operator.LessThan:
3858 case Operator.LessThanOrEqual:
3859 case Operator.GreaterThan:
3860 case Operator.GreaterThanOrEqual:
3861 if (left.Type.IsEnum)
3864 if (left.IsZeroInteger)
3865 return left.Reduce (ec, right.Type);
3869 case Operator.Addition:
3870 case Operator.Subtraction:
3873 case Operator.Multiply:
3874 case Operator.Division:
3875 case Operator.Modulus:
3876 case Operator.LeftShift:
3877 case Operator.RightShift:
3878 if (right.Type.IsEnum || left.Type.IsEnum)
3887 // The `|' operator used on types which were extended is dangerous
3889 void CheckBitwiseOrOnSignExtended (ResolveContext ec)
3891 OpcodeCast lcast = left as OpcodeCast;
3892 if (lcast != null) {
3893 if (IsUnsigned (lcast.UnderlyingType))
3897 OpcodeCast rcast = right as OpcodeCast;
3898 if (rcast != null) {
3899 if (IsUnsigned (rcast.UnderlyingType))
3903 if (lcast == null && rcast == null)
3906 // FIXME: consider constants
3908 var ltype = lcast != null ? lcast.UnderlyingType : rcast.UnderlyingType;
3909 ec.Report.Warning (675, 3, loc,
3910 "The operator `|' used on the sign-extended type `{0}'. Consider casting to a smaller unsigned type first",
3911 ltype.GetSignatureForError ());
3914 public static PredefinedOperator[] CreatePointerOperatorsTable (BuiltinTypes types)
3916 return new PredefinedOperator[] {
3918 // Pointer arithmetic:
3920 // T* operator + (T* x, int y); T* operator - (T* x, int y);
3921 // T* operator + (T* x, uint y); T* operator - (T* x, uint y);
3922 // T* operator + (T* x, long y); T* operator - (T* x, long y);
3923 // T* operator + (T* x, ulong y); T* operator - (T* x, ulong y);
3925 new PredefinedPointerOperator (null, types.Int, Operator.AdditionMask | Operator.SubtractionMask),
3926 new PredefinedPointerOperator (null, types.UInt, Operator.AdditionMask | Operator.SubtractionMask),
3927 new PredefinedPointerOperator (null, types.Long, Operator.AdditionMask | Operator.SubtractionMask),
3928 new PredefinedPointerOperator (null, types.ULong, Operator.AdditionMask | Operator.SubtractionMask),
3931 // T* operator + (int y, T* x);
3932 // T* operator + (uint y, T *x);
3933 // T* operator + (long y, T *x);
3934 // T* operator + (ulong y, T *x);
3936 new PredefinedPointerOperator (types.Int, null, Operator.AdditionMask, null),
3937 new PredefinedPointerOperator (types.UInt, null, Operator.AdditionMask, null),
3938 new PredefinedPointerOperator (types.Long, null, Operator.AdditionMask, null),
3939 new PredefinedPointerOperator (types.ULong, null, Operator.AdditionMask, null),
3942 // long operator - (T* x, T *y)
3944 new PredefinedPointerOperator (null, Operator.SubtractionMask, types.Long)
3948 public static PredefinedOperator[] CreateStandardOperatorsTable (BuiltinTypes types)
3950 TypeSpec bool_type = types.Bool;
3953 new PredefinedOperator (types.Int, Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
3954 new PredefinedOperator (types.UInt, Operator.ArithmeticMask | Operator.BitwiseMask),
3955 new PredefinedOperator (types.Long, Operator.ArithmeticMask | Operator.BitwiseMask),
3956 new PredefinedOperator (types.ULong, Operator.ArithmeticMask | Operator.BitwiseMask),
3957 new PredefinedOperator (types.Float, Operator.ArithmeticMask),
3958 new PredefinedOperator (types.Double, Operator.ArithmeticMask),
3959 new PredefinedOperator (types.Decimal, Operator.ArithmeticMask),
3961 new PredefinedOperator (types.Int, Operator.ComparisonMask, bool_type),
3962 new PredefinedOperator (types.UInt, Operator.ComparisonMask, bool_type),
3963 new PredefinedOperator (types.Long, Operator.ComparisonMask, bool_type),
3964 new PredefinedOperator (types.ULong, Operator.ComparisonMask, bool_type),
3965 new PredefinedOperator (types.Float, Operator.ComparisonMask, bool_type),
3966 new PredefinedOperator (types.Double, Operator.ComparisonMask, bool_type),
3967 new PredefinedOperator (types.Decimal, Operator.ComparisonMask, bool_type),
3969 new PredefinedStringOperator (types.String, Operator.AdditionMask, types.String),
3970 // Remaining string operators are in lifted tables
3972 new PredefinedOperator (bool_type, Operator.BitwiseMask | Operator.LogicalMask | Operator.EqualityMask, bool_type),
3974 new PredefinedOperator (types.UInt, types.Int, Operator.ShiftMask),
3975 new PredefinedOperator (types.Long, types.Int, Operator.ShiftMask),
3976 new PredefinedOperator (types.ULong, types.Int, Operator.ShiftMask)
3980 public static PredefinedOperator[] CreateStandardLiftedOperatorsTable (ModuleContainer module)
3982 var types = module.Compiler.BuiltinTypes;
3985 // Not strictly lifted but need to be in second group otherwise expressions like
3986 // int + null would resolve to +(object, string) instead of +(int?, int?)
3988 var string_operators = new [] {
3989 new PredefinedStringOperator (types.String, types.Object, Operator.AdditionMask, types.String),
3990 new PredefinedStringOperator (types.Object, types.String, Operator.AdditionMask, types.String),
3993 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
3994 if (nullable == null)
3995 return string_operators;
3997 var bool_type = types.Bool;
3999 var nullable_bool = nullable.MakeGenericType (module, new[] { bool_type });
4000 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4001 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4002 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4003 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4004 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4005 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4006 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4009 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask | Operator.ShiftMask),
4010 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4011 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4012 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ArithmeticMask | Operator.BitwiseMask),
4013 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ArithmeticMask),
4014 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ArithmeticMask),
4015 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ArithmeticMask),
4017 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4018 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4019 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4020 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4021 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4022 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4023 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.ComparisonMask, bool_type),
4025 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.BitwiseMask, nullable_bool),
4027 new PredefinedOperator (nullable_uint, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4028 new PredefinedOperator (nullable_long, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4029 new PredefinedOperator (nullable_ulong, nullable_int, Operator.NullableMask | Operator.ShiftMask),
4031 string_operators [0],
4032 string_operators [1]
4036 public static PredefinedOperator[] CreateEqualityOperatorsTable (BuiltinTypes types)
4038 TypeSpec bool_type = types.Bool;
4041 new PredefinedEqualityOperator (types.String, bool_type),
4042 new PredefinedEqualityOperator (types.Delegate, bool_type),
4043 new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type),
4044 new PredefinedOperator (types.Int, Operator.EqualityMask, bool_type),
4045 new PredefinedOperator (types.UInt, Operator.EqualityMask, bool_type),
4046 new PredefinedOperator (types.Long, Operator.EqualityMask, bool_type),
4047 new PredefinedOperator (types.ULong, Operator.EqualityMask, bool_type),
4048 new PredefinedOperator (types.Float, Operator.EqualityMask, bool_type),
4049 new PredefinedOperator (types.Double, Operator.EqualityMask, bool_type),
4050 new PredefinedOperator (types.Decimal, Operator.EqualityMask, bool_type),
4054 public static PredefinedOperator[] CreateEqualityLiftedOperatorsTable (ModuleContainer module)
4056 var nullable = module.PredefinedTypes.Nullable.TypeSpec;
4058 if (nullable == null)
4059 return new PredefinedOperator [0];
4061 var types = module.Compiler.BuiltinTypes;
4062 var bool_type = types.Bool;
4063 var nullable_bool = nullable.MakeGenericType (module, new [] { bool_type });
4064 var nullable_int = nullable.MakeGenericType (module, new[] { types.Int });
4065 var nullable_uint = nullable.MakeGenericType (module, new[] { types.UInt });
4066 var nullable_long = nullable.MakeGenericType (module, new[] { types.Long });
4067 var nullable_ulong = nullable.MakeGenericType (module, new[] { types.ULong });
4068 var nullable_float = nullable.MakeGenericType (module, new[] { types.Float });
4069 var nullable_double = nullable.MakeGenericType (module, new[] { types.Double });
4070 var nullable_decimal = nullable.MakeGenericType (module, new[] { types.Decimal });
4073 new PredefinedOperator (nullable_bool, Operator.NullableMask | Operator.EqualityMask, bool_type),
4074 new PredefinedOperator (nullable_int, Operator.NullableMask | Operator.EqualityMask, bool_type),
4075 new PredefinedOperator (nullable_uint, Operator.NullableMask | Operator.EqualityMask, bool_type),
4076 new PredefinedOperator (nullable_long, Operator.NullableMask | Operator.EqualityMask, bool_type),
4077 new PredefinedOperator (nullable_ulong, Operator.NullableMask | Operator.EqualityMask, bool_type),
4078 new PredefinedOperator (nullable_float, Operator.NullableMask | Operator.EqualityMask, bool_type),
4079 new PredefinedOperator (nullable_double, Operator.NullableMask | Operator.EqualityMask, bool_type),
4080 new PredefinedOperator (nullable_decimal, Operator.NullableMask | Operator.EqualityMask, bool_type)
4085 // 7.2.6.2 Binary numeric promotions
4087 bool DoBinaryOperatorPromotion (ResolveContext rc)
4089 TypeSpec ltype = left.Type;
4090 if (ltype.IsNullableType) {
4091 ltype = Nullable.NullableInfo.GetUnderlyingType (ltype);
4095 // This is numeric promotion code only
4097 if (ltype.BuiltinType == BuiltinTypeSpec.Type.Bool)
4100 TypeSpec rtype = right.Type;
4101 if (rtype.IsNullableType) {
4102 rtype = Nullable.NullableInfo.GetUnderlyingType (rtype);
4105 var lb = ltype.BuiltinType;
4106 var rb = rtype.BuiltinType;
4110 if (lb == BuiltinTypeSpec.Type.Decimal || rb == BuiltinTypeSpec.Type.Decimal) {
4111 type = rc.BuiltinTypes.Decimal;
4112 } else if (lb == BuiltinTypeSpec.Type.Double || rb == BuiltinTypeSpec.Type.Double) {
4113 type = rc.BuiltinTypes.Double;
4114 } else if (lb == BuiltinTypeSpec.Type.Float || rb == BuiltinTypeSpec.Type.Float) {
4115 type = rc.BuiltinTypes.Float;
4116 } else if (lb == BuiltinTypeSpec.Type.ULong || rb == BuiltinTypeSpec.Type.ULong) {
4117 type = rc.BuiltinTypes.ULong;
4119 if (IsSignedType (lb)) {
4120 expr = ConvertSignedConstant (left, type);
4124 } else if (IsSignedType (rb)) {
4125 expr = ConvertSignedConstant (right, type);
4131 } else if (lb == BuiltinTypeSpec.Type.Long || rb == BuiltinTypeSpec.Type.Long) {
4132 type = rc.BuiltinTypes.Long;
4133 } else if (lb == BuiltinTypeSpec.Type.UInt || rb == BuiltinTypeSpec.Type.UInt) {
4134 type = rc.BuiltinTypes.UInt;
4136 if (IsSignedType (lb)) {
4137 expr = ConvertSignedConstant (left, type);
4139 type = rc.BuiltinTypes.Long;
4140 } else if (IsSignedType (rb)) {
4141 expr = ConvertSignedConstant (right, type);
4143 type = rc.BuiltinTypes.Long;
4146 type = rc.BuiltinTypes.Int;
4149 if (ltype != type) {
4150 expr = PromoteExpression (rc, left, type);
4157 if (rtype != type) {
4158 expr = PromoteExpression (rc, right, type);
4168 static bool IsSignedType (BuiltinTypeSpec.Type type)
4171 case BuiltinTypeSpec.Type.Int:
4172 case BuiltinTypeSpec.Type.Short:
4173 case BuiltinTypeSpec.Type.SByte:
4174 case BuiltinTypeSpec.Type.Long:
4181 static Expression ConvertSignedConstant (Expression expr, TypeSpec type)
4183 var c = expr as Constant;
4187 return c.ConvertImplicitly (type);
4190 static Expression PromoteExpression (ResolveContext rc, Expression expr, TypeSpec type)
4192 if (expr.Type.IsNullableType) {
4193 return Convert.ImplicitConversionStandard (rc, expr,
4194 rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc, new[] { type }), expr.Location);
4197 var c = expr as Constant;
4199 return c.ConvertImplicitly (type);
4201 return Convert.ImplicitNumericConversion (expr, type);
4204 protected override Expression DoResolve (ResolveContext ec)
4209 if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
4210 left = ((ParenthesizedExpression) left).Expr;
4211 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
4215 if (left.eclass == ExprClass.Type) {
4216 ec.Report.Error (75, loc, "To cast a negative value, you must enclose the value in parentheses");
4220 left = left.Resolve (ec);
4225 right = right.Resolve (ec);
4229 Constant lc = left as Constant;
4230 Constant rc = right as Constant;
4232 // The conversion rules are ignored in enum context but why
4233 if (!ec.HasSet (ResolveContext.Options.EnumScope) && lc != null && rc != null && (left.Type.IsEnum || right.Type.IsEnum)) {
4234 lc = EnumLiftUp (ec, lc, rc);
4236 rc = EnumLiftUp (ec, rc, lc);
4239 if (rc != null && lc != null) {
4240 int prev_e = ec.Report.Errors;
4241 Expression e = ConstantFold.BinaryFold (ec, oper, lc, rc, loc);
4242 if (e != null || ec.Report.Errors != prev_e)
4246 // Comparison warnings
4247 if ((oper & Operator.ComparisonMask) != 0) {
4248 if (left.Equals (right)) {
4249 ec.Report.Warning (1718, 3, loc, "A comparison made to same variable. Did you mean to compare something else?");
4251 CheckOutOfRangeComparison (ec, lc, right.Type);
4252 CheckOutOfRangeComparison (ec, rc, left.Type);
4255 if (left.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic || right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4256 return DoResolveDynamic (ec);
4258 return DoResolveCore (ec, left, right);
4261 Expression DoResolveDynamic (ResolveContext rc)
4264 var rt = right.Type;
4265 if (lt.Kind == MemberKind.Void || lt == InternalType.MethodGroup || lt == InternalType.AnonymousMethod ||
4266 rt.Kind == MemberKind.Void || rt == InternalType.MethodGroup || rt == InternalType.AnonymousMethod) {
4267 Error_OperatorCannotBeApplied (rc, left, right);
4274 // Special handling for logical boolean operators which require rhs not to be
4275 // evaluated based on lhs value
4277 if ((oper & Operator.LogicalMask) != 0) {
4278 Expression cond_left, cond_right, expr;
4280 args = new Arguments (2);
4282 if (lt.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4283 LocalVariable temp = LocalVariable.CreateCompilerGenerated (lt, rc.CurrentBlock, loc);
4285 var cond_args = new Arguments (1);
4286 cond_args.Add (new Argument (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left).Resolve (rc)));
4289 // dynamic && bool => IsFalse (temp = left) ? temp : temp && right;
4290 // dynamic || bool => IsTrue (temp = left) ? temp : temp || right;
4292 left = temp.CreateReferenceExpression (rc, loc);
4293 if (oper == Operator.LogicalAnd) {
4294 expr = DynamicUnaryConversion.CreateIsFalse (rc, cond_args, loc);
4297 expr = DynamicUnaryConversion.CreateIsTrue (rc, cond_args, loc);
4301 args.Add (new Argument (left));
4302 args.Add (new Argument (right));
4303 cond_right = new DynamicExpressionStatement (this, args, loc);
4305 LocalVariable temp = LocalVariable.CreateCompilerGenerated (rc.BuiltinTypes.Bool, rc.CurrentBlock, loc);
4307 if (!Convert.ImplicitConversionExists (rc, left, temp.Type) && (oper == Operator.LogicalAnd ? GetOperatorFalse (rc, left, loc) : GetOperatorTrue (rc, left, loc)) == null) {
4308 rc.Report.Error (7083, left.Location,
4309 "Expression must be implicitly convertible to Boolean or its type `{0}' must define operator `{1}'",
4310 lt.GetSignatureForError (), oper == Operator.LogicalAnd ? "false" : "true");
4314 args.Add (new Argument (temp.CreateReferenceExpression (rc, loc).Resolve (rc)));
4315 args.Add (new Argument (right));
4316 right = new DynamicExpressionStatement (this, args, loc);
4319 // bool && dynamic => (temp = left) ? temp && right : temp;
4320 // bool || dynamic => (temp = left) ? temp : temp || right;
4322 if (oper == Operator.LogicalAnd) {
4324 cond_right = temp.CreateReferenceExpression (rc, loc);
4326 cond_left = temp.CreateReferenceExpression (rc, loc);
4330 expr = new BooleanExpression (new SimpleAssign (temp.CreateReferenceExpression (rc, loc), left));
4333 return new Conditional (expr, cond_left, cond_right, loc).Resolve (rc);
4336 args = new Arguments (2);
4337 args.Add (new Argument (left));
4338 args.Add (new Argument (right));
4339 return new DynamicExpressionStatement (this, args, loc).Resolve (rc);
4342 Expression DoResolveCore (ResolveContext ec, Expression left_orig, Expression right_orig)
4344 Expression expr = ResolveOperator (ec);
4346 Error_OperatorCannotBeApplied (ec, left_orig, right_orig);
4348 if (left == null || right == null)
4349 throw new InternalErrorException ("Invalid conversion");
4351 if (oper == Operator.BitwiseOr)
4352 CheckBitwiseOrOnSignExtended (ec);
4357 public override SLE.Expression MakeExpression (BuilderContext ctx)
4359 return MakeExpression (ctx, left, right);
4362 public SLE.Expression MakeExpression (BuilderContext ctx, Expression left, Expression right)
4364 var le = left.MakeExpression (ctx);
4365 var re = right.MakeExpression (ctx);
4366 bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
4369 case Operator.Addition:
4370 return is_checked ? SLE.Expression.AddChecked (le, re) : SLE.Expression.Add (le, re);
4371 case Operator.BitwiseAnd:
4372 return SLE.Expression.And (le, re);
4373 case Operator.BitwiseOr:
4374 return SLE.Expression.Or (le, re);
4375 case Operator.Division:
4376 return SLE.Expression.Divide (le, re);
4377 case Operator.Equality:
4378 return SLE.Expression.Equal (le, re);
4379 case Operator.ExclusiveOr:
4380 return SLE.Expression.ExclusiveOr (le, re);
4381 case Operator.GreaterThan:
4382 return SLE.Expression.GreaterThan (le, re);
4383 case Operator.GreaterThanOrEqual:
4384 return SLE.Expression.GreaterThanOrEqual (le, re);
4385 case Operator.Inequality:
4386 return SLE.Expression.NotEqual (le, re);
4387 case Operator.LeftShift:
4388 return SLE.Expression.LeftShift (le, re);
4389 case Operator.LessThan:
4390 return SLE.Expression.LessThan (le, re);
4391 case Operator.LessThanOrEqual:
4392 return SLE.Expression.LessThanOrEqual (le, re);
4393 case Operator.LogicalAnd:
4394 return SLE.Expression.AndAlso (le, re);
4395 case Operator.LogicalOr:
4396 return SLE.Expression.OrElse (le, re);
4397 case Operator.Modulus:
4398 return SLE.Expression.Modulo (le, re);
4399 case Operator.Multiply:
4400 return is_checked ? SLE.Expression.MultiplyChecked (le, re) : SLE.Expression.Multiply (le, re);
4401 case Operator.RightShift:
4402 return SLE.Expression.RightShift (le, re);
4403 case Operator.Subtraction:
4404 return is_checked ? SLE.Expression.SubtractChecked (le, re) : SLE.Expression.Subtract (le, re);
4406 throw new NotImplementedException (oper.ToString ());
4411 // D operator + (D x, D y)
4412 // D operator - (D x, D y)
4414 Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
4416 if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
4418 if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.NullLiteral) {
4419 tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
4424 } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod || l == InternalType.NullLiteral)) {
4425 tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
4435 MethodSpec method = null;
4436 Arguments args = new Arguments (2);
4437 args.Add (new Argument (left));
4438 args.Add (new Argument (right));
4440 if (oper == Operator.Addition) {
4441 method = ec.Module.PredefinedMembers.DelegateCombine.Resolve (loc);
4442 } else if (oper == Operator.Subtraction) {
4443 method = ec.Module.PredefinedMembers.DelegateRemove.Resolve (loc);
4447 return new EmptyExpression (ec.BuiltinTypes.Decimal);
4449 Expression expr = new UserOperatorCall (method, args, CreateExpressionTree, loc);
4450 return new ClassCast (expr, l);
4454 // Resolves enumeration operators where only single predefined overload exists, handles lifted versions too
4456 Expression ResolveSingleEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4459 // bool operator == (E x, E y);
4460 // bool operator != (E x, E y);
4461 // bool operator < (E x, E y);
4462 // bool operator > (E x, E y);
4463 // bool operator <= (E x, E y);
4464 // bool operator >= (E x, E y);
4466 // E operator & (E x, E y);
4467 // E operator | (E x, E y);
4468 // E operator ^ (E x, E y);
4471 if ((oper & Operator.ComparisonMask) != 0) {
4472 type = rc.BuiltinTypes.Bool;
4478 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4484 if (ltype == rtype) {
4488 var lifted = new Nullable.LiftedBinaryOperator (this);
4490 lifted.Right = right;
4491 return lifted.Resolve (rc);
4494 if (renum && !ltype.IsNullableType) {
4495 expr = Convert.ImplicitConversion (rc, left, rtype, loc);
4500 } else if (lenum && !rtype.IsNullableType) {
4501 expr = Convert.ImplicitConversion (rc, right, ltype, loc);
4509 // Now try lifted version of predefined operator
4511 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
4512 if (nullable_type != null) {
4513 if (renum && !ltype.IsNullableType) {
4514 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { rtype });
4516 expr = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4519 right = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4522 if ((oper & Operator.BitwiseMask) != 0)
4526 if ((oper & Operator.BitwiseMask) != 0)
4527 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4529 return CreateLiftedValueTypeResult (rc, rtype);
4533 var lifted = new Nullable.LiftedBinaryOperator (this);
4535 lifted.Right = right;
4536 return lifted.Resolve (rc);
4538 } else if (lenum && !rtype.IsNullableType) {
4539 var lifted_type = nullable_type.MakeGenericType (rc.Module, new[] { ltype });
4541 expr = Convert.ImplicitConversion (rc, right, lifted_type, loc);
4544 left = Convert.ImplicitConversion (rc, left, lifted_type, loc);
4547 if ((oper & Operator.BitwiseMask) != 0)
4551 if ((oper & Operator.BitwiseMask) != 0)
4552 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4554 return CreateLiftedValueTypeResult (rc, ltype);
4558 var lifted = new Nullable.LiftedBinaryOperator (this);
4560 lifted.Right = expr;
4561 return lifted.Resolve (rc);
4563 } else if (rtype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (rtype).IsEnum) {
4564 Nullable.Unwrap unwrap = null;
4565 if (left.IsNull || right.IsNull) {
4566 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4567 left = Convert.ImplicitConversion (rc, left, rtype, left.Location);
4569 if ((oper & Operator.RelationalMask) != 0)
4570 return CreateLiftedValueTypeResult (rc, rtype);
4572 if ((oper & Operator.BitwiseMask) != 0)
4573 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4576 return CreateLiftedValueTypeResult (rc, left.Type);
4578 // Equality operators are valid between E? and null
4580 unwrap = new Nullable.Unwrap (right);
4582 expr = Convert.ImplicitConversion (rc, left, Nullable.NullableInfo.GetUnderlyingType (rtype), loc);
4586 if ((oper & Operator.BitwiseMask) != 0)
4591 var lifted = new Nullable.LiftedBinaryOperator (this);
4593 lifted.Right = right;
4594 lifted.UnwrapRight = unwrap;
4595 return lifted.Resolve (rc);
4597 } else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum) {
4598 Nullable.Unwrap unwrap = null;
4599 if (right.IsNull || left.IsNull) {
4600 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion))
4601 right = Convert.ImplicitConversion (rc, right, ltype, right.Location);
4603 if ((oper & Operator.RelationalMask) != 0)
4604 return CreateLiftedValueTypeResult (rc, ltype);
4606 if ((oper & Operator.BitwiseMask) != 0)
4607 return Nullable.LiftedNull.CreateFromExpression (rc, this);
4610 return CreateLiftedValueTypeResult (rc, right.Type);
4612 // Equality operators are valid between E? and null
4614 unwrap = new Nullable.Unwrap (left);
4616 expr = Convert.ImplicitConversion (rc, right, Nullable.NullableInfo.GetUnderlyingType (ltype), loc);
4620 if ((oper & Operator.BitwiseMask) != 0)
4625 var lifted = new Nullable.LiftedBinaryOperator (this);
4627 lifted.UnwrapLeft = unwrap;
4628 lifted.Right = expr;
4629 return lifted.Resolve (rc);
4637 static Expression ConvertEnumOperandToUnderlyingType (ResolveContext rc, Expression expr, bool liftType)
4639 TypeSpec underlying_type;
4640 if (expr.Type.IsNullableType) {
4641 var nt = Nullable.NullableInfo.GetUnderlyingType (expr.Type);
4643 underlying_type = EnumSpec.GetUnderlyingType (nt);
4645 underlying_type = nt;
4646 } else if (expr.Type.IsEnum) {
4647 underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
4649 underlying_type = expr.Type;
4652 switch (underlying_type.BuiltinType) {
4653 case BuiltinTypeSpec.Type.SByte:
4654 case BuiltinTypeSpec.Type.Byte:
4655 case BuiltinTypeSpec.Type.Short:
4656 case BuiltinTypeSpec.Type.UShort:
4657 underlying_type = rc.BuiltinTypes.Int;
4661 if (expr.Type.IsNullableType || liftType)
4662 underlying_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { underlying_type });
4664 if (expr.Type == underlying_type)
4667 return EmptyCast.Create (expr, underlying_type);
4670 Expression ResolveEnumOperators (ResolveContext rc, bool lenum, bool renum, TypeSpec ltype, TypeSpec rtype)
4673 // U operator - (E e, E f)
4674 // E operator - (E e, U x) // Internal decomposition operator
4675 // E operator - (U x, E e) // Internal decomposition operator
4677 // E operator + (E e, U x)
4678 // E operator + (U x, E e)
4687 else if (ltype.IsNullableType && Nullable.NullableInfo.GetUnderlyingType (ltype).IsEnum)
4693 if (!enum_type.IsNullableType) {
4694 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, false), false);
4696 if (oper == Operator.Subtraction)
4697 expr = ConvertEnumSubtractionResult (rc, expr);
4699 expr = ConvertEnumAdditionalResult (expr, enum_type);
4701 enum_conversion = GetEnumResultCast (expr.Type);
4706 var nullable = rc.Module.PredefinedTypes.Nullable;
4709 // Don't try nullable version when nullable type is undefined
4711 if (!nullable.IsDefined)
4714 enum_type = nullable.TypeSpec.MakeGenericType (rc.Module, new[] { enum_type });
4717 expr = ResolveOperatorPredefined (rc, rc.Module.GetPredefinedEnumAritmeticOperators (enum_type, true), false);
4719 if (oper == Operator.Subtraction)
4720 expr = ConvertEnumSubtractionResult (rc, expr);
4722 expr = ConvertEnumAdditionalResult (expr, enum_type);
4724 enum_conversion = GetEnumResultCast (expr.Type);
4730 static Expression ConvertEnumAdditionalResult (Expression expr, TypeSpec enumType)
4732 return EmptyCast.Create (expr, enumType);
4735 Expression ConvertEnumSubtractionResult (ResolveContext rc, Expression expr)
4738 // Enumeration subtraction has different result type based on
4741 TypeSpec result_type;
4742 if (left.Type == right.Type) {
4743 var c = right as EnumConstant;
4744 if (c != null && c.IsZeroInteger && !right.Type.IsEnum) {
4746 // LAMESPEC: This is quite unexpected for expression E - 0 the return type is
4747 // E which is not what expressions E - 1 or 0 - E return
4749 result_type = left.Type;
4751 result_type = left.Type.IsNullableType ?
4752 Nullable.NullableInfo.GetEnumUnderlyingType (rc.Module, left.Type) :
4753 EnumSpec.GetUnderlyingType (left.Type);
4756 if (IsEnumOrNullableEnum (left.Type)) {
4757 result_type = left.Type;
4759 result_type = right.Type;
4762 if (expr is Nullable.LiftedBinaryOperator && !result_type.IsNullableType)
4763 result_type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { result_type });
4766 return EmptyCast.Create (expr, result_type);
4769 public static ConvCast.Mode GetEnumResultCast (TypeSpec type)
4771 if (type.IsNullableType)
4772 type = Nullable.NullableInfo.GetUnderlyingType (type);
4775 type = EnumSpec.GetUnderlyingType (type);
4777 switch (type.BuiltinType) {
4778 case BuiltinTypeSpec.Type.SByte:
4779 return ConvCast.Mode.I4_I1;
4780 case BuiltinTypeSpec.Type.Byte:
4781 return ConvCast.Mode.I4_U1;
4782 case BuiltinTypeSpec.Type.Short:
4783 return ConvCast.Mode.I4_I2;
4784 case BuiltinTypeSpec.Type.UShort:
4785 return ConvCast.Mode.I4_U2;
4792 // Equality operators rules
4794 Expression ResolveEquality (ResolveContext ec, TypeSpec l, TypeSpec r, bool primitives_only)
4797 type = ec.BuiltinTypes.Bool;
4798 bool no_arg_conv = false;
4800 if (!primitives_only) {
4803 // a, Both operands are reference-type values or the value null
4804 // b, One operand is a value of type T where T is a type-parameter and
4805 // the other operand is the value null. Furthermore T does not have the
4806 // value type constraint
4808 // LAMESPEC: Very confusing details in the specification, basically any
4809 // reference like type-parameter is allowed
4811 var tparam_l = l as TypeParameterSpec;
4812 var tparam_r = r as TypeParameterSpec;
4813 if (tparam_l != null) {
4814 if (right is NullLiteral) {
4815 if (tparam_l.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4818 left = new BoxedCast (left, ec.BuiltinTypes.Object);
4822 if (!tparam_l.IsReferenceType)
4825 l = tparam_l.GetEffectiveBase ();
4826 left = new BoxedCast (left, l);
4827 } else if (left is NullLiteral && tparam_r == null) {
4828 if (TypeSpec.IsReferenceType (r))
4831 if (r.Kind == MemberKind.InternalCompilerType)
4835 if (tparam_r != null) {
4836 if (left is NullLiteral) {
4837 if (tparam_r.GetEffectiveBase ().BuiltinType == BuiltinTypeSpec.Type.ValueType)
4840 right = new BoxedCast (right, ec.BuiltinTypes.Object);
4844 if (!tparam_r.IsReferenceType)
4847 r = tparam_r.GetEffectiveBase ();
4848 right = new BoxedCast (right, r);
4849 } else if (right is NullLiteral) {
4850 if (TypeSpec.IsReferenceType (l))
4853 if (l.Kind == MemberKind.InternalCompilerType)
4858 // LAMESPEC: method groups can be compared when they convert to other side delegate
4861 if (right.eclass == ExprClass.MethodGroup) {
4862 result = Convert.ImplicitConversion (ec, right, l, loc);
4868 } else if (r.IsDelegate && l != r) {
4871 } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
4872 result = Convert.ImplicitConversionRequired (ec, left, r, loc);
4879 no_arg_conv = l == r && !l.IsStruct;
4884 // bool operator != (string a, string b)
4885 // bool operator == (string a, string b)
4887 // bool operator != (Delegate a, Delegate b)
4888 // bool operator == (Delegate a, Delegate b)
4890 // bool operator != (bool a, bool b)
4891 // bool operator == (bool a, bool b)
4893 // LAMESPEC: Reference equality comparison can apply to value/reference types when
4894 // they implement an implicit conversion to any of types above. This does
4895 // not apply when both operands are of same reference type
4897 if (r.BuiltinType != BuiltinTypeSpec.Type.Object && l.BuiltinType != BuiltinTypeSpec.Type.Object) {
4898 result = ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryEquality, no_arg_conv);
4903 // Now try lifted version of predefined operators
4905 if (no_arg_conv && !l.IsNullableType) {
4907 // Optimizes cases which won't match
4910 result = ResolveOperatorPredefined (ec, ec.Module.OperatorsBinaryEqualityLifted, no_arg_conv);
4916 // The == and != operators permit one operand to be a value of a nullable
4917 // type and the other to be the null literal, even if no predefined or user-defined
4918 // operator (in unlifted or lifted form) exists for the operation.
4920 if ((l.IsNullableType && right.IsNull) || (r.IsNullableType && left.IsNull)) {
4921 var lifted = new Nullable.LiftedBinaryOperator (this);
4923 lifted.Right = right;
4924 return lifted.Resolve (ec);
4929 // bool operator != (object a, object b)
4930 // bool operator == (object a, object b)
4932 // An explicit reference conversion exists from the
4933 // type of either operand to the type of the other operand.
4936 // Optimize common path
4938 return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
4941 if (!Convert.ExplicitReferenceConversionExists (l, r) &&
4942 !Convert.ExplicitReferenceConversionExists (r, l))
4945 // Reject allowed explicit conversions like int->object
4946 if (!TypeSpec.IsReferenceType (l) || !TypeSpec.IsReferenceType (r))
4949 if (l.BuiltinType == BuiltinTypeSpec.Type.String || l.BuiltinType == BuiltinTypeSpec.Type.Delegate || l.IsDelegate || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
4950 ec.Report.Warning (253, 2, loc,
4951 "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
4952 l.GetSignatureForError ());
4954 if (r.BuiltinType == BuiltinTypeSpec.Type.String || r.BuiltinType == BuiltinTypeSpec.Type.Delegate || r.IsDelegate || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
4955 ec.Report.Warning (252, 2, loc,
4956 "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
4957 r.GetSignatureForError ());
4963 Expression ResolveOperatorPointer (ResolveContext ec, TypeSpec l, TypeSpec r)
4966 // bool operator == (void* x, void* y);
4967 // bool operator != (void* x, void* y);
4968 // bool operator < (void* x, void* y);
4969 // bool operator > (void* x, void* y);
4970 // bool operator <= (void* x, void* y);
4971 // bool operator >= (void* x, void* y);
4973 if ((oper & Operator.ComparisonMask) != 0) {
4976 temp = Convert.ImplicitConversion (ec, left, r, left.Location);
4983 temp = Convert.ImplicitConversion (ec, right, l, right.Location);
4989 type = ec.BuiltinTypes.Bool;
4993 return ResolveOperatorPredefined (ec, ec.BuiltinTypes.OperatorsBinaryUnsafe, false);
4997 // Build-in operators method overloading
4999 Expression ResolveOperatorPredefined (ResolveContext ec, PredefinedOperator [] operators, bool primitives_only)
5001 PredefinedOperator best_operator = null;
5002 TypeSpec l = left.Type;
5003 TypeSpec r = right.Type;
5004 Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
5006 foreach (PredefinedOperator po in operators) {
5007 if ((po.OperatorsMask & oper_mask) == 0)
5010 if (primitives_only) {
5011 if (!po.IsPrimitiveApplicable (l, r))
5014 if (!po.IsApplicable (ec, left, right))
5018 if (best_operator == null) {
5020 if (primitives_only)
5026 best_operator = po.ResolveBetterOperator (ec, best_operator);
5028 if (best_operator == null) {
5029 ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
5030 OperName (oper), l.GetSignatureForError (), r.GetSignatureForError ());
5037 if (best_operator == null)
5040 return best_operator.ConvertResult (ec, this);
5044 // Optimize & constant expressions with 0 value
5046 Expression OptimizeAndOperation (Expression expr)
5048 Constant rc = right as Constant;
5049 Constant lc = left as Constant;
5050 if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
5052 // The result is a constant with side-effect
5054 Constant side_effect = rc == null ?
5055 new SideEffectConstant (lc, right, loc) :
5056 new SideEffectConstant (rc, left, loc);
5058 return ReducedExpression.Create (side_effect, expr);
5065 // Value types can be compared with the null literal because of the lifting
5066 // language rules. However the result is always true or false.
5068 public Expression CreateLiftedValueTypeResult (ResolveContext rc, TypeSpec valueType)
5070 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5071 type = rc.BuiltinTypes.Bool;
5075 // FIXME: Handle side effect constants
5076 Constant c = new BoolConstant (rc.BuiltinTypes, Oper == Operator.Inequality, loc);
5078 if ((Oper & Operator.EqualityMask) != 0) {
5079 rc.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is always `{1}'",
5080 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5082 rc.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
5083 valueType.GetSignatureForError (), c.GetValueAsLiteral ());
5090 // Performs user-operator overloading
5092 Expression ResolveUserOperator (ResolveContext rc, Expression left, Expression right)
5094 Expression oper_expr;
5096 var op = ConvertBinaryToUserOperator (oper);
5098 if (l.IsNullableType)
5099 l = Nullable.NullableInfo.GetUnderlyingType (l);
5101 if (r.IsNullableType)
5102 r = Nullable.NullableInfo.GetUnderlyingType (r);
5104 IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
5105 IList<MemberSpec> right_operators = null;
5108 right_operators = MemberCache.GetUserOperator (r, op, false);
5109 if (right_operators == null && left_operators == null)
5111 } else if (left_operators == null) {
5115 Arguments args = new Arguments (2);
5116 Argument larg = new Argument (left);
5118 Argument rarg = new Argument (right);
5122 // User-defined operator implementations always take precedence
5123 // over predefined operator implementations
5125 if (left_operators != null && right_operators != null) {
5126 left_operators = CombineUserOperators (left_operators, right_operators);
5127 } else if (right_operators != null) {
5128 left_operators = right_operators;
5131 const OverloadResolver.Restrictions restr = OverloadResolver.Restrictions.ProbingOnly |
5132 OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded;
5134 var res = new OverloadResolver (left_operators, restr, loc);
5136 var oper_method = res.ResolveOperator (rc, ref args);
5137 if (oper_method == null) {
5139 // Logical && and || cannot be lifted
5141 if ((oper & Operator.LogicalMask) != 0)
5145 // Apply lifted user operators only for liftable types. Implicit conversion
5146 // to nullable types is not allowed
5148 if (!IsLiftedOperatorApplicable ())
5151 // TODO: Cache the result in module container
5152 var lifted_methods = CreateLiftedOperators (rc, left_operators);
5153 if (lifted_methods == null)
5156 res = new OverloadResolver (lifted_methods, restr | OverloadResolver.Restrictions.ProbingOnly, loc);
5158 oper_method = res.ResolveOperator (rc, ref args);
5159 if (oper_method == null)
5162 MethodSpec best_original = null;
5163 foreach (MethodSpec ms in left_operators) {
5164 if (ms.MemberDefinition == oper_method.MemberDefinition) {
5170 if (rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
5172 // Expression trees use lifted notation in this case
5174 this.left = Convert.ImplicitConversion (rc, left, oper_method.Parameters.Types[0], left.Location);
5175 this.right = Convert.ImplicitConversion (rc, right, oper_method.Parameters.Types[1], left.Location);
5178 var ptypes = best_original.Parameters.Types;
5180 if (left.IsNull || right.IsNull) {
5182 // The lifted operator produces a null value if one or both operands are null
5184 if ((oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0) {
5185 type = oper_method.ReturnType;
5186 return Nullable.LiftedNull.CreateFromExpression (rc, this);
5190 // The lifted operator produces the value false if one or both operands are null for
5191 // relational operators.
5193 if ((oper & Operator.RelationalMask) != 0) {
5195 // CSC BUG: This should be different warning, csc reports CS0458 with bool? which is wrong
5196 // because return type is actually bool
5198 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5201 if ((oper & Operator.EqualityMask) != 0 && ((left.IsNull && !right.Type.IsNullableType) || !left.Type.IsNullableType)) {
5202 return CreateLiftedValueTypeResult (rc, left.IsNull ? ptypes [1] : ptypes [0]);
5206 type = oper_method.ReturnType;
5207 var lifted = new Nullable.LiftedBinaryOperator (this);
5208 lifted.UserOperator = best_original;
5210 if (left.Type.IsNullableType && !ptypes[0].IsNullableType) {
5211 lifted.UnwrapLeft = new Nullable.Unwrap (left);
5214 if (right.Type.IsNullableType && !ptypes[1].IsNullableType) {
5215 lifted.UnwrapRight = new Nullable.Unwrap (right);
5218 lifted.Left = Convert.ImplicitConversion (rc, lifted.UnwrapLeft ?? left, ptypes[0], left.Location);
5219 lifted.Right = Convert.ImplicitConversion (rc, lifted.UnwrapRight ?? right, ptypes[1], right.Location);
5221 return lifted.Resolve (rc);
5224 if ((oper & Operator.LogicalMask) != 0) {
5225 // TODO: CreateExpressionTree is allocated every time
5226 oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
5227 oper == Operator.LogicalAnd, loc).Resolve (rc);
5229 oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
5232 this.left = larg.Expr;
5233 this.right = rarg.Expr;
5238 bool IsLiftedOperatorApplicable ()
5240 if (left.Type.IsNullableType) {
5241 if ((oper & Operator.EqualityMask) != 0)
5242 return !right.IsNull;
5247 if (right.Type.IsNullableType) {
5248 if ((oper & Operator.EqualityMask) != 0)
5249 return !left.IsNull;
5254 if (TypeSpec.IsValueType (left.Type))
5255 return right.IsNull;
5257 if (TypeSpec.IsValueType (right.Type))
5263 List<MemberSpec> CreateLiftedOperators (ResolveContext rc, IList<MemberSpec> operators)
5265 var nullable_type = rc.Module.PredefinedTypes.Nullable.TypeSpec;
5266 if (nullable_type == null)
5270 // Lifted operators permit predefined and user-defined operators that operate
5271 // on non-nullable value types to also be used with nullable forms of those types.
5272 // Lifted operators are constructed from predefined and user-defined operators
5273 // that meet certain requirements
5275 List<MemberSpec> lifted = null;
5276 foreach (MethodSpec oper in operators) {
5278 if ((Oper & Operator.ComparisonMask) != 0) {
5280 // Result type must be of type bool for lifted comparison operators
5282 rt = oper.ReturnType;
5283 if (rt.BuiltinType != BuiltinTypeSpec.Type.Bool)
5286 if (!TypeSpec.IsNonNullableValueType (oper.ReturnType))
5292 var ptypes = oper.Parameters.Types;
5293 if (!TypeSpec.IsNonNullableValueType (ptypes [0]) || !TypeSpec.IsNonNullableValueType (ptypes [1]))
5297 // LAMESPEC: I am not sure why but for equality operators to be lifted
5298 // both types have to match
5300 if ((Oper & Operator.EqualityMask) != 0 && ptypes [0] != ptypes [1])
5304 lifted = new List<MemberSpec> ();
5307 // The lifted form is constructed by adding a single ? modifier to each operand and
5308 // result type except for comparison operators where return type is bool
5311 rt = nullable_type.MakeGenericType (rc.Module, new[] { oper.ReturnType });
5313 var parameters = ParametersCompiled.CreateFullyResolved (
5314 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[0] }),
5315 nullable_type.MakeGenericType (rc.Module, new [] { ptypes[1] }));
5317 var lifted_op = new MethodSpec (oper.Kind, oper.DeclaringType, oper.MemberDefinition,
5318 rt, parameters, oper.Modifiers);
5320 lifted.Add (lifted_op);
5327 // Merge two sets of user operators into one, they are mostly distinguish
5328 // except when they share base type and it contains an operator
5330 static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
5332 var combined = new List<MemberSpec> (left.Count + right.Count);
5333 combined.AddRange (left);
5334 foreach (var r in right) {
5336 foreach (var l in left) {
5337 if (l.DeclaringType == r.DeclaringType) {
5350 void CheckOutOfRangeComparison (ResolveContext ec, Constant c, TypeSpec type)
5352 if (c is IntegralConstant || c is CharConstant) {
5354 c.ConvertExplicitly (true, type);
5355 } catch (OverflowException) {
5356 ec.Report.Warning (652, 2, loc,
5357 "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
5358 type.GetSignatureForError ());
5364 /// EmitBranchable is called from Statement.EmitBoolExpression in the
5365 /// context of a conditional bool expression. This function will return
5366 /// false if it is was possible to use EmitBranchable, or true if it was.
5368 /// The expression's code is generated, and we will generate a branch to `target'
5369 /// if the resulting expression value is equal to isTrue
5371 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
5373 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5374 left = left.EmitToField (ec);
5376 if ((oper & Operator.LogicalMask) == 0) {
5377 right = right.EmitToField (ec);
5382 // This is more complicated than it looks, but its just to avoid
5383 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
5384 // but on top of that we want for == and != to use a special path
5385 // if we are comparing against null
5387 if ((oper & Operator.EqualityMask) != 0 && (left is Constant || right is Constant)) {
5388 bool my_on_true = oper == Operator.Inequality ? on_true : !on_true;
5391 // put the constant on the rhs, for simplicity
5393 if (left is Constant) {
5394 Expression swap = right;
5400 // brtrue/brfalse works with native int only
5402 if (((Constant) right).IsZeroInteger && right.Type.BuiltinType != BuiltinTypeSpec.Type.Long && right.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
5403 left.EmitBranchable (ec, target, my_on_true);
5406 if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) {
5407 // right is a boolean, and it's not 'false' => it is 'true'
5408 left.EmitBranchable (ec, target, !my_on_true);
5412 } else if (oper == Operator.LogicalAnd) {
5415 Label tests_end = ec.DefineLabel ();
5417 left.EmitBranchable (ec, tests_end, false);
5418 right.EmitBranchable (ec, target, true);
5419 ec.MarkLabel (tests_end);
5422 // This optimizes code like this
5423 // if (true && i > 4)
5425 if (!(left is Constant))
5426 left.EmitBranchable (ec, target, false);
5428 if (!(right is Constant))
5429 right.EmitBranchable (ec, target, false);
5434 } else if (oper == Operator.LogicalOr){
5436 left.EmitBranchable (ec, target, true);
5437 right.EmitBranchable (ec, target, true);
5440 Label tests_end = ec.DefineLabel ();
5441 left.EmitBranchable (ec, tests_end, true);
5442 right.EmitBranchable (ec, target, false);
5443 ec.MarkLabel (tests_end);
5448 } else if ((oper & Operator.ComparisonMask) == 0) {
5449 base.EmitBranchable (ec, target, on_true);
5456 TypeSpec t = left.Type;
5457 bool is_float = IsFloat (t);
5458 bool is_unsigned = is_float || IsUnsigned (t);
5461 case Operator.Equality:
5463 ec.Emit (OpCodes.Beq, target);
5465 ec.Emit (OpCodes.Bne_Un, target);
5468 case Operator.Inequality:
5470 ec.Emit (OpCodes.Bne_Un, target);
5472 ec.Emit (OpCodes.Beq, target);
5475 case Operator.LessThan:
5477 if (is_unsigned && !is_float)
5478 ec.Emit (OpCodes.Blt_Un, target);
5480 ec.Emit (OpCodes.Blt, target);
5483 ec.Emit (OpCodes.Bge_Un, target);
5485 ec.Emit (OpCodes.Bge, target);
5488 case Operator.GreaterThan:
5490 if (is_unsigned && !is_float)
5491 ec.Emit (OpCodes.Bgt_Un, target);
5493 ec.Emit (OpCodes.Bgt, target);
5496 ec.Emit (OpCodes.Ble_Un, target);
5498 ec.Emit (OpCodes.Ble, target);
5501 case Operator.LessThanOrEqual:
5503 if (is_unsigned && !is_float)
5504 ec.Emit (OpCodes.Ble_Un, target);
5506 ec.Emit (OpCodes.Ble, target);
5509 ec.Emit (OpCodes.Bgt_Un, target);
5511 ec.Emit (OpCodes.Bgt, target);
5515 case Operator.GreaterThanOrEqual:
5517 if (is_unsigned && !is_float)
5518 ec.Emit (OpCodes.Bge_Un, target);
5520 ec.Emit (OpCodes.Bge, target);
5523 ec.Emit (OpCodes.Blt_Un, target);
5525 ec.Emit (OpCodes.Blt, target);
5528 throw new InternalErrorException (oper.ToString ());
5532 public override void Emit (EmitContext ec)
5534 if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
5535 left = left.EmitToField (ec);
5537 if ((oper & Operator.LogicalMask) == 0) {
5538 right = right.EmitToField (ec);
5543 // Handle short-circuit operators differently
5546 if ((oper & Operator.LogicalMask) != 0) {
5547 Label load_result = ec.DefineLabel ();
5548 Label end = ec.DefineLabel ();
5550 bool is_or = oper == Operator.LogicalOr;
5551 left.EmitBranchable (ec, load_result, is_or);
5553 ec.Emit (OpCodes.Br_S, end);
5555 ec.MarkLabel (load_result);
5556 ec.EmitInt (is_or ? 1 : 0);
5562 // Optimize zero-based operations which cannot be optimized at expression level
5564 if (oper == Operator.Subtraction) {
5565 var lc = left as IntegralConstant;
5566 if (lc != null && lc.IsDefaultValue) {
5568 ec.Emit (OpCodes.Neg);
5573 EmitOperator (ec, left, right);
5576 public void EmitOperator (EmitContext ec, Expression left, Expression right)
5581 EmitOperatorOpcode (ec, oper, left.Type, right);
5584 // Emit result enumerable conversion this way because it's quite complicated get it
5585 // to resolved tree because expression tree cannot see it.
5587 if (enum_conversion != 0)
5588 ConvCast.Emit (ec, enum_conversion);
5591 public override void EmitSideEffect (EmitContext ec)
5593 if ((oper & Operator.LogicalMask) != 0 ||
5594 (ec.HasSet (EmitContext.Options.CheckedScope) && (oper == Operator.Multiply || oper == Operator.Addition || oper == Operator.Subtraction))) {
5595 base.EmitSideEffect (ec);
5597 left.EmitSideEffect (ec);
5598 right.EmitSideEffect (ec);
5602 public override Expression EmitToField (EmitContext ec)
5604 if ((oper & Operator.LogicalMask) == 0) {
5605 var await_expr = left as Await;
5606 if (await_expr != null && right.IsSideEffectFree) {
5607 await_expr.Statement.EmitPrologue (ec);
5608 left = await_expr.Statement.GetResultExpression (ec);
5612 await_expr = right as Await;
5613 if (await_expr != null && left.IsSideEffectFree) {
5614 await_expr.Statement.EmitPrologue (ec);
5615 right = await_expr.Statement.GetResultExpression (ec);
5620 return base.EmitToField (ec);
5623 protected override void CloneTo (CloneContext clonectx, Expression t)
5625 Binary target = (Binary) t;
5627 target.left = left.Clone (clonectx);
5628 target.right = right.Clone (clonectx);
5631 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
5633 Arguments binder_args = new Arguments (4);
5635 MemberAccess sle = new MemberAccess (new MemberAccess (
5636 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
5638 CSharpBinderFlags flags = 0;
5639 if (ec.HasSet (ResolveContext.Options.CheckedScope))
5640 flags = CSharpBinderFlags.CheckedContext;
5642 if ((oper & Operator.LogicalMask) != 0)
5643 flags |= CSharpBinderFlags.BinaryOperationLogical;
5645 binder_args.Add (new Argument (new EnumConstant (new IntLiteral (ec.BuiltinTypes, (int) flags, loc), ec.Module.PredefinedTypes.BinderFlags.Resolve ())));
5646 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
5647 binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
5648 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
5650 return new Invocation (new MemberAccess (new TypeExpression (ec.Module.PredefinedTypes.Binder.TypeSpec, loc), "BinaryOperation", loc), binder_args);
5653 public override Expression CreateExpressionTree (ResolveContext ec)
5655 return CreateExpressionTree (ec, null);
5658 public Expression CreateExpressionTree (ResolveContext ec, Expression method)
5661 bool lift_arg = false;
5664 case Operator.Addition:
5665 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5666 method_name = "AddChecked";
5668 method_name = "Add";
5670 case Operator.BitwiseAnd:
5671 method_name = "And";
5673 case Operator.BitwiseOr:
5676 case Operator.Division:
5677 method_name = "Divide";
5679 case Operator.Equality:
5680 method_name = "Equal";
5683 case Operator.ExclusiveOr:
5684 method_name = "ExclusiveOr";
5686 case Operator.GreaterThan:
5687 method_name = "GreaterThan";
5690 case Operator.GreaterThanOrEqual:
5691 method_name = "GreaterThanOrEqual";
5694 case Operator.Inequality:
5695 method_name = "NotEqual";
5698 case Operator.LeftShift:
5699 method_name = "LeftShift";
5701 case Operator.LessThan:
5702 method_name = "LessThan";
5705 case Operator.LessThanOrEqual:
5706 method_name = "LessThanOrEqual";
5709 case Operator.LogicalAnd:
5710 method_name = "AndAlso";
5712 case Operator.LogicalOr:
5713 method_name = "OrElse";
5715 case Operator.Modulus:
5716 method_name = "Modulo";
5718 case Operator.Multiply:
5719 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5720 method_name = "MultiplyChecked";
5722 method_name = "Multiply";
5724 case Operator.RightShift:
5725 method_name = "RightShift";
5727 case Operator.Subtraction:
5728 if (method == null && ec.HasSet (ResolveContext.Options.CheckedScope) && !IsFloat (type))
5729 method_name = "SubtractChecked";
5731 method_name = "Subtract";
5735 throw new InternalErrorException ("Unknown expression tree binary operator " + oper);
5738 Arguments args = new Arguments (2);
5739 args.Add (new Argument (left.CreateExpressionTree (ec)));
5740 args.Add (new Argument (right.CreateExpressionTree (ec)));
5741 if (method != null) {
5743 args.Add (new Argument (new BoolLiteral (ec.BuiltinTypes, false, loc)));
5745 args.Add (new Argument (method));
5748 return CreateExpressionFactoryCall (ec, method_name, args);
5751 public override object Accept (StructuralVisitor visitor)
5753 return visitor.Visit (this);
5759 // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
5760 // b, c, d... may be strings or objects.
5762 public class StringConcat : Expression
5764 Arguments arguments;
5766 StringConcat (Location loc)
5769 arguments = new Arguments (2);
5772 public override bool ContainsEmitWithAwait ()
5774 return arguments.ContainsEmitWithAwait ();
5777 public static StringConcat Create (ResolveContext rc, Expression left, Expression right, Location loc)
5779 if (left.eclass == ExprClass.Unresolved || right.eclass == ExprClass.Unresolved)
5780 throw new ArgumentException ();
5782 var s = new StringConcat (loc);
5783 s.type = rc.BuiltinTypes.String;
5784 s.eclass = ExprClass.Value;
5786 s.Append (rc, left);
5787 s.Append (rc, right);
5791 public override Expression CreateExpressionTree (ResolveContext ec)
5793 Argument arg = arguments [0];
5794 return CreateExpressionAddCall (ec, arg, arg.CreateExpressionTree (ec), 1);
5798 // Creates nested calls tree from an array of arguments used for IL emit
5800 Expression CreateExpressionAddCall (ResolveContext ec, Argument left, Expression left_etree, int pos)
5802 Arguments concat_args = new Arguments (2);
5803 Arguments add_args = new Arguments (3);
5805 concat_args.Add (left);
5806 add_args.Add (new Argument (left_etree));
5808 concat_args.Add (arguments [pos]);
5809 add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
5811 var methods = GetConcatMethodCandidates ();
5812 if (methods == null)
5815 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
5816 var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
5820 add_args.Add (new Argument (new TypeOfMethod (method, loc)));
5822 Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
5823 if (++pos == arguments.Count)
5826 left = new Argument (new EmptyExpression (method.ReturnType));
5827 return CreateExpressionAddCall (ec, left, expr, pos);
5830 protected override Expression DoResolve (ResolveContext ec)
5835 void Append (ResolveContext rc, Expression operand)
5840 StringConstant sc = operand as StringConstant;
5842 if (arguments.Count != 0) {
5843 Argument last_argument = arguments [arguments.Count - 1];
5844 StringConstant last_expr_constant = last_argument.Expr as StringConstant;
5845 if (last_expr_constant != null) {
5846 last_argument.Expr = new StringConstant (rc.BuiltinTypes, last_expr_constant.Value + sc.Value, sc.Location);
5852 // Multiple (3+) concatenation are resolved as multiple StringConcat instances
5854 StringConcat concat_oper = operand as StringConcat;
5855 if (concat_oper != null) {
5856 arguments.AddRange (concat_oper.arguments);
5861 arguments.Add (new Argument (operand));
5864 IList<MemberSpec> GetConcatMethodCandidates ()
5866 return MemberCache.FindMembers (type, "Concat", true);
5869 public override void Emit (EmitContext ec)
5871 // Optimize by removing any extra null arguments, they are no-op
5872 for (int i = 0; i < arguments.Count; ++i) {
5873 if (arguments[i].Expr is NullConstant)
5874 arguments.RemoveAt (i--);
5877 var members = GetConcatMethodCandidates ();
5878 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
5879 var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
5880 if (method != null) {
5881 var call = new CallEmitter ();
5882 call.EmitPredefined (ec, method, arguments, false);
5886 public override void FlowAnalysis (FlowAnalysisContext fc)
5888 arguments.FlowAnalysis (fc);
5891 public override SLE.Expression MakeExpression (BuilderContext ctx)
5893 if (arguments.Count != 2)
5894 throw new NotImplementedException ("arguments.Count != 2");
5896 var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
5897 return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
5902 // User-defined conditional logical operator
5904 public class ConditionalLogicalOperator : UserOperatorCall
5906 readonly bool is_and;
5907 Expression oper_expr;
5909 public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
5910 : base (oper, arguments, expr_tree, loc)
5912 this.is_and = is_and;
5913 eclass = ExprClass.Unresolved;
5916 protected override Expression DoResolve (ResolveContext ec)
5918 AParametersCollection pd = oper.Parameters;
5919 if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
5920 ec.Report.Error (217, loc,
5921 "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",
5922 oper.GetSignatureForError ());
5926 Expression left_dup = new EmptyExpression (type);
5927 Expression op_true = GetOperatorTrue (ec, left_dup, loc);
5928 Expression op_false = GetOperatorFalse (ec, left_dup, loc);
5929 if (op_true == null || op_false == null) {
5930 ec.Report.Error (218, loc,
5931 "The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
5932 type.GetSignatureForError (), oper.GetSignatureForError ());
5936 oper_expr = is_and ? op_false : op_true;
5937 eclass = ExprClass.Value;
5941 public override void Emit (EmitContext ec)
5943 Label end_target = ec.DefineLabel ();
5946 // Emit and duplicate left argument
5948 bool right_contains_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments[1].Expr.ContainsEmitWithAwait ();
5949 if (right_contains_await) {
5950 arguments[0] = arguments[0].EmitToField (ec, false);
5951 arguments[0].Expr.Emit (ec);
5953 arguments[0].Expr.Emit (ec);
5954 ec.Emit (OpCodes.Dup);
5955 arguments.RemoveAt (0);
5958 oper_expr.EmitBranchable (ec, end_target, true);
5962 if (right_contains_await) {
5964 // Special handling when right expression contains await and left argument
5965 // could not be left on stack before logical branch
5967 Label skip_left_load = ec.DefineLabel ();
5968 ec.Emit (OpCodes.Br_S, skip_left_load);
5969 ec.MarkLabel (end_target);
5970 arguments[0].Expr.Emit (ec);
5971 ec.MarkLabel (skip_left_load);
5973 ec.MarkLabel (end_target);
5978 public class PointerArithmetic : Expression {
5979 Expression left, right;
5980 readonly Binary.Operator op;
5983 // We assume that `l' is always a pointer
5985 public PointerArithmetic (Binary.Operator op, Expression l, Expression r, TypeSpec t, Location loc)
5994 public override bool ContainsEmitWithAwait ()
5996 throw new NotImplementedException ();
5999 public override Expression CreateExpressionTree (ResolveContext ec)
6001 Error_PointerInsideExpressionTree (ec);
6005 protected override Expression DoResolve (ResolveContext ec)
6007 eclass = ExprClass.Variable;
6009 var pc = left.Type as PointerContainer;
6010 if (pc != null && pc.Element.Kind == MemberKind.Void) {
6011 Error_VoidPointerOperation (ec);
6018 public override void Emit (EmitContext ec)
6020 TypeSpec op_type = left.Type;
6022 // It must be either array or fixed buffer
6024 if (TypeManager.HasElementType (op_type)) {
6025 element = TypeManager.GetElementType (op_type);
6027 FieldExpr fe = left as FieldExpr;
6029 element = ((FixedFieldSpec) (fe.Spec)).ElementType;
6034 int size = BuiltinTypeSpec.GetSize(element);
6035 TypeSpec rtype = right.Type;
6037 if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
6039 // handle (pointer - pointer)
6043 ec.Emit (OpCodes.Sub);
6047 ec.Emit (OpCodes.Sizeof, element);
6050 ec.Emit (OpCodes.Div);
6052 ec.Emit (OpCodes.Conv_I8);
6055 // handle + and - on (pointer op int)
6057 Constant left_const = left as Constant;
6058 if (left_const != null) {
6060 // Optimize ((T*)null) pointer operations
6062 if (left_const.IsDefaultValue) {
6063 left = EmptyExpression.Null;
6071 var right_const = right as Constant;
6072 if (right_const != null) {
6074 // Optimize 0-based arithmetic
6076 if (right_const.IsDefaultValue)
6080 right = new IntConstant (ec.BuiltinTypes, size, right.Location);
6082 right = new SizeOf (new TypeExpression (element, right.Location), right.Location);
6084 // TODO: Should be the checks resolve context sensitive?
6085 ResolveContext rc = new ResolveContext (ec.MemberContext, ResolveContext.Options.UnsafeScope);
6086 right = new Binary (Binary.Operator.Multiply, right, right_const).Resolve (rc);
6092 if (right_const == null) {
6093 switch (rtype.BuiltinType) {
6094 case BuiltinTypeSpec.Type.SByte:
6095 case BuiltinTypeSpec.Type.Byte:
6096 case BuiltinTypeSpec.Type.Short:
6097 case BuiltinTypeSpec.Type.UShort:
6098 case BuiltinTypeSpec.Type.Int:
6099 ec.Emit (OpCodes.Conv_I);
6101 case BuiltinTypeSpec.Type.UInt:
6102 ec.Emit (OpCodes.Conv_U);
6107 if (right_const == null && size != 1){
6109 ec.Emit (OpCodes.Sizeof, element);
6112 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long || rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6113 ec.Emit (OpCodes.Conv_I8);
6115 Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype, right);
6118 if (left_const == null) {
6119 if (rtype.BuiltinType == BuiltinTypeSpec.Type.Long)
6120 ec.Emit (OpCodes.Conv_I);
6121 else if (rtype.BuiltinType == BuiltinTypeSpec.Type.ULong)
6122 ec.Emit (OpCodes.Conv_U);
6124 Binary.EmitOperatorOpcode (ec, op, op_type, right);
6131 // A boolean-expression is an expression that yields a result
6134 public class BooleanExpression : ShimExpression
6136 public BooleanExpression (Expression expr)
6139 this.loc = expr.Location;
6142 public override Expression CreateExpressionTree (ResolveContext ec)
6144 // TODO: We should emit IsTrue (v4) instead of direct user operator
6145 // call but that would break csc compatibility
6146 return base.CreateExpressionTree (ec);
6149 protected override Expression DoResolve (ResolveContext ec)
6151 // A boolean-expression is required to be of a type
6152 // that can be implicitly converted to bool or of
6153 // a type that implements operator true
6155 expr = expr.Resolve (ec);
6159 Assign ass = expr as Assign;
6160 if (ass != null && ass.Source is Constant) {
6161 ec.Report.Warning (665, 3, loc,
6162 "Assignment in conditional expression is always constant. Did you mean to use `==' instead ?");
6165 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Bool)
6168 if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
6169 Arguments args = new Arguments (1);
6170 args.Add (new Argument (expr));
6171 return DynamicUnaryConversion.CreateIsTrue (ec, args, loc).Resolve (ec);
6174 type = ec.BuiltinTypes.Bool;
6175 Expression converted = Convert.ImplicitConversion (ec, expr, type, loc);
6176 if (converted != null)
6180 // If no implicit conversion to bool exists, try using `operator true'
6182 converted = GetOperatorTrue (ec, expr, loc);
6183 if (converted == null) {
6184 expr.Error_ValueCannotBeConverted (ec, type, false);
6191 public override object Accept (StructuralVisitor visitor)
6193 return visitor.Visit (this);
6197 public class BooleanExpressionFalse : Unary
6199 public BooleanExpressionFalse (Expression expr)
6200 : base (Operator.LogicalNot, expr, expr.Location)
6204 protected override Expression ResolveOperator (ResolveContext ec, Expression expr)
6206 return GetOperatorFalse (ec, expr, loc) ?? base.ResolveOperator (ec, expr);
6211 /// Implements the ternary conditional operator (?:)
6213 public class Conditional : Expression {
6214 Expression expr, true_expr, false_expr;
6216 public Conditional (Expression expr, Expression true_expr, Expression false_expr, Location loc)
6219 this.true_expr = true_expr;
6220 this.false_expr = false_expr;
6226 public Expression Expr {
6232 public Expression TrueExpr {
6238 public Expression FalseExpr {
6246 public override bool ContainsEmitWithAwait ()
6248 return Expr.ContainsEmitWithAwait () || true_expr.ContainsEmitWithAwait () || false_expr.ContainsEmitWithAwait ();
6251 public override Expression CreateExpressionTree (ResolveContext ec)
6253 Arguments args = new Arguments (3);
6254 args.Add (new Argument (expr.CreateExpressionTree (ec)));
6255 args.Add (new Argument (true_expr.CreateExpressionTree (ec)));
6256 args.Add (new Argument (false_expr.CreateExpressionTree (ec)));
6257 return CreateExpressionFactoryCall (ec, "Condition", args);
6260 protected override Expression DoResolve (ResolveContext ec)
6262 expr = expr.Resolve (ec);
6263 true_expr = true_expr.Resolve (ec);
6264 false_expr = false_expr.Resolve (ec);
6266 if (true_expr == null || false_expr == null || expr == null)
6269 eclass = ExprClass.Value;
6270 TypeSpec true_type = true_expr.Type;
6271 TypeSpec false_type = false_expr.Type;
6275 // First, if an implicit conversion exists from true_expr
6276 // to false_expr, then the result type is of type false_expr.Type
6278 if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
6279 Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
6280 if (conv != null && true_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6282 // Check if both can convert implicitly to each other's type
6286 if (false_type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
6287 var conv_false_expr = Convert.ImplicitConversion (ec, false_expr, true_type, loc);
6289 // LAMESPEC: There seems to be hardcoded promotition to int type when
6290 // both sides are numeric constants and one side is int constant and
6291 // other side is numeric constant convertible to int.
6293 // var res = condition ? (short)1 : 1;
6295 // Type of res is int even if according to the spec the conversion is
6296 // ambiguous because 1 literal can be converted to short.
6298 if (conv_false_expr != null) {
6299 if (conv_false_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Int && conv is Constant) {
6301 conv_false_expr = null;
6302 } else if (type.BuiltinType == BuiltinTypeSpec.Type.Int && conv_false_expr is Constant) {
6303 conv_false_expr = null;
6307 if (conv_false_expr != null) {
6308 ec.Report.Error (172, true_expr.Location,
6309 "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
6310 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6315 if (true_expr.Type != type)
6316 true_expr = EmptyCast.Create (true_expr, type);
6317 } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
6320 if (false_type != InternalType.ErrorType) {
6321 ec.Report.Error (173, true_expr.Location,
6322 "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
6323 true_type.GetSignatureForError (), false_type.GetSignatureForError ());
6329 Constant c = expr as Constant;
6331 bool is_false = c.IsDefaultValue;
6334 // Don't issue the warning for constant expressions
6336 if (!(is_false ? true_expr is Constant : false_expr is Constant)) {
6337 // CSC: Missing warning
6338 Warning_UnreachableExpression (ec, is_false ? true_expr.Location : false_expr.Location);
6341 return ReducedExpression.Create (
6342 is_false ? false_expr : true_expr, this,
6343 false_expr is Constant && true_expr is Constant).Resolve (ec);
6349 public override void Emit (EmitContext ec)
6351 Label false_target = ec.DefineLabel ();
6352 Label end_target = ec.DefineLabel ();
6354 expr.EmitBranchable (ec, false_target, false);
6355 true_expr.Emit (ec);
6358 // Verifier doesn't support interface merging. When there are two types on
6359 // the stack without common type hint and the common type is an interface.
6360 // Use temporary local to give verifier hint on what type to unify the stack
6362 if (type.IsInterface && true_expr is EmptyCast && false_expr is EmptyCast) {
6363 var temp = ec.GetTemporaryLocal (type);
6364 ec.Emit (OpCodes.Stloc, temp);
6365 ec.Emit (OpCodes.Ldloc, temp);
6366 ec.FreeTemporaryLocal (temp, type);
6369 ec.Emit (OpCodes.Br, end_target);
6370 ec.MarkLabel (false_target);
6371 false_expr.Emit (ec);
6372 ec.MarkLabel (end_target);
6375 public override void FlowAnalysis (FlowAnalysisContext fc)
6377 expr.FlowAnalysisConditional (fc);
6378 var expr_true = fc.DefiniteAssignmentOnTrue;
6379 var expr_false = fc.DefiniteAssignmentOnFalse;
6381 fc.BranchDefiniteAssignment (expr_true);
6382 true_expr.FlowAnalysis (fc);
6383 var true_fc = fc.DefiniteAssignment;
6385 fc.BranchDefiniteAssignment (expr_false);
6386 false_expr.FlowAnalysis (fc);
6388 fc.DefiniteAssignment &= true_fc;
6391 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
6393 expr.FlowAnalysisConditional (fc);
6394 var expr_true = fc.DefiniteAssignmentOnTrue;
6395 var expr_false = fc.DefiniteAssignmentOnFalse;
6397 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_true);
6398 true_expr.FlowAnalysisConditional (fc);
6399 var true_fc = fc.DefiniteAssignment;
6400 var true_da_true = fc.DefiniteAssignmentOnTrue;
6401 var true_da_false = fc.DefiniteAssignmentOnFalse;
6403 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment = new DefiniteAssignmentBitSet (expr_false);
6404 false_expr.FlowAnalysisConditional (fc);
6406 fc.DefiniteAssignment &= true_fc;
6407 fc.DefiniteAssignmentOnTrue = true_da_true & fc.DefiniteAssignmentOnTrue;
6408 fc.DefiniteAssignmentOnFalse = true_da_false & fc.DefiniteAssignmentOnFalse;
6411 protected override void CloneTo (CloneContext clonectx, Expression t)
6413 Conditional target = (Conditional) t;
6415 target.expr = expr.Clone (clonectx);
6416 target.true_expr = true_expr.Clone (clonectx);
6417 target.false_expr = false_expr.Clone (clonectx);
6421 public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference
6423 LocalTemporary temp;
6426 public abstract HoistedVariable GetHoistedVariable (AnonymousExpression ae);
6427 public abstract void SetHasAddressTaken ();
6429 public abstract bool IsLockedByStatement { get; set; }
6431 public abstract bool IsFixed { get; }
6432 public abstract bool IsRef { get; }
6433 public abstract string Name { get; }
6436 // Variable IL data, it has to be protected to encapsulate hoisted variables
6438 protected abstract ILocalVariable Variable { get; }
6441 // Variable flow-analysis data
6443 public abstract VariableInfo VariableInfo { get; }
6446 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6448 HoistedVariable hv = GetHoistedVariable (ec);
6450 hv.AddressOf (ec, mode);
6454 Variable.EmitAddressOf (ec);
6457 public override bool ContainsEmitWithAwait ()
6462 public override Expression CreateExpressionTree (ResolveContext ec)
6464 HoistedVariable hv = GetHoistedVariable (ec);
6466 return hv.CreateExpressionTree ();
6468 Arguments arg = new Arguments (1);
6469 arg.Add (new Argument (this));
6470 return CreateExpressionFactoryCall (ec, "Constant", arg);
6473 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
6475 if (IsLockedByStatement) {
6476 rc.Report.Warning (728, 2, loc,
6477 "Possibly incorrect assignment to `{0}' which is the argument to a using or lock statement",
6484 public override void Emit (EmitContext ec)
6489 public override void EmitSideEffect (EmitContext ec)
6495 // This method is used by parameters that are references, that are
6496 // being passed as references: we only want to pass the pointer (that
6497 // is already stored in the parameter, not the address of the pointer,
6498 // and not the value of the variable).
6500 public void EmitLoad (EmitContext ec)
6505 public void Emit (EmitContext ec, bool leave_copy)
6507 HoistedVariable hv = GetHoistedVariable (ec);
6509 hv.Emit (ec, leave_copy);
6517 // If we are a reference, we loaded on the stack a pointer
6518 // Now lets load the real value
6520 ec.EmitLoadFromPtr (type);
6524 ec.Emit (OpCodes.Dup);
6527 temp = new LocalTemporary (Type);
6533 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
6534 bool prepare_for_load)
6536 HoistedVariable hv = GetHoistedVariable (ec);
6538 hv.EmitAssign (ec, source, leave_copy, prepare_for_load);
6542 New n_source = source as New;
6543 if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
6544 if (!n_source.Emit (ec, this)) {
6548 ec.EmitLoadFromPtr (type);
6560 ec.Emit (OpCodes.Dup);
6562 temp = new LocalTemporary (Type);
6568 ec.EmitStoreFromPtr (type);
6570 Variable.EmitAssign (ec);
6578 public override Expression EmitToField (EmitContext ec)
6580 HoistedVariable hv = GetHoistedVariable (ec);
6582 return hv.EmitToField (ec);
6585 return base.EmitToField (ec);
6588 public HoistedVariable GetHoistedVariable (ResolveContext rc)
6590 return GetHoistedVariable (rc.CurrentAnonymousMethod);
6593 public HoistedVariable GetHoistedVariable (EmitContext ec)
6595 return GetHoistedVariable (ec.CurrentAnonymousMethod);
6598 public override string GetSignatureForError ()
6603 public bool IsHoisted {
6604 get { return GetHoistedVariable ((AnonymousExpression) null) != null; }
6609 // Resolved reference to a local variable
6611 public class LocalVariableReference : VariableReference
6613 public LocalVariable local_info;
6615 public LocalVariableReference (LocalVariable li, Location l)
6617 this.local_info = li;
6621 public override VariableInfo VariableInfo {
6622 get { return local_info.VariableInfo; }
6625 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6627 return local_info.HoistedVariant;
6633 // A local variable is always fixed
6635 public override bool IsFixed {
6641 public override bool IsLockedByStatement {
6643 return local_info.IsLocked;
6646 local_info.IsLocked = value;
6650 public override bool IsRef {
6651 get { return false; }
6654 public override string Name {
6655 get { return local_info.Name; }
6660 public override void FlowAnalysis (FlowAnalysisContext fc)
6662 VariableInfo variable_info = VariableInfo;
6663 if (variable_info == null)
6666 if (fc.IsDefinitelyAssigned (variable_info))
6669 fc.Report.Error (165, loc, "Use of unassigned local variable `{0}'", Name);
6670 variable_info.SetAssigned (fc.DefiniteAssignment, true);
6673 public override void SetHasAddressTaken ()
6675 local_info.SetHasAddressTaken ();
6678 void DoResolveBase (ResolveContext ec)
6680 eclass = ExprClass.Variable;
6681 type = local_info.Type;
6684 // If we are referencing a variable from the external block
6685 // flag it for capturing
6687 if (ec.MustCaptureVariable (local_info)) {
6688 if (local_info.AddressTaken) {
6689 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6690 } else if (local_info.IsFixed) {
6691 ec.Report.Error (1764, loc,
6692 "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
6693 GetSignatureForError ());
6696 if (ec.IsVariableCapturingRequired) {
6697 AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
6698 storey.CaptureLocalVariable (ec, local_info);
6703 protected override Expression DoResolve (ResolveContext ec)
6705 local_info.SetIsUsed ();
6709 if (local_info.Type == InternalType.VarOutType) {
6710 ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
6711 GetSignatureForError ());
6713 type = InternalType.ErrorType;
6719 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
6722 // Don't be too pedantic when variable is used as out param or for some broken code
6723 // which uses property/indexer access to run some initialization
6725 if (rhs == EmptyExpression.OutAccess || rhs.eclass == ExprClass.PropertyAccess || rhs.eclass == ExprClass.IndexerAccess)
6726 local_info.SetIsUsed ();
6728 if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
6729 if (rhs == EmptyExpression.LValueMemberAccess) {
6730 // CS1654 already reported
6734 if (rhs == EmptyExpression.OutAccess) {
6735 code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
6736 } else if (rhs == EmptyExpression.LValueMemberOutAccess) {
6737 code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
6738 } else if (rhs == EmptyExpression.UnaryAddress) {
6739 code = 459; msg = "Cannot take the address of {1} `{0}'";
6741 code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
6743 ec.Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
6747 if (eclass == ExprClass.Unresolved)
6750 return base.DoResolveLValue (ec, rhs);
6753 public override int GetHashCode ()
6755 return local_info.GetHashCode ();
6758 public override bool Equals (object obj)
6760 LocalVariableReference lvr = obj as LocalVariableReference;
6764 return local_info == lvr.local_info;
6767 protected override ILocalVariable Variable {
6768 get { return local_info; }
6771 public override string ToString ()
6773 return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
6776 protected override void CloneTo (CloneContext clonectx, Expression t)
6783 /// This represents a reference to a parameter in the intermediate
6786 public class ParameterReference : VariableReference
6788 protected ParametersBlock.ParameterInfo pi;
6790 public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
6798 public override bool IsLockedByStatement {
6803 pi.IsLocked = value;
6807 public override bool IsRef {
6808 get { return (pi.Parameter.ModFlags & Parameter.Modifier.RefOutMask) != 0; }
6811 bool HasOutModifier {
6812 get { return (pi.Parameter.ModFlags & Parameter.Modifier.OUT) != 0; }
6815 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6817 return pi.Parameter.HoistedVariant;
6821 // A ref or out parameter is classified as a moveable variable, even
6822 // if the argument given for the parameter is a fixed variable
6824 public override bool IsFixed {
6825 get { return !IsRef; }
6828 public override string Name {
6829 get { return Parameter.Name; }
6832 public Parameter Parameter {
6833 get { return pi.Parameter; }
6836 public override VariableInfo VariableInfo {
6837 get { return pi.VariableInfo; }
6840 protected override ILocalVariable Variable {
6841 get { return Parameter; }
6846 public override void AddressOf (EmitContext ec, AddressOp mode)
6849 // ParameterReferences might already be a reference
6856 base.AddressOf (ec, mode);
6859 public override void SetHasAddressTaken ()
6861 Parameter.HasAddressTaken = true;
6864 bool DoResolveBase (ResolveContext ec)
6866 if (eclass != ExprClass.Unresolved)
6869 type = pi.ParameterType;
6870 eclass = ExprClass.Variable;
6873 // If we are referencing a parameter from the external block
6874 // flag it for capturing
6876 if (ec.MustCaptureVariable (pi)) {
6877 if (Parameter.HasAddressTaken)
6878 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
6881 ec.Report.Error (1628, loc,
6882 "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
6883 Name, ec.CurrentAnonymousMethod.ContainerType);
6886 if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
6887 AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
6888 storey.CaptureParameter (ec, pi, this);
6895 public override int GetHashCode ()
6897 return Name.GetHashCode ();
6900 public override bool Equals (object obj)
6902 ParameterReference pr = obj as ParameterReference;
6906 return Name == pr.Name;
6909 protected override void CloneTo (CloneContext clonectx, Expression target)
6915 public override Expression CreateExpressionTree (ResolveContext ec)
6917 HoistedVariable hv = GetHoistedVariable (ec);
6919 return hv.CreateExpressionTree ();
6921 return Parameter.ExpressionTreeVariableReference ();
6924 protected override Expression DoResolve (ResolveContext ec)
6926 if (!DoResolveBase (ec))
6932 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6934 if (!DoResolveBase (ec))
6937 if (Parameter.HoistedVariant != null)
6938 Parameter.HoistedVariant.IsAssigned = true;
6940 return base.DoResolveLValue (ec, right_side);
6943 public override void FlowAnalysis (FlowAnalysisContext fc)
6945 VariableInfo variable_info = VariableInfo;
6946 if (variable_info == null)
6949 if (fc.IsDefinitelyAssigned (variable_info))
6952 fc.Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
6953 fc.SetVariableAssigned (variable_info);
6958 /// Invocation of methods or delegates.
6960 public class Invocation : ExpressionStatement
6962 public class Predefined : Invocation
6964 public Predefined (MethodGroupExpr expr, Arguments arguments)
6965 : base (expr, arguments)
6970 protected override MethodGroupExpr DoResolveOverload (ResolveContext rc)
6972 mg.BestCandidate.CheckObsoleteness (rc, loc);
6978 protected Arguments arguments;
6979 protected Expression expr;
6980 protected MethodGroupExpr mg;
6981 bool conditional_access_receiver;
6983 public Invocation (Expression expr, Arguments arguments)
6986 this.arguments = arguments;
6988 loc = expr.Location;
6993 public Arguments Arguments {
6999 public Expression Exp {
7005 public MethodGroupExpr MethodGroup {
7011 public override Location StartLocation {
7013 return expr.StartLocation;
7019 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
7021 if (MethodGroup == null)
7024 var candidate = MethodGroup.BestCandidate;
7025 if (candidate == null || !(candidate.IsStatic || Exp is This))
7028 var args_count = arguments == null ? 0 : arguments.Count;
7029 if (args_count != body.Parameters.Count)
7032 var lambda_parameters = body.Block.Parameters.FixedParameters;
7033 for (int i = 0; i < args_count; ++i) {
7034 var pr = arguments[i].Expr as ParameterReference;
7038 if (lambda_parameters[i] != pr.Parameter)
7041 if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
7045 var emg = MethodGroup as ExtensionMethodGroupExpr;
7047 var mg = MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
7048 if (candidate.IsGeneric) {
7049 var targs = new TypeExpression [candidate.Arity];
7050 for (int i = 0; i < targs.Length; ++i) {
7051 targs[i] = new TypeExpression (candidate.TypeArguments[i], MethodGroup.Location);
7054 mg.SetTypeArguments (null, new TypeArguments (targs));
7063 protected override void CloneTo (CloneContext clonectx, Expression t)
7065 Invocation target = (Invocation) t;
7067 if (arguments != null)
7068 target.arguments = arguments.Clone (clonectx);
7070 target.expr = expr.Clone (clonectx);
7073 public override bool ContainsEmitWithAwait ()
7075 if (arguments != null && arguments.ContainsEmitWithAwait ())
7078 return mg.ContainsEmitWithAwait ();
7081 public override Expression CreateExpressionTree (ResolveContext ec)
7083 Expression instance = mg.IsInstance ?
7084 mg.InstanceExpression.CreateExpressionTree (ec) :
7085 new NullLiteral (loc);
7087 var args = Arguments.CreateForExpressionTree (ec, arguments,
7089 mg.CreateExpressionTree (ec));
7091 return CreateExpressionFactoryCall (ec, "Call", args);
7094 void ResolveConditionalAccessReceiver (ResolveContext rc)
7096 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && expr.HasConditionalAccess ()) {
7097 conditional_access_receiver = true;
7101 bool statement_resolve;
7102 public override ExpressionStatement ResolveStatement (BlockContext bc)
7104 statement_resolve = true;
7105 var es = base.ResolveStatement (bc);
7106 statement_resolve = false;
7111 protected override Expression DoResolve (ResolveContext rc)
7113 ResolveConditionalAccessReceiver (rc);
7114 return DoResolveInvocation (rc);
7117 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7119 var sn = expr as SimpleName;
7120 if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
7121 var targets = new List<Expression> (arguments.Count);
7122 var variables = new List<LocalVariable> (arguments.Count);
7123 foreach (var arg in arguments) {
7124 var arg_sn = arg.Expr as SimpleName;
7125 if (arg_sn == null || arg_sn.Arity != 0) {
7126 rc.Report.Error (8199, loc, "The syntax `var (...)' as an lvalue is reserved");
7127 return ErrorExpression.Instance;
7130 var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
7131 rc.CurrentBlock.AddLocalName (lv);
7134 targets.Add (new LocalVariableReference (lv, arg_sn.Location));
7137 var res = new TupleDeconstruct (targets, variables, right_side, loc);
7138 return res.Resolve (rc);
7141 return base.DoResolveLValue (rc, right_side);
7144 Expression DoResolveInvocation (ResolveContext ec)
7146 Expression member_expr;
7147 var atn = expr as ATypeNameExpression;
7149 var flags = default (ResolveContext.FlagsHandle);
7150 if (conditional_access_receiver)
7151 flags = ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
7154 member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
7155 if (member_expr != null) {
7156 var name_of = member_expr as NameOf;
7157 if (name_of != null) {
7158 return name_of.ResolveOverload (ec, arguments);
7161 member_expr = member_expr.Resolve (ec);
7164 member_expr = expr.Resolve (ec);
7167 if (conditional_access_receiver)
7170 if (member_expr == null)
7174 // Next, evaluate all the expressions in the argument list
7176 bool dynamic_arg = false;
7177 if (arguments != null) {
7178 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
7179 arguments.Resolve (ec, out dynamic_arg);
7183 TypeSpec expr_type = member_expr.Type;
7184 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
7185 return DoResolveDynamic (ec, member_expr);
7187 mg = member_expr as MethodGroupExpr;
7188 Expression invoke = null;
7191 if (expr_type != null && expr_type.IsDelegate) {
7192 invoke = new DelegateInvocation (member_expr, arguments, conditional_access_receiver, loc);
7193 invoke = invoke.Resolve (ec);
7194 if (invoke == null || !dynamic_arg)
7197 if (member_expr is RuntimeValueExpression) {
7198 ec.Report.Error (Report.RuntimeErrorId, loc, "Cannot invoke a non-delegate type `{0}'",
7199 member_expr.Type.GetSignatureForError ());
7203 MemberExpr me = member_expr as MemberExpr;
7205 member_expr.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
7209 ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
7210 member_expr.GetSignatureForError ());
7215 if (invoke == null) {
7216 mg = DoResolveOverload (ec);
7222 return DoResolveDynamic (ec, member_expr);
7224 var method = mg.BestCandidate;
7225 type = mg.BestCandidateReturnType;
7226 if (conditional_access_receiver && !statement_resolve)
7227 type = LiftMemberType (ec, type);
7229 if (arguments == null && method.DeclaringType.BuiltinType == BuiltinTypeSpec.Type.Object && method.Name == Destructor.MetadataName) {
7231 ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
7233 ec.Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
7237 IsSpecialMethodInvocation (ec, method, loc);
7239 eclass = ExprClass.Value;
7243 protected virtual Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr)
7246 DynamicMemberBinder dmb = memberExpr as DynamicMemberBinder;
7248 args = dmb.Arguments;
7249 if (arguments != null)
7250 args.AddRange (arguments);
7251 } else if (mg == null) {
7252 if (arguments == null)
7253 args = new Arguments (1);
7257 args.Insert (0, new Argument (memberExpr));
7261 ec.Report.Error (1971, loc,
7262 "The base call to method `{0}' cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access",
7267 if (arguments == null)
7268 args = new Arguments (1);
7272 MemberAccess ma = expr as MemberAccess;
7274 var inst = mg.InstanceExpression;
7275 var left_type = inst as TypeExpr;
7276 if (left_type != null) {
7277 args.Insert (0, new Argument (new TypeOf (left_type.Type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7278 } else if (inst != null) {
7280 // Any value type has to be pass as by-ref to get back the same
7281 // instance on which the member was called
7283 var mod = inst is IMemoryLocation && TypeSpec.IsValueType (inst.Type) ?
7284 Argument.AType.Ref : Argument.AType.None;
7285 args.Insert (0, new Argument (inst.Resolve (ec), mod));
7287 } else { // is SimpleName
7288 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer)) {
7289 args.Insert (0, new Argument (new TypeOf (ec.CurrentType, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7291 args.Insert (0, new Argument (new This (loc).Resolve (ec)));
7296 return new DynamicInvocation (expr as ATypeNameExpression, args, conditional_access_receiver, loc).Resolve (ec);
7299 protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
7301 return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
7304 public override void FlowAnalysis (FlowAnalysisContext fc)
7306 if (mg.IsConditionallyExcluded)
7309 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7311 mg.FlowAnalysis (fc);
7313 if (arguments != null)
7314 arguments.FlowAnalysis (fc);
7316 if (conditional_access_receiver)
7317 fc.DefiniteAssignment = da;
7320 public override string GetSignatureForError ()
7322 return mg.GetSignatureForError ();
7325 public override bool HasConditionalAccess ()
7327 return expr.HasConditionalAccess ();
7331 // If a member is a method or event, or if it is a constant, field or property of either a delegate type
7332 // or the type dynamic, then the member is invocable
7334 public static bool IsMemberInvocable (MemberSpec member)
7336 switch (member.Kind) {
7337 case MemberKind.Event:
7339 case MemberKind.Field:
7340 case MemberKind.Property:
7341 var m = member as IInterfaceMemberSpec;
7342 return m.MemberType.IsDelegate || m.MemberType.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
7348 public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
7350 if (!method.IsReservedMethod)
7353 if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
7356 ec.Report.SymbolRelatedToPreviousError (method);
7357 ec.Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
7358 method.GetSignatureForError ());
7363 public override void Emit (EmitContext ec)
7365 if (mg.IsConditionallyExcluded)
7368 if (conditional_access_receiver)
7369 mg.EmitCall (ec, arguments, type, false);
7371 mg.EmitCall (ec, arguments, false);
7374 public override void EmitStatement (EmitContext ec)
7376 if (mg.IsConditionallyExcluded)
7379 if (conditional_access_receiver)
7380 mg.EmitCall (ec, arguments, type, true);
7382 mg.EmitCall (ec, arguments, true);
7385 public override SLE.Expression MakeExpression (BuilderContext ctx)
7387 return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
7390 public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
7393 throw new NotSupportedException ();
7395 var instance_expr = instance == null ? null : instance.MakeExpression (ctx);
7396 return SLE.Expression.Call (instance_expr, (MethodInfo) mi.GetMetaInfo (), Arguments.MakeExpression (args, ctx));
7400 public override object Accept (StructuralVisitor visitor)
7402 return visitor.Visit (this);
7407 // Implements simple new expression
7409 public class New : ExpressionStatement, IMemoryLocation
7411 protected Arguments arguments;
7414 // During bootstrap, it contains the RequestedType,
7415 // but if `type' is not null, it *might* contain a NewDelegate
7416 // (because of field multi-initialization)
7418 protected Expression RequestedType;
7420 protected MethodSpec method;
7422 public New (Expression requested_type, Arguments arguments, Location l)
7424 RequestedType = requested_type;
7425 this.arguments = arguments;
7430 public Arguments Arguments {
7437 // Returns true for resolved `new S()' when S does not declare parameterless constructor
7439 public bool IsGeneratedStructConstructor {
7441 return arguments == null && method == null && type.IsStruct && GetType () == typeof (New);
7445 public Expression TypeExpression {
7447 return RequestedType;
7454 /// Converts complex core type syntax like 'new int ()' to simple constant
7456 public static Constant Constantify (TypeSpec t, Location loc)
7458 switch (t.BuiltinType) {
7459 case BuiltinTypeSpec.Type.Int:
7460 return new IntConstant (t, 0, loc);
7461 case BuiltinTypeSpec.Type.UInt:
7462 return new UIntConstant (t, 0, loc);
7463 case BuiltinTypeSpec.Type.Long:
7464 return new LongConstant (t, 0, loc);
7465 case BuiltinTypeSpec.Type.ULong:
7466 return new ULongConstant (t, 0, loc);
7467 case BuiltinTypeSpec.Type.Float:
7468 return new FloatConstant (t, 0, loc);
7469 case BuiltinTypeSpec.Type.Double:
7470 return new DoubleConstant (t, 0, loc);
7471 case BuiltinTypeSpec.Type.Short:
7472 return new ShortConstant (t, 0, loc);
7473 case BuiltinTypeSpec.Type.UShort:
7474 return new UShortConstant (t, 0, loc);
7475 case BuiltinTypeSpec.Type.SByte:
7476 return new SByteConstant (t, 0, loc);
7477 case BuiltinTypeSpec.Type.Byte:
7478 return new ByteConstant (t, 0, loc);
7479 case BuiltinTypeSpec.Type.Char:
7480 return new CharConstant (t, '\0', loc);
7481 case BuiltinTypeSpec.Type.Bool:
7482 return new BoolConstant (t, false, loc);
7483 case BuiltinTypeSpec.Type.Decimal:
7484 return new DecimalConstant (t, 0, loc);
7488 return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
7490 if (t.IsNullableType)
7491 return Nullable.LiftedNull.Create (t, loc);
7496 public override bool ContainsEmitWithAwait ()
7498 return arguments != null && arguments.ContainsEmitWithAwait ();
7502 // Checks whether the type is an interface that has the
7503 // [ComImport, CoClass] attributes and must be treated
7506 public Expression CheckComImport (ResolveContext ec)
7508 if (!type.IsInterface)
7512 // Turn the call into:
7513 // (the-interface-stated) (new class-referenced-in-coclassattribute ())
7515 var real_class = type.MemberDefinition.GetAttributeCoClass ();
7516 if (real_class == null)
7519 New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
7520 Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
7521 return cast.Resolve (ec);
7524 public override Expression CreateExpressionTree (ResolveContext ec)
7527 if (method == null) {
7528 args = new Arguments (1);
7529 args.Add (new Argument (new TypeOf (type, loc)));
7531 args = Arguments.CreateForExpressionTree (ec,
7532 arguments, new TypeOfMethod (method, loc));
7535 return CreateExpressionFactoryCall (ec, "New", args);
7538 protected override Expression DoResolve (ResolveContext ec)
7540 if (RequestedType is TupleTypeExpr) {
7541 ec.Report.Error (8181, loc, "Tuple type cannot be used in an object creation expression. Use a tuple literal expression instead.");
7544 type = RequestedType.ResolveAsType (ec);
7548 eclass = ExprClass.Value;
7550 if (type.IsPointer) {
7551 ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
7552 type.GetSignatureForError ());
7556 if (arguments == null) {
7557 Constant c = Constantify (type, RequestedType.Location);
7559 return ReducedExpression.Create (c, this);
7562 if (type.IsDelegate) {
7563 return (new NewDelegate (type, arguments, loc)).Resolve (ec);
7566 var tparam = type as TypeParameterSpec;
7567 if (tparam != null) {
7569 // Check whether the type of type parameter can be constructed. BaseType can be a struct for method overrides
7570 // where type parameter constraint is inflated to struct
7572 if ((tparam.SpecialConstraint & (SpecialConstraint.Struct | SpecialConstraint.Constructor)) == 0 && !TypeSpec.IsValueType (tparam)) {
7573 ec.Report.Error (304, loc,
7574 "Cannot create an instance of the variable type `{0}' because it does not have the new() constraint",
7575 type.GetSignatureForError ());
7578 if ((arguments != null) && (arguments.Count != 0)) {
7579 ec.Report.Error (417, loc,
7580 "`{0}': cannot provide arguments when creating an instance of a variable type",
7581 type.GetSignatureForError ());
7587 if (type.IsStatic) {
7588 ec.Report.SymbolRelatedToPreviousError (type);
7589 ec.Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", type.GetSignatureForError ());
7593 if (type.IsInterface || type.IsAbstract){
7594 if (!TypeManager.IsGenericType (type)) {
7595 RequestedType = CheckComImport (ec);
7596 if (RequestedType != null)
7597 return RequestedType;
7600 ec.Report.SymbolRelatedToPreviousError (type);
7601 ec.Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", type.GetSignatureForError ());
7606 if (arguments != null) {
7607 arguments.Resolve (ec, out dynamic);
7612 method = ConstructorLookup (ec, type, ref arguments, loc);
7615 arguments.Insert (0, new Argument (new TypeOf (type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
7616 return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
7622 void DoEmitTypeParameter (EmitContext ec)
7624 var m = ec.Module.PredefinedMembers.ActivatorCreateInstance.Resolve (loc);
7628 var ctor_factory = m.MakeGenericMethod (ec.MemberContext, type);
7629 ec.Emit (OpCodes.Call, ctor_factory);
7633 // This Emit can be invoked in two contexts:
7634 // * As a mechanism that will leave a value on the stack (new object)
7635 // * As one that wont (init struct)
7637 // If we are dealing with a ValueType, we have a few
7638 // situations to deal with:
7640 // * The target is a ValueType, and we have been provided
7641 // the instance (this is easy, we are being assigned).
7643 // * The target of New is being passed as an argument,
7644 // to a boxing operation or a function that takes a
7647 // In this case, we need to create a temporary variable
7648 // that is the argument of New.
7650 // Returns whether a value is left on the stack
7652 // *** Implementation note ***
7654 // To benefit from this optimization, each assignable expression
7655 // has to manually cast to New and call this Emit.
7657 // TODO: It's worth to implement it for arrays and fields
7659 public virtual bool Emit (EmitContext ec, IMemoryLocation target)
7661 bool is_value_type = type.IsStructOrEnum;
7662 VariableReference vr = target as VariableReference;
7664 bool prepare_await = ec.HasSet (BuilderContext.Options.AsyncBody) && arguments?.ContainsEmitWithAwait () == true;
7666 if (target != null && is_value_type && (vr != null || method == null)) {
7667 if (prepare_await) {
7668 arguments = arguments.Emit (ec, false, true);
7669 prepare_await = false;
7672 target.AddressOf (ec, AddressOp.Store);
7673 } else if (vr != null && vr.IsRef) {
7677 if (arguments != null) {
7679 arguments = arguments.Emit (ec, false, true);
7681 arguments.Emit (ec);
7684 if (is_value_type) {
7685 if (method == null) {
7686 ec.Emit (OpCodes.Initobj, type);
7691 ec.MarkCallEntry (loc);
7692 ec.Emit (OpCodes.Call, method);
7697 if (type is TypeParameterSpec) {
7698 DoEmitTypeParameter (ec);
7702 ec.MarkCallEntry (loc);
7703 ec.Emit (OpCodes.Newobj, method);
7707 public override void Emit (EmitContext ec)
7709 LocalTemporary v = null;
7710 if (method == null && type.IsStructOrEnum) {
7711 // TODO: Use temporary variable from pool
7712 v = new LocalTemporary (type);
7719 public override void EmitStatement (EmitContext ec)
7721 LocalTemporary v = null;
7722 if (method == null && TypeSpec.IsValueType (type)) {
7723 // TODO: Use temporary variable from pool
7724 v = new LocalTemporary (type);
7728 ec.Emit (OpCodes.Pop);
7731 public virtual bool CanEmitOptimizedLocalTarget (EmitContext ec)
7736 public override void FlowAnalysis (FlowAnalysisContext fc)
7738 if (arguments != null)
7739 arguments.FlowAnalysis (fc);
7742 public void AddressOf (EmitContext ec, AddressOp mode)
7744 EmitAddressOf (ec, mode);
7747 protected virtual IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp mode)
7749 LocalTemporary value_target = new LocalTemporary (type);
7751 if (type is TypeParameterSpec) {
7752 DoEmitTypeParameter (ec);
7753 value_target.Store (ec);
7754 value_target.AddressOf (ec, mode);
7755 return value_target;
7758 value_target.AddressOf (ec, AddressOp.Store);
7760 if (method == null) {
7761 ec.Emit (OpCodes.Initobj, type);
7763 if (arguments != null)
7764 arguments.Emit (ec);
7766 ec.Emit (OpCodes.Call, method);
7769 value_target.AddressOf (ec, mode);
7770 return value_target;
7773 protected override void CloneTo (CloneContext clonectx, Expression t)
7775 New target = (New) t;
7777 target.RequestedType = RequestedType.Clone (clonectx);
7778 if (arguments != null){
7779 target.arguments = arguments.Clone (clonectx);
7783 public override SLE.Expression MakeExpression (BuilderContext ctx)
7786 return base.MakeExpression (ctx);
7788 return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
7792 public override object Accept (StructuralVisitor visitor)
7794 return visitor.Visit (this);
7799 // Array initializer expression, the expression is allowed in
7800 // variable or field initialization only which makes it tricky as
7801 // the type has to be infered based on the context either from field
7802 // type or variable type (think of multiple declarators)
7804 public class ArrayInitializer : Expression
7806 List<Expression> elements;
7807 BlockVariable variable;
7809 public ArrayInitializer (List<Expression> init, Location loc)
7815 public ArrayInitializer (int count, Location loc)
7816 : this (new List<Expression> (count), loc)
7820 public ArrayInitializer (Location loc)
7828 get { return elements.Count; }
7831 public List<Expression> Elements {
7837 public Expression this [int index] {
7839 return elements [index];
7843 public BlockVariable VariableDeclaration {
7854 public void Add (Expression expr)
7856 elements.Add (expr);
7859 public override bool ContainsEmitWithAwait ()
7861 throw new NotSupportedException ();
7864 public override Expression CreateExpressionTree (ResolveContext ec)
7866 throw new NotSupportedException ("ET");
7869 protected override void CloneTo (CloneContext clonectx, Expression t)
7871 var target = (ArrayInitializer) t;
7873 target.elements = new List<Expression> (elements.Count);
7874 foreach (var element in elements)
7875 target.elements.Add (element.Clone (clonectx));
7878 protected override Expression DoResolve (ResolveContext rc)
7880 var current_field = rc.CurrentMemberDefinition as FieldBase;
7881 TypeExpression type;
7882 if (current_field != null && rc.CurrentAnonymousMethod == null) {
7883 type = new TypeExpression (current_field.MemberType, current_field.Location);
7884 } else if (variable != null) {
7885 if (variable.TypeExpression is VarExpr) {
7886 rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
7887 return EmptyExpression.Null;
7890 type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
7892 throw new NotImplementedException ("Unexpected array initializer context");
7895 return new ArrayCreation (type, this).Resolve (rc);
7898 public override void Emit (EmitContext ec)
7900 throw new InternalErrorException ("Missing Resolve call");
7903 public override void FlowAnalysis (FlowAnalysisContext fc)
7905 throw new InternalErrorException ("Missing Resolve call");
7908 public override object Accept (StructuralVisitor visitor)
7910 return visitor.Visit (this);
7915 /// 14.5.10.2: Represents an array creation expression.
7919 /// There are two possible scenarios here: one is an array creation
7920 /// expression that specifies the dimensions and optionally the
7921 /// initialization data and the other which does not need dimensions
7922 /// specified but where initialization data is mandatory.
7924 public class ArrayCreation : Expression
7926 FullNamedExpression requested_base_type;
7927 ArrayInitializer initializers;
7930 // The list of Argument types.
7931 // This is used to construct the `newarray' or constructor signature
7933 protected List<Expression> arguments;
7935 protected TypeSpec array_element_type;
7937 protected int dimensions;
7938 protected readonly ComposedTypeSpecifier rank;
7939 Expression first_emit;
7940 LocalTemporary first_emit_temp;
7942 protected List<Expression> array_data;
7944 Dictionary<int, int> bounds;
7947 // The number of constants in array initializers
7948 int const_initializers_count;
7949 bool only_constant_initializers;
7951 public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
7952 : this (requested_base_type, rank, initializers, l)
7954 arguments = new List<Expression> (exprs);
7955 num_arguments = arguments.Count;
7959 // For expressions like int[] foo = new int[] { 1, 2, 3 };
7961 public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
7963 this.requested_base_type = requested_base_type;
7965 this.initializers = initializers;
7969 num_arguments = rank.Dimension;
7973 // For compiler generated single dimensional arrays only
7975 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
7976 : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
7981 // For expressions like int[] foo = { 1, 2, 3 };
7983 public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
7984 : this (requested_base_type, null, initializers, initializers.Location)
7988 public bool NoEmptyInterpolation { get; set; }
7990 public ComposedTypeSpecifier Rank {
7996 public FullNamedExpression TypeExpression {
7998 return this.requested_base_type;
8002 public ArrayInitializer Initializers {
8004 return this.initializers;
8008 bool CheckIndices (ResolveContext ec, ArrayInitializer probe, int idx, bool specified_dims, int child_bounds)
8010 if (initializers != null && bounds == null) {
8012 // We use this to store all the data values in the order in which we
8013 // will need to store them in the byte blob later
8015 array_data = new List<Expression> (probe.Count);
8016 bounds = new Dictionary<int, int> ();
8019 if (specified_dims) {
8020 Expression a = arguments [idx];
8025 a = ConvertExpressionToArrayIndex (ec, a);
8031 if (initializers != null) {
8032 Constant c = a as Constant;
8033 if (c == null && a is ArrayIndexCast)
8034 c = ((ArrayIndexCast) a).Child as Constant;
8037 ec.Report.Error (150, a.Location, "A constant value is expected");
8043 value = System.Convert.ToInt32 (c.GetValue ());
8045 ec.Report.Error (150, a.Location, "A constant value is expected");
8049 // TODO: probe.Count does not fit ulong in
8050 if (value != probe.Count) {
8051 ec.Report.Error (847, loc, "An array initializer of length `{0}' was expected", value.ToString ());
8055 bounds[idx] = value;
8059 if (initializers == null)
8062 for (int i = 0; i < probe.Count; ++i) {
8064 if (o is ArrayInitializer) {
8065 var sub_probe = o as ArrayInitializer;
8066 if (idx + 1 >= dimensions){
8067 ec.Report.Error (623, loc, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
8071 // When we don't have explicitly specified dimensions, record whatever dimension we first encounter at each level
8072 if (!bounds.ContainsKey(idx + 1))
8073 bounds[idx + 1] = sub_probe.Count;
8075 if (bounds[idx + 1] != sub_probe.Count) {
8076 ec.Report.Error(847, sub_probe.Location, "An array initializer of length `{0}' was expected", bounds[idx + 1].ToString());
8080 bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims, child_bounds - 1);
8083 } else if (child_bounds > 1) {
8084 ec.Report.Error (846, o.Location, "A nested array initializer was expected");
8086 Expression element = ResolveArrayElement (ec, o);
8087 if (element == null)
8090 // Initializers with the default values can be ignored
8091 Constant c = element as Constant;
8093 if (!c.IsDefaultInitializer (array_element_type)) {
8094 ++const_initializers_count;
8097 only_constant_initializers = false;
8100 array_data.Add (element);
8107 public override bool ContainsEmitWithAwait ()
8109 foreach (var arg in arguments) {
8110 if (arg.ContainsEmitWithAwait ())
8114 return InitializersContainAwait ();
8117 public override Expression CreateExpressionTree (ResolveContext ec)
8121 if (array_data == null) {
8122 args = new Arguments (arguments.Count + 1);
8123 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8124 foreach (Expression a in arguments)
8125 args.Add (new Argument (a.CreateExpressionTree (ec)));
8127 return CreateExpressionFactoryCall (ec, "NewArrayBounds", args);
8130 if (dimensions > 1) {
8131 ec.Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
8135 args = new Arguments (array_data == null ? 1 : array_data.Count + 1);
8136 args.Add (new Argument (new TypeOf (array_element_type, loc)));
8137 if (array_data != null) {
8138 for (int i = 0; i < array_data.Count; ++i) {
8139 Expression e = array_data [i];
8140 args.Add (new Argument (e.CreateExpressionTree (ec)));
8144 return CreateExpressionFactoryCall (ec, "NewArrayInit", args);
8147 void UpdateIndices (ResolveContext rc)
8150 for (var probe = initializers; probe != null;) {
8151 Expression e = new IntConstant (rc.BuiltinTypes, probe.Count, Location.Null);
8153 bounds[i++] = probe.Count;
8155 if (probe.Count > 0 && probe [0] is ArrayInitializer) {
8156 probe = (ArrayInitializer) probe[0];
8157 } else if (dimensions > i) {
8165 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
8167 ec.Report.Error (248, loc, "Cannot create an array with a negative size");
8170 public override void FlowAnalysis (FlowAnalysisContext fc)
8172 foreach (var arg in arguments)
8173 arg.FlowAnalysis (fc);
8175 if (array_data != null) {
8176 foreach (var ad in array_data)
8177 ad.FlowAnalysis (fc);
8181 bool InitializersContainAwait ()
8183 if (array_data == null)
8186 foreach (var expr in array_data) {
8187 if (expr.ContainsEmitWithAwait ())
8194 protected virtual Expression ResolveArrayElement (ResolveContext ec, Expression element)
8196 element = element.Resolve (ec);
8197 if (element == null)
8200 var te = element as CompoundAssign.TargetExpression;
8202 for (int i = 1; i < initializers.Count; ++i) {
8203 if (initializers [i].ContainsEmitWithAwait ()) {
8204 te.RequiresEmitWithAwait = true;
8209 if (!te.RequiresEmitWithAwait) {
8210 if (first_emit != null)
8211 throw new InternalErrorException ("Can only handle one mutator at a time");
8212 first_emit = element;
8213 element = first_emit_temp = new LocalTemporary (element.Type);
8217 return Convert.ImplicitConversionRequired (
8218 ec, element, array_element_type, loc);
8221 protected bool ResolveInitializers (ResolveContext ec)
8224 only_constant_initializers = true;
8227 if (arguments != null) {
8229 for (int i = 0; i < arguments.Count; ++i) {
8230 res &= CheckIndices (ec, initializers, i, true, dimensions);
8231 if (initializers != null)
8238 arguments = new List<Expression> ();
8240 if (!CheckIndices (ec, initializers, 0, false, dimensions))
8249 // Resolved the type of the array
8251 bool ResolveArrayType (ResolveContext ec)
8256 FullNamedExpression array_type_expr;
8257 if (num_arguments > 0) {
8258 array_type_expr = new ComposedCast (requested_base_type, rank);
8260 array_type_expr = requested_base_type;
8263 type = array_type_expr.ResolveAsType (ec);
8264 if (array_type_expr == null)
8267 var ac = type as ArrayContainer;
8269 ec.Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
8273 array_element_type = ac.Element;
8274 dimensions = ac.Rank;
8279 protected override Expression DoResolve (ResolveContext ec)
8284 if (!ResolveArrayType (ec))
8288 // validate the initializers and fill in any missing bits
8290 if (!ResolveInitializers (ec))
8293 eclass = ExprClass.Value;
8297 byte [] MakeByteBlob ()
8302 int count = array_data.Count;
8304 TypeSpec element_type = array_element_type;
8305 if (element_type.IsEnum)
8306 element_type = EnumSpec.GetUnderlyingType (element_type);
8308 factor = BuiltinTypeSpec.GetSize (element_type);
8310 throw new Exception ("unrecognized type in MakeByteBlob: " + element_type);
8312 data = new byte [(count * factor + 3) & ~3];
8315 for (int i = 0; i < count; ++i) {
8316 var c = array_data[i] as Constant;
8322 object v = c.GetValue ();
8324 switch (element_type.BuiltinType) {
8325 case BuiltinTypeSpec.Type.Long:
8326 long lval = (long) v;
8328 for (int j = 0; j < factor; ++j) {
8329 data[idx + j] = (byte) (lval & 0xFF);
8333 case BuiltinTypeSpec.Type.ULong:
8334 ulong ulval = (ulong) v;
8336 for (int j = 0; j < factor; ++j) {
8337 data[idx + j] = (byte) (ulval & 0xFF);
8338 ulval = (ulval >> 8);
8341 case BuiltinTypeSpec.Type.Float:
8342 var fval = SingleConverter.SingleToInt32Bits((float) v);
8344 data[idx] = (byte) (fval & 0xff);
8345 data[idx + 1] = (byte) ((fval >> 8) & 0xff);
8346 data[idx + 2] = (byte) ((fval >> 16) & 0xff);
8347 data[idx + 3] = (byte) (fval >> 24);
8349 case BuiltinTypeSpec.Type.Double:
8350 element = BitConverter.GetBytes ((double) v);
8352 for (int j = 0; j < factor; ++j)
8353 data[idx + j] = element[j];
8355 // FIXME: Handle the ARM float format.
8356 if (!BitConverter.IsLittleEndian)
8357 System.Array.Reverse (data, idx, 8);
8359 case BuiltinTypeSpec.Type.Char:
8360 int chval = (int) ((char) v);
8362 data[idx] = (byte) (chval & 0xff);
8363 data[idx + 1] = (byte) (chval >> 8);
8365 case BuiltinTypeSpec.Type.Short:
8366 int sval = (int) ((short) v);
8368 data[idx] = (byte) (sval & 0xff);
8369 data[idx + 1] = (byte) (sval >> 8);
8371 case BuiltinTypeSpec.Type.UShort:
8372 int usval = (int) ((ushort) v);
8374 data[idx] = (byte) (usval & 0xff);
8375 data[idx + 1] = (byte) (usval >> 8);
8377 case BuiltinTypeSpec.Type.Int:
8380 data[idx] = (byte) (val & 0xff);
8381 data[idx + 1] = (byte) ((val >> 8) & 0xff);
8382 data[idx + 2] = (byte) ((val >> 16) & 0xff);
8383 data[idx + 3] = (byte) (val >> 24);
8385 case BuiltinTypeSpec.Type.UInt:
8386 uint uval = (uint) v;
8388 data[idx] = (byte) (uval & 0xff);
8389 data[idx + 1] = (byte) ((uval >> 8) & 0xff);
8390 data[idx + 2] = (byte) ((uval >> 16) & 0xff);
8391 data[idx + 3] = (byte) (uval >> 24);
8393 case BuiltinTypeSpec.Type.SByte:
8394 data[idx] = (byte) (sbyte) v;
8396 case BuiltinTypeSpec.Type.Byte:
8397 data[idx] = (byte) v;
8399 case BuiltinTypeSpec.Type.Bool:
8400 data[idx] = (byte) ((bool) v ? 1 : 0);
8402 case BuiltinTypeSpec.Type.Decimal:
8403 int[] bits = Decimal.GetBits ((decimal) v);
8406 // FIXME: For some reason, this doesn't work on the MS runtime.
8407 int[] nbits = new int[4];
8413 for (int j = 0; j < 4; j++) {
8414 data[p++] = (byte) (nbits[j] & 0xff);
8415 data[p++] = (byte) ((nbits[j] >> 8) & 0xff);
8416 data[p++] = (byte) ((nbits[j] >> 16) & 0xff);
8417 data[p++] = (byte) (nbits[j] >> 24);
8421 throw new Exception ("Unrecognized type in MakeByteBlob: " + element_type);
8430 public override SLE.Expression MakeExpression (BuilderContext ctx)
8433 return base.MakeExpression (ctx);
8435 var initializers = new SLE.Expression [array_data.Count];
8436 for (var i = 0; i < initializers.Length; i++) {
8437 if (array_data [i] == null)
8438 initializers [i] = SLE.Expression.Default (array_element_type.GetMetaInfo ());
8440 initializers [i] = array_data [i].MakeExpression (ctx);
8443 return SLE.Expression.NewArrayInit (array_element_type.GetMetaInfo (), initializers);
8448 // Emits the initializers for the array
8450 void EmitStaticInitializers (EmitContext ec, FieldExpr stackArray)
8452 var m = ec.Module.PredefinedMembers.RuntimeHelpersInitializeArray.Resolve (loc);
8457 // First, the static data
8459 byte [] data = MakeByteBlob ();
8460 var fb = ec.CurrentTypeDefinition.Module.MakeStaticData (data, loc);
8462 if (stackArray == null) {
8463 ec.Emit (OpCodes.Dup);
8465 stackArray.Emit (ec);
8468 ec.Emit (OpCodes.Ldtoken, fb);
8469 ec.Emit (OpCodes.Call, m);
8474 // Emits pieces of the array that can not be computed at compile
8475 // time (variables and string locations).
8477 // This always expect the top value on the stack to be the array
8479 void EmitDynamicInitializers (EmitContext ec, bool emitConstants, StackFieldExpr stackArray)
8481 int dims = bounds.Count;
8482 var current_pos = new int [dims];
8484 for (int i = 0; i < array_data.Count; i++){
8486 Expression e = array_data [i];
8487 var c = e as Constant;
8489 // Constant can be initialized via StaticInitializer
8490 if (c == null || (c != null && emitConstants && !c.IsDefaultInitializer (array_element_type))) {
8494 if (stackArray != null) {
8495 if (e.ContainsEmitWithAwait ()) {
8496 e = e.EmitToField (ec);
8499 stackArray.EmitLoad (ec);
8501 ec.Emit (OpCodes.Dup);
8504 for (int idx = 0; idx < dims; idx++)
8505 ec.EmitInt (current_pos [idx]);
8508 // If we are dealing with a struct, get the
8509 // address of it, so we can store it.
8511 if (dims == 1 && etype.IsStruct && !BuiltinTypeSpec.IsPrimitiveType (etype))
8512 ec.Emit (OpCodes.Ldelema, etype);
8516 ec.EmitArrayStore ((ArrayContainer) type);
8522 for (int j = dims - 1; j >= 0; j--){
8524 if (current_pos [j] < bounds [j])
8526 current_pos [j] = 0;
8530 if (stackArray != null)
8531 stackArray.PrepareCleanup (ec);
8534 public override void Emit (EmitContext ec)
8536 if (!NoEmptyInterpolation && EmitOptimizedEmpty (ec))
8539 var await_field = EmitToFieldSource (ec);
8540 if (await_field != null)
8541 await_field.Emit (ec);
8544 bool EmitOptimizedEmpty (EmitContext ec)
8546 if (arguments.Count != 1 || dimensions != 1)
8549 var c = arguments [0] as Constant;
8550 if (c == null || !c.IsZeroInteger)
8553 var m = ec.Module.PredefinedMembers.ArrayEmpty.Get ();
8554 if (m == null || ec.CurrentType.MemberDefinition.DeclaringAssembly == m.DeclaringType.MemberDefinition.DeclaringAssembly)
8557 m = m.MakeGenericMethod (ec.MemberContext, array_element_type);
8558 ec.Emit (OpCodes.Call, m);
8562 protected sealed override FieldExpr EmitToFieldSource (EmitContext ec)
8564 if (first_emit != null) {
8565 first_emit.Emit (ec);
8566 first_emit_temp.Store (ec);
8569 StackFieldExpr await_stack_field;
8570 if (ec.HasSet (BuilderContext.Options.AsyncBody) && InitializersContainAwait ()) {
8571 await_stack_field = ec.GetTemporaryField (type);
8574 await_stack_field = null;
8577 EmitExpressionsList (ec, arguments);
8579 ec.EmitArrayNew ((ArrayContainer) type);
8581 if (initializers == null)
8582 return await_stack_field;
8584 if (await_stack_field != null)
8585 await_stack_field.EmitAssignFromStack (ec);
8589 // Emit static initializer for arrays which contain more than 2 items and
8590 // the static initializer will initialize at least 25% of array values or there
8591 // is more than 10 items to be initialized
8593 // NOTE: const_initializers_count does not contain default constant values.
8595 if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
8596 (BuiltinTypeSpec.IsPrimitiveType (array_element_type) || array_element_type.IsEnum)) {
8597 EmitStaticInitializers (ec, await_stack_field);
8599 if (!only_constant_initializers)
8600 EmitDynamicInitializers (ec, false, await_stack_field);
8604 EmitDynamicInitializers (ec, true, await_stack_field);
8607 if (first_emit_temp != null)
8608 first_emit_temp.Release (ec);
8610 return await_stack_field;
8613 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
8615 // no multi dimensional or jagged arrays
8616 if (arguments.Count != 1 || array_element_type.IsArray) {
8617 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8621 // No array covariance, except for array -> object
8622 if (type != targetType) {
8623 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
8624 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8628 if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
8629 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
8634 // Single dimensional array of 0 size
8635 if (array_data == null) {
8636 IntConstant ic = arguments[0] as IntConstant;
8637 if (ic == null || !ic.IsDefaultValue) {
8638 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
8646 enc.Encode (array_data.Count);
8647 foreach (var element in array_data) {
8648 element.EncodeAttributeValue (rc, enc, array_element_type, parameterType);
8652 protected override void CloneTo (CloneContext clonectx, Expression t)
8654 ArrayCreation target = (ArrayCreation) t;
8656 if (requested_base_type != null)
8657 target.requested_base_type = (FullNamedExpression)requested_base_type.Clone (clonectx);
8659 if (arguments != null){
8660 target.arguments = new List<Expression> (arguments.Count);
8661 foreach (Expression e in arguments)
8662 target.arguments.Add (e.Clone (clonectx));
8665 if (initializers != null)
8666 target.initializers = (ArrayInitializer) initializers.Clone (clonectx);
8669 public override object Accept (StructuralVisitor visitor)
8671 return visitor.Visit (this);
8676 // Represents an implicitly typed array epxression
8678 class ImplicitlyTypedArrayCreation : ArrayCreation
8680 TypeInferenceContext best_type_inference;
8682 public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
8683 : base (null, rank, initializers, loc)
8687 public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
8688 : base (null, initializers, loc)
8692 protected override Expression DoResolve (ResolveContext ec)
8697 dimensions = rank.Dimension;
8699 best_type_inference = new TypeInferenceContext ();
8701 if (!ResolveInitializers (ec))
8704 best_type_inference.FixAllTypes (ec);
8705 array_element_type = best_type_inference.InferredTypeArguments[0];
8706 best_type_inference = null;
8708 if (array_element_type == null || InternalType.HasNoType (array_element_type) || arguments.Count != rank.Dimension) {
8709 ec.Report.Error (826, loc,
8710 "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
8715 // At this point we found common base type for all initializer elements
8716 // but we have to be sure that all static initializer elements are of
8719 UnifyInitializerElement (ec);
8721 type = ArrayContainer.MakeType (ec.Module, array_element_type, dimensions);
8722 eclass = ExprClass.Value;
8727 // Converts static initializer only
8729 void UnifyInitializerElement (ResolveContext ec)
8731 for (int i = 0; i < array_data.Count; ++i) {
8732 Expression e = array_data[i];
8734 array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
8738 protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
8740 element = element.Resolve (ec);
8741 if (element != null)
8742 best_type_inference.AddCommonTypeBound (element.Type);
8748 sealed class CompilerGeneratedThis : This
8750 public CompilerGeneratedThis (TypeSpec type, Location loc)
8756 protected override Expression DoResolve (ResolveContext rc)
8758 eclass = ExprClass.Variable;
8760 var block = rc.CurrentBlock;
8761 if (block != null) {
8762 var top = block.ParametersBlock.TopBlock;
8763 if (top.ThisVariable != null)
8764 variable_info = top.ThisVariable.VariableInfo;
8771 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
8773 return DoResolve (rc);
8776 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8783 /// Represents the `this' construct
8786 public class This : VariableReference
8788 sealed class ThisVariable : ILocalVariable
8790 public static readonly ILocalVariable Instance = new ThisVariable ();
8792 public void Emit (EmitContext ec)
8797 public void EmitAssign (EmitContext ec)
8799 throw new InvalidOperationException ();
8802 public void EmitAddressOf (EmitContext ec)
8808 protected VariableInfo variable_info;
8810 public This (Location loc)
8817 public override string Name {
8818 get { return "this"; }
8821 public override bool IsLockedByStatement {
8829 public override bool IsRef {
8830 get { return type.IsStruct; }
8833 public override bool IsSideEffectFree {
8839 protected override ILocalVariable Variable {
8840 get { return ThisVariable.Instance; }
8843 public override VariableInfo VariableInfo {
8844 get { return variable_info; }
8847 public override bool IsFixed {
8848 get { return false; }
8853 void CheckStructThisDefiniteAssignment (FlowAnalysisContext fc)
8856 // It's null for all cases when we don't need to check `this'
8857 // definitive assignment
8859 if (variable_info == null)
8862 if (fc.IsDefinitelyAssigned (variable_info))
8865 fc.Report.Error (188, loc, "The `this' object cannot be used before all of its fields are assigned to");
8868 protected virtual void Error_ThisNotAvailable (ResolveContext ec)
8870 if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
8871 ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
8872 } else if (ec.CurrentAnonymousMethod != null) {
8873 ec.Report.Error (1673, loc,
8874 "Anonymous methods inside structs cannot access instance members of `this'. " +
8875 "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
8877 ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
8881 public override void FlowAnalysis (FlowAnalysisContext fc)
8883 CheckStructThisDefiniteAssignment (fc);
8886 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
8891 AnonymousMethodStorey storey = ae.Storey;
8892 return storey != null ? storey.HoistedThis : null;
8895 public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
8897 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
8900 if (ignoreAnonymous || ec.CurrentAnonymousMethod == null)
8903 if (ec.CurrentType.IsStruct && !(ec.CurrentAnonymousMethod is StateMachineInitializer))
8909 public virtual void ResolveBase (ResolveContext ec)
8911 eclass = ExprClass.Variable;
8912 type = ec.CurrentType;
8914 if (!IsThisAvailable (ec, false)) {
8915 Error_ThisNotAvailable (ec);
8919 var block = ec.CurrentBlock;
8920 if (block != null) {
8921 var top = block.ParametersBlock.TopBlock;
8922 if (top.ThisVariable != null)
8923 variable_info = top.ThisVariable.VariableInfo;
8925 AnonymousExpression am = ec.CurrentAnonymousMethod;
8926 if (am != null && ec.IsVariableCapturingRequired && !block.Explicit.HasCapturedThis) {
8928 // Hoisted this is almost like hoisted variable but not exactly. When
8929 // there is no variable hoisted we can simply emit an instance method
8930 // without lifting this into a storey. Unfotunatelly this complicates
8931 // things in other cases because we don't know where this will be hoisted
8932 // until top-level block is fully resolved
8934 top.AddThisReferenceFromChildrenBlock (block.Explicit);
8935 am.SetHasThisAccess ();
8940 protected override Expression DoResolve (ResolveContext ec)
8946 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
8948 if (eclass == ExprClass.Unresolved)
8952 if (right_side == EmptyExpression.UnaryAddress)
8953 ec.Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
8954 else if (right_side == EmptyExpression.OutAccess)
8955 ec.Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
8957 ec.Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
8963 public override int GetHashCode()
8965 throw new NotImplementedException ();
8968 public override bool Equals (object obj)
8970 This t = obj as This;
8977 protected override void CloneTo (CloneContext clonectx, Expression t)
8982 public override void SetHasAddressTaken ()
8987 public override object Accept (StructuralVisitor visitor)
8989 return visitor.Visit (this);
8994 /// Represents the `__arglist' construct
8996 public class ArglistAccess : Expression
8998 public ArglistAccess (Location loc)
9003 protected override void CloneTo (CloneContext clonectx, Expression target)
9008 public override bool ContainsEmitWithAwait ()
9013 public override Expression CreateExpressionTree (ResolveContext ec)
9015 throw new NotSupportedException ("ET");
9018 protected override Expression DoResolve (ResolveContext ec)
9020 eclass = ExprClass.Variable;
9021 type = ec.Module.PredefinedTypes.RuntimeArgumentHandle.Resolve ();
9023 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
9024 ec.Report.Error (190, loc,
9025 "The __arglist construct is valid only within a variable argument method");
9031 public override void Emit (EmitContext ec)
9033 ec.Emit (OpCodes.Arglist);
9036 public override object Accept (StructuralVisitor visitor)
9038 return visitor.Visit (this);
9043 /// Represents the `__arglist (....)' construct
9045 public class Arglist : Expression
9047 Arguments arguments;
9049 public Arglist (Location loc)
9054 public Arglist (Arguments args, Location l)
9060 public Arguments Arguments {
9066 public MetaType[] ArgumentTypes {
9068 if (arguments == null)
9069 return MetaType.EmptyTypes;
9071 var retval = new MetaType[arguments.Count];
9072 for (int i = 0; i < retval.Length; i++)
9073 retval[i] = arguments[i].Expr.Type.GetMetaInfo ();
9079 public override bool ContainsEmitWithAwait ()
9081 throw new NotImplementedException ();
9084 public override Expression CreateExpressionTree (ResolveContext ec)
9086 ec.Report.Error (1952, loc, "An expression tree cannot contain a method with variable arguments");
9090 protected override Expression DoResolve (ResolveContext ec)
9092 eclass = ExprClass.Variable;
9093 type = InternalType.Arglist;
9094 if (arguments != null) {
9095 bool dynamic; // Can be ignored as there is always only 1 overload
9096 arguments.Resolve (ec, out dynamic);
9102 public override void Emit (EmitContext ec)
9104 if (arguments != null)
9105 arguments.Emit (ec);
9108 protected override void CloneTo (CloneContext clonectx, Expression t)
9110 Arglist target = (Arglist) t;
9112 if (arguments != null)
9113 target.arguments = arguments.Clone (clonectx);
9116 public override object Accept (StructuralVisitor visitor)
9118 return visitor.Visit (this);
9122 public class RefValueExpr : ShimExpression, IAssignMethod, IMemoryLocation
9124 FullNamedExpression texpr;
9126 public RefValueExpr (Expression expr, FullNamedExpression texpr, Location loc)
9133 public FullNamedExpression TypeExpression {
9139 public override bool ContainsEmitWithAwait ()
9144 public void AddressOf (EmitContext ec, AddressOp mode)
9147 ec.Emit (OpCodes.Refanyval, type);
9150 protected override Expression DoResolve (ResolveContext rc)
9152 expr = expr.Resolve (rc);
9153 type = texpr.ResolveAsType (rc);
9154 if (expr == null || type == null)
9157 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9158 eclass = ExprClass.Variable;
9162 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
9164 return DoResolve (rc);
9167 public override void Emit (EmitContext ec)
9170 ec.Emit (OpCodes.Refanyval, type);
9171 ec.EmitLoadFromPtr (type);
9174 public void Emit (EmitContext ec, bool leave_copy)
9176 throw new NotImplementedException ();
9179 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
9182 ec.Emit (OpCodes.Refanyval, type);
9185 LocalTemporary temporary = null;
9187 ec.Emit (OpCodes.Dup);
9188 temporary = new LocalTemporary (source.Type);
9189 temporary.Store (ec);
9192 ec.EmitStoreFromPtr (type);
9194 if (temporary != null) {
9195 temporary.Emit (ec);
9196 temporary.Release (ec);
9200 public override object Accept (StructuralVisitor visitor)
9202 return visitor.Visit (this);
9206 public class RefTypeExpr : ShimExpression
9208 public RefTypeExpr (Expression expr, Location loc)
9214 protected override Expression DoResolve (ResolveContext rc)
9216 expr = expr.Resolve (rc);
9220 expr = Convert.ImplicitConversionRequired (rc, expr, rc.Module.PredefinedTypes.TypedReference.Resolve (), loc);
9224 type = rc.BuiltinTypes.Type;
9225 eclass = ExprClass.Value;
9229 public override void Emit (EmitContext ec)
9232 ec.Emit (OpCodes.Refanytype);
9233 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9235 ec.Emit (OpCodes.Call, m);
9238 public override object Accept (StructuralVisitor visitor)
9240 return visitor.Visit (this);
9244 public class MakeRefExpr : ShimExpression
9246 public MakeRefExpr (Expression expr, Location loc)
9252 public override bool ContainsEmitWithAwait ()
9254 throw new NotImplementedException ();
9257 protected override Expression DoResolve (ResolveContext rc)
9259 expr = expr.ResolveLValue (rc, EmptyExpression.LValueMemberAccess);
9260 type = rc.Module.PredefinedTypes.TypedReference.Resolve ();
9261 eclass = ExprClass.Value;
9265 public override void Emit (EmitContext ec)
9267 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.Load);
9268 ec.Emit (OpCodes.Mkrefany, expr.Type);
9271 public override object Accept (StructuralVisitor visitor)
9273 return visitor.Visit (this);
9278 /// Implements the typeof operator
9280 public class TypeOf : Expression {
9281 FullNamedExpression QueriedType;
9284 public TypeOf (FullNamedExpression queried_type, Location l)
9286 QueriedType = queried_type;
9291 // Use this constructor for any compiler generated typeof expression
9293 public TypeOf (TypeSpec type, Location loc)
9295 this.typearg = type;
9301 public override bool IsSideEffectFree {
9307 public TypeSpec TypeArgument {
9313 public FullNamedExpression TypeExpression {
9322 protected override void CloneTo (CloneContext clonectx, Expression t)
9324 TypeOf target = (TypeOf) t;
9325 if (QueriedType != null)
9326 target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
9329 public override bool ContainsEmitWithAwait ()
9334 public override Expression CreateExpressionTree (ResolveContext ec)
9336 Arguments args = new Arguments (2);
9337 args.Add (new Argument (this));
9338 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
9339 return CreateExpressionFactoryCall (ec, "Constant", args);
9342 protected override Expression DoResolve (ResolveContext ec)
9344 if (eclass != ExprClass.Unresolved)
9347 if (typearg == null) {
9349 // Pointer types are allowed without explicit unsafe, they are just tokens
9351 using (ec.Set (ResolveContext.Options.UnsafeScope)) {
9352 typearg = QueriedType.ResolveAsType (ec, true);
9355 if (typearg == null)
9358 if (typearg.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9359 ec.Report.Error (1962, QueriedType.Location,
9360 "The typeof operator cannot be used on the dynamic type");
9364 type = ec.BuiltinTypes.Type;
9366 // Even though what is returned is a type object, it's treated as a value by the compiler.
9367 // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
9368 eclass = ExprClass.Value;
9372 static bool ContainsDynamicType (TypeSpec type)
9374 if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
9377 var element_container = type as ElementTypeSpec;
9378 if (element_container != null)
9379 return ContainsDynamicType (element_container.Element);
9381 foreach (var t in type.TypeArguments) {
9382 if (ContainsDynamicType (t)) {
9390 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
9392 // Target type is not System.Type therefore must be object
9393 // and we need to use different encoding sequence
9394 if (targetType != type)
9397 if (typearg is InflatedTypeSpec) {
9400 if (InflatedTypeSpec.ContainsTypeParameter (gt)) {
9401 rc.Module.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
9402 typearg.GetSignatureForError ());
9406 gt = gt.DeclaringType;
9407 } while (gt != null);
9410 if (ContainsDynamicType (typearg)) {
9411 Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
9415 enc.EncodeTypeName (typearg);
9418 public override void Emit (EmitContext ec)
9420 ec.Emit (OpCodes.Ldtoken, typearg);
9421 var m = ec.Module.PredefinedMembers.TypeGetTypeFromHandle.Resolve (loc);
9423 ec.Emit (OpCodes.Call, m);
9426 public override object Accept (StructuralVisitor visitor)
9428 return visitor.Visit (this);
9432 sealed class TypeOfMethod : TypeOfMember<MethodSpec>
9434 public TypeOfMethod (MethodSpec method, Location loc)
9435 : base (method, loc)
9439 protected override Expression DoResolve (ResolveContext ec)
9441 if (member.IsConstructor) {
9442 type = ec.Module.PredefinedTypes.ConstructorInfo.Resolve ();
9444 type = ec.Module.PredefinedTypes.MethodInfo.Resolve ();
9450 return base.DoResolve (ec);
9453 public override void Emit (EmitContext ec)
9455 ec.Emit (OpCodes.Ldtoken, member);
9458 ec.Emit (OpCodes.Castclass, type);
9461 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9463 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle;
9466 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9468 return ec.Module.PredefinedMembers.MethodInfoGetMethodFromHandle2;
9472 abstract class TypeOfMember<T> : Expression where T : MemberSpec
9474 protected readonly T member;
9476 protected TypeOfMember (T member, Location loc)
9478 this.member = member;
9482 public override bool IsSideEffectFree {
9488 public override bool ContainsEmitWithAwait ()
9493 public override Expression CreateExpressionTree (ResolveContext ec)
9495 Arguments args = new Arguments (2);
9496 args.Add (new Argument (this));
9497 args.Add (new Argument (new TypeOf (type, loc)));
9498 return CreateExpressionFactoryCall (ec, "Constant", args);
9501 protected override Expression DoResolve (ResolveContext ec)
9503 eclass = ExprClass.Value;
9507 public override void Emit (EmitContext ec)
9509 bool is_generic = member.DeclaringType.IsGenericOrParentIsGeneric;
9510 PredefinedMember<MethodSpec> p;
9512 p = GetTypeFromHandleGeneric (ec);
9513 ec.Emit (OpCodes.Ldtoken, member.DeclaringType);
9515 p = GetTypeFromHandle (ec);
9518 var mi = p.Resolve (loc);
9520 ec.Emit (OpCodes.Call, mi);
9523 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec);
9524 protected abstract PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec);
9527 sealed class TypeOfField : TypeOfMember<FieldSpec>
9529 public TypeOfField (FieldSpec field, Location loc)
9534 protected override Expression DoResolve (ResolveContext ec)
9536 type = ec.Module.PredefinedTypes.FieldInfo.Resolve ();
9540 return base.DoResolve (ec);
9543 public override void Emit (EmitContext ec)
9545 ec.Emit (OpCodes.Ldtoken, member);
9549 protected override PredefinedMember<MethodSpec> GetTypeFromHandle (EmitContext ec)
9551 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle;
9554 protected override PredefinedMember<MethodSpec> GetTypeFromHandleGeneric (EmitContext ec)
9556 return ec.Module.PredefinedMembers.FieldInfoGetFieldFromHandle2;
9561 /// Implements the sizeof expression
9563 public class SizeOf : Expression {
9564 readonly Expression texpr;
9565 TypeSpec type_queried;
9567 public SizeOf (Expression queried_type, Location l)
9569 this.texpr = queried_type;
9573 public override bool IsSideEffectFree {
9579 public Expression TypeExpression {
9585 public override bool ContainsEmitWithAwait ()
9590 public override Expression CreateExpressionTree (ResolveContext ec)
9592 Error_PointerInsideExpressionTree (ec);
9596 protected override Expression DoResolve (ResolveContext ec)
9598 type_queried = texpr.ResolveAsType (ec);
9599 if (type_queried == null)
9602 if (type_queried.IsEnum)
9603 type_queried = EnumSpec.GetUnderlyingType (type_queried);
9605 int size_of = BuiltinTypeSpec.GetSize (type_queried);
9607 return new IntConstant (ec.BuiltinTypes, size_of, loc);
9610 if (!TypeManager.VerifyUnmanaged (ec.Module, type_queried, loc)){
9615 ec.Report.Error (233, loc,
9616 "`{0}' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)",
9617 type_queried.GetSignatureForError ());
9620 type = ec.BuiltinTypes.Int;
9621 eclass = ExprClass.Value;
9625 public override void Emit (EmitContext ec)
9627 ec.Emit (OpCodes.Sizeof, type_queried);
9630 protected override void CloneTo (CloneContext clonectx, Expression t)
9634 public override object Accept (StructuralVisitor visitor)
9636 return visitor.Visit (this);
9641 /// Implements the qualified-alias-member (::) expression.
9643 public class QualifiedAliasMember : MemberAccess
9645 readonly string alias;
9646 public static readonly string GlobalAlias = "global";
9648 public QualifiedAliasMember (string alias, string identifier, Location l)
9649 : base (null, identifier, l)
9654 public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
9655 : base (null, identifier, targs, l)
9660 public QualifiedAliasMember (string alias, string identifier, int arity, Location l)
9661 : base (null, identifier, arity, l)
9666 public string Alias {
9672 public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
9674 if (alias == GlobalAlias)
9675 return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
9677 int errors = mc.Module.Compiler.Report.Errors;
9678 var expr = mc.LookupNamespaceAlias (alias);
9680 if (errors == mc.Module.Compiler.Report.Errors)
9681 mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
9689 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
9691 expr = CreateExpressionFromAlias (mc);
9695 return base.ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
9698 protected override Expression DoResolve (ResolveContext rc)
9700 return ResolveAsTypeOrNamespace (rc, false);
9703 public override string GetSignatureForError ()
9706 if (targs != null) {
9707 name = Name + "<" + targs.GetSignatureForError () + ">";
9710 return alias + "::" + name;
9713 public override bool HasConditionalAccess ()
9718 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9720 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
9721 rc.Module.Compiler.Report.Error (687, loc,
9722 "The namespace alias qualifier `::' cannot be used to invoke a method. Consider using `.' instead",
9723 GetSignatureForError ());
9728 return DoResolve (rc);
9731 protected override void CloneTo (CloneContext clonectx, Expression t)
9736 public override object Accept (StructuralVisitor visitor)
9738 return visitor.Visit (this);
9743 /// Implements the member access expression
9745 public class MemberAccess : ATypeNameExpression
9747 protected Expression expr;
9749 public MemberAccess (Expression expr, string id)
9750 : base (id, expr.Location)
9755 public MemberAccess (Expression expr, string identifier, Location loc)
9756 : base (identifier, loc)
9761 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
9762 : base (identifier, args, loc)
9767 public MemberAccess (Expression expr, string identifier, int arity, Location loc)
9768 : base (identifier, arity, loc)
9773 public Expression LeftExpression {
9779 public override Location StartLocation {
9781 return expr == null ? loc : expr.StartLocation;
9785 protected override Expression DoResolve (ResolveContext rc)
9787 var e = LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.DontSetConditionalAccess);
9789 e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type | ResolveFlags.MethodGroup);
9794 public override Expression DoResolveLValue (ResolveContext rc, Expression rhs)
9796 var e = LookupNameExpression (rc, MemberLookupRestrictions.None);
9798 if (e is TypeExpr) {
9799 e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
9804 e = e.ResolveLValue (rc, rhs);
9809 protected virtual void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
9811 if (type == InternalType.NullLiteral && rc.IsRuntimeBinder)
9812 rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
9814 expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
9817 public override bool HasConditionalAccess ()
9819 return LeftExpression.HasConditionalAccess ();
9822 public static bool IsValidDotExpression (TypeSpec type)
9824 const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
9825 MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
9827 return (type.Kind & dot_kinds) != 0 || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
9830 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
9832 var sn = expr as SimpleName;
9833 const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
9836 expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
9839 // Resolve expression which does have type set as we need expression type
9840 // with disable flow analysis as we don't know whether left side expression
9841 // is used as variable or type
9843 if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess || expr is EventExpr) {
9844 expr = expr.Resolve (rc);
9845 } else if (expr is TypeParameterExpr) {
9846 expr.Error_UnexpectedKind (rc, flags, sn.Location);
9850 if ((restrictions & MemberLookupRestrictions.DontSetConditionalAccess) != 0) {
9851 using (rc.Set (ResolveContext.Options.DontSetConditionalAccessReceiver)) {
9852 expr = expr.Resolve (rc, flags);
9855 expr = expr.Resolve (rc, flags);
9862 var ns = expr as NamespaceExpression;
9864 var retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
9866 if (retval == null) {
9867 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
9872 if (HasTypeArguments)
9873 return new GenericTypeExpr (retval.Type, targs, loc);
9875 targs.Resolve (rc, false);
9881 var cma = this as ConditionalMemberAccess;
9884 TypeSpec expr_type = expr.Type;
9885 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
9886 me = expr as MemberExpr;
9888 me.ResolveInstanceExpression (rc, null);
9890 Arguments args = new Arguments (1);
9891 args.Add (new Argument (expr));
9894 return new DynamicConditionalMemberBinder (Name, args, loc);
9896 return new DynamicMemberBinder (Name, args, loc);
9900 if (!IsNullPropagatingValid (expr.Type)) {
9901 expr.Error_OperatorCannotBeApplied (rc, loc, "?", expr.Type);
9905 if (expr_type.IsNullableType) {
9906 expr = Nullable.Unwrap.Create (expr.Resolve (rc), true);
9907 expr_type = expr.Type;
9911 if (!IsValidDotExpression (expr_type)) {
9912 Error_OperatorCannotBeApplied (rc, expr_type);
9916 var lookup_arity = Arity;
9917 bool errorMode = false;
9918 Expression member_lookup;
9920 member_lookup = MemberLookup (rc, errorMode, expr_type, Name, lookup_arity, restrictions, loc);
9921 if (member_lookup == null) {
9923 // Try to look for extension method when member lookup failed
9925 if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
9926 var methods = rc.LookupExtensionMethod (Name, lookup_arity);
9927 if (methods != null) {
9928 var emg = new ExtensionMethodGroupExpr (methods, expr, loc);
9929 if (HasTypeArguments) {
9930 if (!targs.Resolve (rc, false))
9933 emg.SetTypeArguments (rc, targs);
9937 emg.ConditionalAccess = true;
9939 // TODO: it should really skip the checks bellow
9940 return emg.Resolve (rc);
9946 if (member_lookup == null) {
9947 var dep = expr_type.GetMissingDependencies ();
9949 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
9950 } else if (expr is TypeExpr) {
9951 base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9953 Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
9959 if (member_lookup is MethodGroupExpr || member_lookup is PropertyExpr) {
9960 // Leave it to overload resolution to report correct error
9961 } else if (!(member_lookup is TypeExpr)) {
9962 // TODO: rc.SymbolRelatedToPreviousError
9963 ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
9968 if (member_lookup != null)
9972 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
9976 TypeExpr texpr = member_lookup as TypeExpr;
9977 if (texpr != null) {
9978 if (!(expr is TypeExpr) && (sn == null || expr.ProbeIdenticalTypeName (rc, expr, sn) == expr)) {
9979 rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression. Consider using `{1}' instead",
9980 Name, texpr.GetSignatureForError ());
9983 if (!texpr.Type.IsAccessible (rc)) {
9984 rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
9985 ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
9989 if (HasTypeArguments) {
9990 return new GenericTypeExpr (member_lookup.Type, targs, loc);
9993 return member_lookup;
9996 me = member_lookup as MemberExpr;
9998 if (sn != null && me.IsStatic && (expr = me.ProbeIdenticalTypeName (rc, expr, sn)) != expr) {
10003 me.ConditionalAccess = true;
10006 me = me.ResolveMemberAccess (rc, expr, sn);
10009 if (!targs.Resolve (rc, false))
10012 me.SetTypeArguments (rc, targs);
10018 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext rc, bool allowUnboundTypeArguments)
10020 FullNamedExpression fexpr = expr as FullNamedExpression;
10021 if (fexpr == null) {
10022 expr.ResolveAsType (rc);
10026 FullNamedExpression expr_resolved = fexpr.ResolveAsTypeOrNamespace (rc, allowUnboundTypeArguments);
10028 if (expr_resolved == null)
10031 var ns = expr_resolved as NamespaceExpression;
10033 FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, Name, Arity, LookupMode.Normal, loc);
10035 if (retval == null) {
10036 ns.Error_NamespaceDoesNotExist (rc, Name, Arity, loc);
10037 } else if (Arity > 0) {
10038 if (HasTypeArguments) {
10039 retval = new GenericTypeExpr (retval.Type, targs, loc);
10040 if (retval.ResolveAsType (rc) == null)
10043 targs.Resolve (rc, allowUnboundTypeArguments);
10045 retval = new GenericOpenTypeExpr (retval.Type, loc);
10052 var tnew_expr = expr_resolved.ResolveAsType (rc);
10053 if (tnew_expr == null)
10056 TypeSpec expr_type = tnew_expr;
10057 if (TypeManager.IsGenericParameter (expr_type)) {
10058 rc.Module.Compiler.Report.Error (704, loc, "A nested type cannot be specified through a type parameter `{0}'",
10059 tnew_expr.GetSignatureForError ());
10063 var qam = this as QualifiedAliasMember;
10065 rc.Module.Compiler.Report.Error (431, loc,
10066 "Alias `{0}' cannot be used with `::' since it denotes a type. Consider replacing `::' with `.'",
10071 TypeSpec nested = null;
10072 while (expr_type != null) {
10073 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10074 if (nested == null) {
10075 if (expr_type == tnew_expr) {
10076 Error_IdentifierNotFound (rc, expr_type);
10080 expr_type = tnew_expr;
10081 nested = MemberCache.FindNestedType (expr_type, Name, Arity, false);
10082 ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
10086 if (nested.IsAccessible (rc))
10090 // Keep looking after inaccessible candidate but only if
10091 // we are not in same context as the definition itself
10093 if (expr_type.MemberDefinition == rc.CurrentMemberDefinition)
10096 expr_type = expr_type.BaseType;
10101 if (HasTypeArguments) {
10102 texpr = new GenericTypeExpr (nested, targs, loc);
10104 targs.Resolve (rc, allowUnboundTypeArguments && !(expr_resolved is GenericTypeExpr));
10106 texpr = new GenericOpenTypeExpr (nested, loc);
10108 } else if (expr_resolved is GenericOpenTypeExpr) {
10109 texpr = new GenericOpenTypeExpr (nested, loc);
10111 texpr = new TypeExpression (nested, loc);
10114 if (texpr.ResolveAsType (rc) == null)
10120 public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
10122 var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity), false);
10124 if (nested != null) {
10125 Error_TypeArgumentsCannotBeUsed (rc, nested, expr.Location);
10129 var any_other_member = MemberLookup (rc, false, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
10130 if (any_other_member != null) {
10131 Error_UnexpectedKind (rc, any_other_member, "type", any_other_member.ExprClassName, loc);
10135 rc.Module.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
10136 Name, expr_type.GetSignatureForError ());
10139 protected override void Error_InvalidExpressionStatement (Report report, Location loc)
10141 base.Error_InvalidExpressionStatement (report, LeftExpression.Location);
10144 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
10146 if (ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2 && !ec.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
10147 ec.Report.SymbolRelatedToPreviousError (type);
10149 var cand = ec.Module.GlobalRootNamespace.FindExtensionMethodNamespaces (ec, name, Arity);
10151 // a using directive or an assembly reference
10152 if (cand != null) {
10153 missing = "`" + string.Join ("' or `", cand.ToArray ()) + "' using directive";
10155 missing = "an assembly reference";
10158 ec.Report.Error (1061, loc,
10159 "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found. Are you missing {2}?",
10160 type.GetSignatureForError (), name, missing);
10164 base.Error_TypeDoesNotContainDefinition (ec, type, name);
10167 public override string GetSignatureForError ()
10169 return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
10172 protected override void CloneTo (CloneContext clonectx, Expression t)
10174 MemberAccess target = (MemberAccess) t;
10176 target.expr = expr.Clone (clonectx);
10179 public override object Accept (StructuralVisitor visitor)
10181 return visitor.Visit (this);
10185 public class ConditionalMemberAccess : MemberAccess
10187 public ConditionalMemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
10188 : base (expr, identifier, args, loc)
10192 public override bool HasConditionalAccess ()
10199 /// Implements checked expressions
10201 public class CheckedExpr : Expression {
10203 public Expression Expr;
10205 public CheckedExpr (Expression e, Location l)
10211 public override bool ContainsEmitWithAwait ()
10213 return Expr.ContainsEmitWithAwait ();
10216 public override Expression CreateExpressionTree (ResolveContext ec)
10218 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10219 return Expr.CreateExpressionTree (ec);
10222 protected override Expression DoResolve (ResolveContext ec)
10224 using (ec.With (ResolveContext.Options.AllCheckStateFlags, true))
10225 Expr = Expr.Resolve (ec);
10230 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10233 eclass = Expr.eclass;
10238 public override void Emit (EmitContext ec)
10240 using (ec.With (EmitContext.Options.CheckedScope, true))
10244 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10246 using (ec.With (EmitContext.Options.CheckedScope, true))
10247 Expr.EmitBranchable (ec, target, on_true);
10250 public override void FlowAnalysis (FlowAnalysisContext fc)
10252 Expr.FlowAnalysis (fc);
10255 public override SLE.Expression MakeExpression (BuilderContext ctx)
10257 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10258 return Expr.MakeExpression (ctx);
10262 protected override void CloneTo (CloneContext clonectx, Expression t)
10264 CheckedExpr target = (CheckedExpr) t;
10266 target.Expr = Expr.Clone (clonectx);
10269 public override object Accept (StructuralVisitor visitor)
10271 return visitor.Visit (this);
10276 /// Implements the unchecked expression
10278 public class UnCheckedExpr : Expression {
10280 public Expression Expr;
10282 public UnCheckedExpr (Expression e, Location l)
10288 public override bool ContainsEmitWithAwait ()
10290 return Expr.ContainsEmitWithAwait ();
10293 public override Expression CreateExpressionTree (ResolveContext ec)
10295 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10296 return Expr.CreateExpressionTree (ec);
10299 protected override Expression DoResolve (ResolveContext ec)
10301 using (ec.With (ResolveContext.Options.AllCheckStateFlags, false))
10302 Expr = Expr.Resolve (ec);
10307 if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression || Expr is DefaultValueExpression)
10310 eclass = Expr.eclass;
10315 public override void Emit (EmitContext ec)
10317 using (ec.With (EmitContext.Options.CheckedScope, false))
10321 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
10323 using (ec.With (EmitContext.Options.CheckedScope, false))
10324 Expr.EmitBranchable (ec, target, on_true);
10327 public override void FlowAnalysis (FlowAnalysisContext fc)
10329 Expr.FlowAnalysis (fc);
10332 protected override void CloneTo (CloneContext clonectx, Expression t)
10334 UnCheckedExpr target = (UnCheckedExpr) t;
10336 target.Expr = Expr.Clone (clonectx);
10339 public override object Accept (StructuralVisitor visitor)
10341 return visitor.Visit (this);
10346 /// An Element Access expression.
10348 /// During semantic analysis these are transformed into
10349 /// IndexerAccess, ArrayAccess or a PointerArithmetic.
10351 public class ElementAccess : Expression
10353 public Arguments Arguments;
10354 public Expression Expr;
10355 bool conditional_access_receiver;
10357 public ElementAccess (Expression e, Arguments args, Location loc)
10361 this.Arguments = args;
10364 public bool ConditionalAccess { get; set; }
10366 public override Location StartLocation {
10368 return Expr.StartLocation;
10372 public override bool ContainsEmitWithAwait ()
10374 return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();
10378 // We perform some simple tests, and then to "split" the emit and store
10379 // code we create an instance of a different class, and return that.
10381 Expression CreateAccessExpression (ResolveContext ec, bool conditionalAccessReceiver)
10383 if (conditionalAccessReceiver)
10384 ec.Set (ResolveContext.Options.DontSetConditionalAccessReceiver);
10386 Expr = Expr.Resolve (ec);
10388 if (conditionalAccessReceiver)
10389 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
10396 if (ConditionalAccess && !IsNullPropagatingValid (type)) {
10397 Error_OperatorCannotBeApplied (ec, loc, "?", type);
10401 if (type.IsArray) {
10402 var aa = new ArrayAccess (this, loc) {
10403 ConditionalAccess = ConditionalAccess,
10406 if (conditionalAccessReceiver)
10407 aa.SetConditionalAccessReceiver ();
10412 if (type.IsPointer)
10413 return Expr.MakePointerAccess (ec, type, Arguments);
10415 FieldExpr fe = Expr as FieldExpr;
10417 var ff = fe.Spec as FixedFieldSpec;
10419 return Expr.MakePointerAccess (ec, ff.ElementType, Arguments);
10423 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
10424 if (indexers != null || type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
10425 var indexer = new IndexerExpr (indexers, type, this) {
10426 ConditionalAccess = ConditionalAccess
10429 if (conditionalAccessReceiver)
10430 indexer.SetConditionalAccessReceiver ();
10435 Error_CannotApplyIndexing (ec, type, loc);
10440 public override Expression CreateExpressionTree (ResolveContext ec)
10442 Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
10443 Expr.CreateExpressionTree (ec));
10445 return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
10448 public static void Error_CannotApplyIndexing (ResolveContext rc, TypeSpec type, Location loc)
10450 if (type != InternalType.ErrorType) {
10451 rc.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
10452 type.GetSignatureForError ());
10456 public override bool HasConditionalAccess ()
10458 return ConditionalAccess || Expr.HasConditionalAccess ();
10461 void ResolveConditionalAccessReceiver (ResolveContext rc)
10463 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
10464 conditional_access_receiver = true;
10468 protected override Expression DoResolve (ResolveContext rc)
10470 ResolveConditionalAccessReceiver (rc);
10472 var expr = CreateAccessExpression (rc, conditional_access_receiver);
10476 return expr.Resolve (rc);
10479 public override Expression DoResolveLValue (ResolveContext ec, Expression rhs)
10481 var res = CreateAccessExpression (ec, false);
10485 return res.ResolveLValue (ec, rhs);
10488 public override void Emit (EmitContext ec)
10490 throw new Exception ("Should never be reached");
10493 public override void FlowAnalysis (FlowAnalysisContext fc)
10495 Expr.FlowAnalysis (fc);
10497 Arguments.FlowAnalysis (fc);
10500 public override string GetSignatureForError ()
10502 return Expr.GetSignatureForError ();
10505 protected override void CloneTo (CloneContext clonectx, Expression t)
10507 ElementAccess target = (ElementAccess) t;
10509 target.Expr = Expr.Clone (clonectx);
10510 if (Arguments != null)
10511 target.Arguments = Arguments.Clone (clonectx);
10514 public override object Accept (StructuralVisitor visitor)
10516 return visitor.Visit (this);
10521 /// Implements array access
10523 public class ArrayAccess : Expression, IDynamicAssign, IMemoryLocation {
10525 // Points to our "data" repository
10529 LocalTemporary temp;
10531 bool? has_await_args;
10532 bool conditional_access_receiver;
10534 public ArrayAccess (ElementAccess ea_data, Location l)
10540 public bool ConditionalAccess { get; set; }
10542 public void AddressOf (EmitContext ec, AddressOp mode)
10544 var ac = (ArrayContainer) ea.Expr.Type;
10546 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10547 LoadInstanceAndArguments (ec, false, true);
10550 LoadInstanceAndArguments (ec, false, false);
10552 if (ac.Element.IsGenericParameter && mode == AddressOp.Load)
10553 ec.Emit (OpCodes.Readonly);
10555 ec.EmitArrayAddress (ac);
10558 public override Expression CreateExpressionTree (ResolveContext ec)
10560 if (ConditionalAccess)
10561 Error_NullShortCircuitInsideExpressionTree (ec);
10563 return ea.CreateExpressionTree (ec);
10566 public override bool ContainsEmitWithAwait ()
10568 return ea.ContainsEmitWithAwait ();
10571 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
10573 if (HasConditionalAccess ())
10574 Error_NullPropagatingLValue (ec);
10576 return DoResolve (ec);
10579 protected override Expression DoResolve (ResolveContext ec)
10581 // dynamic is used per argument in ConvertExpressionToArrayIndex case
10583 ea.Arguments.Resolve (ec, out dynamic);
10585 var ac = ea.Expr.Type as ArrayContainer;
10586 int rank = ea.Arguments.Count;
10587 if (ac.Rank != rank) {
10588 ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
10589 rank.ToString (), ac.Rank.ToString ());
10594 if (type.IsPointer) {
10595 if (ec.CurrentIterator != null) {
10596 UnsafeInsideIteratorError (ec, ea.Location);
10597 } else if (!ec.IsUnsafe) {
10598 UnsafeError (ec, ea.Location);
10602 if (conditional_access_receiver)
10603 type = LiftMemberType (ec, type);
10605 foreach (Argument a in ea.Arguments) {
10606 var na = a as NamedArgument;
10608 ElementAccess.Error_NamedArgument (na, ec.Report);
10610 a.Expr = ConvertExpressionToArrayIndex (ec, a.Expr);
10613 eclass = ExprClass.Variable;
10618 protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
10620 ec.Report.Warning (251, 2, loc, "Indexing an array with a negative index (array indices always start at zero)");
10623 public override void FlowAnalysis (FlowAnalysisContext fc)
10625 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10627 ea.FlowAnalysis (fc);
10629 if (conditional_access_receiver)
10630 fc.DefiniteAssignment = da;
10633 public override bool HasConditionalAccess ()
10635 return ConditionalAccess || ea.Expr.HasConditionalAccess ();
10639 // Load the array arguments into the stack.
10641 void LoadInstanceAndArguments (EmitContext ec, bool duplicateArguments, bool prepareAwait)
10643 if (prepareAwait) {
10644 ea.Expr = ea.Expr.EmitToField (ec);
10646 var ie = new InstanceEmitter (ea.Expr, false);
10647 ie.Emit (ec, ConditionalAccess);
10649 if (duplicateArguments) {
10650 ec.Emit (OpCodes.Dup);
10652 var copy = new LocalTemporary (ea.Expr.Type);
10658 var dup_args = ea.Arguments.Emit (ec, duplicateArguments, prepareAwait);
10659 if (dup_args != null)
10660 ea.Arguments = dup_args;
10663 public void Emit (EmitContext ec, bool leave_copy)
10666 ec.EmitLoadFromPtr (type);
10668 if (!has_await_args.HasValue && ec.HasSet (BuilderContext.Options.AsyncBody) && ea.Arguments.ContainsEmitWithAwait ()) {
10669 LoadInstanceAndArguments (ec, false, true);
10672 if (conditional_access_receiver)
10673 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
10675 var ac = (ArrayContainer) ea.Expr.Type;
10676 LoadInstanceAndArguments (ec, false, false);
10677 ec.EmitArrayLoad (ac);
10679 if (conditional_access_receiver)
10680 ec.CloseConditionalAccess (type.IsNullableType && type != ac.Element ? type : null);
10684 ec.Emit (OpCodes.Dup);
10685 temp = new LocalTemporary (this.type);
10690 public override void Emit (EmitContext ec)
10695 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10697 var ac = (ArrayContainer) ea.Expr.Type;
10698 TypeSpec t = source.Type;
10700 has_await_args = ec.HasSet (BuilderContext.Options.AsyncBody) && (ea.Arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ());
10703 // When we are dealing with a struct, get the address of it to avoid value copy
10704 // Same cannot be done for reference type because array covariance and the
10705 // check in ldelema requires to specify the type of array element stored at the index
10707 if (t.IsStruct && ((isCompound && !(source is DynamicExpressionStatement)) || !BuiltinTypeSpec.IsPrimitiveType (t))) {
10708 LoadInstanceAndArguments (ec, false, has_await_args.Value);
10710 if (has_await_args.Value) {
10711 if (source.ContainsEmitWithAwait ()) {
10712 source = source.EmitToField (ec);
10713 isCompound = false;
10717 LoadInstanceAndArguments (ec, isCompound, false);
10722 ec.EmitArrayAddress (ac);
10725 ec.Emit (OpCodes.Dup);
10729 LoadInstanceAndArguments (ec, isCompound, has_await_args.Value);
10731 if (has_await_args.Value) {
10732 if (source.ContainsEmitWithAwait ())
10733 source = source.EmitToField (ec);
10735 LoadInstanceAndArguments (ec, false, false);
10742 var lt = ea.Expr as LocalTemporary;
10748 ec.Emit (OpCodes.Dup);
10749 temp = new LocalTemporary (this.type);
10754 ec.EmitStoreFromPtr (t);
10756 ec.EmitArrayStore (ac);
10759 if (temp != null) {
10765 public override Expression EmitToField (EmitContext ec)
10768 // Have to be specialized for arrays to get access to
10769 // underlying element. Instead of another result copy we
10770 // need direct access to element
10774 // CallRef (ref a[await Task.Factory.StartNew (() => 1)]);
10776 ea.Expr = ea.Expr.EmitToField (ec);
10777 ea.Arguments = ea.Arguments.Emit (ec, false, true);
10781 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10783 return SLE.Expression.ArrayAccess (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10786 public override SLE.Expression MakeExpression (BuilderContext ctx)
10788 return SLE.Expression.ArrayIndex (ea.Expr.MakeExpression (ctx), MakeExpressionArguments (ctx));
10791 SLE.Expression[] MakeExpressionArguments (BuilderContext ctx)
10793 using (ctx.With (BuilderContext.Options.CheckedScope, true)) {
10794 return Arguments.MakeExpression (ea.Arguments, ctx);
10798 public void SetConditionalAccessReceiver ()
10800 conditional_access_receiver = true;
10805 // Indexer access expression
10807 class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
10809 IList<MemberSpec> indexers;
10810 Arguments arguments;
10811 TypeSpec queried_type;
10813 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, ElementAccess ea)
10814 : this (indexers, queriedType, ea.Expr, ea.Arguments, ea.Location)
10818 public IndexerExpr (IList<MemberSpec> indexers, TypeSpec queriedType, Expression instance, Arguments args, Location loc)
10821 this.indexers = indexers;
10822 this.queried_type = queriedType;
10823 this.InstanceExpression = instance;
10824 this.arguments = args;
10829 protected override Arguments Arguments {
10838 protected override TypeSpec DeclaringType {
10840 return best_candidate.DeclaringType;
10844 public override bool IsInstance {
10850 public override bool IsStatic {
10856 public override string KindName {
10857 get { return "indexer"; }
10860 public override string Name {
10868 public override bool ContainsEmitWithAwait ()
10870 return base.ContainsEmitWithAwait () || arguments.ContainsEmitWithAwait ();
10873 public override Expression CreateExpressionTree (ResolveContext ec)
10875 if (ConditionalAccess) {
10876 Error_NullShortCircuitInsideExpressionTree (ec);
10879 Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
10880 InstanceExpression.CreateExpressionTree (ec),
10881 new TypeOfMethod (Getter, loc));
10883 return CreateExpressionFactoryCall (ec, "Call", args);
10886 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
10888 LocalTemporary await_source_arg = null;
10891 emitting_compound_assignment = true;
10892 if (source is DynamicExpressionStatement) {
10897 emitting_compound_assignment = false;
10899 if (has_await_arguments) {
10900 await_source_arg = new LocalTemporary (Type);
10901 await_source_arg.Store (ec);
10903 arguments.Add (new Argument (await_source_arg));
10906 temp = await_source_arg;
10909 has_await_arguments = false;
10914 ec.Emit (OpCodes.Dup);
10915 temp = new LocalTemporary (Type);
10921 if (ec.HasSet (BuilderContext.Options.AsyncBody) && (arguments.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ())) {
10922 source = source.EmitToField (ec);
10924 temp = new LocalTemporary (Type);
10931 arguments.Add (new Argument (source));
10934 var call = new CallEmitter ();
10935 call.InstanceExpression = InstanceExpression;
10936 if (arguments == null)
10937 call.InstanceExpressionOnStack = true;
10939 call.Emit (ec, Setter, arguments, loc);
10941 if (temp != null) {
10944 } else if (leave_copy) {
10948 if (await_source_arg != null) {
10949 await_source_arg.Release (ec);
10953 public override void FlowAnalysis (FlowAnalysisContext fc)
10955 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
10957 base.FlowAnalysis (fc);
10958 arguments.FlowAnalysis (fc);
10960 if (conditional_access_receiver)
10961 fc.DefiniteAssignment = da;
10964 public override string GetSignatureForError ()
10966 return best_candidate.GetSignatureForError ();
10969 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
10972 throw new NotSupportedException ();
10974 var value = new[] { source.MakeExpression (ctx) };
10975 var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
10976 return SLE.Expression.Block (
10977 SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
10982 public override SLE.Expression MakeExpression (BuilderContext ctx)
10985 return base.MakeExpression (ctx);
10987 var args = Arguments.MakeExpression (arguments, ctx);
10988 return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
10992 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
10994 if (best_candidate != null)
10997 eclass = ExprClass.IndexerAccess;
11000 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
11001 arguments.Resolve (rc, out dynamic);
11004 if (indexers == null && InstanceExpression.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11007 var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
11008 res.BaseMembersProvider = this;
11009 res.InstanceQualifier = this;
11011 // TODO: Do I need 2 argument sets?
11012 best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
11013 if (best_candidate != null)
11014 type = res.BestCandidateReturnType;
11015 else if (!res.BestCandidateIsDynamic)
11020 // It has dynamic arguments
11023 Arguments args = new Arguments (arguments.Count + 1);
11025 rc.Report.Error (1972, loc,
11026 "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
11028 args.Add (new Argument (InstanceExpression));
11030 args.AddRange (arguments);
11032 best_candidate = null;
11033 return new DynamicIndexBinder (args, conditional_access_receiver, ConditionalAccess, loc);
11037 // Try to avoid resolving left expression again
11039 if (right_side != null)
11040 ResolveInstanceExpression (rc, right_side);
11045 protected override void CloneTo (CloneContext clonectx, Expression t)
11047 IndexerExpr target = (IndexerExpr) t;
11049 if (arguments != null)
11050 target.arguments = arguments.Clone (clonectx);
11053 public void SetConditionalAccessReceiver ()
11055 conditional_access_receiver = true;
11058 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
11060 Error_TypeArgumentsCannotBeUsed (ec, "indexer", GetSignatureForError (), loc);
11063 #region IBaseMembersProvider Members
11065 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec type)
11067 var baseType = type.BaseType;
11068 var members = baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
11070 if (members == null && !type.IsInterface) {
11071 var tps = queried_type as TypeParameterSpec;
11073 members = MemberCache.FindInterfaceMembers (tps, MemberCache.IndexerNameAlias);
11079 IParametersMember OverloadResolver.IBaseMembersProvider.GetOverrideMemberParameters (MemberSpec member)
11081 if (queried_type == member.DeclaringType)
11084 var filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, ((IndexerSpec) member).Parameters, null);
11085 return MemberCache.FindMember (queried_type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
11088 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
11097 // A base access expression
11099 public class BaseThis : This
11101 public BaseThis (Location loc)
11106 public BaseThis (TypeSpec type, Location loc)
11110 eclass = ExprClass.Variable;
11115 public override string Name {
11123 public override Expression CreateExpressionTree (ResolveContext ec)
11125 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
11126 return base.CreateExpressionTree (ec);
11129 public override void Emit (EmitContext ec)
11133 if (type == ec.Module.Compiler.BuiltinTypes.ValueType) {
11134 var context_type = ec.CurrentType;
11135 ec.Emit (OpCodes.Ldobj, context_type);
11136 ec.Emit (OpCodes.Box, context_type);
11140 protected override void Error_ThisNotAvailable (ResolveContext ec)
11143 ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
11145 ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
11149 public override void ResolveBase (ResolveContext ec)
11151 base.ResolveBase (ec);
11152 type = ec.CurrentType.BaseType;
11155 public override object Accept (StructuralVisitor visitor)
11157 return visitor.Visit (this);
11162 /// This class exists solely to pass the Type around and to be a dummy
11163 /// that can be passed to the conversion functions (this is used by
11164 /// foreach implementation to typecast the object return value from
11165 /// get_Current into the proper type. All code has been generated and
11166 /// we only care about the side effect conversions to be performed
11168 /// This is also now used as a placeholder where a no-action expression
11169 /// is needed (the `New' class).
11171 public class EmptyExpression : Expression
11173 sealed class OutAccessExpression : EmptyExpression
11175 public OutAccessExpression (TypeSpec t)
11180 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11182 rc.Report.Error (206, right_side.Location,
11183 "A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter");
11189 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (InternalType.FakeInternalType);
11190 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (InternalType.FakeInternalType);
11191 public static readonly EmptyExpression UnaryAddress = new EmptyExpression (InternalType.FakeInternalType);
11192 public static readonly EmptyExpression EventAddition = new EmptyExpression (InternalType.FakeInternalType);
11193 public static readonly EmptyExpression EventSubtraction = new EmptyExpression (InternalType.FakeInternalType);
11194 public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
11195 public static readonly Expression Null = new EmptyExpression (InternalType.FakeInternalType);
11196 public static readonly EmptyExpression OutAccess = new OutAccessExpression (InternalType.FakeInternalType);
11198 public EmptyExpression (TypeSpec t)
11201 eclass = ExprClass.Value;
11202 loc = Location.Null;
11205 protected override void CloneTo (CloneContext clonectx, Expression target)
11209 public override bool ContainsEmitWithAwait ()
11214 public override Expression CreateExpressionTree (ResolveContext ec)
11216 throw new NotSupportedException ("ET");
11219 protected override Expression DoResolve (ResolveContext ec)
11224 public override void Emit (EmitContext ec)
11226 // nothing, as we only exist to not do anything.
11229 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
11233 public override void EmitSideEffect (EmitContext ec)
11237 public override object Accept (StructuralVisitor visitor)
11239 return visitor.Visit (this);
11243 sealed class EmptyAwaitExpression : EmptyExpression
11245 public EmptyAwaitExpression (TypeSpec type)
11250 public override bool ContainsEmitWithAwait ()
11257 // Empty statement expression
11259 public sealed class EmptyExpressionStatement : ExpressionStatement
11261 public static readonly EmptyExpressionStatement Instance = new EmptyExpressionStatement ();
11263 private EmptyExpressionStatement ()
11265 loc = Location.Null;
11268 public override bool ContainsEmitWithAwait ()
11273 public override Expression CreateExpressionTree (ResolveContext ec)
11278 public override void EmitStatement (EmitContext ec)
11283 protected override Expression DoResolve (ResolveContext ec)
11285 eclass = ExprClass.Value;
11286 type = ec.BuiltinTypes.Object;
11290 public override void Emit (EmitContext ec)
11295 public override object Accept (StructuralVisitor visitor)
11297 return visitor.Visit (this);
11301 public class ErrorExpression : EmptyExpression
11303 public static readonly ErrorExpression Instance = new ErrorExpression ();
11305 private ErrorExpression ()
11306 : base (InternalType.ErrorType)
11310 public override Expression CreateExpressionTree (ResolveContext ec)
11315 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
11320 public override void Error_ValueAssignment (ResolveContext rc, Expression rhs)
11324 public override void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
11328 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
11332 public override void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
11336 public override object Accept (StructuralVisitor visitor)
11338 return visitor.Visit (this);
11342 public class UserCast : Expression {
11346 public UserCast (MethodSpec method, Expression source, Location l)
11348 if (source == null)
11349 throw new ArgumentNullException ("source");
11351 this.method = method;
11352 this.source = source;
11353 type = method.ReturnType;
11357 public Expression Source {
11366 public override bool ContainsEmitWithAwait ()
11368 return source.ContainsEmitWithAwait ();
11371 public override Expression CreateExpressionTree (ResolveContext ec)
11373 Arguments args = new Arguments (3);
11374 args.Add (new Argument (source.CreateExpressionTree (ec)));
11375 args.Add (new Argument (new TypeOf (type, loc)));
11376 args.Add (new Argument (new TypeOfMethod (method, loc)));
11377 return CreateExpressionFactoryCall (ec, "Convert", args);
11380 protected override Expression DoResolve (ResolveContext ec)
11382 method.CheckObsoleteness (ec, source.Location);
11384 eclass = ExprClass.Value;
11388 public override void Emit (EmitContext ec)
11391 ec.MarkCallEntry (loc);
11392 ec.Emit (OpCodes.Call, method);
11395 public override void FlowAnalysis (FlowAnalysisContext fc)
11397 source.FlowAnalysis (fc);
11400 public override string GetSignatureForError ()
11402 return TypeManager.CSharpSignature (method);
11405 public override SLE.Expression MakeExpression (BuilderContext ctx)
11408 return base.MakeExpression (ctx);
11410 return SLE.Expression.Convert (source.MakeExpression (ctx), type.GetMetaInfo (), (MethodInfo) method.GetMetaInfo ());
11416 // Holds additional type specifiers like ?, *, []
11418 public class ComposedTypeSpecifier
11420 public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
11422 public readonly int Dimension;
11423 public readonly Location Location;
11425 public ComposedTypeSpecifier (int specifier, Location loc)
11427 this.Dimension = specifier;
11428 this.Location = loc;
11432 public bool IsNullable {
11434 return Dimension == -1;
11438 public bool IsPointer {
11440 return Dimension == -2;
11444 public ComposedTypeSpecifier Next { get; set; }
11448 public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
11450 return new ComposedTypeSpecifier (dimension, loc);
11453 public static ComposedTypeSpecifier CreateNullable (Location loc)
11455 return new ComposedTypeSpecifier (-1, loc);
11458 public static ComposedTypeSpecifier CreatePointer (Location loc)
11460 return new ComposedTypeSpecifier (-2, loc);
11463 public string GetSignatureForError ()
11468 ArrayContainer.GetPostfixSignature (Dimension);
11470 return Next != null ? s + Next.GetSignatureForError () : s;
11475 // This class is used to "construct" the type during a typecast
11476 // operation. Since the Type.GetType class in .NET can parse
11477 // the type specification, we just use this to construct the type
11478 // one bit at a time.
11480 public class ComposedCast : TypeExpr {
11481 FullNamedExpression left;
11482 ComposedTypeSpecifier spec;
11484 public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
11487 throw new ArgumentNullException ("spec");
11491 this.loc = left.Location;
11494 public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
11496 type = left.ResolveAsType (ec);
11500 eclass = ExprClass.Type;
11502 var single_spec = spec;
11504 if (single_spec.IsNullable) {
11505 type = new Nullable.NullableType (type, loc).ResolveAsType (ec);
11509 single_spec = single_spec.Next;
11510 } else if (single_spec.IsPointer) {
11512 // Declared fields cannot have unmanaged check done before all types are defined
11514 if (!(ec.CurrentMemberDefinition is Field) && !TypeManager.VerifyUnmanaged (ec.Module, type, loc))
11517 var rc = ec as ResolveContext;
11518 if (rc?.CurrentIterator != null) {
11519 UnsafeInsideIteratorError (ec.Module.Compiler.Report, loc);
11520 } else if (!ec.IsUnsafe) {
11521 UnsafeError (ec.Module.Compiler.Report, loc);
11525 type = PointerContainer.MakeType (ec.Module, type);
11526 single_spec = single_spec.Next;
11527 } while (single_spec != null && single_spec.IsPointer);
11530 if (single_spec != null && single_spec.Dimension > 0) {
11531 if (type.IsSpecialRuntimeType) {
11532 ec.Module.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
11533 } else if (type.IsStatic) {
11534 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
11535 ec.Module.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
11536 type.GetSignatureForError ());
11538 MakeArray (ec.Module, single_spec);
11545 void MakeArray (ModuleContainer module, ComposedTypeSpecifier spec)
11547 if (spec.Next != null)
11548 MakeArray (module, spec.Next);
11550 type = ArrayContainer.MakeType (module, type, spec.Dimension);
11553 public override string GetSignatureForError ()
11555 return left.GetSignatureForError () + spec.GetSignatureForError ();
11558 public override object Accept (StructuralVisitor visitor)
11560 return visitor.Visit (this);
11564 class FixedBufferPtr : Expression
11566 readonly Expression array;
11568 public FixedBufferPtr (Expression array, TypeSpec array_type, Location l)
11570 this.type = array_type;
11571 this.array = array;
11575 public override bool ContainsEmitWithAwait ()
11577 throw new NotImplementedException ();
11580 public override Expression CreateExpressionTree (ResolveContext ec)
11582 Error_PointerInsideExpressionTree (ec);
11586 public override void Emit(EmitContext ec)
11591 protected override Expression DoResolve (ResolveContext ec)
11593 type = PointerContainer.MakeType (ec.Module, type);
11594 eclass = ExprClass.Value;
11601 // This class is used to represent the address of an array, used
11602 // only by the Fixed statement, this generates "&a [0]" construct
11603 // for fixed (char *pa = a)
11605 class ArrayPtr : FixedBufferPtr
11607 public ArrayPtr (Expression array, TypeSpec array_type, Location l):
11608 base (array, array_type, l)
11612 public override void Emit (EmitContext ec)
11617 ec.Emit (OpCodes.Ldelema, ((PointerContainer) type).Element);
11622 // Encapsulates a conversion rules required for array indexes
11624 public class ArrayIndexCast : TypeCast
11626 public ArrayIndexCast (Expression expr, TypeSpec returnType)
11627 : base (expr, returnType)
11629 if (expr.Type == returnType) // int -> int
11630 throw new ArgumentException ("unnecessary array index conversion");
11633 public override Expression CreateExpressionTree (ResolveContext ec)
11635 using (ec.Set (ResolveContext.Options.CheckedScope)) {
11636 return base.CreateExpressionTree (ec);
11640 public override void Emit (EmitContext ec)
11644 switch (child.Type.BuiltinType) {
11645 case BuiltinTypeSpec.Type.UInt:
11646 ec.Emit (OpCodes.Conv_U);
11648 case BuiltinTypeSpec.Type.Long:
11649 ec.Emit (OpCodes.Conv_Ovf_I);
11651 case BuiltinTypeSpec.Type.ULong:
11652 ec.Emit (OpCodes.Conv_Ovf_I_Un);
11655 throw new InternalErrorException ("Cannot emit cast to unknown array element type", type);
11661 // Implements the `stackalloc' keyword
11663 public class StackAlloc : Expression {
11668 public StackAlloc (Expression type, Expression count, Location l)
11671 this.count = count;
11675 public Expression TypeExpression {
11681 public Expression CountExpression {
11687 public override bool ContainsEmitWithAwait ()
11692 public override Expression CreateExpressionTree (ResolveContext ec)
11694 throw new NotSupportedException ("ET");
11697 protected override Expression DoResolve (ResolveContext ec)
11699 count = count.Resolve (ec);
11703 if (count.Type.BuiltinType != BuiltinTypeSpec.Type.UInt){
11704 count = Convert.ImplicitConversionRequired (ec, count, ec.BuiltinTypes.Int, loc);
11709 Constant c = count as Constant;
11710 if (c != null && c.IsNegative) {
11711 ec.Report.Error (247, loc, "Cannot use a negative size with stackalloc");
11714 if (ec.HasAny (ResolveContext.Options.CatchScope | ResolveContext.Options.FinallyScope)) {
11715 ec.Report.Error (255, loc, "Cannot use stackalloc in finally or catch");
11718 otype = texpr.ResolveAsType (ec);
11722 if (!TypeManager.VerifyUnmanaged (ec.Module, otype, loc))
11725 type = PointerContainer.MakeType (ec.Module, otype);
11726 eclass = ExprClass.Value;
11731 public override void Emit (EmitContext ec)
11733 int size = BuiltinTypeSpec.GetSize (otype);
11738 ec.Emit (OpCodes.Sizeof, otype);
11742 ec.Emit (OpCodes.Mul_Ovf_Un);
11743 ec.Emit (OpCodes.Localloc);
11746 protected override void CloneTo (CloneContext clonectx, Expression t)
11748 StackAlloc target = (StackAlloc) t;
11749 target.count = count.Clone (clonectx);
11750 target.texpr = texpr.Clone (clonectx);
11753 public override object Accept (StructuralVisitor visitor)
11755 return visitor.Visit (this);
11760 // An object initializer expression
11762 public class ElementInitializer : Assign
11764 public readonly string Name;
11766 public ElementInitializer (string name, Expression initializer, Location loc)
11767 : base (null, initializer, loc)
11772 public bool IsDictionaryInitializer {
11774 return Name == null;
11778 protected override void CloneTo (CloneContext clonectx, Expression t)
11780 ElementInitializer target = (ElementInitializer) t;
11781 target.source = source.Clone (clonectx);
11784 public override Expression CreateExpressionTree (ResolveContext ec)
11786 Arguments args = new Arguments (2);
11787 FieldExpr fe = target as FieldExpr;
11789 args.Add (new Argument (fe.CreateTypeOfExpression ()));
11791 args.Add (new Argument (((PropertyExpr) target).CreateSetterTypeOfExpression (ec)));
11794 Expression arg_expr;
11795 var cinit = source as CollectionOrObjectInitializers;
11796 if (cinit == null) {
11798 arg_expr = source.CreateExpressionTree (ec);
11800 mname = cinit.IsEmpty || cinit.Initializers[0] is ElementInitializer ? "MemberBind" : "ListBind";
11801 arg_expr = cinit.CreateExpressionTree (ec, !cinit.IsEmpty);
11804 args.Add (new Argument (arg_expr));
11805 return CreateExpressionFactoryCall (ec, mname, args);
11808 protected override Expression DoResolve (ResolveContext ec)
11810 if (source == null)
11811 return EmptyExpressionStatement.Instance;
11813 if (!ResolveElement (ec))
11816 if (source is CollectionOrObjectInitializers) {
11817 target = target.Resolve (ec);
11818 if (target == null)
11821 Expression previous = ec.CurrentInitializerVariable;
11822 ec.CurrentInitializerVariable = target;
11823 source = source.Resolve (ec);
11824 ec.CurrentInitializerVariable = previous;
11825 if (source == null)
11828 eclass = source.eclass;
11829 type = source.Type;
11834 return base.DoResolve (ec);
11837 public override void EmitStatement (EmitContext ec)
11839 if (source is CollectionOrObjectInitializers)
11842 base.EmitStatement (ec);
11845 protected virtual bool ResolveElement (ResolveContext rc)
11847 var t = rc.CurrentInitializerVariable.Type;
11848 if (t.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
11849 Arguments args = new Arguments (1);
11850 args.Add (new Argument (rc.CurrentInitializerVariable));
11851 target = new DynamicMemberBinder (Name, args, loc);
11853 var member = MemberLookup (rc, false, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11854 if (member == null) {
11855 member = Expression.MemberLookup (rc, true, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
11857 if (member != null) {
11858 // TODO: ec.Report.SymbolRelatedToPreviousError (member);
11859 ErrorIsInaccesible (rc, member.GetSignatureForError (), loc);
11864 if (member == null) {
11865 Error_TypeDoesNotContainDefinition (rc, loc, t, Name);
11869 var me = member as MemberExpr;
11870 if (me is EventExpr) {
11871 me = me.ResolveMemberAccess (rc, null, null);
11872 } else if (!(member is PropertyExpr || member is FieldExpr)) {
11873 rc.Report.Error (1913, loc,
11874 "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
11875 member.GetSignatureForError ());
11881 rc.Report.Error (1914, loc,
11882 "Static field or property `{0}' cannot be assigned in an object initializer",
11883 me.GetSignatureForError ());
11887 me.InstanceExpression = rc.CurrentInitializerVariable;
11895 // A collection initializer expression
11897 class CollectionElementInitializer : Invocation
11899 public class ElementInitializerArgument : Argument
11901 public ElementInitializerArgument (Expression e)
11907 sealed class AddMemberAccess : MemberAccess
11909 public AddMemberAccess (Expression expr, Location loc)
11910 : base (expr, "Add", loc)
11914 public override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
11916 if (TypeManager.HasElementType (type))
11919 base.Error_TypeDoesNotContainDefinition (ec, type, name);
11923 public CollectionElementInitializer (Expression argument)
11924 : base (null, new Arguments (1))
11926 base.arguments.Add (new ElementInitializerArgument (argument));
11927 this.loc = argument.Location;
11930 public CollectionElementInitializer (List<Expression> arguments, Location loc)
11931 : base (null, new Arguments (arguments.Count))
11933 foreach (Expression e in arguments)
11934 base.arguments.Add (new ElementInitializerArgument (e));
11939 public CollectionElementInitializer (Location loc)
11940 : base (null, null)
11945 public override Expression CreateExpressionTree (ResolveContext ec)
11947 Arguments args = new Arguments (2);
11948 args.Add (new Argument (mg.CreateExpressionTree (ec)));
11950 var expr_initializers = new ArrayInitializer (arguments.Count, loc);
11951 foreach (Argument a in arguments) {
11952 if (a.ArgType == Argument.AType.ExtensionType) {
11953 ec.Report.Error (8075, a.Expr.Location, "An expression tree cannot contain a collection initializer with extension method");
11956 expr_initializers.Add (a.CreateExpressionTree (ec));
11959 args.Add (new Argument (new ArrayCreation (
11960 CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
11961 return CreateExpressionFactoryCall (ec, "ElementInit", args);
11964 protected override void CloneTo (CloneContext clonectx, Expression t)
11966 CollectionElementInitializer target = (CollectionElementInitializer) t;
11967 if (arguments != null)
11968 target.arguments = arguments.Clone (clonectx);
11971 protected override Expression DoResolve (ResolveContext ec)
11973 base.expr = new AddMemberAccess (ec.CurrentInitializerVariable, loc);
11975 return base.DoResolve (ec);
11979 class DictionaryElementInitializer : ElementInitializer
11981 readonly Arguments args;
11983 public DictionaryElementInitializer (Arguments arguments, Expression initializer, Location loc)
11984 : base (null, initializer, loc)
11986 this.args = arguments;
11989 public override Expression CreateExpressionTree (ResolveContext ec)
11991 ec.Report.Error (8074, loc, "Expression tree cannot contain a dictionary initializer");
11995 protected override bool ResolveElement (ResolveContext rc)
11997 var init = rc.CurrentInitializerVariable;
11998 var type = init.Type;
12000 if (type.IsArray) {
12001 target = new ArrayAccess (new ElementAccess (init, args, loc), loc);
12005 if (type.IsPointer) {
12006 target = init.MakePointerAccess (rc, type, args);
12010 var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
12011 if (indexers == null && type.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12012 ElementAccess.Error_CannotApplyIndexing (rc, type, loc);
12016 target = new IndexerExpr (indexers, type, init, args, loc);
12022 // A block of object or collection initializers
12024 public class CollectionOrObjectInitializers : ExpressionStatement
12026 IList<Expression> initializers;
12027 bool is_collection_initialization;
12029 public CollectionOrObjectInitializers (Location loc)
12030 : this (new Expression[0], loc)
12034 public CollectionOrObjectInitializers (IList<Expression> initializers, Location loc)
12036 this.initializers = initializers;
12040 public IList<Expression> Initializers {
12042 return initializers;
12046 public bool IsEmpty {
12048 return initializers.Count == 0;
12052 public bool IsCollectionInitializer {
12054 return is_collection_initialization;
12058 protected override void CloneTo (CloneContext clonectx, Expression target)
12060 CollectionOrObjectInitializers t = (CollectionOrObjectInitializers) target;
12062 t.initializers = new List<Expression> (initializers.Count);
12063 foreach (var e in initializers)
12064 t.initializers.Add (e.Clone (clonectx));
12067 public override bool ContainsEmitWithAwait ()
12069 foreach (var e in initializers) {
12070 if (e.ContainsEmitWithAwait ())
12077 public override Expression CreateExpressionTree (ResolveContext ec)
12079 return CreateExpressionTree (ec, false);
12082 public Expression CreateExpressionTree (ResolveContext ec, bool inferType)
12084 var expr_initializers = new ArrayInitializer (initializers.Count, loc);
12085 foreach (Expression e in initializers) {
12086 Expression expr = e.CreateExpressionTree (ec);
12088 expr_initializers.Add (expr);
12092 return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
12094 return new ArrayCreation (new TypeExpression (ec.Module.PredefinedTypes.MemberBinding.Resolve (), loc), expr_initializers, loc);
12097 protected override Expression DoResolve (ResolveContext ec)
12099 List<string> element_names = null;
12100 for (int i = 0; i < initializers.Count; ++i) {
12101 Expression initializer = initializers [i];
12102 ElementInitializer element_initializer = initializer as ElementInitializer;
12105 if (element_initializer != null) {
12106 element_names = new List<string> (initializers.Count);
12107 if (!element_initializer.IsDictionaryInitializer)
12108 element_names.Add (element_initializer.Name);
12109 } else if (initializer is CompletingExpression) {
12110 initializer.Resolve (ec);
12111 throw new InternalErrorException ("This line should never be reached");
12113 var t = ec.CurrentInitializerVariable.Type;
12114 // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
12115 if (!t.ImplementsInterface (ec.BuiltinTypes.IEnumerable, false) && t.BuiltinType != BuiltinTypeSpec.Type.Dynamic) {
12116 ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
12117 "object initializer because type `{1}' does not implement `{2}' interface",
12118 ec.CurrentInitializerVariable.GetSignatureForError (),
12119 ec.CurrentInitializerVariable.Type.GetSignatureForError (),
12120 ec.BuiltinTypes.IEnumerable.GetSignatureForError ());
12123 is_collection_initialization = true;
12126 if (is_collection_initialization != (element_initializer == null)) {
12127 ec.Report.Error (747, initializer.Location, "Inconsistent `{0}' member declaration",
12128 is_collection_initialization ? "collection initializer" : "object initializer");
12132 if (!is_collection_initialization && !element_initializer.IsDictionaryInitializer) {
12133 if (element_names.Contains (element_initializer.Name)) {
12134 ec.Report.Error (1912, element_initializer.Location,
12135 "An object initializer includes more than one member `{0}' initialization",
12136 element_initializer.Name);
12138 element_names.Add (element_initializer.Name);
12143 Expression e = initializer.Resolve (ec);
12144 if (e == EmptyExpressionStatement.Instance)
12145 initializers.RemoveAt (i--);
12147 initializers [i] = e;
12150 type = ec.CurrentInitializerVariable.Type;
12151 if (is_collection_initialization) {
12152 if (TypeManager.HasElementType (type)) {
12153 ec.Report.Error (1925, loc, "Cannot initialize object of type `{0}' with a collection initializer",
12154 type.GetSignatureForError ());
12158 eclass = ExprClass.Variable;
12162 public override void Emit (EmitContext ec)
12164 EmitStatement (ec);
12167 public override void EmitStatement (EmitContext ec)
12169 foreach (ExpressionStatement e in initializers) {
12170 // TODO: need location region
12171 ec.Mark (e.Location);
12172 e.EmitStatement (ec);
12176 public override void FlowAnalysis (FlowAnalysisContext fc)
12178 foreach (var initializer in initializers) {
12179 if (initializer != null)
12180 initializer.FlowAnalysis (fc);
12186 // New expression with element/object initializers
12188 public class NewInitialize : New
12191 // This class serves as a proxy for variable initializer target instances.
12192 // A real variable is assigned later when we resolve left side of an
12195 sealed class InitializerTargetExpression : Expression, IMemoryLocation
12197 NewInitialize new_instance;
12199 public InitializerTargetExpression (NewInitialize newInstance)
12201 this.type = newInstance.type;
12202 this.loc = newInstance.loc;
12203 this.eclass = newInstance.eclass;
12204 this.new_instance = newInstance;
12207 public override bool ContainsEmitWithAwait ()
12212 public override Expression CreateExpressionTree (ResolveContext ec)
12214 // Should not be reached
12215 throw new NotSupportedException ("ET");
12218 protected override Expression DoResolve (ResolveContext ec)
12223 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
12228 public override void Emit (EmitContext ec)
12230 Expression e = (Expression) new_instance.instance;
12234 public override Expression EmitToField (EmitContext ec)
12236 return (Expression) new_instance.instance;
12239 #region IMemoryLocation Members
12241 public void AddressOf (EmitContext ec, AddressOp mode)
12243 new_instance.instance.AddressOf (ec, mode);
12249 CollectionOrObjectInitializers initializers;
12250 IMemoryLocation instance;
12251 DynamicExpressionStatement dynamic;
12253 public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
12254 : base (requested_type, arguments, l)
12256 this.initializers = initializers;
12259 public CollectionOrObjectInitializers Initializers {
12261 return initializers;
12265 protected override void CloneTo (CloneContext clonectx, Expression t)
12267 base.CloneTo (clonectx, t);
12269 NewInitialize target = (NewInitialize) t;
12270 target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
12273 public override bool ContainsEmitWithAwait ()
12275 return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
12278 public override Expression CreateExpressionTree (ResolveContext ec)
12280 Arguments args = new Arguments (2);
12281 args.Add (new Argument (base.CreateExpressionTree (ec)));
12282 if (!initializers.IsEmpty)
12283 args.Add (new Argument (initializers.CreateExpressionTree (ec, initializers.IsCollectionInitializer)));
12285 return CreateExpressionFactoryCall (ec,
12286 initializers.IsCollectionInitializer ? "ListInit" : "MemberInit",
12290 protected override Expression DoResolve (ResolveContext rc)
12292 Expression e = base.DoResolve (rc);
12296 if (type.IsDelegate) {
12297 rc.Report.Error (1958, Initializers.Location,
12298 "Object and collection initializers cannot be used to instantiate a delegate");
12301 Expression previous = rc.CurrentInitializerVariable;
12302 rc.CurrentInitializerVariable = new InitializerTargetExpression (this);
12303 using (rc.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false)) {
12304 initializers.Resolve (rc);
12306 rc.CurrentInitializerVariable = previous;
12308 dynamic = e as DynamicExpressionStatement;
12309 if (dynamic != null)
12315 public override void Emit (EmitContext ec)
12317 if (!CanEmitOptimizedLocalTarget (ec)) {
12318 var fe = ec.GetTemporaryField (type);
12320 if (!Emit (ec, fe))
12329 public override bool Emit (EmitContext ec, IMemoryLocation target)
12332 // Expression is initialized into temporary target then moved
12333 // to real one for atomicity
12335 IMemoryLocation temp_target = target;
12337 LocalTemporary temp = null;
12338 bool by_ref = false;
12339 if (!initializers.IsEmpty) {
12340 temp_target = target as LocalTemporary;
12341 if (temp_target == null)
12342 temp_target = target as StackFieldExpr;
12344 if (temp_target == null) {
12345 var vr = target as VariableReference;
12346 if (vr != null && vr.IsRef) {
12352 if (temp_target == null)
12353 temp_target = temp = new LocalTemporary (type);
12356 bool left_on_stack;
12357 if (dynamic != null) {
12359 left_on_stack = true;
12361 left_on_stack = base.Emit (ec, temp_target);
12364 if (initializers.IsEmpty)
12365 return left_on_stack;
12367 StackFieldExpr sf = null;
12369 // Move a new instance (reference-type) to local temporary variable
12370 if (left_on_stack) {
12372 temp_target = temp = new LocalTemporary (type);
12378 if (ec.HasSet (BuilderContext.Options.AsyncBody) && initializers.ContainsEmitWithAwait ()) {
12380 throw new NotImplementedException ();
12382 sf = ec.GetTemporaryField (type);
12383 sf.AutomaticallyReuse = false;
12384 sf.EmitAssign (ec, temp, false, false);
12387 left_on_stack = false;
12391 instance = temp_target;
12393 initializers.Emit (ec);
12395 ((Expression)temp_target).Emit (ec);
12401 sf.PrepareCleanup (ec);
12406 public override bool CanEmitOptimizedLocalTarget (EmitContext ec)
12408 return !(method == null && TypeSpec.IsValueType (type) &&
12409 initializers.Initializers.Count > 1 && ec.HasSet (BuilderContext.Options.AsyncBody) &&
12410 initializers.ContainsEmitWithAwait ());
12413 protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
12415 instance = base.EmitAddressOf (ec, Mode);
12417 if (!initializers.IsEmpty)
12418 initializers.Emit (ec);
12423 public override void FlowAnalysis (FlowAnalysisContext fc)
12425 base.FlowAnalysis (fc);
12426 initializers.FlowAnalysis (fc);
12429 public override object Accept (StructuralVisitor visitor)
12431 return visitor.Visit (this);
12435 public class NewAnonymousType : New
12437 static readonly AnonymousTypeParameter[] EmptyParameters = new AnonymousTypeParameter[0];
12439 List<AnonymousTypeParameter> parameters;
12440 readonly TypeContainer parent;
12441 AnonymousTypeClass anonymous_type;
12443 public NewAnonymousType (List<AnonymousTypeParameter> parameters, TypeContainer parent, Location loc)
12444 : base (null, null, loc)
12446 this.parameters = parameters;
12447 this.parent = parent;
12450 public List<AnonymousTypeParameter> Parameters {
12452 return this.parameters;
12456 protected override void CloneTo (CloneContext clonectx, Expression target)
12458 if (parameters == null)
12461 NewAnonymousType t = (NewAnonymousType) target;
12462 t.parameters = new List<AnonymousTypeParameter> (parameters.Count);
12463 foreach (AnonymousTypeParameter atp in parameters)
12464 t.parameters.Add ((AnonymousTypeParameter) atp.Clone (clonectx));
12467 AnonymousTypeClass CreateAnonymousType (ResolveContext ec, IList<AnonymousTypeParameter> parameters)
12469 AnonymousTypeClass type = parent.Module.GetAnonymousType (parameters);
12473 type = AnonymousTypeClass.Create (parent, parameters, loc);
12477 int errors = ec.Report.Errors;
12478 type.CreateContainer ();
12479 type.DefineContainer ();
12480 type.ExpandBaseInterfaces ();
12482 if ((ec.Report.Errors - errors) == 0) {
12483 parent.Module.AddAnonymousType (type);
12484 type.PrepareEmit ();
12490 public override Expression CreateExpressionTree (ResolveContext ec)
12492 if (parameters == null)
12493 return base.CreateExpressionTree (ec);
12495 var init = new ArrayInitializer (parameters.Count, loc);
12496 foreach (var m in anonymous_type.Members) {
12497 var p = m as Property;
12499 init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
12502 var ctor_args = new ArrayInitializer (arguments.Count, loc);
12503 foreach (Argument a in arguments)
12504 ctor_args.Add (a.CreateExpressionTree (ec));
12506 Arguments args = new Arguments (3);
12507 args.Add (new Argument (new TypeOfMethod (method, loc)));
12508 args.Add (new Argument (new ArrayCreation (CreateExpressionTypeExpression (ec, loc), ctor_args, loc)));
12509 args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
12511 return CreateExpressionFactoryCall (ec, "New", args);
12514 protected override Expression DoResolve (ResolveContext ec)
12516 if (ec.HasSet (ResolveContext.Options.ConstantScope)) {
12517 ec.Report.Error (836, loc, "Anonymous types cannot be used in this expression");
12521 if (parameters == null) {
12522 anonymous_type = CreateAnonymousType (ec, EmptyParameters);
12523 RequestedType = new TypeExpression (anonymous_type.Definition, loc);
12524 return base.DoResolve (ec);
12527 bool error = false;
12528 arguments = new Arguments (parameters.Count);
12529 var t_args = new TypeSpec [parameters.Count];
12530 for (int i = 0; i < parameters.Count; ++i) {
12531 Expression e = parameters [i].Resolve (ec);
12537 arguments.Add (new Argument (e));
12538 t_args [i] = e.Type;
12544 anonymous_type = CreateAnonymousType (ec, parameters);
12545 if (anonymous_type == null)
12548 type = anonymous_type.Definition.MakeGenericType (ec.Module, t_args);
12549 method = (MethodSpec) MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly);
12550 eclass = ExprClass.Value;
12554 public override object Accept (StructuralVisitor visitor)
12556 return visitor.Visit (this);
12560 public class AnonymousTypeParameter : ShimExpression
12562 public readonly string Name;
12564 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
12565 : base (initializer)
12571 public AnonymousTypeParameter (Parameter parameter)
12572 : base (new SimpleName (parameter.Name, parameter.Location))
12574 this.Name = parameter.Name;
12575 this.loc = parameter.Location;
12578 public override bool Equals (object o)
12580 AnonymousTypeParameter other = o as AnonymousTypeParameter;
12581 return other != null && Name == other.Name;
12584 public override int GetHashCode ()
12586 return Name.GetHashCode ();
12589 protected override Expression DoResolve (ResolveContext ec)
12591 Expression e = expr.Resolve (ec);
12595 if (e.eclass == ExprClass.MethodGroup) {
12596 Error_InvalidInitializer (ec, e.ExprClassName);
12601 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || type.IsPointer || (e is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
12602 Error_InvalidInitializer (ec, type.GetSignatureForError ());
12609 protected virtual void Error_InvalidInitializer (ResolveContext ec, string initializer)
12611 ec.Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
12612 Name, initializer);
12616 public class CatchFilterExpression : BooleanExpression
12618 public CatchFilterExpression (Expression expr, Location loc)
12625 public class InterpolatedString : Expression
12627 readonly StringLiteral start, end;
12628 List<Expression> interpolations;
12629 Arguments arguments;
12631 public InterpolatedString (StringLiteral start, List<Expression> interpolations, StringLiteral end)
12633 this.start = start;
12635 this.interpolations = interpolations;
12636 loc = start.Location;
12639 protected override void CloneTo (CloneContext clonectx, Expression t)
12641 InterpolatedString target = (InterpolatedString) t;
12643 if (interpolations != null) {
12644 target.interpolations = new List<Expression> ();
12645 foreach (var interpolation in interpolations) {
12646 target.interpolations.Add (interpolation.Clone (clonectx));
12651 public Expression ConvertTo (ResolveContext rc, TypeSpec type)
12653 var factory = rc.Module.PredefinedTypes.FormattableStringFactory.Resolve ();
12654 if (factory == null)
12657 var ma = new MemberAccess (new TypeExpression (factory, loc), "Create", loc);
12658 var res = new Invocation (ma, arguments).Resolve (rc);
12659 if (res != null && res.Type != type)
12660 res = Convert.ExplicitConversion (rc, res, type, loc);
12665 public override bool ContainsEmitWithAwait ()
12667 if (interpolations == null)
12670 foreach (var expr in interpolations) {
12671 if (expr.ContainsEmitWithAwait ())
12678 public override Expression CreateExpressionTree (ResolveContext rc)
12680 var best = ResolveBestFormatOverload (rc);
12684 Expression instance = new NullLiteral (loc);
12685 var args = Arguments.CreateForExpressionTree (rc, arguments, instance, new TypeOfMethod (best, loc));
12686 return CreateExpressionFactoryCall (rc, "Call", args);
12689 protected override Expression DoResolve (ResolveContext rc)
12693 if (interpolations == null) {
12695 arguments = new Arguments (1);
12697 arguments = new Arguments (interpolations.Count);
12699 var sb = new StringBuilder (start.Value);
12700 for (int i = 0; i < interpolations.Count; ++i) {
12702 sb.Append ('{').Append (i / 2);
12703 var isi = (InterpolatedStringInsert)interpolations [i];
12704 if (isi.Alignment != null) {
12706 var value = isi.ResolveAligment (rc);
12708 sb.Append (value.Value);
12711 if (isi.Format != null) {
12713 sb.Append (isi.Format);
12717 arguments.Add (new Argument (isi.Resolve (rc)));
12719 sb.Append (((StringLiteral)interpolations [i]).Value);
12723 sb.Append (end.Value);
12724 str = sb.ToString ();
12727 arguments.Insert (0, new Argument (new StringLiteral (rc.BuiltinTypes, str, start.Location)));
12729 eclass = ExprClass.Value;
12730 type = rc.BuiltinTypes.String;
12734 public override void Emit (EmitContext ec)
12736 // No interpolation, convert to simple string result (needs to match string.Format unescaping)
12737 if (interpolations == null) {
12738 var str = start.Value.Replace ("{{", "{").Replace ("}}", "}");
12739 if (str != start.Value)
12740 new StringConstant (ec.BuiltinTypes, str, loc).Emit (ec);
12747 var best = ResolveBestFormatOverload (new ResolveContext (ec.MemberContext));
12751 var ca = new CallEmitter ();
12752 ca.Emit (ec, best, arguments, loc);
12755 public override void FlowAnalysis (FlowAnalysisContext fc)
12757 if (interpolations != null) {
12758 foreach (var expr in interpolations) {
12759 expr.FlowAnalysis (fc);
12764 MethodSpec ResolveBestFormatOverload (ResolveContext rc)
12766 var members = MemberCache.FindMembers (rc.BuiltinTypes.String, "Format", true);
12767 var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
12768 return res.ResolveMember<MethodSpec> (rc, ref arguments);
12772 public class InterpolatedStringInsert : CompositeExpression
12774 public InterpolatedStringInsert (Expression expr)
12779 public Expression Alignment { get; set; }
12780 public string Format { get; set; }
12782 protected override void CloneTo (CloneContext clonectx, Expression t)
12784 var target = (InterpolatedStringInsert)t;
12785 target.expr = expr.Clone (clonectx);
12786 if (Alignment != null)
12787 target.Alignment = Alignment.Clone (clonectx);
12790 protected override Expression DoResolve (ResolveContext rc)
12792 var expr = base.DoResolve (rc);
12797 // For better error reporting, assumes the built-in implementation uses object
12800 return Convert.ImplicitConversionRequired (rc, expr, rc.BuiltinTypes.Object, expr.Location);
12803 public override void FlowAnalysis (FlowAnalysisContext fc)
12805 Child.FlowAnalysis (fc);
12808 public int? ResolveAligment (ResolveContext rc)
12810 var c = Alignment.ResolveLabelConstant (rc);
12814 c = c.ImplicitConversionRequired (rc, rc.BuiltinTypes.Int);
12818 var value = (int) c.GetValueAsLong ();
12819 if (value > 32767 || value < -32767) {
12820 rc.Report.Warning (8094, 1, Alignment.Location,
12821 "Alignment value has a magnitude greater than 32767 and may result in a large formatted string");
12828 class ThrowExpression : ExpressionStatement
12832 public ThrowExpression (Expression expr, Location loc)
12838 protected override void CloneTo (CloneContext clonectx, Expression t)
12840 var target = (ThrowExpression)t;
12841 target.expr = expr.Clone (clonectx);
12844 public override bool ContainsEmitWithAwait ()
12846 return expr.ContainsEmitWithAwait ();
12849 public override Expression CreateExpressionTree (ResolveContext rc)
12851 rc.Report.Error (8188, loc, "An expression tree cannot not contain a throw expression");
12855 protected override Expression DoResolve (ResolveContext rc)
12857 expr = expr.Resolve (rc, ResolveFlags.Type | ResolveFlags.VariableOrValue);
12862 expr = Throw.ConvertType (rc, expr);
12864 eclass = ExprClass.Value;
12865 type = InternalType.ThrowExpr;
12869 public override void Emit (EmitContext ec)
12871 EmitStatement (ec);
12874 public override void EmitStatement (EmitContext ec)
12878 ec.Emit (OpCodes.Throw);
12881 public override void FlowAnalysis (FlowAnalysisContext fc)
12883 expr.FlowAnalysis (fc);
12886 public override Reachability MarkReachable (Reachability rc)
12888 return Reachability.CreateUnreachable ();